diff --git a/configure.ac b/configure.ac index 154351ad4..dec2f9d7d 100644 --- a/configure.ac +++ b/configure.ac @@ -1053,11 +1053,11 @@ AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_RAW_LINK_API],[${OPENTHREAD_ENABLE_RAW_LIN AC_ARG_WITH(examples, [AS_HELP_STRING([--with-examples=TARGET], - [Specify the examples from one of: none, posix, cc2538, cc2650, da15000, efr32, kw41z, nrf52840 @<:@default=none@:>@.])], + [Specify the examples from one of: none, posix, cc2538, cc2650, da15000, efr32, emsk, kw41z, nrf52840 @<:@default=none@:>@.])], [ case "${with_examples}" in - none|posix|cc2538|cc2650|da15000|efr32|kw41z|nrf52840) + none|posix|cc2538|cc2650|da15000|efr32|emsk|kw41z|nrf52840) ;; *) AC_MSG_ERROR([Invalid value ${with_examples} for --with-examples]) @@ -1095,6 +1095,11 @@ case ${with_examples} in AC_DEFINE_UNQUOTED([OPENTHREAD_EXAMPLES_EFR32],[${OPENTHREAD_EXAMPLES_EFR32}],[Define to 1 if you want to use efr32 examples]) ;; + emsk) + OPENTHREAD_EXAMPLES_EMSK=1 + AC_DEFINE_UNQUOTED([OPENTHREAD_EXAMPLES_EMSK],[${OPENTHREAD_EXAMPLES_EMSK}],[Define to 1 if you want to use emsk examples]) + ;; + kw41z) OPENTHREAD_EXAMPLES_KW41Z=1 AC_DEFINE_UNQUOTED([OPENTHREAD_EXAMPLES_KW41Z],[${OPENTHREAD_EXAMPLES_KW41Z}],[Define to 1 if you want to use kw41z examples]) @@ -1129,6 +1134,9 @@ AM_CONDITIONAL([OPENTHREAD_EXAMPLES_DA15000], [test "${OPENTHREAD_EXAMPLES}" = " AC_SUBST(OPENTHREAD_EXAMPLES_EFR32) AM_CONDITIONAL([OPENTHREAD_EXAMPLES_EFR32], [test "${OPENTHREAD_EXAMPLES}" = "efr32"]) +AC_SUBST(OPENTHREAD_EXAMPLES_EMSK) +AM_CONDITIONAL([OPENTHREAD_EXAMPLES_EMSK], [test "${OPENTHREAD_EXAMPLES}" = "emsk"]) + AC_SUBST(OPENTHREAD_EXAMPLES_KW41Z) AM_CONDITIONAL([OPENTHREAD_EXAMPLES_KW41Z], [test "${OPENTHREAD_EXAMPLES}" = "kw41z"]) @@ -1295,6 +1303,7 @@ examples/platforms/cc2538/Makefile examples/platforms/cc2650/Makefile examples/platforms/da15000/Makefile examples/platforms/efr32/Makefile +examples/platforms/emsk/Makefile examples/platforms/kw41z/Makefile examples/platforms/nrf52840/Makefile examples/platforms/posix/Makefile diff --git a/examples/Makefile-emsk b/examples/Makefile-emsk new file mode 100644 index 000000000..250f8cef5 --- /dev/null +++ b/examples/Makefile-emsk @@ -0,0 +1,328 @@ +# +# Copyright (c) 2017, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +.NOTPARALLEL: + +AR = arc-elf32-ar +CCAS = arc-elf32-gcc +CPP = arc-elf32-cpp +CC = arc-elf32-gcc +CXX = arc-elf32-g++ +LD = arc-elf32-gcc +STRIP = arc-elf32-strip +NM = arc-elf32-nm +RANLIB = arc-elf32-ranlib +OBJCOPY = arc-elf32-objcopy + +BuildJobs ?= 10 + +configure_OPTIONS = \ + --enable-cli-app=all \ + --enable-ncp-app=all \ + --with-ncp-bus=uart \ + --enable-default-logging \ + --with-examples=emsk \ + --with-platform-info=EMSK \ + $(NULL) + +ifeq ($(CERT_LOG),1) +configure_OPTIONS += --enable-cert-log +endif + +ifeq ($(COMMISSIONER),1) +configure_OPTIONS += --enable-commissioner +endif + +ifeq ($(JOINER),1) +configure_OPTIONS += --enable-joiner +endif + +ifeq ($(DHCP6_SERVER),1) +configure_OPTIONS += --enable-dhcp6-server +endif + +ifeq ($(DHCP6_CLIENT),1) +configure_OPTIONS += --enable-dhcp6-client +endif + +TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST)))).. +AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))).. + +CONFIG_FILE = OPENTHREAD_PROJECT_CORE_CONFIG_FILE='\"openthread-core-emsk-config.h\"' +CONFIG_FILE_PATH = $(AbsTopSourceDir)/examples/platforms/emsk/ + +COMMONCFLAGS := \ + -fdata-sections \ + -ffunction-sections \ + -Os \ + -g \ + -D$(CONFIG_FILE) \ + -I$(CONFIG_FILE_PATH) \ + $(NULL) + +CPPFLAGS += \ + $(COMMONCFLAGS) \ + $(target_CPPFLAGS) \ + $(NULL) + +CFLAGS += \ + $(COMMONCFLAGS) \ + $(target_CFLAGS) \ + $(NULL) + +CXXFLAGS += \ + $(COMMONCFLAGS) \ + $(target_CXXFLAGS) \ + -fno-exceptions \ + -fno-rtti \ + $(NULL) + +CCASFLAGS += \ + $(COMMONCCASFLAGS) \ + $(target_CCASFLAGS) \ + $(NULL) + +LDFLAGS += \ + $(COMMONCFLAGS) \ + $(target_LDFLAGS) \ + -nostartfiles \ + -specs=nano.specs \ + -Wl,--gc-sections \ + -Wl,-Map=map.map \ + -Wl,--defsym=_STACKSIZE=524288 \ + -Wl,--defsym=_HEAPSIZE=524288 \ + $(NULL) + +ECHO := @echo +MAKE := make +MKDIR_P := mkdir -p +LN_S := ln -s +RM_F := rm -f + +INSTALL := /usr/bin/install +INSTALLFLAGS := -p + +BuildPath = build +TopBuildDir = $(BuildPath) +AbsTopBuildDir = $(PWD)/$(TopBuildDir) + +ResultPath = output +TopResultDir = $(ResultPath) +AbsTopResultDir = $(PWD)/$(TopResultDir) + +TargetTuple = arc-elf32 + +ARCHS = arcem11d + +TopTargetLibDir = $(TopResultDir)/$(TargetTuple)/lib + +ifndef BuildJobs +BuildJobs := $(shell getconf _NPROCESSORS_ONLN) +endif +JOBSFLAG := -j$(BuildJobs) + +# +# configure-arch +# +# Configure OpenThread for the specified architecture. +# +# arch - The architecture to configure. +# +define configure-arch +$(ECHO) " CONFIG $(TargetTuple)..." +(cd $(BuildPath)/$(TargetTuple) && $(AbsTopSourceDir)/configure \ +INSTALL="$(INSTALL) $(INSTALLFLAGS)" \ +CPP="$(CPP)" CC="$(CC)" CXX="$(CXX)" CCAS="$(CCAS)" OBJC="$(OBJC)" OBJCXX="$(OBJCXX)" AR="$(AR)" RANLIB="$(RANLIB)" NM="$(NM)" STRIP="$(STRIP)" CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CCASFLAGS="$(CCASFLAGS)" LDFLAGS="$(LDFLAGS)" \ +--host=arc-elf32 \ +--prefix=/ \ +--exec-prefix=/$(TargetTuple) \ +$(configure_OPTIONS)) +endef # configure-arch + +# +# build-arch +# +# Build the OpenThread intermediate build products for the specified +# architecture. +# +# arch - The architecture to build. +# +define build-arch +$(ECHO) " BUILD $(TargetTuple)" +$(MAKE) $(JOBSFLAG) -C $(BuildPath)/$(TargetTuple) --no-print-directory \ +all +endef # build-arch + +# +# stage-arch +# +# Stage (install) the OpenThread final build products for the specified +# architecture. +# +# arch - The architecture to stage. +# +define stage-arch +$(ECHO) " STAGE $(TargetTuple)" +$(MAKE) $(JOBSFLAG) -C $(BuildPath)/$(TargetTuple) --no-print-directory \ +DESTDIR=$(AbsTopResultDir) \ +install +endef # stage-arch + +# +# ARCH_template +# +# Define macros, targets and rules to configure, build, and stage the +# OpenThread for a single architecture. +# +# arch - The architecture to instantiate the template for. +# +define ARCH_template +CONFIGURE_TARGETS += configure-$(1) +BUILD_TARGETS += do-build-$(1) +STAGE_TARGETS += stage-$(1) +BUILD_DIRS += $(BuildPath)/$(TargetTuple) +DIRECTORIES += $(BuildPath)/$(TargetTuple) + +configure-$(1): target_CPPFLAGS=$($(1)_target_CPPFLAGS) +configure-$(1): target_CFLAGS=$($(1)_target_CFLAGS) +configure-$(1): target_CXXFLAGS=$($(1)_target_CXXFLAGS) +configure-$(1): target_LDFLAGS=$($(1)_target_LDFLAGS) +configure-$(1): target_CCASFLAGS=$($(1)_target_CCASFLAGS) + +configure-$(1): $(BuildPath)/$(TargetTuple)/config.status + +$(BuildPath)/$(TargetTuple)/config.status: | $(BuildPath)/$(TargetTuple) + $$(call configure-arch,$(1)) + +do-build-$(1): configure-$(1) + +do-build-$(1): + +$$(call build-arch,$(1)) + +stage-$(1): do-build-$(1) + +stage-$(1): | $(TopResultDir) + $$(call stage-arch,$(1)) + +$(1): stage-$(1) +endef # ARCH_template + +.DEFAULT_GOAL := all + +all: stage + +# +# EMSK2.3 arcem11d +# + +# Common options +MKDEP_OPT = -MMD -MT $@ -MF $@.d +OPT_OLEVEL = -O0 + +# Include EMSK BSP folder +ALL_INCLUDES = -I$(top_srcdir)/third_party/synopsys/embarc_emsk_bsp \ + -I$(top_srcdir)/examples/platforms/emsk \ + -I$(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib + +# COMMON_COMPILE_OPT = -mno-sdata $(OPT_OLEVEL) \ + $(ALL_INCLUDES) $(MKDEP_OPT) + +# Core options of arcem11d in EMSK2.3 from ARC TCF file +COMMON_CORE_OPT_GNU = -mcpu=em4_fpuda \ + -mlittle-endian \ + -mcode-density \ + -mdiv-rem \ + -mswap \ + -mnorm \ + -mmpy-option=6 \ + -mbarrel-shifter \ + -mfpu=fpuda_all \ + --param l1-cache-size=16384 \ + --param l1-cache-line-size=32 + +CCORE_OPT_GNU += $(COMMON_CORE_OPT_GNU) +CXXCORE_OPT_GNU += $(COMMON_CORE_OPT_GNU) +ACORE_OPT_GNU += $(COMMON_CORE_OPT_GNU) +LCORE_OPT_GNU += $(COMMON_CORE_OPT_GNU) + +# C/CPP/ASM/Linker Options +COMPILE_OPT += $(CCORE_OPT_GNU) \ + $(COMMON_COMPILE_OPT) -std=gnu99 +CXX_COMPILE_OPT += $(CXXCORE_OPT_GNU) \ + $(COMMON_COMPILE_OPT) +ASM_OPT += $(ACORE_OPT_GNU) \ + $(COMMON_COMPILE_OPT) -x assembler-with-cpp +LINK_OPT += $(LCORE_OPT_GNU) \ + -mno-sdata -nostartfiles --verbose + +arcem11d_target_ABI = arcem11d +arcem11d_target_CPPFLAGS = $(CXX_COMPILE_OPT) +arcem11d_target_CFLAGS = $(COMPILE_OPT) +arcem11d_target_CXXFLAGS = $(CXX_COMPILE_OPT) +arcem11d_target_CCASFLAGS = $(ASM_OPT) +arcem11d_target_LDFLAGS = $(LINK_OPT) + +# Instantiate an architecture-specific build template for each target +# architecture. + +$(foreach arch,$(ARCHS),$(eval $(call ARCH_template,$(arch)))) + +# +# Common / Finalization +# + +configure: $(CONFIGURE_TARGETS) + +build: $(BUILD_TARGETS) + +stage: $(STAGE_TARGETS) + +DIRECTORIES = $(TopResultDir) $(TopResultDir)/$(TargetTuple)/lib $(BUILD_DIRS) + +CLEAN_DIRS = $(TopResultDir) $(BUILD_DIRS) + +all: stage + +$(DIRECTORIES): + $(ECHO) " MKDIR $@" + @$(MKDIR_P) "$@" + +clean: + $(ECHO) " CLEAN" + @$(RM_F) -r $(CLEAN_DIRS) + +help: + $(ECHO) "Simply type 'make -f $(firstword $(MAKEFILE_LIST))' to build OpenThread for the following " + $(ECHO) "architectures: " + $(ECHO) "" + $(ECHO) " $(ARCHS)" + $(ECHO) "" + $(ECHO) "To build only a particular architecture, specify: " + $(ECHO) "" + $(ECHO) " make -f $(firstword $(MAKEFILE_LIST)) " + $(ECHO) "" diff --git a/examples/apps/cli/Makefile.am b/examples/apps/cli/Makefile.am index 78bb8bd7f..9f09f2239 100644 --- a/examples/apps/cli/Makefile.am +++ b/examples/apps/cli/Makefile.am @@ -113,6 +113,16 @@ LDFLAGS_COMMON += \ $(NULL) endif # OPENTHREAD_EXAMPLES_EFR32 +if OPENTHREAD_EXAMPLES_EMSK +LDADD_COMMON += \ + $(top_builddir)/examples/platforms/emsk/libopenthread-emsk.a \ + $(NULL) + +LDFLAGS_COMMON += \ + -T $(top_srcdir)/examples/platforms/emsk/emsk.ld \ + $(NULL) +endif # OPENTHREAD_EXAMPLES_EMSK + if OPENTHREAD_EXAMPLES_NRF52840 LDADD_COMMON += \ $(top_builddir)/examples/platforms/nrf52840/libopenthread-nrf52840.a \ diff --git a/examples/apps/ncp/Makefile.am b/examples/apps/ncp/Makefile.am index e3c15d45f..462e979c3 100644 --- a/examples/apps/ncp/Makefile.am +++ b/examples/apps/ncp/Makefile.am @@ -113,6 +113,16 @@ LDFLAGS_COMMON += \ $(NULL) endif # OPENTHREAD_EXAMPLES_EFR32 +if OPENTHREAD_EXAMPLES_EMSK +LDADD_COMMON += \ + $(top_builddir)/examples/platforms/emsk/libopenthread-emsk.a \ + $(NULL) + +LDFLAGS_COMMON += \ + -T $(top_srcdir)/examples/platforms/emsk/emsk.ld \ + $(NULL) +endif # OPENTHREAD_EXAMPLES_EMSK + if OPENTHREAD_EXAMPLES_NRF52840 LDADD_COMMON += \ $(top_builddir)/examples/platforms/nrf52840/libopenthread-nrf52840.a \ diff --git a/examples/platforms/Makefile.am b/examples/platforms/Makefile.am index 6144235c7..fd2b21446 100644 --- a/examples/platforms/Makefile.am +++ b/examples/platforms/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, The OpenThread Authors. +# Copyright (c) 2017, The OpenThread Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,6 +35,7 @@ DIST_SUBDIRS = \ cc2650 \ da15000 \ efr32 \ + emsk \ kw41z \ nrf52840 \ posix \ @@ -63,6 +64,10 @@ if OPENTHREAD_EXAMPLES_EFR32 SUBDIRS += efr32 endif +if OPENTHREAD_EXAMPLES_EMSK +SUBDIRS += emsk +endif + if OPENTHREAD_EXAMPLES_KW41Z SUBDIRS += kw41z endif @@ -82,6 +87,7 @@ PRETTY_SUBDIRS = \ cc2650 \ da15000 \ efr32 \ + emsk \ kw41z \ nrf52840 \ posix \ diff --git a/examples/platforms/emsk/Makefile.am b/examples/platforms/emsk/Makefile.am new file mode 100644 index 000000000..c105702c7 --- /dev/null +++ b/examples/platforms/emsk/Makefile.am @@ -0,0 +1,172 @@ +# +# Copyright (c) 2017, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +include $(abs_top_nlbuild_autotools_dir)/automake/pre.am + +lib_LIBRARIES = libopenthread-emsk.a + +# Do not enable -Wconversion for emsk +override CFLAGS := $(filter-out -Wconversion,$(CFLAGS)) +override CXXFLAGS := $(filter-out -Wconversion,$(CXXFLAGS)) + +# Do not enable -pedantic-errors for emsk +override CFLAGS := $(filter-out -pedantic-errors,$(CFLAGS)) +override CXXFLAGS := $(filter-out -pedantic-errors,$(CXXFLAGS)) + +# Do not enable -Werror for emsk +override CFLAGS := $(filter-out -Werror,$(CFLAGS)) +override CXXFLAGS := $(filter-out -Werror,$(CXXFLAGS)) + +# Do not enable -Wformat for emsk +override CFLAGS := $(filter-out -Wformat,$(CFLAGS)) +override CXXFLAGS := $(filter-out -Wformat,$(CXXFLAGS)) + +libopenthread_emsk_a_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/examples/platforms \ + -I$(top_srcdir)/src/core \ + -I$(top_srcdir)/third_party/synopsys/embarc_emsk_bsp \ + -I$(top_srcdir)/examples/platforms/emsk \ + -I$(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib \ + -Wno-unknown-pragmas \ + -Wno-unused-function \ + -Wno-unused-parameter \ + -Wno-unused-variable \ + -Wno-implicit-function-declaration \ + -Wno-unused-variable \ + -Wno-unused-but-set-variable \ + -Wno-type-limits \ + -Wno-sign-compare \ + -Wno-unused-label \ + $(NULL) + +libopenthread_emsk_a_SOURCES = \ + alarm.c \ + flash.c \ + misc.c \ + platform.c \ + radio.c \ + random.c \ + uart.c \ + $(NULL) + +# EMSK BSP DIR +top_emsk_bspdir = @top_builddir@/third_party/synopsys/embarc_emsk_bsp + +libopenthread_emsk_a_SOURCES += \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_cxx_support.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_startup.S \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/arc_cache.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/arc_exc_asm.S \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/arc_exception.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/arc/arc_timer.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_init.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/board/board.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/common/console_io.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.c \ + $(NULL) + +libopenthread_emsk_a_SOURCES += \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_misc.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_sbrk.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/malloc.c \ + @top_builddir@/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.c \ + $(NULL) + + +noinst_HEADERS = \ + platform-emsk.h \ + $(NULL) + +noinst_HEADERS += \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux_hal.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk_hardware.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/common/console_io.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal_cfg.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart_hal.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_common.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_gpio.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_spi.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_uart.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_asm_common.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_builtin.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_cache.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_em.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_exception.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_feature_config.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_timer.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/embARC_error.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/inc/embARC_toolchain.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/arc_core_config.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/embARC_BSP_config.h \ + $(NULL) + +noinst_HEADERS += \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib/dirent.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.h \ + $(top_srcdir)/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.h \ + $(NULL) + +Dash = - +libopenthread_emsk_a_LIBADD = \ + $(shell find $(top_builddir)/examples/platforms/utils $(Dash)type f $(Dash)name "*.o") + +include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/examples/platforms/emsk/README.md b/examples/platforms/emsk/README.md new file mode 100644 index 000000000..d5a37824f --- /dev/null +++ b/examples/platforms/emsk/README.md @@ -0,0 +1,158 @@ +# OpenThread on EMSK Example + +This directory contains example platform drivers for Synopsys [DesignWare® ARC® EM][arcem] Starter Kit 2.3[(EMSK2.3)][emsk23] and Digilent [Pmod RF2][pmodrf2] equipped with the Microchip [MRF24J40][mrf24j40] IEEE 802.15.4â„¢ 2.4GHz RF transceiver. + +[arcem]: https://www.synopsys.com/designware-ip/processor-solutions/arc-processors/arc-em-family.html + +[emsk23]: https://www.synopsys.com/dw/ipdir.php?ds=arc_em_starter_kit + +[pmodrf2]: https://reference.digilentinc.com/reference/pmod/pmodrf2/start + +[mrf24j40]: http://www.microchip.com/wwwproducts/en/en027752 + +## Note + +The EMSK platform is a configurable, FPGA-based software development platform for the ARC EM Processor Family. Please note that: + +* The platform does not currently feature a True Random Number Generator (TRNG), which is required for certification to the Thread Specification. Users looking to certify the OpenThread implementation for their own ARC-based platforms will need to add a TRNG to their platform and modify our reference implementation based on EMSK accordingly in order to achieve certification for their platform. +* The platform does not currently contain a on-chip EUI64, which is required for a network device. Users will need to add a unique number as EUI64 for their own ARC-based platform in `/examples/platforms/emsk/radio.c`. It can be set manually or loaded from non-volatile memory. + +## Toolchain + +Download and install [GNU toolchain for ARC EM][gnu-toolchain]. + +[gnu-toolchain]: https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/tags + +Download and install [Digilent Adept Software][digilent-adept] for the Digilent JTAG-USB cable. + +[digilent-adept]: https://store.digilentinc.com/digilent-adept-2-download-only + +## Building the examples + +```bash +$ cd +$ ./bootstrap +$ make -f examples/Makefile-emsk clean +$ make -f examples/Makefile-emsk +``` + +After a successful build, the `elf` files can be found in +`/output/arc-elf32/bin`. You can convert them to `bin` +files using `arc-elf32-objcopy`: +```bash +$ arc-elf32-objcopy -O binary ot-cli-ftd ot-cli-ftd.bin +``` + +## Booting the binaries from SD card + +embARC [embarc] is an open software platform to facilitate the development of embedded systems based on ARCv2 processors. Download embARC [embarc] to generate and flash the EMSK bootloader from source code. See the application note [Using a secondary bootloader on the EMSK][bootloader-appnote] for details. + +[embarc]: https://embarc.org/index.html + +[bootloader-appnote]: https://embarc.org/pdf/20150710_embARC_application_note_secondary_bootloader.pdf + +Modify the file name `arc-elf32-ot-cli-ftd.bin` to `boot.bin`. Copy `boot.bin` to the SD card. The EMSK2.3 includes an SPI flash storage device pre-programmed with FPGA images containing different configurations of DesignWare® ARC EM cores. Set pins 1 and 4 of `SW1` DIP switch and press `FPGA configure` button to configure the ARC EM11D and secondary bootloader. + +## Running the example + +1. Prepare two EMSK2.3 boards and copy the `boot.bin` (CLI example) to the EMSK2.3 SD card (as shown above). + +2. The CLI example uses UART connection. To view raw UART output, start a terminal emulator like Tera Term and PuTTY. Connect EMSK J7 to the COM port with the following serial port settings: + - Baud rate: 115200 + - 8 data bits + - 1 stop bit + - No parity + - No flow control + +3. Open a terminal connection on the first board. The `boot.bin` in the SD card will be loaded to the EMSK after a few seconds. + + ```bash + MRF24J40 Init started. + MRF24J40 Init finished. + Node No. : + ``` + +4. Set the node number manually. Input `1` and press the `Enter` key in the terminal emulator. + + ```bash + Node No. :1 + OpenThread Init Finished + ``` + +4. Start a new Thread network. + + ```bash + > panid 0x1234 + Done + > ifconfig up + Done + > thread start + Done + ``` + +4. After a couple of seconds the node will become a Leader of the network. + + ```bash + > state + Leader + ``` + +5. Open a terminal connection and reset the second board. After a few seconds, input `2` and press the `Enter` key in the terminal emulator. + + ```bash + MRF24J40 Init started. + MRF24J40 Init finished. + Node No. :2 + OpenThread Init Finished + ``` + +6. Attach the second node to the network. + + ```bash + > panid 0x1234 + Done + > ifconfig up + Done + > thread start + Done + ``` + +6. After a couple of seconds the second node will attach and become a Child. + + ```bash + > state + Child + ``` + +7. List all IPv6 addresses of the first board. + + ```bash + > ipaddr + fdde:ad00:beef:0:0:ff:fe00:fc00 + fdde:ad00:beef:0:0:ff:fe00:ec00 + fdde:ad00:beef:0:4f6e:7e53:67c8:f5b0 + fe80:0:0:0:c462:f165:44eb:ef9f + ``` + +8. Choose one of them and send an ICMPv6 ping from the second board. + + ```bash + > ping fdde:ad00:beef:0:0:ff:fe00:ec00 + 8 bytes from fdde:ad00:beef:0:0:ff:fe00:ec00: icmp_seq=1 hlim=64 time=30ms + ``` + +For a list of all available commands, visit [OpenThread CLI Reference README.md][CLI]. + +[CLI]: https://github.com/openthread/openthread/blob/master/src/cli/README.md + +## Verification + +The following hardware have been used for testin and verification: + - ARC EM11D on EMSK2.3 + - Pmod RF2 + +The following toolchains and software have been used for testing and verification: + - arc-2016.09-release + - embARC 2016.05 + +The EMSK example has been verified by Synopsys with commit `064aba2`. diff --git a/examples/platforms/emsk/alarm.c b/examples/platforms/emsk/alarm.c new file mode 100755 index 000000000..53e0d618f --- /dev/null +++ b/examples/platforms/emsk/alarm.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for the alarm. + * + */ + +#include +#include +#include "openthread/platform/alarm.h" +#include "platform-emsk.h" + +static uint32_t sCounter = 0; +static uint32_t expires; +static bool sIsRunning = false; + +void emskAlarmInit(void) +{ + sCounter = OSP_GET_CUR_MS(); +} + +uint32_t otPlatAlarmGetNow(void) +{ + return (OSP_GET_CUR_MS() - sCounter); +} + +void otPlatAlarmStartAt(otInstance *aInstance, uint32_t t0, uint32_t dt) +{ + (void)aInstance; + expires = t0 + dt; + sIsRunning = true; +} + +void otPlatAlarmStop(otInstance *aInstance) +{ + (void)aInstance; + sIsRunning = false; +} + +void emskAlarmUpdateTimeout(int32_t *aTimeout) +{ + int32_t remaining; + + otEXPECT(aTimeout != NULL); + + if (sIsRunning) + { + remaining = (int32_t)(expires - otPlatAlarmGetNow()); + + if (remaining > 0) + { + *aTimeout = remaining; + } + else + { + *aTimeout = 0; + } + } + else + { + *aTimeout = 10000; + } + +exit: + return; + +} + +void emskAlarmProcess(otInstance *aInstance) +{ + int32_t remaining; + + if (sIsRunning) + { + remaining = (int32_t)(expires - otPlatAlarmGetNow()); + + if (remaining <= 0) + { + sIsRunning = false; + otPlatAlarmFired(aInstance); + } + + } + +} diff --git a/examples/platforms/emsk/emsk.ld b/examples/platforms/emsk/emsk.ld new file mode 100755 index 000000000..e4096b853 --- /dev/null +++ b/examples/platforms/emsk/emsk.ld @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +SEARCH_DIR(.) +GROUP(../../../examples/platforms/emsk/libopenthread-emsk.a libgcc.a libc.a libnosys.a) + +MEMORY +{ + ICCM : ORIGIN = 0x00000000, LENGTH = 0x10000 + DCCM : ORIGIN = 0x80000000, LENGTH = 0x10000 + EXT_RAM : ORIGIN = 0x10000000, LENGTH = 0x8000000 +} +ENTRY(_start) +SECTIONS +{ + .init : + { + _f_init = .; + KEEP (*(.init_vector)) + KEEP (*(.init_bootstrap)) + _e_init = .; + } > EXT_RAM + .vector : ALIGN(1024) + { + _f_vector = .; + *(.vector) + _e_vector = .; + } > EXT_RAM + .text : ALIGN(4) + { + _f_text = .; + *(.text .text.* .gnu.linkonce.t.*) + _e_text = .; + } > EXT_RAM + .rodata : ALIGN(4) + { + _f_rodata = .; + . = ALIGN(4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + KEEP(*(SORT_BY_NAME(".ctors*"))) + LONG(0) + __CTOR_END__ = .; + . = ALIGN(4); + __init_array_start = .; + KEEP(*(SORT_BY_NAME(".init_array*"))) + __init_array_end = .; + . = ALIGN(4); + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + KEEP(*(SORT_BY_NAME(".dtors*"))) + LONG(0) + __DTOR_END__ = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + _e_rodata = .; + } > EXT_RAM + .data : ALIGN(4) + { + _f_data = .; + *(.data .data.* .gnu.linkonce.d.*) + _f_sdata = .; + __SDATA_BEGIN__ = .; + *(.sdata .sdata.* .gnu.linkonce.s.*) + _e_sdata = .; + _e_data = .; + } > EXT_RAM AT > EXT_RAM + .bss (NOLOAD) : ALIGN(8) + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + _f_bss = .; + _f_sbss = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + _e_sbss = .; + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + _e_bss = .; + } > EXT_RAM + .stack (NOLOAD) : + { + . = ALIGN(4); + _f_stack = .; + . = . + 524288; + _e_stack = .; + } > EXT_RAM + .heap (NOLOAD) : + { + . = ALIGN(4); + __start_heap = . ; + _f_heap = .; + . = . + 524288; + _e_heap = .; + __end_heap = . ; + } > EXT_RAM + _load_addr_text = LOADADDR(.text); + _load_addr_rodata = LOADADDR(.rodata); + _load_addr_data = LOADADDR(.data); +} diff --git a/examples/platforms/emsk/flash.c b/examples/platforms/emsk/flash.c new file mode 100644 index 000000000..955074ffc --- /dev/null +++ b/examples/platforms/emsk/flash.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for flash. + * + */ + +#include +#include "openthread/platform/alarm.h" +#include +#include +#include "platform-emsk.h" + +/** + * EMSK HAS 128 Mbit (16 MB) SPI flash memory (Winbond W25Q128BV). + * The Winbond W25Q128BV array is organized into 65536 programmable pages of + * 256-byte each. Up to 256 bytes can be programmed at a time. Pages can be + * erased in groups of 16 (4KB sector erase). + */ + +/** + * EMSK SPIflash memory map with using embARC + * FPGA image: from 0x0000 0000 + * Secondary bootloader: from 0x0078 0000 + * Available for OpenThread: from 0x00FF D000 to 0x00FF EFFF + */ +#define OPENTHREAD_FLASH_BASE 0x00ffd000 +#define OPENTHREAD_FLASH_SIZE 0x00002000 + +/** + * Define SETTINGS_CONFIG_BASE_ADDRESS, + * SETTINGS_CONFIG_PAGE_SIZE, and + * SETTINGS_CONFIG_PAGE_NUM for EMSK + */ +#ifdef SETTINGS_CONFIG_BASE_ADDRESS +#undef SETTINGS_CONFIG_BASE_ADDRESS +#endif // SETTINGS_CONFIG_BASE_ADDRESS +#define SETTINGS_CONFIG_BASE_ADDRESS 0x00ffe000 + +#ifdef SETTINGS_CONFIG_PAGE_SIZE +#undef SETTINGS_CONFIG_PAGE_SIZE +#endif // SETTINGS_CONFIG_PAGE_SIZE +#define SETTINGS_CONFIG_PAGE_SIZE FLASH_SECTOR_SIZE + +#ifdef SETTINGS_CONFIG_PAGE_NUM +#undef SETTINGS_CONFIG_PAGE_NUM +#endif // SETTINGS_CONFIG_PAGE_NUM +#define SETTINGS_CONFIG_PAGE_NUM 1 + +ThreadError utilsFlashInit(void) +{ + flash_init(); + return kThreadError_None; +} + +uint32_t utilsFlashGetSize(void) +{ + return (uint32_t)FLASH_SECTOR_SIZE; +} + +ThreadError utilsFlashErasePage(uint32_t aAddress) +{ + ThreadError error = kThreadError_None; + int32_t status; + + otEXPECT_ACTION((aAddress >= OPENTHREAD_FLASH_BASE) && (aAddress < (OPENTHREAD_FLASH_BASE + OPENTHREAD_FLASH_SIZE - 1)), + error = kThreadError_InvalidArgs); + + /* Use 2 sectors in the implementation, cannot erase the address over the boundry */ + status = flash_erase(aAddress, FLASH_SECTOR_SIZE); + + otEXPECT_ACTION(status != -1, error = kThreadError_Failed); + +exit: + return error; +} + +ThreadError utilsFlashStatusWait(uint32_t aTimeout) +{ + ThreadError error = kThreadError_None; + uint32_t start = otPlatAlarmGetNow(); + bool busy = true; + uint32_t status = 0x01; + + while (busy && ((otPlatAlarmGetNow() - start) < aTimeout)) + { + status = flash_read_status(); + busy = status & 0x01; + } + + otEXPECT_ACTION(!busy, error = kThreadError_Busy); + +exit: + return error; +} + +uint32_t utilsFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize) +{ + int32_t written_size = 0; + uint32_t size = 0; + + otEXPECT_ACTION((aAddress >= OPENTHREAD_FLASH_BASE) && + ((aAddress + aSize) <= OPENTHREAD_FLASH_BASE + OPENTHREAD_FLASH_SIZE) && + (!(aAddress & 3)) && (!(aSize & 3)), ;); + + written_size = flash_write(aAddress, aSize, aData); + + if (written_size < 0) + { + size = 0; + } + else + { + size = (uint32_t)written_size; + } + +exit: + return size; +} + +uint32_t utilsFlashRead(uint32_t aAddress, uint8_t *aData, uint32_t aSize) +{ + int32_t read_size = 0; + uint32_t size = 0; + + otEXPECT_ACTION((aAddress >= OPENTHREAD_FLASH_BASE) && + ((aAddress + aSize) <= OPENTHREAD_FLASH_BASE + OPENTHREAD_FLASH_SIZE), ;); + + read_size = flash_read(aAddress, aSize, aData); + + if (read_size < 0) + { + size = 0; + } + else + { + size = (uint32_t)read_size; + } + + +exit: + return size; +} diff --git a/examples/platforms/emsk/logging.c b/examples/platforms/emsk/logging.c new file mode 100755 index 000000000..b436a40c9 --- /dev/null +++ b/examples/platforms/emsk/logging.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for logging. + * + */ + +#include "openthread/platform/logging.h" + +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...) +{ + (void)aLogLevel; + (void)aLogRegion; + (void)aFormat; +} + diff --git a/examples/platforms/emsk/misc.c b/examples/platforms/emsk/misc.c new file mode 100755 index 000000000..30df877ed --- /dev/null +++ b/examples/platforms/emsk/misc.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "openthread/platform/misc.h" +#include "platform-emsk.h" + +void otPlatReset(otInstance *aInstance) +{ + // Default + (void)aInstance; + mrf24j40_hard_reset(); +} + +otPlatResetReason otPlatGetResetReason(otInstance *aInstance) +{ + (void)aInstance; + // TODO: Write me! + return kPlatResetReason_PowerOn; +} + +void otPlatWakeHost(void) +{ + // TODO: implement an operation to wake the host from sleep state. +} diff --git a/examples/platforms/emsk/openthread-core-emsk-config.h b/examples/platforms/emsk/openthread-core-emsk-config.h new file mode 100644 index 000000000..94f1e443d --- /dev/null +++ b/examples/platforms/emsk/openthread-core-emsk-config.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes EMSK compile-time configuration constants for OpenThread. + */ + +#ifndef OPENTHREAD_CORE_EMSK_CONFIG_H_ +#define OPENTHREAD_CORE_EMSK_CONFIG_H_ + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + * + * Define to 1 if you want to enable software ACK timeout logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT 0 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + * + * Define to 1 if you want to enable software retransmission logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 0 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + * + * Define to 1 if you want to enable software energy scanning logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN 0 + +#endif // OPENTHREAD_CORE_EMSK_CONFIG_H_ diff --git a/examples/platforms/emsk/platform-emsk.h b/examples/platforms/emsk/platform-emsk.h new file mode 100755 index 000000000..217d84e32 --- /dev/null +++ b/examples/platforms/emsk/platform-emsk.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes the platform-specific initializers. + * + */ + +#ifndef PLATFORM_EMSK_H_ +#define PLATFORM_EMSK_H_ + +#include +#include +#include "openthread/types.h" + +#include "board/board.h" + +// Global OpenThread instance structure +extern otInstance *sInstance; + +/** + * This function initializes the alarm service used by OpenThread. + * + */ +void emskAlarmInit(void); + +/** + * This function retrieves the time remaining until the alarm fires. + * + * @param[out] aTimeval A pointer to timer value. + * + */ +void emskAlarmUpdateTimeout(int32_t *aTimeout); + +/** + * This function performs alarm driver processing. + * + */ +void emskAlarmProcess(otInstance *aInstance); + +/** + * This function initializes the radio service used by OpenThread. + * + */ +void emskRadioInit(void); + +/** + * This function performs radio driver processing. + * + */ +void emskRadioProcess(otInstance *aInstance); + +/** + * This function initializes the random number service used by OpenThread. + * + */ +void emskRandomInit(void); + +/** + * This function performs UART driver processing. + * + */ +void emskUartProcess(void); + +#endif // PLATFORM_EMSK_H_ diff --git a/examples/platforms/emsk/platform.c b/examples/platforms/emsk/platform.c new file mode 100755 index 000000000..ac79e400d --- /dev/null +++ b/examples/platforms/emsk/platform.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file includes the platform-specific initializers. + * + */ + +#include "openthread/openthread.h" +#include "openthread/platform/uart.h" +#include "platform-emsk.h" + +#include +#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__) + +void PlatformInit(int argc, char *argv[]) +{ + emskAlarmInit(); + emskRadioInit(); + emskRandomInit(); + otPlatUartEnable(); + + DBG("OpenThread Init Finished\r\n"); + + (void)argc; + (void)argv; +} + +void PlatformProcessDrivers(otInstance *aInstance) +{ + // sInstance = aInstance; + + emskUartProcess(); + emskRadioProcess(aInstance); + emskAlarmProcess(aInstance); +} diff --git a/examples/platforms/emsk/radio.c b/examples/platforms/emsk/radio.c new file mode 100644 index 000000000..1fa3509b6 --- /dev/null +++ b/examples/platforms/emsk/radio.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for radio communication. + * + */ + +#include "openthread/types.h" + +#include +#include "openthread/platform/radio.h" +#include "platform-emsk.h" + +#include "device/device_hal/inc/dev_gpio.h" +#include + +#include +#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__) + +enum +{ + IEEE802154_MIN_LENGTH = 5, + IEEE802154_MAX_LENGTH = 127, + IEEE802154_ACK_LENGTH = 5, + + IEEE802154_BROADCAST = 0xffff, + + IEEE802154_FRAME_TYPE_ACK = 2 << 0, + IEEE802154_FRAME_TYPE_MACCMD = 3 << 0, + IEEE802154_FRAME_TYPE_MASK = 7 << 0, + + IEEE802154_SECURITY_ENABLED = 1 << 3, + IEEE802154_FRAME_PENDING = 1 << 4, + IEEE802154_ACK_REQUEST = 1 << 5, + IEEE802154_PANID_COMPRESSION = 1 << 6, + + IEEE802154_DST_ADDR_NONE = 0 << 2, + IEEE802154_DST_ADDR_SHORT = 2 << 2, + IEEE802154_DST_ADDR_EXT = 3 << 2, + IEEE802154_DST_ADDR_MASK = 3 << 2, + + IEEE802154_SRC_ADDR_NONE = 0 << 6, + IEEE802154_SRC_ADDR_SHORT = 2 << 6, + IEEE802154_SRC_ADDR_EXT = 3 << 6, + IEEE802154_SRC_ADDR_MASK = 3 << 6, + + IEEE802154_DSN_OFFSET = 2, + IEEE802154_DSTPAN_OFFSET = 3, + IEEE802154_DSTADDR_OFFSET = 5, + + IEEE802154_SEC_LEVEL_MASK = 7 << 0, + + IEEE802154_KEY_ID_MODE_0 = 0 << 3, + IEEE802154_KEY_ID_MODE_1 = 1 << 3, + IEEE802154_KEY_ID_MODE_2 = 2 << 3, + IEEE802154_KEY_ID_MODE_3 = 3 << 3, + IEEE802154_KEY_ID_MODE_MASK = 3 << 3, + + IEEE802154_MACCMD_DATA_REQ = 4 +}; + +enum +{ + EMSK_RECEIVE_SENSITIVITY = -100, // dBm +}; + +enum +{ + MRF24J40_RSSI_OFFSET = 90, + MRF24J40_RSSI_SLOPE = 5 +}; + +static void radioTransmitMessage(otInstance *aInstance); + +static RadioPacket sTransmitFrame; +static RadioPacket sReceiveFrame; +static RadioPacket sAckFrame; + +static ThreadError sTransmitError; +static ThreadError sReceiveError; + +static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH]; +static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH]; +static uint8_t sAckPsdu[IEEE802154_MAX_LENGTH]; + +static PhyState sState = kStateDisabled; +static bool sIsReceiverEnabled = false; + +static volatile uint8_t Mrf24StatusTx = 0; +static volatile uint8_t Mrf24StatusRx = 0; +static volatile uint8_t Mrf24StatusSec = 0; + +static DEV_SPI_PTR pmrf_spi_ptr; +static DEV_GPIO_PTR pmrf_gpio_ptr; +static void RadioIsr(void *ptr); + +/* Variables for test */ +static uint32_t numInterruptRev = 0; +static uint32_t numInterruptTrans = 0; +static uint32_t numRadioProcess = 0; + +static inline bool isSecurityEnabled(const uint8_t *frame) +{ + return (frame[0] & IEEE802154_SECURITY_ENABLED) != 0; +} + +static inline bool isAckRequested(const uint8_t *frame) +{ + return (frame[0] & IEEE802154_ACK_REQUEST) != 0; +} + +static inline bool isPanIdCompressed(const uint8_t *frame) +{ + return (frame[0] & IEEE802154_PANID_COMPRESSION) != 0; +} + +static inline uint8_t getHeadLength(const uint8_t *frame) +{ + uint8_t length = 0; + /* Frame Control-2 + Sequence Number-1 */ + length += 2 + 1; + + /* Destination PAN + Address */ + switch (frame[1] & IEEE802154_DST_ADDR_MASK) + { + case IEEE802154_DST_ADDR_SHORT: + length += sizeof(otPanId) + sizeof(otShortAddress); + break; + + case IEEE802154_DST_ADDR_EXT: + length += sizeof(otPanId) + sizeof(otExtAddress); + break; + + default: + length = 0; + goto exit; + } + + /* Source PAN + Address */ + switch (frame[1] & IEEE802154_SRC_ADDR_MASK) + { + case IEEE802154_SRC_ADDR_SHORT: + if (!isPanIdCompressed(frame)) + { + length += sizeof(otPanId); + } + + length += sizeof(otShortAddress); + break; + + case IEEE802154_SRC_ADDR_EXT: + if (!isPanIdCompressed(frame)) + { + length += sizeof(otPanId); + } + + length += sizeof(otExtAddress); + break; + + default: + length = 0; + goto exit; + } + +exit: + return length; +} + +void enableReceiver(void) +{ + if (!sIsReceiverEnabled) + { + mrf24j40_rxfifo_flush(); + /* add code to enable receiver (wakeup) */ + sIsReceiverEnabled = true; + } +} + +void disableReceiver(void) +{ + if (sIsReceiverEnabled) + { + mrf24j40_rxfifo_flush(); + /* add code to disable receiver (sleep) */ + sIsReceiverEnabled = false; + } +} + +void setChannel(uint8_t channel) +{ + mrf24j40_set_channel((int16_t)(channel - 11)); +} + +void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + (void)aInstance; + /* should set it manually or preset it in memory */ + aIeeeEui64[0] = 0x00; + aIeeeEui64[1] = 0x50; + aIeeeEui64[2] = 0xC2; + aIeeeEui64[3] = 0xFF; + aIeeeEui64[4] = 0XFE; + aIeeeEui64[5] = 0X1D; + aIeeeEui64[6] = 0X30; + aIeeeEui64[7] = 0x00; +} + +void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid) +{ + (void)aInstance; + uint8_t pan[2]; + + pan[0] = (uint8_t)(panid & 0xFF); + pan[1] = (uint8_t)(panid >> 8); + mrf24j40_set_pan(pan); +} + +void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *address) +{ + (void)aInstance; + mrf24j40_set_eui(address); +} + +void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t address) +{ + (void)aInstance; + uint8_t addr[2]; + + addr[0] = (uint8_t)(address & 0xFF); + addr[1] = (uint8_t)(address >> 8); + mrf24j40_set_short_addr(addr); +} + +void emskRadioInit(void) +{ + DEV_GPIO_BIT_ISR isr; + DEV_GPIO_INT_CFG int_cfg; + + int32_t ercd; + uint32_t temp; + + sTransmitFrame.mLength = 0; + sTransmitFrame.mPsdu = sTransmitPsdu; + sReceiveFrame.mLength = 0; + sReceiveFrame.mPsdu = sReceivePsdu; + sAckFrame.mLength = 0; + sAckFrame.mPsdu = sAckPsdu; + + pmrf_spi_ptr = spi_get_dev(EMSK_PMRF_0_SPI_ID); + ercd = pmrf_spi_ptr->spi_open(DEV_MASTER_MODE, EMSK_PMRF_0_SPIFREQ); + + if ((ercd != E_OK) && (ercd != E_OPNED)) + { + DBG("PmodRF2 SPI open error\r\n"); + } + + pmrf_spi_ptr->spi_control(SPI_CMD_SET_CLK_MODE, CONV2VOID(EMSK_PMRF_0_SPICLKMODE)); + + /*MRF24J40 wakepin:output, rstpin:output, INT_PIN:input, interrupt */ + pmrf_gpio_ptr = gpio_get_dev(EMSK_PMRF_0_GPIO_ID); + ercd = pmrf_gpio_ptr->gpio_open(MRF24J40_WAKE_PIN | MRF24J40_RST_PIN); + + if ((ercd != E_OK) && (ercd != E_OPNED)) + { + DBG("PmodRF2 CRTL port open error"); + } + + if (ercd == E_OPNED) + { + pmrf_gpio_ptr->gpio_control(GPIO_CMD_SET_BIT_DIR_OUTPUT, (void *)(MRF24J40_WAKE_PIN | MRF24J40_RST_PIN)); + pmrf_gpio_ptr->gpio_control(GPIO_CMD_SET_BIT_DIR_INPUT, (void *)MRF24J40_INT_PIN); + } + + pmrf_gpio_ptr->gpio_control(GPIO_CMD_DIS_BIT_INT, (void *)MRF24J40_INT_PIN); + + temp = MRF24J40_INT_PIN; + int_cfg.int_bit_mask = temp; + int_cfg.int_bit_type = GPIO_INT_BITS_EDGE_TRIG(temp); + int_cfg.int_bit_polarity = GPIO_INT_BITS_POL_FALL_EDGE(temp); + int_cfg.int_bit_debounce = GPIO_INT_BITS_DIS_DEBOUNCE(temp); + pmrf_gpio_ptr->gpio_control(GPIO_CMD_SET_BIT_INT_CFG, (void *)(&int_cfg)); + + isr.int_bit_ofs = MRF24J40_INT_PIN_OFS; + isr.int_bit_handler = RadioIsr; + pmrf_gpio_ptr->gpio_control(GPIO_CMD_SET_BIT_ISR, (void *)(&isr)); + + /* interrupt for mrf24j40 is enabled at the end of the init process */ + DBG("MRF24J40 Init Started\r\n"); + mrf24j40_initialize(); + DBG("MRF24J40 Init Finished\r\n"); + + pmrf_gpio_ptr->gpio_control(GPIO_CMD_ENA_BIT_INT, (void *)MRF24J40_INT_PIN); + +} + +bool otPlatRadioIsEnabled(otInstance *aInstance) +{ + (void)aInstance; + return (sState != kStateDisabled); +} + +ThreadError otPlatRadioEnable(otInstance *aInstance) +{ + if (!otPlatRadioIsEnabled(aInstance)) + { + sState = kStateSleep; + } + + return kThreadError_None; +} + +ThreadError otPlatRadioDisable(otInstance *aInstance) +{ + if (otPlatRadioIsEnabled(aInstance)) + { + sState = kStateDisabled; + } + + return kThreadError_None; +} + +ThreadError otPlatRadioSleep(otInstance *aInstance) +{ + ThreadError error = kThreadError_InvalidState; + (void)aInstance; + + if (sState == kStateSleep || sState == kStateReceive) + { + error = kThreadError_None; + sState = kStateSleep; + disableReceiver(); + } + + return error; +} + +ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) +{ + ThreadError error = kThreadError_InvalidState; + (void)aInstance; + + if (sState != kStateDisabled) + { + error = kThreadError_None; + sState = kStateReceive; + setChannel(aChannel); + sReceiveFrame.mChannel = aChannel; + enableReceiver(); + } + + return error; +} + +ThreadError otPlatRadioTransmit(otInstance *aInstance, RadioPacket *aPacket) +{ + ThreadError error = kThreadError_InvalidState; + (void)aInstance; + (void)aPacket; + + if (sState == kStateReceive) + { + error = kThreadError_None; + sState = kStateTransmit; + } + + return error; + +} + +RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + (void)aInstance; + return &sTransmitFrame; +} + +int8_t otPlatRadioGetRssi(otInstance *aInstance) +{ + (void)aInstance; + return 0; +} + +otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) +{ + (void)aInstance; + return kRadioCapsNone; +} + +bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + (void)aInstance; + return (bool)(mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) & MRF24J40_PROMI); +} + +// should be checked again with CC2538 +void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) +{ + (void)aInstance; + mrf24j40_set_promiscuous(~aEnable); +} + +void readFrame(void) +{ + + /* readBuffer + * 1 bit -- 5 to 127 bits -- 1 bit -- 1bit + * Frame Length -- PSDU (Header + Data Payload + FCS) -- LQI -- RSSI + */ + uint8_t readBuffer[MRF24J40_RXFIFO_SIZE]; + uint8_t readPlqi = 0; + uint8_t readRssi = 0; + + uint16_t length; + int16_t i; + + memset(readBuffer, 0, MRF24J40_RXFIFO_SIZE); + + otEXPECT_ACTION(sState == kStateReceive || sState == kStateTransmit, ;); + otEXPECT_ACTION(Mrf24StatusRx, ;); + + if (Mrf24StatusRx == 1) + { + Mrf24StatusRx = 0; + } + + if (Mrf24StatusSec == 1) + { + Mrf24StatusSec = 0; + } + + /* Read length */ + length = (uint16_t)mrf24j40_rxpkt_intcb(readBuffer, &readPlqi, &readRssi); + + otEXPECT_ACTION(IEEE802154_MIN_LENGTH <= length && length <= IEEE802154_MAX_LENGTH, ;); + + /* Read PSDU */ + memcpy(sReceiveFrame.mPsdu, readBuffer, length - 2); + + sReceiveFrame.mPower = (int8_t)(readRssi / MRF24J40_RSSI_SLOPE) - MRF24J40_RSSI_OFFSET; + sReceiveFrame.mLength = (uint8_t) length; + sReceiveFrame.mLqi = readPlqi; + +exit: + return; + +} + +void radioTransmitMessage(otInstance *aInstance) +{ + (void)aInstance; + uint8_t header_len = 0; + + sTransmitError = kThreadError_None; + setChannel(sTransmitFrame.mChannel); + + uint8_t reg = mrf24j40_read_short_ctrl_reg(MRF24J40_TXNCON); + + header_len = getHeadLength(sTransmitFrame.mPsdu); + + if (isAckRequested(sTransmitFrame.mPsdu)) + { + reg |= MRF24J40_TXNACKREQ; + } + else + { + reg &= ~(MRF24J40_TXNACKREQ); + } + + if (isSecurityEnabled(sTransmitFrame.mPsdu)) + { + reg |= MRF24J40_TXNSECEN; + } + else + { + reg &= ~(MRF24J40_TXNSECEN); + mrf24j40_write_short_ctrl_reg(MRF24J40_TXNCON, mrf24j40_read_short_ctrl_reg(MRF24J40_TXNCON) & (~MRF24J40_TXNSECEN)); + } + + mrf24j40_txfifo_write(MRF24J40_TXNFIFO, sTransmitFrame.mPsdu, header_len, (sTransmitFrame.mLength - 2)); + + mrf24j40_write_short_ctrl_reg(MRF24J40_TXNCON, reg | MRF24J40_TXNTRIG); + + int16_t tx_timeout = 500; + Mrf24StatusTx = 0; + + while ((tx_timeout > 0) && (Mrf24StatusTx != 1)) + { + mrf24j40_delay_ms(1); + tx_timeout--; + + if (tx_timeout <= 0) + { + DBG("Radio Transmit Timeout!!!!!!!!!!!!\r\n"); + } + } +} + +void emskRadioProcess(otInstance *aInstance) +{ + numRadioProcess++; + + readFrame(); + uint8_t reg = mrf24j40_read_short_ctrl_reg(MRF24J40_TXSTAT); + + if (reg & MRF24J40_TXNSTAT) + { + DBG("TX MAC Timeout!!!!!!\r\n"); + + if (reg & MRF24J40_CCAFAIL) + { + DBG("Channel busy!!!!!!\r\n"); + } + } + + if ((sState == kStateReceive) && (sReceiveFrame.mLength > 0)) + { + otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); + } + + if (sState == kStateTransmit) + { + radioTransmitMessage(aInstance); + + if (sTransmitError != kThreadError_None || (sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0) + { + sState = kStateReceive; + otPlatRadioTransmitDone(aInstance, &sTransmitFrame, false, sTransmitError); + } + else if (Mrf24StatusTx == 1) + { + Mrf24StatusTx = 0; + sState = kStateReceive; + otPlatRadioTransmitDone(aInstance, &sTransmitFrame, + (mrf24j40_read_short_ctrl_reg(MRF24J40_TXNCON) & MRF24J40_FPSTAT) != 0, + sTransmitError); + } + } + + sReceiveFrame.mLength = 0; + +} + +/** + * \brief isr routine of mrf24j40 + * \param[in] ptr pointer transferred frome interrupt entry + */ +static void RadioIsr(void *ptr) +{ + uint8_t int_status = 0; + + int_status = pmrf_read_short_ctrl_reg(MRF24J40_INTSTAT); + + /* a frame is received */ + if (int_status & MRF24J40_RXIF) + { + numInterruptRev++; + Mrf24StatusRx = 1; + } + + /* a frame is transmitted */ + if (int_status & MRF24J40_TXNIF) + { + switch (mrf24j40_txpkt_intcb()) + { + case MRF24J40_EBUSY: + /* Channel busy */ + break; + + case MRF24J40_EIO: + /* Channel idle */ + break; + + case 0: + numInterruptTrans++; + Mrf24StatusTx = 1; + break; + } + } + + /* a frame with security key request is received */ + if (int_status & MRF24J40_SECIF) + { + Mrf24StatusSec = 1; + mrf24j40_sec_intcb(false); + } + +} + +/* CC2538 supports source address matching for low power consumption + and this is not supported in MRF24J40 */ +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + (void)aInstance; + (void)aEnable; +} + +ThreadError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return kThreadError_None; +} + +ThreadError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return kThreadError_None; +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + (void)aInstance; +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + (void)aInstance; +} + +ThreadError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + (void)aInstance; + (void)aScanChannel; + (void)aScanDuration; + return kThreadError_NotImplemented; +} + +void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower) +{ + // TODO: Create a proper implementation for this driver. + (void)aInstance; + (void)aPower; +} + +int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) +{ + (void)aInstance; + return EMSK_RECEIVE_SENSITIVITY; +} diff --git a/examples/platforms/emsk/random.c b/examples/platforms/emsk/random.c new file mode 100755 index 000000000..60087ef1e --- /dev/null +++ b/examples/platforms/emsk/random.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements a pseudo-random number generator. + * + * @warning + * This implementation is not a true random number generator and does @em satisfy the Thread requirements. + * + */ + +#include + +#include "openthread/platform/random.h" +#include "openthread/platform/radio.h" +#include "platform-emsk.h" + +#include + +#include + +static unsigned int seed; + +void emskRandomInit(void) +{ + unsigned int i; + + printf("Node No.:"); + scanf("%d", &i); + printf("%d\n", i); + seed = 10 + i; + srand(seed); +} + +uint32_t otPlatRandomGet(void) +{ + + return (uint32_t)rand(); +} + +ThreadError otPlatRandomGetTrue(uint8_t *aOutput, uint16_t aOutputLength) +{ + ThreadError error = kThreadError_None; + uint8_t channel = 0; + + otEXPECT_ACTION(aOutput && aOutputLength, error = kThreadError_InvalidArgs); + + /* disable radio*/ + if (otPlatRadioIsEnabled(sInstance)) + { + channel = (mrf24j40_read_long_ctrl_reg(MRF24J40_RFCON0) >> 4) + 11; + otPlatRadioSleep(sInstance); + otPlatRadioDisable(sInstance); + } + + /* + * THE IMPLEMENTATION BELOW IS NOT COMPLIANT WITH THE THREAD SPECIFICATION. + * + * Please see Note in `/examples/platforms/emsk/README.md` + * for TRNG features on EMSK. + */ + otEXPECT_ACTION(aOutput && aOutputLength, error = kThreadError_InvalidArgs); + + for (uint16_t length = 0; length < aOutputLength; length++) + { + /* Get random number */ + aOutput[length] = (uint8_t)otPlatRandomGet(); + } + + /* Enable radio*/ + if (channel) + { + emskRadioInit(); + otPlatRadioEnable(sInstance); + otPlatRadioReceive(sInstance, channel); + } + +exit: + return error; +} diff --git a/examples/platforms/emsk/uart.c b/examples/platforms/emsk/uart.c new file mode 100644 index 000000000..af4923c32 --- /dev/null +++ b/examples/platforms/emsk/uart.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for UART communication. + * + */ + +#include + +#include "openthread/types.h" +#include +#include "openthread/platform/uart.h" +#include "platform-emsk.h" + +#include +#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__) + +enum +{ + kUartId = BOARD_CONSOLE_UART_ID, + kBaudRate = BOARD_CONSOLE_UART_BAUD, + kReceiveBufferSize = 128, +}; + +static void processReceive(void); +static void processTransmit(void); + +static const uint8_t *sTransmitBuffer = NULL; +static uint16_t sTransmitLength = 0; + +static uint8_t sReceiveBuffer[kReceiveBufferSize]; +static uint16_t sReceiveHead = 0; + +static DEV_UART *consoleUart; + +ThreadError otPlatUartEnable(void) +{ + int32_t stateUart = 0; + ThreadError error = kThreadError_Drop; + + /* UART in embARC */ + consoleUart = uart_get_dev(BOARD_CONSOLE_UART_ID); + + otEXPECT_ACTION(!(consoleUart == NULL), DBG("Console UART is missing.\r\n")); + + stateUart = consoleUart->uart_open(BOARD_CONSOLE_UART_BAUD); + + if (stateUart == E_OPNED) + { + consoleUart->uart_control(UART_CMD_SET_BAUD, (void *)(BOARD_CONSOLE_UART_BAUD)); + error = kThreadError_None; + DBG("Set Console UART Baudrate to %d.\r\n", BOARD_CONSOLE_UART_BAUD); + } + else if (stateUart == E_OK) + { + error = kThreadError_None; + DBG("Open Console UART Successfully.\r\n"); + } + else + { + DBG("Open Console UART Error.\r\n"); + } + +exit: + + return error; + +} + +ThreadError otPlatUartDisable(void) +{ + return kThreadError_None; +} + +ThreadError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength) +{ + ThreadError error = kThreadError_None; + + otEXPECT_ACTION(sTransmitBuffer == NULL, error = kThreadError_Busy); + + sTransmitBuffer = aBuf; + sTransmitLength = aBufLength; + +exit: + return error; +} + +void processReceive(void) +{ + + int32_t rdAvail = 0; + uint16_t remaining; + + consoleUart->uart_control(UART_CMD_GET_RXAVAIL, (void *)(&rdAvail)); + otEXPECT_ACTION(rdAvail > 0, ;); + + remaining = kReceiveBufferSize - sReceiveHead; + + if (rdAvail >= remaining) + { + consoleUart->uart_read((void *)(sReceiveBuffer + sReceiveHead), (uint32_t)remaining); + otPlatUartReceived(sReceiveBuffer + sReceiveHead, remaining); + sReceiveHead = 0; + rdAvail -= (int32_t)remaining; + } + + while (rdAvail >= kReceiveBufferSize) + { + consoleUart->uart_read((void *)(sReceiveBuffer + sReceiveHead), (uint32_t)kReceiveBufferSize); + otPlatUartReceived(sReceiveBuffer + sReceiveHead, kReceiveBufferSize); + rdAvail -= kReceiveBufferSize; + } + + if (rdAvail > 0) + { + consoleUart->uart_read((void *)(sReceiveBuffer + sReceiveHead), (uint32_t)rdAvail); + otPlatUartReceived(sReceiveBuffer + sReceiveHead, rdAvail); + sReceiveHead += (uint16_t)rdAvail; + } + +exit: + return; +} + +void processTransmit(void) +{ + otEXPECT_ACTION(sTransmitBuffer != NULL, ;); + + consoleUart->uart_write((void *)sTransmitBuffer, (int32_t)sTransmitLength); + + sTransmitBuffer = NULL; + otPlatUartSendDone(); + +exit: + return; +} + +void emskUartProcess(void) +{ + processReceive(); + processTransmit(); +} + diff --git a/third_party/Makefile.am b/third_party/Makefile.am index 19ed12672..5aff31d99 100644 --- a/third_party/Makefile.am +++ b/third_party/Makefile.am @@ -34,6 +34,7 @@ EXTRA_DIST = \ nlbuild-autotools \ openthread-test-driver \ NordicSemiconductor \ + synopsys \ $(NULL) if OPENTHREAD_EXAMPLES_EFR32 diff --git a/third_party/synopsys/embarc_emsk_bsp/README.md b/third_party/synopsys/embarc_emsk_bsp/README.md new file mode 100644 index 000000000..03854d367 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/README.md @@ -0,0 +1,21 @@ +# embARC Board Support Package (BSP) +## Introduction +embARC BSP is a board support package to facilitate the development of embedded systems based on ARCv2 processors. + +It is designed to provide a board support package for ARCv2 users by defining consistent and simple software interfaces to the processor and peripherals. + +## URL +https://www.embarc.org/ + +## License +Copyright (c) 2017, Synopsys, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3) Neither the name of the Synopsys, Inc., nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/arc_cache.c b/third_party/synopsys/embarc_emsk_bsp/arc/arc_cache.c new file mode 100644 index 000000000..cf25e684b --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/arc_cache.c @@ -0,0 +1,482 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_MISC_CACHE + * \brief implementation of cache related functions + */ + +#include "inc/arc/arc_cache.h" + +#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) + + +struct cache_config +{ + uint8_t ver; /* version */ + uint8_t assoc; /* Cache Associativity */ + uint16_t line; /* cache line/block size */ + uint32_t capacity; /* capacity */ +}; + + +static struct cache_config icache_config, dcache_config; + +/** + * \brief invalidate multi instruction cache lines + * + * \param[in] start_addr start address in instruction cache + * \param[in] size the bytes to be invalidated + * \return 0, succeeded, -1, failed + */ +int32_t icache_invalidate_mlines(uint32_t start_addr, uint32_t size) +{ + if (!icache_available()) { return -1; } + + if ((size == 0) || (size > icache_config.capacity)) + { + return -1; + } + + uint32_t end_addr; + uint32_t line_size; + uint32_t status; + + line_size = (uint32_t)(icache_config.line); + end_addr = start_addr + size - 1; + start_addr &= (uint32_t)(~(line_size - 1)); + + status = cpu_lock_save(); + + do + { + _arc_aux_write(AUX_IC_IVIL, start_addr); + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); + start_addr += line_size; + } + while (start_addr <= end_addr); + + cpu_unlock_restore(status); + + return 0; +} + +/** + * \brief lock multi lines in instruction cache + * + * \param[in] start_addr start address in instruction cache + * \param[in] size the bytes to be locked + * \return 0, succeeded, -1, failed (cache already locked or other reasons) + */ +int32_t icache_lock_mlines(uint32_t start_addr, uint32_t size) +{ + if (!icache_available()) { return -1; } + + if ((size == 0) || (size > icache_config.capacity)) + { + return -1; + } + + uint32_t end_addr; + uint32_t line_size; + uint32_t status; + int32_t ercd = 0; + + line_size = (uint32_t)(icache_config.line); + end_addr = start_addr + size - 1; + start_addr &= (uint32_t)(~(line_size - 1)); + + status = cpu_lock_save(); + + do + { + _arc_aux_write(AUX_IC_LIL, start_addr); + + if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) + { + start_addr += line_size; + } + else + { + ercd = -1; /* the operation failed */ + break; + } + } + while (start_addr <= end_addr); + + cpu_unlock_restore(status); + + return ercd; +} + +/** + * \brief directly write icache internal ram + * + * \param[in] cache_addr, icache internal address(way+index+offset) + * \param[in] tag cache tag to write (tag+lock bit+valid bit) + * \param[in] data cache data to write + * \return 0, succeeded, -1, failed + */ +int32_t icache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data) +{ + if (!icache_available()) { return -1; } + + if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS) + { + return -1; + } + + _arc_aux_write(AUX_IC_RAM_ADDR, cache_addr); + _arc_aux_write(AUX_IC_TAG, tag); + _arc_aux_write(AUX_IC_DATA, data); + + return 0; +} + +/** + * \brief directly read icache internal ram + * + * \param[in] cache_addr, icache internal address(way+index+offset) + * \param[out] tag cache tag to read (tag+index+lock bit+valid bit) + * \param[out] data cache data to read + * \return 0, succeeded, -1, failed + */ +int32_t icache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data) +{ + if (!icache_available()) { return -1; } + + if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS) + { + return -1; + } + + _arc_aux_write(AUX_IC_RAM_ADDR, cache_addr); + *tag = _arc_aux_read(AUX_IC_TAG); + *data = _arc_aux_read(AUX_IC_DATA); + + return 0; +} + +/** + * \brief indirectly read icache internal ram + * + * \param[in] mem_addr, memory address + * \param[out] tag cache tag to read + * \param[out] data cache data to read + * \return 0, succeeded, -1, failed + */ +int32_t icache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data) +{ + if (!icache_available()) { return -1; } + + if (!(_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS)) + { + return -1; + } + + _arc_aux_write(AUX_IC_RAM_ADDR, mem_addr); + + if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) + { + *tag = _arc_aux_read(AUX_IC_TAG); + *data = _arc_aux_read(AUX_IC_DATA); + } + else + { + return -1; /* the specified memory is not in icache */ + } + + return 0; +} + +/** + * \brief invalidate multi data cache lines + * + * \param[in] start_addr start address in data cache + * \param[in] size the bytes to be invalidated + * \return 0, succeeded, -1, failed + */ +int32_t dcache_invalidate_mlines(uint32_t start_addr, uint32_t size) +{ + if (!dcache_available()) { return -1; } + + uint32_t end_addr; + uint32_t line_size; + uint32_t status; + + if ((size == 0) || (size > dcache_config.capacity)) + { + return -1; + } + + line_size = (uint32_t)(dcache_config.line); + end_addr = start_addr + size - 1; + start_addr &= (uint32_t)(~(line_size - 1)); + + status = cpu_lock_save(); + + do + { + _arc_aux_write(AUX_DC_IVDL, start_addr); + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); + + /* wait for flush completion */ + while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); + + start_addr += line_size; + } + while (start_addr <= end_addr); + + cpu_unlock_restore(status); + + return 0; + +} + +/** + * \brief flush multi lines in data cache + * + * \param[in] start_addr start address + * \param[in] size the bytes to be flushed + * \return 0, succeeded, -1, failed + */ +int32_t dcache_flush_mlines(uint32_t start_addr, uint32_t size) +{ + if (!dcache_available()) { return -1; } + + if ((size == 0) || (size > dcache_config.capacity)) + { + return -1; + } + + uint32_t end_addr; + uint32_t line_size; + uint32_t status; + + line_size = (uint32_t)(dcache_config.line); + end_addr = start_addr + size - 1; + start_addr &= (uint32_t)(~(line_size - 1)); + + status = cpu_lock_save(); + + do + { + _arc_aux_write(AUX_DC_FLDL, start_addr); + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); + + /* wait for flush completion */ + while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); + + start_addr += line_size; + } + while (start_addr <= end_addr); + + cpu_unlock_restore(status); + + return 0; +} + +/** + * \brief lock multi lines in data cache + * + * \param[in] start_addr start address in data cache + * \param[in] size the bytes to be locked + * \return 0, succeeded, -1, failed + */ +int32_t dcache_lock_mlines(uint32_t start_addr, uint32_t size) +{ + if (!dcache_available()) { return -1; } + + if ((size == 0) || (size > dcache_config.capacity)) + { + return -1; + } + + uint32_t end_addr; + uint32_t line_size; + uint32_t status; + int32_t ercd = 0; + + line_size = (uint32_t)(dcache_config.line); + end_addr = start_addr + size - 1; + start_addr &= (uint32_t)(~(line_size - 1)); + + status = cpu_lock_save(); + + do + { + _arc_aux_write(AUX_DC_LDL, start_addr); + Asm("nop_s"); + + if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) + { + start_addr += line_size; + } + else + { + ercd = -1; /* the operation failed */ + break; + } + } + while (start_addr <= end_addr); + + cpu_unlock_restore(status); + + return ercd; +} + +/** + * \brief directly write dcache internal ram + * + * \param[in] cache_addr, dcache internal address(way+index+offset) + * \param[in] tag cache tag to write + * \param[in] data cache data to write + * \return 0, succeeded, -1, failed + */ +int32_t dcache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data) +{ + if (!dcache_available()) { return -1; } + + if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS) + { + return -1; + } + + _arc_aux_write(AUX_DC_RAM_ADDR, cache_addr); + _arc_aux_write(AUX_DC_TAG, tag); + _arc_aux_write(AUX_DC_DATA, data); + + return 0; +} + +/** + * \brief directly read dcache internal ram + * + * \param[in] cache_addr, dcache internal address(way+index+offset) + * \param[out] tag cache tag to read + * \param[out] data cache data to read + * \return 0, succeeded, -1, failed + */ +int32_t dcache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data) +{ + if (!dcache_available()) { return -1; } + + if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS) + { + return -1; + } + + _arc_aux_write(AUX_DC_RAM_ADDR, cache_addr); + *tag = _arc_aux_read(AUX_DC_TAG); + *data = _arc_aux_read(AUX_DC_DATA); + + return 0; +} + +/** + * \brief indirectly read dcache internal ram + * + * \param[in] mem_addr, memory address(tag+index+offset) + * \param[out] tag cache tag to read + * \param[out] data cache data to read + * \return 0, succeeded, -1, failed + */ +int32_t dcache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data) +{ + if (!dcache_available()) { return -1; } + + if (!(_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS)) + { + return -1; + } + + _arc_aux_write(AUX_DC_RAM_ADDR, mem_addr); + + if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) + { + *tag = _arc_aux_read(AUX_DC_TAG); + *data = _arc_aux_read(AUX_DC_DATA); + } + else + { + return -1; /* the specified memory is not in dcache */ + } + + return 0; +} + +/** + * \brief initialize cache + * 1. invalidate icache and dcache + * 2. Only support ARCv2 cache + */ +void arc_cache_init(void) +{ + uint32_t build_cfg; + + build_cfg = _arc_aux_read(AUX_BCR_D_CACHE); + + dcache_config.ver = build_cfg & 0xff; + + if (dcache_config.ver >= 0x04) /* ARCv2 */ + { + dcache_enable(DC_CTRL_DISABLE_FLUSH_LOCKED | + DC_CTRL_INDIRECT_ACCESS | DC_CTRL_INVALID_FLUSH); + dcache_invalidate(); + dcache_config.assoc = 1 << ((build_cfg >> 8) & 0xf); + dcache_config.capacity = 512 << ((build_cfg >> 12) & 0xf); + dcache_config.line = 16 << ((build_cfg >> 16) & 0xf); + } + + build_cfg = _arc_aux_read(AUX_BCR_I_CACHE); + + icache_config.ver = build_cfg & 0xff; + + if (icache_config.ver >= 0x04) /* ARCv2 */ + { + icache_config.assoc = 1 << ((build_cfg >> 8) & 0xf); + icache_config.capacity = 512 << ((build_cfg >> 12) & 0xf); + icache_config.line = 8 << ((build_cfg >> 16) & 0xf); + + icache_enable(IC_CTRL_IC_ENABLE); + icache_invalidate(); + } + +} diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/arc_exc_asm.S b/third_party/synopsys/embarc_emsk_bsp/arc/arc_exc_asm.S new file mode 100644 index 000000000..3af9d8331 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/arc_exc_asm.S @@ -0,0 +1,202 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief assembly part of exception and interrupt processing + */ + +/** + * \addtogroup ARC_HAL_EXCEPTION_CPU + * @{ + */ + +/* function documentation */ +/** + * \fn void exc_entry_cpu(void) + * \brief default entry of CPU exceptions, such as TLB miss and swap. + * + * \fn void exc_entry_int(void) + * \brief normal interrupt exception entry. + * In default, all interrupt exceptions are installed with normal entry. + * If FIRQ is required, exc_entry_firq should be the entry. + * + * \fn void exc_entry_firq(void) + * \brief firq exception entry + */ +/** }@ */ + +/** @cond EXCEPTION_ASM */ + +#define __ASSEMBLY__ +#include "embARC_BSP_config.h" +#include "../inc/arc/arc.h" +#include "../inc/arc/arc_asm_common.h" + +.file "arc_exc_asm.S" + +/* entry for cpu exception handling */ +.text +.global exc_entry_cpu +.weak exc_entry_cpu +.align 4 +exc_entry_cpu: + +EXCEPTION_PROLOGUE + +mov r3, sp /* as exception handler's para(exc_frame) */ + +/* exc_nest_count +1 */ +ld r0, [exc_nest_count] +add r0, r0, 1 +st r0, [exc_nest_count] + +/* find the exception cause */ +lr r0, [AUX_ECR] +lsr r0, r0, 16 +bmsk r0, r0, 7 +mov r1, exc_int_handler_table +ld.as r2, [r1, r0] + +mov r0, r3 +jl [r2] /* jump to exception handler where interrupts are not allowed! */ + +/* interrupts are not allowed */ +exc_return: + +/* exc_nest_count -1 */ +ld r0, [exc_nest_count] +sub r0, r0, 1 +st r0, [exc_nest_count] + +EXCEPTION_EPILOGUE +rtie + + +/****** entry for normal interrupt exception handling ******/ +.global exc_entry_int +.weak exc_entry_int +.align 4 +exc_entry_int: +clri /* disable interrupt */ + +#if ARC_FEATURE_FIRQ == 1 +#if ARC_FEATURE_RGF_NUM_BANKS > 1 +lr r0, [AUX_IRQ_ACT] /* check whether it is P0 interrupt */ +btst r0, 0 +bnz exc_entry_firq +#else +PUSH r10 +lr r10, [AUX_IRQ_ACT] +btst r10, 0 +POP r10 +bnz exc_entry_firq +#endif +#endif +INTERRUPT_PROLOGUE /* save scratch regs, this will be affected */ + + +/* exc_nest_count +1 */ +ld r0, [exc_nest_count] +add r0, r0, 1 +st r0, [exc_nest_count] + + +lr r0, [AUX_IRQ_CAUSE] +mov r1, exc_int_handler_table +ld.as r2, [r1, r0] /* r2 = _kernel_exc_tbl + irqno *4 */ + +/* for the case of software triggered interrupt */ +lr r3, [AUX_IRQ_HINT] +cmp r3, r0 +bne.d irq_hint_handled +xor r3, r3, r3 +sr r3, [AUX_IRQ_HINT] +irq_hint_handled: +seti /* enable higher priority interrupt */ + +mov r0, sp +jl [r2] /* jump to interrupt handler */ + +/* no interrupts are allowed from here */ +int_return: +clri /* disable interrupt */ + +/* exc_nest_count -1 */ +ld r0, [exc_nest_count] +sub r0, r0, 1 +st r0, [exc_nest_count] + +INTERRUPT_EPILOGUE +rtie + +/****** entry for fast irq exception handling ******/ +.global exc_entry_firq +.weak exc_entry_firq +.align 4 +exc_entry_firq: +clri /* disable interrupt */ +SAVE_FIQ_EXC_REGS + +/* exc_nest_count +1 */ +ld r0, [exc_nest_count] +add r0, r0, 1 +st r0, [exc_nest_count] + +lr r0, [AUX_IRQ_CAUSE] +mov r1, exc_int_handler_table +ld.as r2, [r1, r0] /* r2 = _kernel_exc_tbl + irqno *4 */ + +/* for the case of software triggered interrupt */ +lr r3, [AUX_IRQ_HINT] +cmp r3, r0 +bne.d firq_hint_handled +xor r3, r3, r3 +sr r3, [AUX_IRQ_HINT] +firq_hint_handled: + +jl [r2] /* jump to interrupt handler */ + +/* no interrupts are allowed from here */ +firq_return: + +/* exc_nest_count -1 */ +ld r0, [exc_nest_count] +sub r0, r0, 1 +st r0, [exc_nest_count] + +RESTORE_FIQ_EXC_REGS +rtie + +/** @endcond */ diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/arc_exception.c b/third_party/synopsys/embarc_emsk_bsp/arc/arc_exception.c new file mode 100644 index 000000000..b2ba5dc69 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/arc_exception.c @@ -0,0 +1,552 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_EXCEPTION_CPU ARC_HAL_EXCEPTION_INTERRUPT + * \brief C Implementation of exception and interrupt management + */ +#include "inc/arc/arc_exception.h" +#include "inc/arc/arc_cache.h" + +//#define DBG_LESS +//#include "embARC_debug.h" + +/** + * \addtogroup ARC_HAL_EXCEPTION_CPU + * @{ + * \var exc_entry_table + * \brief exception entry table + * + * install exception entry table to ARC_AUX_INT_VECT_BASE in startup. + * According to ARCv2 ISA, vectors are fetched in instruction space and thus + * may be present in ICCM, Instruction Cache, or + * main memory accessed by instruction fetch logic. + * So it is put into a specific section .vector. + * + * Please note that the exc_entry_table maybe cached in ARC. Some functions is + * defined in .s files. + * + */ + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief default cpu exception handler + * \param p_excinf pointer to the exception frame + */ +static void exc_handler_default(void *p_excinf) +{ + uint32_t excpt_cause_reg = 0; + uint32_t excpt_ret_reg = 0; + uint32_t exc_no = 0; + + excpt_cause_reg = _arc_aux_read(AUX_ECR); + excpt_ret_reg = _arc_aux_read(AUX_ERRET); + exc_no = (excpt_cause_reg >> 16) & 0xff; + + //dbg_printf(DBG_LESS_INFO, "default cpu exception handler\r\n"); + //dbg_printf(DBG_LESS_INFO, "exc_no:%d, last sp:0x%08x, ecr:0x%08x, eret:0x%08x\r\n", + //exc_no, (uint32_t)p_excinf, excpt_cause_reg, excpt_ret_reg); +#if SECURESHIELD_VERSION == 2 + + while (1); + +#else + Asm("kflag 1"); +#endif +} + + +/** + * \ingroup ARC_HAL_EXCEPTION_INTERRUPT + * \brief default interrupt handler + * \param[in] p_excinf information for interrupt handler + */ +static void int_handler_default(void *p_excinf) +{ + uint32_t int_cause_reg = 0; + + int_cause_reg = _arc_aux_read(AUX_IRQ_CAUSE); + //dbg_printf(DBG_LESS_INFO, "default interrupt handler\r\n"); + //dbg_printf(DBG_LESS_INFO, "last sp:0x%08x, icause:0x%08x\r\n", (uint32_t)p_excinf, int_cause_reg); +#if SECURESHIELD_VERSION == 2 + + while (1); + +#else + Asm("kflag 1"); +#endif +} + +__attribute__((aligned(1024), section(".vector"))) +EXC_ENTRY exc_entry_table[NUM_EXC_ALL] = +{ + [0] = _arc_reset, + [1 ... NUM_EXC_CPU - 1] = exc_entry_cpu, + [NUM_EXC_CPU ... NUM_EXC_ALL - 1] = exc_entry_int +}; +/** + * \var exc_int_handler_table + * \brief the cpu exception and interrupt exception handler table + * called in exc_entry_default and exc_entry_int + */ +EXC_HANDLER exc_int_handler_table[NUM_EXC_ALL] = +{ + [0 ... NUM_EXC_CPU - 1] = exc_handler_default, + [NUM_EXC_CPU ... NUM_EXC_ALL - 1] = int_handler_default +}; + +/** + * \var exc_nest_count + * \brief the counter for exc/int processing, =0 no int/exc + * >1 in int/exc processing + * @} + */ +uint32_t exc_nest_count; + +typedef struct aux_irq_ctrl_field +{ + /* note: little endian */ + uint32_t save_nr_gpr_pairs: 5; /** Indicates number of general-purpose register pairs saved, from 0 to 8/16 */ + uint32_t res: 4; /** Reserved */ + uint32_t save_blink: 1; /** Indicates whether to save and restore BLINK */ + uint32_t save_lp_regs: 1; /** Indicates whether to save and restore loop registers (LP_COUNT, LP_START, LP_END) */ + uint32_t save_u_to_u: 1; /** Indicates if user context is saved to user stack */ + uint32_t res2: 1; /** Reserved */ +uint32_t save_idx_regs: + 1; /** Indicates whether to save and restore code-density registers (EI_BASE, JLI_BASE, LDI_BASE) */ + uint32_t res3: 18; /** Reserved */ +} aux_irq_ctrl_field_t; + +typedef union +{ + aux_irq_ctrl_field_t bits; + uint32_t value; +} aux_irq_ctrl_t; + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU ARC_HAL_EXCEPTION_INTERRUPT + * \brief intialize the exception and interrupt handling + */ +void exc_int_init(void) +{ + uint32_t i; + uint32_t status; + aux_irq_ctrl_t ictrl; + + ictrl.value = 0; + +#ifndef ARC_FEATURE_RF16 + ictrl.bits.save_nr_gpr_pairs = 6; /* r0 to r11 (r12 saved manually) */ +#else + ictrl.bits.save_nr_gpr_pairs = 3; /* r0 to r3, r10, r11 */ +#endif + ictrl.bits.save_blink = 1; + ictrl.bits.save_lp_regs = 1; /* LP_COUNT, LP_START, LP_END */ + ictrl.bits.save_u_to_u = 0; /* user ctxt saved on kernel stack */ + ictrl.bits.save_idx_regs = 1; /* JLI, LDI, EI */ + + status = arc_lock_save(); + + for (i = NUM_EXC_CPU; i < NUM_EXC_ALL; i++) + { + /* interrupt level triggered, disabled, priority is the lowest */ + _arc_aux_write(AUX_IRQ_SELECT, i); + _arc_aux_write(AUX_IRQ_ENABLE, 0); + _arc_aux_write(AUX_IRQ_TRIGGER, 0); +#if defined(ARC_FEATURE_SEC_PRESENT) && (SECURESHIELD_VERSION < 2) + _arc_aux_write(AUX_IRQ_PRIORITY, (1 << AUX_IRQ_PRIORITY_BIT_S) | (INT_PRI_MAX - INT_PRI_MIN)); +#else + _arc_aux_write(AUX_IRQ_PRIORITY, INT_PRI_MAX - INT_PRI_MIN); +#endif + } + + _arc_aux_write(AUX_IRQ_CTRL, ictrl.value); + + arc_unlock_restore(status); + + /** ipm should be set after cpu unlock restore to avoid reset of the status32 value */ + arc_int_ipm_set((INT_PRI_MAX - INT_PRI_MIN)); +} + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief install a CPU exception entry + * \param[in] excno exception number + * \param[in] entry the entry of exception to install + */ +int32_t exc_entry_install(const uint32_t excno, EXC_ENTRY entry) +{ + uint32_t status; + + EXC_ENTRY *table = (EXC_ENTRY *)_arc_aux_read(AUX_INT_VECT_BASE); + + if (excno < NUM_EXC_ALL && entry != NULL + && table[excno] != entry) + { + status = cpu_lock_save(); + /* directly write to mem, as arc gets exception handler from mem not from cache */ + /* FIXME, here maybe icache is dirty, need to be invalidated */ + table[excno] = entry; + + if (_arc_aux_read(AUX_BCR_D_CACHE) > 0x2) + { + /* dcache is available */ + dcache_flush_line((uint32_t)&table[excno]); + } + + if (_arc_aux_read(AUX_BCR_D_CACHE) > 0x2) + { + /* icache is available */ + icache_invalidate_line((uint32_t)&table[excno]); + } + + cpu_unlock_restore(status); + return 0; + } + + return -1; +} + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief get the installed CPU exception entry + * \param[in] excno exception number + * \return the installed CPU exception entry + */ +EXC_ENTRY exc_entry_get(const uint32_t excno) +{ + if (excno < NUM_EXC_ALL) + { + return exc_entry_table[excno]; + } + + return NULL; +} + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief install an exception handler + * \param[in] excno exception number + * \param[in] handler the handler of exception to install + */ +int32_t exc_handler_install(const uint32_t excno, EXC_HANDLER handler) +{ + if (excno < NUM_EXC_ALL && handler != NULL) + { + exc_int_handler_table[excno] = handler; + return 0; + } + + return -1; +} + +/** + * \ingroup ARC_HAL_EXCEPTION_CPU + * \brief get the installed exception handler + * \param[in] excno exception number + * \return the installed exception handler or NULL + */ +EXC_HANDLER exc_handler_get(const uint32_t excno) +{ + if (excno < NUM_EXC_ALL) + { + return exc_int_handler_table[excno]; + } + + return NULL; +} + + +#ifndef EMBARC_OVERRIDE_ARC_INTERRUPT_MANAGEMENT +/** + * \brief disable the specific interrupt + * + * \param[in] intno interrupt number + */ +int32_t int_disable(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + arc_int_disable(intno); + return 0; + } + + return -1; +} + +/** + * \brief enable the specific int + * + * \param[in] intno interrupt number + */ +int32_t int_enable(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + arc_int_enable(intno); + return 0; + } + + return -1; +} + +/** + * \brief check whether the specific int is enabled + * + * \param[in] intno interrupt number + * \return 0 disabled, 1 enabled, < 0 error + */ +int32_t int_enabled(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + _arc_aux_write(AUX_IRQ_SELECT, intno); + return _arc_aux_read(AUX_IRQ_ENABLE); + } + + return -1; +} + +/** + * \brief get the interrupt priority mask + * + * \returns interrupt priority mask, negative num + */ +int32_t int_ipm_get(void) +{ + return ((int32_t)arc_int_ipm_get() + INT_PRI_MIN); +} + + +/** + * \brief set the interrupt priority mask + * + * \param[in] intpri interrupt priority + */ +int32_t int_ipm_set(int32_t intpri) +{ + if (intpri >= INT_PRI_MIN && intpri <= INT_PRI_MAX) + { + intpri = intpri - INT_PRI_MIN; + arc_int_ipm_set(intpri); + return 0; + } + + return -1; +} + + +/** + * \brief get current interrupt priority mask + * + * \param[in] intno interrupt number + * \return <0 interrupt priority, 0 error + */ +int32_t int_pri_get(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + return (int32_t)arc_int_pri_get(intno) + INT_PRI_MIN; + } + + return 0; +} + + +/** + * \brief set interrupt priority + * + * \param[in] intno interrupt number + * \param[in] intpri interrupt priority + * \return <0 error, 0 ok + */ +int32_t int_pri_set(const uint32_t intno, int32_t intpri) +{ + uint32_t status; + + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + status = cpu_lock_save(); + intpri = intpri - INT_PRI_MIN; + arc_int_pri_set(intno, (uint32_t)intpri); + cpu_unlock_restore(status); + return 0; + } + + return -1; +} + +/** + * \brief set interrupt secure or not secure + * This function is valid in secureshield v2 + * \param[in] intno interrupt number + * \param[in] secure, 0 for normal, >0 for secure + * \return <0 error, 0 ok + */ +int32_t int_secure_set(const uint32_t intno, uint32_t secure) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + arc_int_secure_set(intno, secure); + return 0; + } + + return -1; + +} + + +/** + * \brief probe the pending status of interrupt + * + * \param[in] intno interrupt number + * + * \returns 1 pending, 0 no pending, -1 error + */ +int32_t int_probe(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + return arc_int_probe(intno); + } + + return -1; +} + + +/** + * \brief trigger the interrupt in software + * + * \param[in] intno interrupt number + * \return 0 ok, -1 error + */ +int32_t int_sw_trigger(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + arc_int_sw_trigger(intno); + return 0; + } + + return -1; +} + +/** + * \brief config the interrupt level triggered or pulse triggered + * + * \param[in] intno interrupt number + * \param[in] level, 0-level trigger, 1-pulse triggered + * \return 0 ok, -1 error + */ +int32_t int_level_config(const uint32_t intno, const uint32_t level) +{ + if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) + { + arc_int_level_config(intno, level); + return 0; + } + + return -1; +} + + +/** + * \brief lock cpu, disable interrupts + */ +void cpu_lock(void) +{ + arc_lock(); +} + +/** + * \brief unlock cpu, enable interrupts to happen + */ +void cpu_unlock(void) +{ + arc_unlock(); +} + +/** + * \brief lock cpu and return status + * + * \returns cpu status + */ +uint32_t cpu_lock_save(void) +{ + return arc_lock_save(); +} + +/** + * \brief unlock cpu with the specific status + * + * \param[in] status cpu status saved by cpu_lock_save + */ +void cpu_unlock_restore(const uint32_t status) +{ + arc_unlock_restore(status); +} + +/** + * \ingroup ARC_HAL_EXCEPTION_INTERRUPT + * \brief install an interrupt handler + * \param[in] intno interrupt number + * \param[in] handler interrupt handler to install + */ +int32_t int_handler_install(const uint32_t intno, INT_HANDLER handler) +{ + /*!< \todo parameter check ? */ + if (intno >= NUM_EXC_CPU) + { + return exc_handler_install(intno, handler); + } + + return -1; +} + +/** + * \ingroup ARC_HAL_EXCEPTION_INTERRUPT + * \brief get the installed an interrupt handler + * \param[in] intno interrupt number + * \return the installed interrupt handler or NULL + */ +INT_HANDLER int_handler_get(const uint32_t intno) +{ + if (intno >= NUM_EXC_CPU) + { + return exc_handler_get(intno); + } + + return NULL; +} +#endif /* EMBARC_OVERRIDE_ARC_INTERRUPT_MANAGEMENT */ diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/arc_timer.c b/third_party/synopsys/embarc_emsk_bsp/arc/arc_timer.c new file mode 100644 index 000000000..a5837e3d3 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/arc_timer.c @@ -0,0 +1,235 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_MISC_TIMER + * \brief implementation of internal timer related functions + * \todo RTC support should be improved if RTC is enabled + */ +#include "inc/arc/arc_timer.h" +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" + +/** + * \brief check whether the specific timer present + * \param[in] no timer number + * \retval 1 present + * \retval 0 not present + */ +int32_t timer_present(const uint32_t no) +{ + uint32_t bcr = _arc_aux_read(AUX_BCR_TIMERS); + + switch (no) + { + case TIMER_0: + bcr = (bcr >> 8) & 1; + break; + + case TIMER_1: + bcr = (bcr >> 9) & 1; + break; + + case TIMER_RTC: + bcr = (bcr >> 10) & 1; + break; + + default: + bcr = 0; + /* illegal argument so return false */ + break; + } + + return (int)bcr; +} + +/** + * \brief start the specific timer + * \param[in] no timer number + * \param[in] mode timer mode + * \param[in] val timer limit value (not for RTC) + * \return 0 success, -1 failure + */ +int32_t timer_start(const uint32_t no, const uint32_t mode, const uint32_t val) +{ + if (timer_present(no) == 0) + { + return -1; + } + + switch (no) + { + case TIMER_0: + _arc_aux_write(AUX_TIMER0_CTRL, 0); + _arc_aux_write(AUX_TIMER0_LIMIT, val); + _arc_aux_write(AUX_TIMER0_CTRL, mode); + _arc_aux_write(AUX_TIMER0_CNT, 0); + break; + + case TIMER_1: + _arc_aux_write(AUX_TIMER1_CTRL, 0); + _arc_aux_write(AUX_TIMER1_LIMIT, val); + _arc_aux_write(AUX_TIMER1_CTRL, mode); + _arc_aux_write(AUX_TIMER1_CNT, 0); + break; + + case TIMER_RTC: + _arc_aux_write(AUX_RTC_CTRL, mode); + break; + + default: + return -1; + } + + return 0; +} + +/** + * \brief stop and clear the specific timer + * + * \param[in] no timer number + * \return 0 success, -1 failure + */ +int32_t timer_stop(const uint32_t no) +{ + if (timer_present(no) == 0) + { + return -1; + } + + switch (no) + { + case TIMER_0 : + _arc_aux_write(AUX_TIMER0_CTRL, 0); + _arc_aux_write(AUX_TIMER0_LIMIT, 0); + _arc_aux_write(AUX_TIMER0_CNT, 0); + break; + + case TIMER_1: + _arc_aux_write(AUX_TIMER1_CTRL, 0); + _arc_aux_write(AUX_TIMER1_LIMIT, 0); + _arc_aux_write(AUX_TIMER1_CNT, 0); + break; + + case TIMER_RTC: + _arc_aux_write(AUX_RTC_CTRL, TIMER_RTC_CLEAR); + break; + + default: + return -1; + } + + return 0; +} + +/** + * \brief get timer current tick + * + * \param[in] no timer number + * \param[out] val, timer value + * \return 0 success, -1 failure + */ +int32_t timer_current(const uint32_t no, void *val) +{ + if (timer_present(no) == 0) + { + return -1; + } + + switch (no) + { + case TIMER_0 : + *((uint32_t *)val) = _arc_aux_read(AUX_TIMER0_CNT); + break; + + case TIMER_1 : + *((uint32_t *)val) = _arc_aux_read(AUX_TIMER1_CNT); + break; + + case TIMER_RTC: + *((uint64_t *)val) = _arc_aux_read(AUX_RTC_LOW); + break; + + default : + return -1; + } + + return 0; +} + +/** + * \brief clear the interrupt pending bit of timer + * + * \param[in] no timer number + * \return 0 success, -1 failure + */ +int32_t timer_int_clear(const uint32_t no) +{ + uint32_t val; + + if (timer_present(no) == 0) + { + return -1; + } + + switch (no) + { + case TIMER_0 : + val = _arc_aux_read(AUX_TIMER0_CTRL); + val &= ~TIMER_CTRL_IP; + _arc_aux_write(AUX_TIMER0_CTRL, val); + break; + + case TIMER_1 : + val = _arc_aux_read(AUX_TIMER1_CTRL); + val &= ~TIMER_CTRL_IP; + _arc_aux_write(AUX_TIMER1_CTRL, val); + break; + + default : + return -1; + } + + return 0; +} + +/** + * \brief init internal timer + */ +void timer_init(void) +{ + timer_stop(TIMER_0); + timer_stop(TIMER_1); + timer_stop(TIMER_RTC); +} diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_cxx_support.c b/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_cxx_support.c new file mode 100644 index 000000000..8de209c8a --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_cxx_support.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ------------------------------------------ + * Copyright (c) 2015, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2016-03-02 + * \author Wayne Ren(wei.ren@synopsys.com) +--------------------------------------------- */ +#include "embARC_BSP_config.h" +#if defined(__GNU__) +/* embARC's GNU C++ support takes reference from Zephyr (cpp_xxx.c) */ + +/** + * @file - Constructor module + * @brief + * The ctors section contains a list of function pointers that execute the + * C++ constructors of static global objects. These must be executed before + * the application's main() routine. + * + * NOTE: Not all compilers put those function pointers into the ctors section; + * some put them into the init_array section instead. + */ + +/* What a constructor function pointer looks like */ + +typedef void (*CtorFuncPtr)(void); + +/* Constructor function pointer list is generated by the linker script. */ + +extern CtorFuncPtr __CTOR_LIST__[]; +extern CtorFuncPtr __CTOR_END__[]; + +/** + * + * @brief Invoke all C++ style global object constructors + * + * This routine is invoked before the execution of the + * application's main(). + */ +void __do_global_ctors_aux(void) +{ + unsigned int nCtors; + + nCtors = (unsigned int)__CTOR_LIST__[0]; + + while (nCtors >= 1) + { + __CTOR_LIST__[nCtors--](); + } +} + +typedef void (*DtorFuncPtr)(void); + +extern DtorFuncPtr __DTOR_LIST__[]; +extern DtorFuncPtr __DTOR_END__[]; + +/** + * + * @brief Invoke all C++ style global object destructors + * + * This routine is invoked after the execution of the + * application's main(). + */ +void __do_global_dtors_aux(void) +{ + unsigned int nDtors; + unsigned int i; + + nDtors = (unsigned int)__DTOR_LIST__[0]; + i = 0; + + while (i <= nDtors) + { + __DTOR_LIST__[i++](); + } +} + +void *__dso_handle = 0; + +/** + * @brief Register destructor for a global object + * + * @param destructor the global object destructor function + * @param objptr global object pointer + * @param dso Dynamic Shared Object handle for shared libraries + * + * Function does nothing at the moment, assuming the global objects + * do not need to be deleted + * + * @return N/A + */ +int __cxa_atexit(void (*destructor)(void *), void *objptr, void *dso) +{ + return 0; +} + +typedef void (*func_ptr)(void); + +extern func_ptr __init_array_start[0]; +extern func_ptr __init_array_end[0]; + +/** + * @brief Execute initialization routines referenced in .init_array section + * + * @return N/A + */ +void __do_init_array_aux(void) +{ + for (func_ptr *func = __init_array_start; + func < __init_array_end; + func++) + { + (*func)(); + } +} + +/** + * @brief Stub for pure virtual functions + * + * This routine is needed for linking C++ code that uses pure virtual + * functions. + * + * @return N/A + */ +void __cxa_pure_virtual(void) +{ + while (1) + { + ; + } +} +#endif diff --git a/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_startup.S b/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_startup.S new file mode 100644 index 000000000..861e6a7b6 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc/startup/arc_startup.S @@ -0,0 +1,266 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_STARTUP + * \brief assembly part of startup process + */ + +/** + * \addtogroup ARC_HAL_STARTUP + * @{ + */ +/** @cond STARTUP_ASM */ + +#define __ASSEMBLY__ +#include "embARC_BSP_config.h" +#include "inc/arc/arc.h" + +.file "arc_startup.S" + +.weak _f_sdata /* start of small data, defined in link script */ +.weak init_hardware_hook /* app hardware init hook */ +.weak init_software_hook /* app software init hook */ + +.extern board_main +.extern exc_entry_table + +/* initial vector table */ +.section .init_vector, "a" +.long _arc_reset +.section .init_bootstrap, "ax" +.global _arc_reset +.global _start +.align 4 +_start: +_arc_reset: +_arc_reset_stage1: +kflag STATUS32_RESET_VALUE + +/* STAGE 1 */ + +/* necessary hardware should be done first to speed up initialization + 1. system clk + 2. mem controller must be initialized before any access to external + mem. + 3. others +*/ +_arc_cache_init_start: +lr r0, [AUX_BCR_D_CACHE] +cmp r0, 2 +/* invalidate dcache */ +jle _arc_icache_init +mov r0, 1 +sr r0, [AUX_DC_IVDC] +sr r0, [AUX_DC_CTRL] +_arc_icache_init: +lr r0, [AUX_BCR_I_CACHE] +cmp r0, 2 +jle _arc_cache_init_end +/* invalidate icache */ +mov r0, 1 +sr r0, [AUX_IC_IVIC] +nop_s +nop_s +nop_s +sr r0, [AUX_IC_CTRL] + +_arc_cache_init_end: +mov r0, init_hardware_hook +cmp r0, 0 +jlne [r0] + +/* STAGE 2: init necessary registers */ + +_arc_reset_stage2: +mov r0, 0 + +/* interrupt related init */ +sr r0, [AUX_IRQ_ACT] +sr r0, [AUX_IRQ_CTRL] +sr r0, [AUX_IRQ_HINT] + +/* use the new vector table to replace the old one */ +#if defined(ARC_FEATURE_SEC_PRESENT) && (SECURESHIELD_VERSION < 2) +sr exc_entry_table, [AUX_INT_VECT_BASE_S] +#else +sr exc_entry_table, [AUX_INT_VECT_BASE] +#endif + +/* init stack */ +#if ARC_FEATURE_RGF_BANKED_REGS >= 16 && ARC_FEATURE_RGF_BANKED_REGS > 1 && ARC_FEATURE_FIRQ == 1 +#if _STACKSIZE < 512 +#error "not enough stack size for irq and firq" +#endif + +/* switch to register bank1 */ +lr r0, [AUX_STATUS32] +bic r0, r0, 0x70000 +or r0, r0, 0x10000 +kflag r0 +/* set sp, gp, fp in bank1 */ +mov sp, _e_stack +mov gp, _f_sdata +mov fp, 0 +/* come back to bank0 */ +lr r0, [AUX_STATUS32] +bic r0, r0, 0x70000 +kflag r0 +mov sp, _e_stack - 256 +#else +mov sp, _e_stack /* init stack pointer */ +#endif +mov gp, _f_sdata /* init small-data base register */ +mov fp, 0 /* init fp register */ + +_arc_reset_stage3: +_s3_copy_text: +mov r0, _f_text +mov r1, _load_addr_text +cmp r0, r1 + +/* if load addr == run addr, no need to copy */ +jeq _s3_copy_rodata +mov r3, _e_text +_s3_copy_text_loop: +ld.ab r2, [r1, 4] +st.ab r2, [r0, 4] +cmp r0, r3 +jlt _s3_copy_text_loop +_s3_copy_rodata: +mov r0, _f_rodata +mov r1, _load_addr_rodata +cmp r0, r1 + +/* if load addr == run addr, no need to copy */ +jeq _s3_copy_data +mov r3, _e_rodata +_s3_copy_rodata_loop: +ld.ab r2, [r1, 4] +st.ab r2, [r0, 4] +cmp r0, r3 +jlt _s3_copy_rodata_loop +_s3_copy_data: +mov r0, _f_data +mov r1, _load_addr_data +cmp r0, r1 +jeq _s3_clear_bss + +/* if load addr == run addr, no need to copy */ +mov r3, _e_data +_s3_copy_data_loop: +ld.ab r2, [r1, 4] +st.ab r2, [r0, 4] +cmp r0, r3 +jlt _s3_copy_data_loop +_s3_clear_bss: +mov r0, _f_bss +mov r1, _e_bss +cmp r0, r1 +jge _arc_reset_call_main +mov r2, 0 +_s3_clear_bss_loop: +st.ab r2, [r0, 4] +cmp r0, r1 +jlt _s3_clear_bss_loop + +/* STAGE 3: go to main */ + +_arc_reset_call_main: + +/* \todo add cpp init here */ +mov r0, init_software_hook +cmp r0, 0 +jlne [r0] +/* board level library init */ +#ifdef LIB_SECURESHIELD +jl secureshield_start +#else +/* early init of interrupt and exception */ +jl exc_int_init +#endif +/* init cache */ +jl arc_cache_init +#if defined(__MW__) +jl _init +#elif defined(__GNU__) +jl __do_global_ctors_aux +jl __do_init_array_aux +#endif +jl board_main /* board-level main */ +#if defined(__MW__) +jl _fini +#elif defined(__GNU__) +jl __do_global_dtors_aux +#endif +.global _exit_loop +.global _exit_halt +.align 4 +_exit_halt: +_exit_loop: +flag 0x1 +nop +nop +nop +b _exit_loop + +#if defined(__MW__) +.global _init, _fini +.section ".init", text +_init: +.cfa_bf _init +push % blink +.cfa_push { % blink} + +.section ".init$999999", text, 1, 2, check_text_align = 0 + pop % blink + .cfa_pop { % blink} + j [ % blink] + .cfa_ef + + .section ".fini", text + _fini: + .cfa_bf _fini + push % blink + .cfa_push { % blink} + + .section ".fini$999999", text, 1, 2, check_text_align = 0 + pop % blink + .cfa_pop { % blink} + j [ % blink] + .cfa_ef +#endif + /** @endcond */ + + /** }@*/ diff --git a/third_party/synopsys/embarc_emsk_bsp/arc_core_config.h b/third_party/synopsys/embarc_emsk_bsp/arc_core_config.h new file mode 100644 index 000000000..38936ed8b --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/arc_core_config.h @@ -0,0 +1,255 @@ +/* EMSK2.3 ARC EM11D */ + +#ifndef __core_config_h +#define __core_config_h 1 +#define core_config_cir_identity 0x00000043 +#define core_config_cir_identity_chipid 0 +#define core_config_cir_identity_arcnum 0 +#define core_config_cir_identity_arcver 67 +#define core_config_cir_identity_family 4 +#define core_config_cir_identity_corever 3 +#define core_config_cir_aux_dccm 0x80000000 +#define core_config_bcr_bcr_ver 0x00000002 +#define core_config_bcr_bcr_ver_version 2 +#define core_config_bcr_vecbase_ac_build 0x00000010 +#define core_config_bcr_rf_build 0x0000c902 +#define core_config_bcr_rf_build_version 2 +#define core_config_bcr_rf_build_p 1 +#define core_config_bcr_rf_build_e 0 +#define core_config_bcr_rf_build_r 0 +#define core_config_bcr_rf_build_b 1 +#define core_config_bcr_rf_build_d 3 +#define core_config_bcr_d_cache_build 0x00215104 +#define core_config_bcr_d_cache_build_version 4 +#define core_config_bcr_d_cache_build_assoc 1 +#define core_config_bcr_d_cache_build_capacity 5 +#define core_config_bcr_d_cache_build_bsize 1 +#define core_config_bcr_d_cache_build_fl 2 +#define core_config_bcr_d_cache_build_ioc 0 +#define core_config_bcr_d_cache_build_cp 0 +#define core_config_bcr_d_cache_build_u 0 +#define core_config_bcr_d_cache_build_cycles 0 +#define core_config_bcr_dccm_build 0x00010804 +#define core_config_bcr_dccm_build_w 0 +#define core_config_bcr_dccm_build_cycles 0 +#define core_config_bcr_dccm_build_interleave 1 +#define core_config_bcr_dccm_build_size1 0 +#define core_config_bcr_dccm_build_size0 8 +#define core_config_bcr_dccm_build_version 4 +#define core_config_bcr_timer_build 0x00010304 +#define core_config_bcr_timer_build_sp1 0 +#define core_config_bcr_timer_build_sp0 0 +#define core_config_bcr_timer_build_p1 0 +#define core_config_bcr_timer_build_p0 1 +#define core_config_bcr_timer_build_st1 0 +#define core_config_bcr_timer_build_st0 0 +#define core_config_bcr_timer_build_rtc 0 +#define core_config_bcr_timer_build_rtsc_ver 1 +#define core_config_bcr_timer_build_rtsc 0 +#define core_config_bcr_timer_build_t0 1 +#define core_config_bcr_timer_build_t1 1 +#define core_config_bcr_timer_build_version 4 +#define core_config_bcr_ap_build 0x00000405 +#define core_config_bcr_ap_build_version 5 +#define core_config_bcr_ap_build_type 4 +#define core_config_bcr_i_cache_build 0x00135104 +#define core_config_bcr_i_cache_build_assoc 1 +#define core_config_bcr_i_cache_build_version 4 +#define core_config_bcr_i_cache_build_capacity 5 +#define core_config_bcr_i_cache_build_bsize 3 +#define core_config_bcr_i_cache_build_fl 1 +#define core_config_bcr_i_cache_build_d 0 +#define core_config_bcr_iccm_build 0x00000804 +#define core_config_bcr_iccm_build_iccm1_size1 0 +#define core_config_bcr_iccm_build_iccm0_size1 0 +#define core_config_bcr_iccm_build_iccm1_size0 0 +#define core_config_bcr_iccm_build_iccm0_size0 8 +#define core_config_bcr_iccm_build_version 4 +#define core_config_bcr_xy_build 0x00001520 +#define core_config_bcr_xy_build_memsize 1 +#define core_config_bcr_xy_build_interleaved 1 +#define core_config_bcr_xy_build_config 1 +#define core_config_bcr_xy_build_version 32 +#define core_config_bcr_dsp_build 0x00003521 +#define core_config_bcr_dsp_build_wide 0 +#define core_config_bcr_dsp_build_itu_pa 1 +#define core_config_bcr_dsp_build_acc_shift 2 +#define core_config_bcr_dsp_build_comp 1 +#define core_config_bcr_dsp_build_divsqrt 1 +#define core_config_bcr_dsp_build_version 33 +#define core_config_bcr_multiply_build 0x00022206 +#define core_config_bcr_multiply_build_version16x16 2 +#define core_config_bcr_multiply_build_dsp 2 +#define core_config_bcr_multiply_build_cyc 0 +#define core_config_bcr_multiply_build_type 2 +#define core_config_bcr_multiply_build_version32x32 6 +#define core_config_bcr_swap_build 0x00000003 +#define core_config_bcr_swap_build_version 3 +#define core_config_bcr_norm_build 0x00000003 +#define core_config_bcr_norm_build_version 3 +#define core_config_bcr_minmax_build 0x00000002 +#define core_config_bcr_minmax_build_version 2 +#define core_config_bcr_barrel_build 0x00000303 +#define core_config_bcr_barrel_build_version 3 +#define core_config_bcr_barrel_build_shift_option 3 +#define core_config_bcr_isa_config 0x12447402 +#define core_config_bcr_isa_config_res1 0 +#define core_config_bcr_isa_config_d 1 +#define core_config_bcr_isa_config_res2 0 +#define core_config_bcr_isa_config_f 0 +#define core_config_bcr_isa_config_c 2 +#define core_config_bcr_isa_config_l 0 +#define core_config_bcr_isa_config_n 1 +#define core_config_bcr_isa_config_a 0 +#define core_config_bcr_isa_config_b 0 +#define core_config_bcr_isa_config_addr_size 4 +#define core_config_bcr_isa_config_lpc_size 7 +#define core_config_bcr_isa_config_pc_size 4 +#define core_config_bcr_isa_config_version 2 +#define core_config_bcr_stack_region_build 0x00000002 +#define core_config_bcr_fpu_build 0x01000f02 +#define core_config_bcr_fpu_build_da 1 +#define core_config_bcr_fpu_build_dd 0 +#define core_config_bcr_fpu_build_dc 0 +#define core_config_bcr_fpu_build_df 0 +#define core_config_bcr_fpu_build_dp 0 +#define core_config_bcr_fpu_build_fd 0 +#define core_config_bcr_fpu_build_fm 0 +#define core_config_bcr_fpu_build_sd 1 +#define core_config_bcr_fpu_build_sc 1 +#define core_config_bcr_fpu_build_sf 1 +#define core_config_bcr_fpu_build_sp 1 +#define core_config_bcr_fpu_build_version 2 +#define core_config_bcr_bs_build 0x00000002 +#define core_config_bcr_bs_build_version 2 +#define core_config_bcr_agu_build 0x01988c02 +#define core_config_bcr_agu_build_accordian 1 +#define core_config_bcr_agu_build_wb_size 4 +#define core_config_bcr_agu_build_num_modifier 24 +#define core_config_bcr_agu_build_num_offset 8 +#define core_config_bcr_agu_build_num_addr 12 +#define core_config_bcr_agu_build_version 2 +#define core_config_bcr_dmac_build 0x000a0102 +#define core_config_bcr_dmac_build_int_cfg 1 +#define core_config_bcr_dmac_build_fifo 1 +#define core_config_bcr_dmac_build_chan_mem 0 +#define core_config_bcr_dmac_build_channels 1 +#define core_config_bcr_dmac_build_version 2 +#define core_config_bcr_core_config 0x00000101 +#define core_config_bcr_core_config_turbo_boost 1 +#define core_config_bcr_core_config_version 1 +#define core_config_bcr_irq_build 0x13121601 +#define core_config_bcr_irq_build_raz 0 +#define core_config_bcr_irq_build_f 1 +#define core_config_bcr_irq_build_p 3 +#define core_config_bcr_irq_build_exts 18 +#define core_config_bcr_irq_build_irqs 22 +#define core_config_bcr_irq_build_version 1 +#define core_config_bcr_pct_build 0x08080102 +#define core_config_bcr_pct_build_version 2 +#define core_config_bcr_pct_build_s 1 +#define core_config_bcr_pct_build_i 0 +#define core_config_bcr_pct_build_c 8 +#define core_config_bcr_cc_build 0x006f0004 +#define core_config_bcr_cc_build_version 4 +#define core_config_bcr_cc_build_cc 111 +#define core_config_bcr_smart_build 0x00002003 +#define core_config_bcr_smart_build_version 3 +#define core_config_bcr_smart_build_stack_size 8 +#define core_config_cir_aux_iccm 0x00000000 +#define core_config_cir_dmp_peripheral 0xf0000000 +#define core_config_cir_yccm_base 0xe0000000 +#define core_config_family 4 +#define core_config_core_version 3 +#define core_config_family_name "arcv2em" +#define core_config_rgf_num_banks 2 +#define core_config_rgf_banked_regs 32 +#define core_config_rgf_num_wr_ports 2 +#define core_config_endian "little" +#define core_config_endian_little 1 +#define core_config_endian_big 0 +#define core_config_lpc_size 32 +#define core_config_pc_size 32 +#define core_config_addr_size 32 +#define core_config_unaligned 1 +#define core_config_code_density 1 +#define core_config_div_rem "radix2" +#define core_config_div_rem_radix2 1 +#define core_config_turbo_boost 1 +#define core_config_swap 1 +#define core_config_bitscan 1 +#define core_config_mpy_option "mpyd" +#define core_config_mpy_option_num 8 +#define core_config_shift_assist 1 +#define core_config_barrel_shifter 1 +#define core_config_dsp 1 +#define core_config_dsp2 1 +#define core_config_dsp_complex 1 +#define core_config_dsp_divsqrt "radix2" +#define core_config_dsp_divsqrt_radix2 1 +#define core_config_dsp_itu 1 +#define core_config_dsp_accshift "full" +#define core_config_dsp_accshift_full 1 +#define core_config_agu_large 1 +#define core_config_agu_wb_depth 4 +#define core_config_agu_accord 1 +#define core_config_xy 1 +#define core_config_xy_config "dccm_y" +#define core_config_xy_config_dccm_y 1 +#define core_config_xy_size 8192 +#define core_config_xy_size_KM "8K" +#define core_config_xy_interleave 1 +#define core_config_xy_y_base 0xe0000000 +#define core_config_bitstream 1 +#define core_config_fpus_div 1 +#define core_config_fpu_mac 1 +#define core_config_fpuda 1 +#define core_config_fpus_mpy_slow 1 +#define core_config_fpus_div_slow 1 +#define core_config_timer0 1 +#define core_config_timer0_level 1 +#define core_config_timer0_vector 16 +#define core_config_timer1 1 +#define core_config_timer1_level 0 +#define core_config_timer1_vector 17 +#define core_config_action_points 2 +#define core_config_stack_check 1 +#define core_config_smart_stack_entries 8 +#define core_config_interrupts_present 1 +#define core_config_interrupts_number 22 +#define core_config_interrupts_priorities 4 +#define core_config_interrupts_externals 18 +#define core_config_interrupts 22 +#define core_config_interrupt_priorities 4 +#define core_config_ext_interrupts 18 +#define core_config_interrupts_firq 1 +#define core_config_interrupts_base 0x0 +#define core_config_dcache_present 1 +#define core_config_dcache_size 16384 +#define core_config_dcache_line_size 32 +#define core_config_dcache_ways 2 +#define core_config_dcache_feature 2 +#define core_config_icache_present 1 +#define core_config_icache_size 16384 +#define core_config_icache_line_size 64 +#define core_config_icache_ways 2 +#define core_config_icache_feature 1 +#define core_config_dccm_present 1 +#define core_config_dccm_size 0x10000 +#define core_config_dccm_base 0x80000000 +#define core_config_dccm_interleave 1 +#define core_config_iccm_present 1 +#define core_config_iccm0_present 1 +#define core_config_iccm_size 0x10000 +#define core_config_iccm0_size 0x10000 +#define core_config_iccm_base 0x00000000 +#define core_config_iccm0_base 0x00000000 +#define core_config_pct_counters 8 +#define core_config_dmac 1 +#define core_config_dmac_channels 2 +#define core_config_dmac_registers 0 +#define core_config_dmac_fifo_depth 2 +#define core_config_dmac_int_config "single_internal" +#define core_config_clock_speed 20 +#endif /* __core_config_h */ + diff --git a/third_party/synopsys/embarc_emsk_bsp/board/board.c b/third_party/synopsys/embarc_emsk_bsp/board/board.c new file mode 100644 index 000000000..7d78c2487 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/board.c @@ -0,0 +1,66 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-20 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +#include "inc/arc/arc_builtin.h" +#include "board/board.h" +#include "common/console_io.h" + +typedef struct main_args +{ + int argc; + char *argv[]; +} MAIN_ARGS; + +/** Change this to pass your own arguments to main functions */ +MAIN_ARGS s_main_args = {1, {"main"}}; + +static void enter_to_main(MAIN_ARGS *main_arg) +{ + if (main_arg == NULL) + { + /* null or aligned not to 4 bytes */ + _arc_goto_main(0, NULL); + } + else + { + _arc_goto_main(main_arg->argc, main_arg->argv); + } +} + +void board_main(void) +{ + /* board level hardware init */ + board_init(); + xprintf_setup(); + cpu_unlock(); /* unlock cpu to let interrupt work */ + enter_to_main(&s_main_args); +} \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/board/board.h b/third_party/synopsys/embarc_emsk_bsp/board/board.h new file mode 100755 index 000000000..00b52d2b9 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/board.h @@ -0,0 +1,68 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-07-03 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * + * \file + * \ingroup BOARD_COMMON + * \brief common board header file + * \details + * - This header file will contain board related settings for different boards. + * - Each board configurations are put in its own header file, like emsk/emsk.h + * - If you want to change the configuration, you need to go to related header file, e.g. + * if you want to change EMSK board settings, you need to go to emsk/emsk.h + * - In embARC 2015.05, all the settings are in this board.h, but now it moved to related board header file + */ + +/** + * \addtogroup BOARD_COMMON + * @{ + */ +#ifndef _EMBARC_BOARD_H_ +#define _EMBARC_BOARD_H_ + +#include "embARC_BSP_config.h" +/** + * \todo add comments and documents to describe the macros + * \note the following macros must use the same name, because + * they are used by middleware and other applications + */ +/** here is a sample of EMSK board resource definitions */ +#ifdef BOARD_EMSK +#include "board/emsk/emsk.h" +#endif /* BOARD_EMSK */ + +/** you can add your board configuration as BOARD_EMSK defined up */ + +#endif /* _EMBARC_BOARD_H_ */ + +/** @} end of group BOARD_COMMON */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_init.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_init.c new file mode 100644 index 000000000..85f1f9e0f --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_init.c @@ -0,0 +1,116 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-31 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \defgroup BOARD_EMSK_COMMON_INIT EMSK Common Init Module + * \ingroup BOARD_EMSK_COMMON + * \brief EMSK Board Common Init Module + * \details + * EMSK timer/gpio/interrupt init process. Device-driver installation is done while + * getting the device object for the first time. + */ + +/** + * \file + * \ingroup BOARD_EMSK_COMMON_INIT + * \brief common emsk init module + */ + +/** + * \addtogroup BOARD_EMSK_COMMON_INIT + * @{ + */ +#include "inc/arc/arc_builtin.h" +#include "inc/arc/arc.h" +#include "inc/arc/arc_timer.h" + +#include "board/emsk/emsk.h" +#include "board/emsk/common/emsk_timer.h" +#include "board/emsk/common/mux.h" + +#ifdef ARC_FEATURE_DMP_PERIPHERAL +#define PERIPHERAL_BASE ARC_FEATURE_DMP_PERIPHERAL +#else +#define PERIPHERAL_BASE _arc_aux_read(AUX_DMP_PERIPHERAL) +#endif + +/** + * \brief emsk-related mux io init + */ +static void emsk_mux_init(void) +{ + MUX_REG *mux_regs; + + mux_regs = (MUX_REG *)(PERIPHERAL_BASE | REL_REGBASE_PINMUX); + mux_init(mux_regs); + + /** + * + Please refer to corresponding EMSK User Guide for detailed information + * -> Appendix: A Hardware Functional Description + * -> Pmods Configuration summary + * + Set up pin-multiplexer of all PMOD connections + * - PM1 J1: Upper row as UART 0, lower row as SPI Slave + * - PM2 J2: IIC 0 and run/halt signals + * - PM3 J3: GPIO Port A and Port C + * - PM4 J4: IIC 1 and Port D + * - PM5 J5: Upper row as SPI Master, lower row as Port A + * - PM6 J6: Upper row as SPI Master, lower row as Port A + */ + set_pmod_mux(mux_regs, PM1_UR_UART_0 | PM1_LR_SPI_S \ + | PM2_I2C_HRI \ + | PM3_GPIO_AC \ + | PM4_I2C_GPIO_D \ + | PM5_UR_SPI_M1 | PM5_LR_GPIO_A \ + | PM6_UR_SPI_M0 | PM6_LR_GPIO_A); + + /** + * PM1 upper row as UART + * UM4:RXD, UM3:TXD + * UM2:RTS_N, UM1:CTS_N + */ + set_uart_map(mux_regs, 0x9c); +} + +/** + * \brief Board init routine MUST be called in each application + * \note It is better to disable interrupts when calling this function + * remember to enable interrupt when you want to use them + */ +void board_init(void) +{ + timer_init(); + emsk_mux_init(); + emsk_gpio_init(); + emsk_timer_init(); +} + +/** @} end of group BOARD_EMSK_COMMON_INIT */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.c new file mode 100644 index 000000000..001df0e28 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.c @@ -0,0 +1,210 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-31 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \defgroup BOARD_EMSK_COMMON_TIMER EMSK Common Timer Module + * \ingroup BOARD_EMSK_COMMON + * \brief provide basic board timer-related functions + * \details + * Provide a 1 MS (default) timer interrupt, + * provide a 64-bit counter value (no clear) count in the timer interrupt, + * provide MS-precision delay, with OS enabled-support delay + */ + +/** + * \file + * \ingroup BOARD_EMSK_COMMON_TIMER + * \brief provide emsk board timer-related functions + */ + +/** + * \addtogroup BOARD_EMSK_COMMON_TIMER + * @{ + */ +#include "inc/arc/arc_builtin.h" +#include "inc/arc/arc.h" +#include "inc/arc/arc_timer.h" +#include "inc/arc/arc_exception.h" + +#include "board/emsk/emsk.h" + +#define MAX_SYS_COUNTER_VALUE (0xffffffff) + +#ifndef BOARD_SYS_TIMER_HZ +#define BOARD_SYS_TIMER_HZ (1000) +#endif + +/** emsk board timer interrupt reset count */ +static uint32_t cyc_hz_count = (BOARD_CPU_CLOCK / BOARD_SYS_TIMER_HZ); + +/** emsk board timer counter in timer interrupt */ +volatile uint64_t gl_emsk_sys_hz_cnt = 0; +/** emsk board 1ms counter */ +volatile uint32_t gl_emsk_ms_cnt = 0; + +#define HZ_COUNT_CONV(precision, base) ((precision)/(base)) + +/** + * \brief Update timer counter and other MS period operation + * in cycling interrupt and must be called periodically. When the OS timer + * interrupt is in conflict with the bare-metal timer interrupt, + * put this function into the OS timer interrupt + * \param[in] precision interrupt-period precision in Hz + */ +void board_timer_update(uint32_t precision) +{ + static uint32_t sys_hz_update = 0; + static uint32_t sys_ms_update = 0; + uint32_t hz_conv = 0; + + /** count sys hz */ + hz_conv = HZ_COUNT_CONV(precision, BOARD_SYS_TIMER_HZ); + sys_hz_update ++; + + if (sys_hz_update >= hz_conv) + { + sys_hz_update = 0; + gl_emsk_sys_hz_cnt ++; + } + + /** count ms */ + hz_conv = HZ_COUNT_CONV(precision, BOARD_SYS_TIMER_MS_HZ); + sys_ms_update ++; + + if (sys_ms_update >= hz_conv) + { + sys_ms_update = 0; + gl_emsk_ms_cnt ++; + + /* no SD card support */ + //emsk_sdcard_1ms_update(); + } +} + +/** + * \brief emsk bare-metal timer interrupt. + * the Interrupt frequency is based on the defined \ref BOARD_SYS_TIMER_HZ + */ +static void emsk_timer_isr(void *ptr) +{ + timer_int_clear(BOARD_SYS_TIMER_ID); + + board_timer_update(BOARD_SYS_TIMER_HZ); +} + +/** + * \brief init bare-metal emsk board timer and interrupt + * \details + * This function is called in \ref board_init, and + * it initializes the 1-MS timer interrupt for bare-metal mode + */ +void emsk_timer_init(void) +{ + if (timer_present(BOARD_SYS_TIMER_ID)) + { + int_disable(BOARD_SYS_TIMER_INTNO); /* disable first then enable */ + int_handler_install(BOARD_SYS_TIMER_INTNO, emsk_timer_isr); + timer_start(BOARD_SYS_TIMER_ID, TIMER_CTRL_IE | TIMER_CTRL_NH, cyc_hz_count); /* start 1ms timer interrupt */ + + int_enable(BOARD_SYS_TIMER_INTNO); + } +} + +/** + * \brief get current cpu hardware ticks + * \retval hardware ticks count in 64bit format + */ +uint64_t board_get_hwticks(void) +{ + uint32_t sub_ticks; + uint64_t total_ticks; + timer_current(TIMER_0, &sub_ticks); + + total_ticks = (uint64_t)OSP_GET_CUR_MS() * (BOARD_CPU_CLOCK / BOARD_SYS_TIMER_HZ); + total_ticks += (uint64_t)sub_ticks; + + return total_ticks; +} + +/** + * \brief get current passed us since timer init + * \retval us count in 64bit format + */ +uint64_t board_get_cur_us(void) +{ + uint32_t sub_us; + uint64_t total_us; + timer_current(TIMER_0, &sub_us); + + sub_us = ((uint64_t)sub_us * 1000000) / BOARD_CPU_CLOCK; + total_us = ((uint64_t)OSP_GET_CUR_MS()) * 1000 + (uint64_t)sub_us; + + return total_us; +} + +/** + * \brief provide MS delay function + * \details + * this function needs a 1-MS timer interrupt to work. + * For bare-metal, it is implemented in this file. + * For OS, you must call \ref board_timer_update in + * the OS 1-MS timer interrupt when the bare-metal timer interrupt + * is not ready + * \param[in] ms MS to delay + * \param[in] os_compat Enable or disable + * When this delay is enabled, use the OS delay function, if one is provided. + * See \ref OSP_DELAY_OS_COMPAT_ENABLE and + * \ref OSP_DELAY_OS_COMPAT_DISABLE + */ +void board_delay_ms(uint32_t ms, uint8_t os_compat) +{ + uint64_t start_us, us_delayed; + +#ifdef ENABLE_OS + + if (os_compat == OSP_DELAY_OS_COMPAT_ENABLE) + { + /** \todo add different os delay functions */ +#ifdef OS_FREERTOS + vTaskDelay(ms); + return; +#endif + } + +#endif + us_delayed = ((uint64_t)ms * 1000); + start_us = board_get_cur_us(); + + while ((board_get_cur_us() - start_us) < us_delayed); +} + +/** @} end of group BOARD_EMSK_COMMON_TIMER */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.h new file mode 100644 index 000000000..0e3753119 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/emsk_timer.h @@ -0,0 +1,63 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-31 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_COMMON_TIMER + * \brief emsk timer functions header + */ + +/** + * \addtogroup BOARD_EMSK_COMMON_TIMER + * @{ + */ +#ifndef _EMSK_TIMER_ +#define _EMSK_TIMER_ + +#include "inc/embARC_toolchain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile uint64_t gl_emsk_sys_hz_cnt; +extern volatile uint32_t gl_emsk_ms_cnt; + +extern void emsk_timer_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMSK_TIMER_ */ + +/** @} end of group BOARD_EMSK_COMMON_TIMER */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.c new file mode 100644 index 000000000..2553296e6 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.c @@ -0,0 +1,116 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-07 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * \defgroup BOARD_EMSK_DRV_MUX EMSK Mux Driver + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Mux Controller Driver + * \details + * Mux controller is the hardware external PMOD port pin connection + * controller, it can distribute the external port pins into different + * functions like general input/output, spi, iic, uart and so on. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_MUX + * \brief emsk mux controller driver + */ + +/** + * \addtogroup BOARD_EMSK_DRV_MUX + * @{ + */ +#include "board/emsk/common/mux_hal.h" +#include "board/emsk/common/mux.h" + +static MUX_REG *mux_ctrl_regs = (MUX_REG *)0; + +/** initialize i2c controller and set slave device address */ +void mux_init(MUX_REG *mux_regs) +{ + // Initialize Mux controller registers by default values + mux_regs[PMOD_MUX_CTRL] = PMOD_MUX_CTRL_DEFAULT; + mux_regs[SPI_MAP_CTRL] = SPI_MAP_CTRL_DEFAULT; + mux_regs[UART_MAP_CTRL] = UART_MAP_CTRL_DEFAULT; + mux_ctrl_regs = mux_regs; +} + +/** Get mux ctrl register pointer, only valid after mux_init */ +MUX_REG *get_mux_regs(void) +{ + return mux_ctrl_regs; +} + +/** set PMOD muxer scheme */ +void set_pmod_mux(MUX_REG *mux_regs, uint32_t val) +{ + mux_regs[PMOD_MUX_CTRL] = val; +} + +/** get PMOD muxer scheme */ +uint32_t get_pmod_mux(MUX_REG *mux_regs) +{ + return (uint32_t) mux_regs[PMOD_MUX_CTRL]; +} + +/** set PMOD muxer scheme */ +void change_pmod_mux(MUX_REG *mux_regs, uint32_t val, uint32_t change_bits) +{ + mux_regs[PMOD_MUX_CTRL] = ((mux_regs[PMOD_MUX_CTRL] & ~change_bits) | val); +} + +/** set SPI connection scheme */ +void set_spi_map(MUX_REG *mux_regs, uint32_t val) +{ + mux_regs[SPI_MAP_CTRL] = val; +} + +/** get SPI connection scheme */ +uint32_t get_spi_map(MUX_REG *mux_regs) +{ + return (uint32_t) mux_regs[SPI_MAP_CTRL]; +} + +/** set UART connection scheme */ +void set_uart_map(MUX_REG *mux_regs, uint32_t val) +{ + mux_regs[UART_MAP_CTRL] = val; +} + +/** get UART connection scheme */ +uint32_t get_uart_map(MUX_REG *mux_regs) +{ + return (uint32_t) mux_regs[UART_MAP_CTRL]; +} +/** @} end of group BOARD_EMSK_DRV_MUX */ + diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.h new file mode 100644 index 000000000..fd78d3890 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux.h @@ -0,0 +1,186 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-07 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_MUX + * \brief header file of emsk mux controller driver + */ + +/** + * \addtogroup BOARD_EMSK_DRV_MUX + * @{ + */ +#ifndef _MUX_H_ +#define _MUX_H_ + +#include "inc/embARC_toolchain.h" + +#define BIT0 (0) +#define BIT1 (1) +#define BIT2 (2) +#define BIT3 (3) +#define PM1_OFFSET (0) +#define PM2_OFFSET (4) +#define PM3_OFFSET (8) +#define PM4_OFFSET (12) +#define PM5_OFFSET (16) +#define PM6_OFFSET (20) +#define PM7_OFFSET (24) + +#define PM1_MASK (0xf << PM1_OFFSET) +#define PM2_MASK (0xf << PM2_OFFSET) +#define PM3_MASK (0xf << PM3_OFFSET) +#define PM4_MASK (0xf << PM4_OFFSET) +#define PM5_MASK (0xf << PM5_OFFSET) +#define PM6_MASK (0xf << PM6_OFFSET) +#define PM7_MASK (0xf << PM7_OFFSET) + + +#define SPI_MAP_NORMAL (0) +#define SPI_MAP_LOOPBACK (1) + +#define UART_MAP_TYPE4 (0xE4) +#define UART_MAP_TYPE3 (0x6C) + +/** + * \name Default pin muxer settings + * @{ + */ +#define PMOD_MUX_CTRL_DEFAULT (0) /*!< all pins are configured as GPIO inputs */ +#define SPI_MAP_CTRL_DEFAULT (SPI_MAP_NORMAL) /*!< normal SPI mode */ +#define UART_MAP_CTRL_DEFAULT (UART_MAP_TYPE4) /*!< TYPE4 PMOD compatible */ +/** @} end of name */ + +/** + * \name PMOD 1 Multiplexor + * @{ + */ +#define PM1_UR_GPIO_C ((0 << BIT0) << PM1_OFFSET) /*!< Pmod1[4:1] are connected to DW GPIO Port C[11:8] */ +#define PM1_UR_UART_0 ((1 << BIT0) << PM1_OFFSET) /*!< Pmod1[4:1] are connected to DW UART0 signals */ + +#define PM1_LR_GPIO_A ((0 << BIT2) << PM1_OFFSET) /*!< Pmod1[10:7] are connected to DW GPIO Port A[11:8] */ +#define PM1_LR_SPI_S ((1 << BIT2) << PM1_OFFSET) /*!< Pmod1[10:7] are connected to DW SPI Slave signals */ +/** @} end of name */ + + +/** + * \name PMOD 2 Multiplexor + * @{ + */ +#define PM2_GPIO_AC ((0 << BIT0) << PM2_OFFSET) /*!< Pmod2[4:1] are connected to DW GPIO Port C[15:12], + Pmod2[10:7] are connected to DW GPIO Port A[15:12] */ + +#define PM2_I2C_HRI ((1 << BIT0) << PM2_OFFSET) /*!< connect I2C to Pmod2[4:1] and halt/run interface to Pmod2[10:7] */ +/** @} end of name */ + + +/** + * \name PMOD 3 Multiplexor + * @{ + */ +#define PM3_GPIO_AC ((0 << BIT0) << PM3_OFFSET) /*!< Pmod3[4:1] are connected to DW GPIO Port C[19:16], + Pmod3[10:7] are connected to DW GPIO Port A[19:16] */ + +#define PM3_I2C_GPIO_D ((1 << BIT0) << PM3_OFFSET) /*!< Pmod3[4:3] are connected to DW I2C signals, + Pmod3[2:1] are connected to DW GPIO Port D[1:0], + Pmod3[10:7] are connected to DW GPIO Port D[3:2] */ +/** @} end of name */ + + +/** + * \name PMOD 4 Multiplexor + * @{ + */ +#define PM4_GPIO_AC ((0 << BIT0) << PM4_OFFSET) /*!< Pmod4[4:1] are connected to DW GPIO Port C[23:20], + Pmod4[10:7] are connected to DW GPIO Port A[23:20] */ + +#define PM4_I2C_GPIO_D ((1 << BIT0) << PM4_OFFSET) /*!< Pmod4[4:3] are connected to DW I2C signals, + Pmod4[2:1] are connected to DW GPIO Port D[5:4], + Pmod4[10:7] are connected to DW GPIO Port D[7:6] */ +/** @} end of name */ + +/** + * \name PMOD 5 Multiplexor + * @{ + */ +#define PM5_UR_GPIO_C ((0 << BIT0) << PM5_OFFSET) /*!< Pmod5[4:1] are connected to DW GPIO Port C[27:24] */ +#define PM5_UR_SPI_M1 ((1 << BIT0) << PM5_OFFSET) /*!< Pmod5[4:1] are connected to DW SPI Master signals using CS1_N */ + +#define PM5_LR_GPIO_A ((0 << BIT2) << PM5_OFFSET) /*!< Pmod5[10:7] are connected to DW GPIO Port A[27:24] */ +#define PM5_LR_SPI_M2 ((1 << BIT2) << PM5_OFFSET) /*!< Pmod5[10:7] are connected to DW SPI Master signals using CS2_N */ +/** @} end of name */ + + +/** + * \name PMOD 6 Multiplexor + * @{ + */ +#define PM6_UR_GPIO_C ((0 << BIT0) << PM6_OFFSET) /*!< Pmod6[4:1] are connected to DW GPIO Port C[31:28] */ +#define PM6_UR_SPI_M0 ((1 << BIT0) << PM6_OFFSET) /*!< Pmod6[4:1] are connected to DW SPI Master signals using CS0_N */ + +#define PM6_LR_GPIO_A ((0 << BIT2) << PM6_OFFSET) /*!< Pmod6[10:7] are connected to DW GPIO Port A[31:28] */ + +#define PM6_LR_CSS_STAT ((1 << BIT2) << PM6_OFFSET) /*!< Pmod6[8:7] are connected to the DW SPI Master chip select signals CS1_N and CS2_N, + Pmod6[6:5] are connected to the ARC EM halt and sleep status signals */ +/** @} end of name */ + +/** + * \name PMOD 7 Multiplexor + * @{ + */ +#define PM7_GPIO_D ((0 << BIT0) << PM7_OFFSET) /*!< Pmod7[4:1] are connected to DW GPIO Port D[11:8] */ +#define PM7_STAT ((1 << BIT0) << PM7_OFFSET) /*!< Pmod7[4:1] are connected to the ARC EM sleep status signals */ +/** @} end of name */ +typedef volatile uint32_t MUX_REG; + +#ifdef __cplusplus +extern "C" { +#endif + +extern void mux_init(MUX_REG *mux_regs); +extern MUX_REG *get_mux_regs(void); +extern void set_pmod_mux(MUX_REG *mux_regs, uint32_t val); +extern uint32_t get_pmod_mux(MUX_REG *mux_regs); +extern void change_pmod_mux(MUX_REG *mux_regs, uint32_t val, uint32_t change_bits); +extern void set_spi_map(MUX_REG *mux_regs, uint32_t val); +extern uint32_t get_spi_map(MUX_REG *mux_regs); +extern void set_uart_map(MUX_REG *mux_regs, uint32_t val); +extern uint32_t get_uart_map(MUX_REG *mux_regs); + +#ifdef __cplusplus +} +#endif + +#endif /* _MUX_H_ */ + +/** @} end of group BOARD_EMSK_DRV_MUX */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux_hal.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux_hal.h new file mode 100644 index 000000000..ad3ff86a5 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/common/mux_hal.h @@ -0,0 +1,69 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-07 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_MUX + * \brief emsk mux control register index header + */ + +/** + * \addtogroup BOARD_EMSK_DRV_MUX + * @{ + */ +#ifndef _MUX_HAL_H_ +#define _MUX_HAL_H_ + +/** + * \name Mux Control Register Index + * @{ + */ +#define PMOD_MUX_CTRL 0 /*!< 32-bits, offset 0x0, + This register controls mapping of the peripheral device signals on Pmod connectors */ + +#define I2C_MAP_CTRL 1 /*!< 32-bits, offset 0x4 */ + +#define SPI_MAP_CTRL 2 /*!< 32-bits, offset 0x8, + SPI_MAP_CTRL[0] selects the mode of operation of the SPI Slave: + - Normal operation, SPI_MAP_CTRL[0]=0: SPI Slave is connected to Pmod1 at connector J1. + - Loop-back mode, SPI_MAP_CTRL[0]=1: SPI Slave is connected to the SPI Master inside the FPGA using CS4. + */ + +#define UART_MAP_CTRL 3 /*!< 32-bits, offset 0x8, + This register controls the mapping of the UART signals on the Pmod1 connector. */ +/** @} end of name */ + + +#endif /* _MUX_HAL_H_ */ + +/** @} end of group BOARD_EMSK_DRV_MUX */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk.h new file mode 100644 index 000000000..8453362b7 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk.h @@ -0,0 +1,142 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-18 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * + * \file + * \ingroup BOARD_EMSK_COMMON_INIT + * \brief emsk resource definitions + */ + +/** + * \addtogroup BOARD_EMSK_COMMON_INIT + * @{ + */ +#ifndef _EMSK_H_ +#define _EMSK_H_ + +#include "inc/arc/arc_em.h" + +#include "board/emsk/uart/dw_uart_obj.h" +#include "board/emsk/gpio/dw_gpio_obj.h" +#include "board/emsk/gpio/emsk_gpio.h" + +#include "board/emsk/common/emsk_timer.h" + +#include "board/emsk/emsk_hardware.h" + +/* Additional hardware driver for embARC BSP */ +#include "board/emsk/spi/dw_spi_obj.h" +#include "board/emsk/pmrf/mrf24j40.h" +#include "board/emsk/pmrf/pmrf.h" +#include "board/emsk/spiflash/spiflash.h" + +#define EMSK_GPIO_PORT_A DW_GPIO_PORT_A +#define EMSK_GPIO_PORT_B DW_GPIO_PORT_B +#define EMSK_GPIO_PORT_C DW_GPIO_PORT_C +#define EMSK_GPIO_PORT_D DW_GPIO_PORT_D + +/* common macros must be defined by all boards */ + +#define BOARD_CONSOLE_UART_ID DW_UART_1_ID +#define BOARD_CONSOLE_UART_BAUD UART_BAUDRATE_115200 +#define BOARD_ADC_IIC_ID DW_IIC_0_ID +#define BOARD_TEMP_SENSOR_IIC_ID DW_IIC_0_ID + +#define BOARD_TEMP_IIC_SLVADDR TEMP_I2C_SLAVE_ADDRESS + +#define BOARD_SDCARD_SPI_ID DW_SPI_0_ID +#define BOARD_WIFI_SPI_ID DW_SPI_0_ID +#define BOARD_SFLASH_SPI_ID DW_SPI_0_ID + +#define BOARD_SDCARD_SPI_LINE EMSK_SPI_LINE_SDCARD +#define BOARD_WIFI_SPI_LINE EMSK_SPI_LINE_1 +#define BOARD_SFLASH_SPI_LINE EMSK_SPI_LINE_SFLASH + +#ifndef BOARD_SPI_FREQ +#define BOARD_SPI_FREQ (1000000) +#endif + +#ifndef BOARD_SPI_CLKMODE +#define BOARD_SPI_CLKMODE (SPI_CLK_MODE_0) +#endif + +#define BOARD_SYS_TIMER_ID TIMER_0 +#define BOARD_SYS_TIMER_INTNO INTNO_TIMER0 +#define BOARD_SYS_TIMER_HZ (1000) + +/** board timer count frequency (HZ) */ +#define BOARD_SYS_TIMER_MS_HZ (1000) +/** board timer count frequency convention based on the global timer counter */ +#define BOARD_SYS_TIMER_MS_CONV (BOARD_SYS_TIMER_MS_HZ/BOARD_SYS_TIMER_HZ) + +#define BOARD_OS_TIMER_ID TIMER_0 +#define BOARD_OS_TIMER_INTNO INTNO_TIMER0 + +#define BOARD_CPU_CLOCK CLK_CPU +#define BOARD_DEV_CLOCK CLK_BUS_APB + +#define BOARD_LED_MASK (0x1ff) +#define BOARD_LED_CNT (9) +#define BOARD_BTN_MASK (0x7) +#define BOARD_BTN_CNT (3) +#define BOARD_SWT_MASK (0xf) +#define BOARD_SWT_CNT (4) + +#define BOARD_ONBOARD_NTSHELL_ID (EMSK_NTSHELL_0_ID) + +#define OSP_DELAY_OS_COMPAT_ENABLE (1) +#define OSP_DELAY_OS_COMPAT_DISABLE (0) + + +#define OSP_GET_CUR_SYSHZ() (gl_emsk_sys_hz_cnt) +#define OSP_GET_CUR_MS() (gl_emsk_ms_cnt) +#define OSP_GET_CUR_US() board_get_cur_us() +#define OSP_GET_CUR_HWTICKS() board_get_hwticks() + +#ifdef __cplusplus +extern "C" { +#endif + +extern void board_init(void); +extern void board_timer_update(uint32_t precision); +extern void board_delay_ms(uint32_t ms, uint8_t os_compat); +extern uint64_t board_get_hwticks(void); +extern uint64_t board_get_cur_us(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMSK_H_ */ + +/** @} end of group BOARD_EMSK_COMMON_INIT */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk_hardware.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk_hardware.h new file mode 100644 index 000000000..b3bac387a --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/emsk_hardware.h @@ -0,0 +1,117 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2015-11-16 + * \author Qiang Gu(Qiang.Gu@synopsys.com) +--------------------------------------------- */ +/** + * + * \file + * \ingroup BOARD_EMSK_COMMON_INIT + * \brief emsk hardware resource definitions + */ + +/** + * \addtogroup BOARD_EMSK_COMMON_INIT + * @{ + */ +#ifndef _EMSK_HARDWARE_H_ +#define _EMSK_HARDWARE_H_ + +/** CPU Clock Frequency definition */ +#if defined(BOARD_CPU_FREQ) +/*!< Get cpu clock frequency definition from build system */ +#define CLK_CPU (BOARD_CPU_FREQ) +#elif defined(ARC_FEATURE_CPU_CLOCK_FREQ) +/*!< Get cpu clock frequency definition from tcf file */ +#define CLK_CPU (ARC_FEATURE_CPU_CLOCK_FREQ) +#else +/*!< Default cpu clock frequency */ +#define CLK_CPU (20000000) +#endif + +/** Peripheral Bus Reference Clock definition */ +#ifdef BOARD_DEV_FREQ +/*!< Get peripheral bus reference clock defintion from build system */ +#define CLK_BUS_APB (BOARD_DEV_FREQ) +#else +/*!< Default peripheral bus reference clock defintion */ +#define CLK_BUS_APB (50000000U) +#endif + +/* Device Register Base Address */ +#define REL_REGBASE_PINMUX (0x00000000U) /*!< PINMUX */ +#define REL_REGBASE_SPI_MST_CS_CTRL (0x00000014U) /*!< SPI Master Select Ctrl */ +#define REL_REGBASE_GPIO0 (0x00002000U) /*!< GPIO 0 Onboard */ +#define REL_REGBASE_TIMERS (0x00003000U) /*!< DW TIMER */ +#define REL_REGBASE_I2C0 (0x00004000U) /*!< I2C 0 */ +#define REL_REGBASE_I2C1 (0x00005000U) /*!< I2C 1 */ +#define REL_REGBASE_SPI0 (0x00006000U) /*!< SPI Master */ +#define REL_REGBASE_SPI1 (0x00007000U) /*!< SPI Slave */ +#define REL_REGBASE_UART0 (0x00008000U) /*!< UART0 is connected to PMOD */ +#define REL_REGBASE_UART1 (0x00009000U) /*!< UART1 is USB-UART£¬ use UART1 as default */ +#define REL_REGBASE_UART2 (0x0000A000U) /*!< UART2 */ +#define REL_REGBASE_WDT (0x0000B000U) /*!< WDT */ +// #define REL_REGBASE_I2S_MASTER_IN (0x0000C000U) /*!< I2S Master In */ +// #define REL_REGBASE_I2S_MASTER_OUT (0x0000D000U) /*!< I2S Master Out */ +// #define REL_REGBASE_GMAC (0x0000E000U) /*!< GMAC */ + +/* Interrupt Connection */ +#define INTNO_TIMER0 16 /*!< ARC Timer0 */ +#define INTNO_TIMER1 17 /*!< ARC Timer1 */ +#define INTNO_SECURE_TIMER0 20 /*!< Core Secure Timer 0 */ +#define INTNO_DMA_START 22 /*!< Core DMA Controller */ +#define INTNO_DMA_COMPLETE 22 /*!< Core DMA Controller Complete */ +#define INTNO_DMA_ERROR 23 /*!< Core DMA Controller Error */ +#define INTNO_GPIO 24 /*!< GPIO controller */ +#define INTNO_I2C0 25 /*!< I2C_0 controller */ +#define INTNO_I2C1 26 /*!< I2C_1 controller */ +#define INTNO_SPI_MASTER 27 /*!< SPI Master controller */ +#define INTNO_SPI_SLAVE 28 /*!< SPI Slave controller */ +#define INTNO_UART0 29 /*!< UART0 */ +#define INTNO_UART1 30 /*!< UART1 */ +#define INTNO_UART2 31 /*!< UART2 */ +#define INTNO_DW_WDT 32 /*!< WDT */ +#define INTNO_DW_TMR0 33 /*!< DW Timer 0 */ +#define INTNO_DW_TMR1 34 /*!< DW Timer 1 */ +// #define INTNO_I2S_Master_In 33 /*!< I2S Master In */ +// #define INTNO_I2S_Master_Out 34 /*!< I2S Master Out */ +// #define INTNO_GMAC 35 /*!< GMAC */ + +/* SPI Mater Signals Usage */ +#define EMSK_SPI_LINE_0 0 /*!< CS0 -- Pmod 6 pin1 */ +#define EMSK_SPI_LINE_1 1 /*!< CS1 -- Pmod 5 pin1 or Pmod 6 pin 7 */ +#define EMSK_SPI_LINE_2 2 /*!< CS2 -- Pmod 6 pin8 */ +#define EMSK_SPI_LINE_SDCARD 3 /*!< CS3 -- On-board SD card */ +#define EMSK_SPI_LINE_SPISLAVE 4 /*!< CS4 -- Internal SPI slave */ +#define EMSK_SPI_LINE_SFLASH 5 /*!< CS5 -- On-board SPI Flash memory */ + +#endif /* _EMSK_HARDWARE_H_ */ + +/** @} end of group BOARD_EMSK_COMMON_INIT */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.c new file mode 100644 index 000000000..9e66cf40a --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.c @@ -0,0 +1,394 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-24 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \defgroup BOARD_EMSK_DRV_DW_GPIO_OBJ EMSK DW GPIO Object + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Designware GPIO Objects + * \details + * Implement the EMSK board GPIO object using the DesignWare GPIO device driver. + * Only need to implement some DesignWare GPIO structures and combine with EMSK GPIO + * hardware resources, like in C++ class instantiation. + * For example, in C++, define a class called gpio + * class gpio { + * + * }; + * then instantiate the gpio class: + * gpio emsk_gpio_a; + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_GPIO_OBJ + * \brief DesignWare GPIO object instantiation on EMSK + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_GPIO_OBJ + * @{ + */ +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" + +#include "board/emsk/gpio/dw_gpio_obj.h" + +#include "board/emsk/emsk.h" +/* + * Uncomment this to enable default + * gpio bit handler output message + * by uart + */ + +#ifdef ARC_FEATURE_DMP_PERIPHERAL +#define PERIPHERAL_BASE ARC_FEATURE_DMP_PERIPHERAL +#else +#define PERIPHERAL_BASE _arc_aux_read(AUX_DMP_PERIPHERAL) +#endif + +#if (USE_DW_GPIO_PORT_A) +static DEV_GPIO port_a; +static DW_GPIO_PORT dw_gpio_port_a; +static DEV_GPIO_HANDLER dw_gpio_bit_handler_a[EMSK_GPIO_A_INT_MAX_COUNT]; +static DW_GPIO_BIT_ISR dw_gpio_bit_isr_a = +{ + EMSK_GPIO_A_INT_MAX_COUNT, dw_gpio_bit_handler_a +}; + +static int32_t porta_open(uint32_t dir) +{ + return dw_gpio_open(&port_a, dir); +} + +static int32_t porta_close(void) +{ + return dw_gpio_close(&port_a); +} + +static int32_t porta_control(uint32_t ctrl_cmd, void *param) +{ + return dw_gpio_control(&port_a, ctrl_cmd, param); +} + +static int32_t porta_write(uint32_t val, uint32_t mask) +{ + return dw_gpio_write(&port_a, val, mask); +} + +static int32_t porta_read(uint32_t *val, uint32_t mask) +{ + return dw_gpio_read(&port_a, val, mask); +} + +static void porta_isr(void *ptr) +{ + dw_gpio_isr_handler(&port_a, ptr); +} + +static void porta_install(void) +{ + uint32_t i; + DEV_GPIO_PTR port_ptr = &port_a; + DEV_GPIO_INFO_PTR info_ptr = &(port_a.gpio_info); + DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_a); + + info_ptr->gpio_ctrl = (void *)dw_port_ptr; + info_ptr->opn_cnt = 0; + info_ptr->method = 0; + info_ptr->direction = 0; + info_ptr->extra = 0; + + dw_port_ptr->no = DW_GPIO_PORT_A; + dw_port_ptr->regs = (DW_GPIO_REG_PTR)(PERIPHERAL_BASE | REL_REGBASE_GPIO0); + dw_port_ptr->valid_bit_mask = EMSK_GPIO_A_VALID_MASK; + dw_port_ptr->intno = INTNO_GPIO; + dw_port_ptr->int_handler = porta_isr; + + for (i = 0; i < dw_gpio_bit_isr_a.int_bit_max_cnt; i++) + { + dw_gpio_bit_isr_a.int_bit_handler_ptr[i] = NULL; + } + + dw_port_ptr->gpio_bit_isr = &dw_gpio_bit_isr_a; + + port_ptr->gpio_open = porta_open; + port_ptr->gpio_close = porta_close; + port_ptr->gpio_control = porta_control; + port_ptr->gpio_write = porta_write; + port_ptr->gpio_read = porta_read; +} +#endif + +#if (USE_DW_GPIO_PORT_B) +static DEV_GPIO port_b; +static DW_GPIO_PORT dw_gpio_port_b; + +static int32_t portb_open(uint32_t dir) +{ + return dw_gpio_open(&port_b, dir); +} + +static int32_t portb_close(void) +{ + return dw_gpio_close(&port_b); +} + +static int32_t portb_control(uint32_t ctrl_cmd, void *param) +{ + return dw_gpio_control(&port_b, ctrl_cmd, param); +} + +static int32_t portb_write(uint32_t val, uint32_t mask) +{ + return dw_gpio_write(&port_b, val, mask); +} + +static int32_t portb_read(uint32_t *val, uint32_t mask) +{ + return dw_gpio_read(&port_b, val, mask); +} + +static void portb_isr(void *ptr) +{ + dw_gpio_isr_handler(&port_b, ptr); +} + +static void portb_install(void) +{ + DEV_GPIO_PTR port_ptr = &port_b; + DEV_GPIO_INFO_PTR info_ptr = &(port_b.gpio_info); + DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_b); + + info_ptr->gpio_ctrl = (void *)dw_port_ptr; + info_ptr->opn_cnt = 0; + info_ptr->method = 0; + info_ptr->direction = 0; + info_ptr->extra = 0; + + dw_port_ptr->no = DW_GPIO_PORT_B; + dw_port_ptr->regs = (DW_GPIO_REG_PTR)(PERIPHERAL_BASE | REL_REGBASE_GPIO0); + dw_port_ptr->valid_bit_mask = EMSK_GPIO_B_VALID_MASK; + + dw_port_ptr->intno = INTNO_GPIO; + dw_port_ptr->int_handler = portb_isr; + dw_port_ptr->gpio_bit_isr = NULL; + + port_ptr->gpio_open = portb_open; + port_ptr->gpio_close = portb_close; + port_ptr->gpio_control = portb_control; + port_ptr->gpio_write = portb_write; + port_ptr->gpio_read = portb_read; +} +#endif + + +#if (USE_DW_GPIO_PORT_C) +static DEV_GPIO port_c; +static DW_GPIO_PORT dw_gpio_port_c; + +static int32_t portc_open(uint32_t dir) +{ + return dw_gpio_open(&port_c, dir); +} + +static int32_t portc_close(void) +{ + return dw_gpio_close(&port_c); +} + +static int32_t portc_control(uint32_t ctrl_cmd, void *param) +{ + return dw_gpio_control(&port_c, ctrl_cmd, param); +} + +static int32_t portc_write(uint32_t val, uint32_t mask) +{ + return dw_gpio_write(&port_c, val, mask); +} + +static int32_t portc_read(uint32_t *val, uint32_t mask) +{ + return dw_gpio_read(&port_c, val, mask); +} + +static void portc_isr(void *ptr) +{ + dw_gpio_isr_handler(&port_c, ptr); +} + +static void portc_install(void) +{ + DEV_GPIO_PTR port_ptr = &port_c; + DEV_GPIO_INFO_PTR info_ptr = &(port_c.gpio_info); + DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_c); + + info_ptr->gpio_ctrl = (void *)dw_port_ptr; + info_ptr->opn_cnt = 0; + info_ptr->method = 0; + info_ptr->direction = 0; + info_ptr->extra = 0; + + dw_port_ptr->no = DW_GPIO_PORT_C; + dw_port_ptr->regs = (DW_GPIO_REG_PTR)(PERIPHERAL_BASE | REL_REGBASE_GPIO0); + dw_port_ptr->valid_bit_mask = EMSK_GPIO_C_VALID_MASK; + + dw_port_ptr->intno = INTNO_GPIO; + dw_port_ptr->int_handler = portc_isr; + dw_port_ptr->gpio_bit_isr = NULL; + + port_ptr->gpio_open = portc_open; + port_ptr->gpio_close = portc_close; + port_ptr->gpio_control = portc_control; + port_ptr->gpio_write = portc_write; + port_ptr->gpio_read = portc_read; +} +#endif + +#if (USE_DW_GPIO_PORT_D) +static DEV_GPIO port_d; +static DW_GPIO_PORT dw_gpio_port_d; + +static int32_t portd_open(uint32_t dir) +{ + return dw_gpio_open(&port_d, dir); +} + +static int32_t portd_close(void) +{ + return dw_gpio_close(&port_d); +} + +static int32_t portd_control(uint32_t ctrl_cmd, void *param) +{ + return dw_gpio_control(&port_d, ctrl_cmd, param); +} + +static int32_t portd_write(uint32_t val, uint32_t mask) +{ + return dw_gpio_write(&port_d, val, mask); +} + +static int32_t portd_read(uint32_t *val, uint32_t mask) +{ + return dw_gpio_read(&port_d, val, mask); +} + +static void portd_isr(void *ptr) +{ + dw_gpio_isr_handler(&port_d, ptr); +} + +static void portd_install(void) +{ + DEV_GPIO_PTR port_ptr = &port_d; + DEV_GPIO_INFO_PTR info_ptr = &(port_d.gpio_info); + DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_d); + + info_ptr->gpio_ctrl = (void *)dw_port_ptr; + info_ptr->opn_cnt = 0; + info_ptr->method = 0; + info_ptr->direction = 0; + info_ptr->extra = 0; + + dw_port_ptr->no = DW_GPIO_PORT_D; + dw_port_ptr->regs = (DW_GPIO_REG_PTR)(PERIPHERAL_BASE | REL_REGBASE_GPIO0); + dw_port_ptr->valid_bit_mask = EMSK_GPIO_D_VALID_MASK; + + dw_port_ptr->intno = INTNO_GPIO; + dw_port_ptr->int_handler = portd_isr; + dw_port_ptr->gpio_bit_isr = NULL; + + port_ptr->gpio_open = portd_open; + port_ptr->gpio_close = portd_close; + port_ptr->gpio_control = portd_control; + port_ptr->gpio_write = portd_write; + port_ptr->gpio_read = portd_read; +} +#endif + +DEV_GPIO_PTR gpio_get_dev(int32_t gpio_id) +{ + static uint32_t install_flag = 0; + + /* intall device objects */ + if (install_flag == 0) + { + install_flag = 1; + dw_gpio_all_install(); + } + + switch (gpio_id) + { +#if (USE_DW_GPIO_PORT_A) + + case DW_GPIO_PORT_A: + return &port_a; +#endif +#if (USE_DW_GPIO_PORT_B) + + case DW_GPIO_PORT_B: + return &port_b; +#endif +#if (USE_DW_GPIO_PORT_C) + + case DW_GPIO_PORT_C: + return &port_c; +#endif +#if (USE_DW_GPIO_PORT_D) + + case DW_GPIO_PORT_D: + return &port_d; +#endif + + default: + break; + } + + return NULL; +} + +void dw_gpio_all_install(void) +{ +#if (USE_DW_GPIO_PORT_A) + porta_install(); +#endif +#if (USE_DW_GPIO_PORT_B) + portb_install(); +#endif +#if (USE_DW_GPIO_PORT_C) + portc_install(); +#endif +#if (USE_DW_GPIO_PORT_D) + portd_install(); +#endif +} + +/** @} end of group BOARD_EMSK_DRV_DW_GPIO_OBJ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.h new file mode 100644 index 000000000..337c4aec1 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/dw_gpio_obj.h @@ -0,0 +1,90 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-24 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_GPIO_OBJ + * \brief header file of designware gpio object instantiation on emsk + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_GPIO_OBJ + * @{ + */ +#ifndef _DW_GPIO_OBJ_H_ +#define _DW_GPIO_OBJ_H_ + +#include "device/designware/gpio/dw_gpio.h" + +/** + * \name Designware GPIO Port Bank Control Macros + * @{ + */ +#define USE_DW_GPIO_PORT_A 1 +#define USE_DW_GPIO_PORT_B 1 +#define USE_DW_GPIO_PORT_C 1 +#define USE_DW_GPIO_PORT_D 1 +/** @} end of name */ + +/** + * \name Designware GPIO Port Interrupt Available Number Macros + * @{ + */ +#define EMSK_GPIO_A_INT_MAX_COUNT 32 +#define EMSK_GPIO_B_INT_MAX_COUNT 0 +#define EMSK_GPIO_C_INT_MAX_COUNT 0 +#define EMSK_GPIO_D_INT_MAX_COUNT 0 +/** @} end of name */ + +/** + * \name Designware GPIO Port Available Bits Macros + * @{ + */ +#define EMSK_GPIO_A_VALID_MASK DW_GPIO_MASK_ALL +#define EMSK_GPIO_B_VALID_MASK DW_GPIO_MASK_ALL +#define EMSK_GPIO_C_VALID_MASK DW_GPIO_MASK_ALL +#define EMSK_GPIO_D_VALID_MASK DW_GPIO_MASK_ALL +/** @} end of name */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void dw_gpio_all_install(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DW_GPIO_OBJ_H_*/ + +/** @} end of group BOARD_EMSK_DRV_DW_GPIO_OBJ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.c new file mode 100644 index 000000000..7a3e5139c --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.c @@ -0,0 +1,202 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-31 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \defgroup BOARD_EMSK_DRV_GPIO EMSK GPIO Driver + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Onboard GPIO Peripherals Driver + * \details + * Implementation of EMSK on-board button, led, dip switch driver, + * this is for better use, you don't have to get a gpio object before operating + * led,button,switch, because some basic functions for usage are provided. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_GPIO + * \brief all on emsk board gpio device init and operate functions + * \details this gpio devices are button, led, dip switch + */ + +/** + * \addtogroup BOARD_EMSK_DRV_GPIO + * @{ + */ +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" + +#include "board/emsk/gpio/emsk_gpio.h" +#include "board/emsk/emsk.h" + +static DEV_GPIO *led_port; +static DEV_GPIO *button_port; +static DEV_GPIO *switch_port; + +#define EMSK_GPIO_CHECK_EXP_NORTN(EXPR) CHECK_EXP_NOERCD(EXPR, error_exit) + +/** emsk on board gpio init */ +void emsk_gpio_init(void) +{ + emsk_led_init(); + emsk_button_init(); + emsk_switch_init(); +} + +/** emsk on-board led init, led default off */ +void emsk_led_init(void) +{ + led_port = gpio_get_dev(EMSK_LED_PORT); + + EMSK_GPIO_CHECK_EXP_NORTN(led_port != NULL); + + if (led_port->gpio_open(EMSK_LED_DIR) == E_OPNED) + { + led_port->gpio_control(GPIO_CMD_SET_BIT_DIR_OUTPUT, (void *)(EMSK_LED_MASK)); + led_port->gpio_control(GPIO_CMD_DIS_BIT_INT, (void *)(EMSK_LED_MASK)); + } + + led_write(0, BOARD_LED_MASK); + +error_exit: + return; +} + +/** emsk on-board button init */ +void emsk_button_init(void) +{ + button_port = gpio_get_dev(EMSK_BUTTON_PORT); + + EMSK_GPIO_CHECK_EXP_NORTN(button_port != NULL); + + if (button_port->gpio_open(EMSK_BUTTON_DIR) == E_OPNED) + { + button_port->gpio_control(GPIO_CMD_SET_BIT_DIR_INPUT, (void *)(EMSK_BUTTON_MASK)); + button_port->gpio_control(GPIO_CMD_DIS_BIT_INT, (void *)(EMSK_BUTTON_MASK)); + } + +error_exit: + return; +} + +/** emsk on-board switch init */ +void emsk_switch_init(void) +{ + switch_port = gpio_get_dev(EMSK_SWITCH_PORT); + + EMSK_GPIO_CHECK_EXP_NORTN(switch_port != NULL); + + if (switch_port->gpio_open(EMSK_SWITCH_DIR) == E_OPNED) + { + switch_port->gpio_control(GPIO_CMD_SET_BIT_DIR_INPUT, (void *)(EMSK_SWITCH_MASK)); + switch_port->gpio_control(GPIO_CMD_DIS_BIT_INT, (void *)(EMSK_SWITCH_MASK)); + } + +error_exit: + return; +} + +/** + * workaround for get led value + * because gpio read return is not right + */ +static uint32_t g_led_val; +/** write 1 to light on led bit, else light off led */ +void led_write(uint32_t led_val, uint32_t mask) +{ + EMSK_GPIO_CHECK_EXP_NORTN(led_port != NULL); + + led_val = (~led_val) & mask; + led_val = led_val << EMSK_LED_OFFSET; + mask = (mask << EMSK_LED_OFFSET) & EMSK_LED_MASK; + led_port->gpio_write(led_val, mask); + + g_led_val = led_val; + +error_exit: + return; +} + +/** read led value, on for 1, off for 0 */ +/** \todo need to find why when led set to output then can't get the right value of led */ +uint32_t led_read(uint32_t mask) +{ + uint32_t value; + + EMSK_GPIO_CHECK_EXP_NORTN(led_port != NULL); + + mask = (mask << EMSK_LED_OFFSET) & EMSK_LED_MASK; + led_port->gpio_read(&value, mask); + value = (~value) & EMSK_LED_MASK; + + return (value >> EMSK_LED_OFFSET); + +error_exit: + return 0; +} + +/** Pull down switch return 1, else 0 */ +uint32_t switch_read(uint32_t mask) +{ + uint32_t value; + + EMSK_GPIO_CHECK_EXP_NORTN(switch_port != NULL); + + mask = (mask << EMSK_SWITCH_OFFSET) & EMSK_SWITCH_MASK; + switch_port->gpio_read(&value, mask); + value = (~value) & mask; + + return (value >> EMSK_SWITCH_OFFSET); + +error_exit: + return 0; +} + +/** Press down bit set to 1 else 0 */ +uint32_t button_read(uint32_t mask) +{ + uint32_t value; + + EMSK_GPIO_CHECK_EXP_NORTN(button_port != NULL); + + mask = (mask << EMSK_BUTTON_OFFSET) & EMSK_BUTTON_MASK; + button_port->gpio_read(&value, mask); + value = (~value) & mask; + + return (value >> EMSK_BUTTON_OFFSET); + +error_exit: + return 0; +} + +/** @} end of group BOARD_EMSK_DRV_GPIO */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.h new file mode 100644 index 000000000..7e442786f --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/gpio/emsk_gpio.h @@ -0,0 +1,96 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-31 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_GPIO + * \brief emsk board gpio related functions header + */ +/** + * \addtogroup BOARD_EMSK_DRV_GPIO + * @{ + */ +#ifndef _EMSK_GPIO_H_ +#define _EMSK_GPIO_H_ + +#include "device/designware/gpio/dw_gpio.h" + +/** + * \name EMSK LED Port Configuration + * @{ + */ +#define EMSK_LED_OFFSET (0) +#define EMSK_LED_MASK ((0x1ff) << EMSK_LED_OFFSET) +#define EMSK_LED_PORT (DW_GPIO_PORT_B) +#define EMSK_LED_DIR ((0x1ff) << EMSK_LED_OFFSET) +/** @} end of name */ + +/** + * \name EMSK Switch Port Configuration + * @{ + */ +#define EMSK_SWITCH_OFFSET (0) +#define EMSK_SWITCH_MASK ((0xf) << EMSK_SWITCH_OFFSET) +#define EMSK_SWITCH_PORT (DW_GPIO_PORT_C) +#define EMSK_SWITCH_DIR ((0x0) << EMSK_SWITCH_OFFSET) +/** @} end of name */ + +/** + * \name EMSK Button Port Configuration + * @{ + */ +#define EMSK_BUTTON_OFFSET (0) +#define EMSK_BUTTON_MASK ((0x7) << EMSK_BUTTON_OFFSET) +#define EMSK_BUTTON_PORT (DW_GPIO_PORT_A) +#define EMSK_BUTTON_DIR ((0x0) << EMSK_BUTTON_OFFSET) +/** @} end of name */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void emsk_led_init(void); +extern void emsk_button_init(void); +extern void emsk_switch_init(void); +extern void emsk_gpio_init(void); +extern void led_write(uint32_t led_val, uint32_t mask); +extern uint32_t led_read(uint32_t mask); +extern uint32_t switch_read(uint32_t mask); +extern uint32_t button_read(uint32_t mask); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMSK_GPIO_H_ */ + +/** @} end of group BOARD_EMSK_DRV_GPIO */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.c new file mode 100644 index 000000000..6e28e364c --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.c @@ -0,0 +1,591 @@ +/* + * Copyright (C) 2014, Michele Balistreri + * + * Derived from code originally Copyright (C) 2011, Alex Hornung + * + * 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. + * + * Modified by Qiang Gu(Qiang.Gu@synopsys.com) for embARC + * \version 2017.03 + * \date 2016-07-29 + */ + +/** + * \defgroup BOARD_EMSK_DRV_RF_MRF24J40 EMSK RF-MRF24J40 Driver + * \ingroup BOARD_EMSK_DRV_RF + * \brief EMSK RF MRF24J40 driver + * \details + * Implement the MRF24J40 driver using the DesignWare SPI device driver. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_RF_MRF24J40 + * \brief RF MRF24J40 driver + * \details Implement MRF24J40 driver. + */ + +/** + * \addtogroup BOARD_EMSK_DRV_RF_MRF24J40 + * @{ + */ + +#include "board/emsk/pmrf/mrf24j40.h" + +#include +#include "board/emsk/pmrf/pmrf.h" + +/* mrf24j40_read_long_ctrl_reg(), mrf24j40_read_short_ctrl_reg(), + * mrf24j40_write_long_ctrl_reg() and mrf24j40_write_short_ctrl_reg() + * is modified for embARC */ +/** Read register in long address memory space */ +uint8_t mrf24j40_read_long_ctrl_reg(uint16_t addr) +{ + return pmrf_read_long_ctrl_reg(addr); +} + +/** Read register in short address memory space */ +uint8_t mrf24j40_read_short_ctrl_reg(uint8_t addr) +{ + return pmrf_read_short_ctrl_reg(addr); +} + +/** Write register in long address memory space */ +void mrf24j40_write_long_ctrl_reg(uint16_t addr, uint8_t value) +{ + pmrf_write_long_ctrl_reg(addr, value); +} + +/** Write register in short address memory space */ +void mrf24j40_write_short_ctrl_reg(uint8_t addr, uint8_t value) +{ + pmrf_write_short_ctrl_reg(addr, value); +} + +/** + * \brief Set INTCON: Interrupt Control Register + * \details Enable TX Normal FIFO transmission interrupt (TXNIE = 0), + * RX FIFO reception interrupt (RXIE = 0), + * security key request interrupt (SECIE = 0) + */ +void mrf24j40_ie(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_INTCON, ~(MRF24J40_TXNIE | MRF24J40_RXIE | MRF24J40_SECIE)); +} + +/** + * \brief Set SOFTRST: Software Reset Register + * \details Reset power management circuitry (RSTPWR = 1) + */ +void mrf24j40_pwr_reset(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_SOFTRST, MRF24J40_RSTPWR); +} + +/** + * \brief Set SOFTRST: Software Reset Register + * \details Reset baseband circuitry (RSTBB = 1) + */ +void mrf24j40_bb_reset(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_SOFTRST, MRF24J40_RSTBB); +} + +/** + * \brief Set SOFTRST: Software Reset Register + * \details Reset MAC circuitry (RSTMAC = 1) + */ +void mrf24j40_mac_reset(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_SOFTRST, MRF24J40_RSTMAC); +} + +/** + * \brief Set RFCTL: RF Mode Control Register + * \details Perform RF Reset by setting RFRST = 1 and then RFRST = 0 + */ +void mrf24j40_rf_reset(void) +{ + uint8_t old = mrf24j40_read_short_ctrl_reg(MRF24J40_RFCTL); + + mrf24j40_write_short_ctrl_reg(MRF24J40_RFCTL, old | MRF24J40_RFRST); + mrf24j40_write_short_ctrl_reg(MRF24J40_RFCTL, old & ~MRF24J40_RFRST); + mrf24j40_delay_ms(2); +} + +/** + * \brief Get FPSTAT in TXNCON: Transmit Normal FIFO Control Register + * \details Get status of the frame pending bit in the received Acknowledgement frame + * \retval 1 Set frame pending bit + * \retval 0 Clear frame pending bit + */ +uint8_t mrf24j40_get_pending_frame(void) +{ + return (mrf24j40_read_short_ctrl_reg(MRF24J40_TXNCON) >> 4) & 0x01; +} + +/** + * \brief Set RXFLUSH in RXFLUSH: Receive FIFO Flush Register + * \details Reset RXFIFO address pointer to zero + */ +void mrf24j40_rxfifo_flush(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_RXFLUSH, (mrf24j40_read_short_ctrl_reg(MRF24J40_RXFLUSH) | MRF24J40__RXFLUSH)); +} + +/** + * \brief Set CHANNEL in RFCON0: RF Control 0 Register + * \details Set channel number + * \param ch Channel number, 0000 = Channel 11 (2405 MHz) as default + */ +void mrf24j40_set_channel(int16_t ch) +{ + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON0, MRF24J40_CHANNEL(ch) | MRF24J40_RFOPT(0x03)); + mrf24j40_rf_reset(); +} + +/** + * \brief Set PROMI in RXMCR: Receive MAC Control Register + * \details Set promiscuous mode + * \param crc_check 1 = Discard packet when there is a MAC address mismatch, + * illegal frame type, dPAN/sPAN or MAC short address mismatch, + * 0 = Receive all packet types with good CRC + */ +void mrf24j40_set_promiscuous(bool crc_check) +{ + uint8_t w = mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR); + + if (!crc_check) + { + w |= MRF24J40_PROMI; + } + else + { + w &= (~MRF24J40_PROMI); + } + + mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, w); +} + +/** + * \brief Set PANCOORD in RXMCR: Receive MAC Control Register + * \details Set device as PAN coordinator + */ +void mrf24j40_set_coordinator(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) | MRF24J40_PANCOORD); +} + +/** + * \brief Clear PANCOORD in RXMCR: Receive MAC Control Register + * \details Device is not set as PAN coordinator + */ +void mrf24j40_clear_coordinator(void) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) & ~MRF24J40_PANCOORD); +} + +/** + * \brief Set PAN ID in PANIDL and PANIDH + * \param *pan Pointer of PAN ID, pan[0] for low byte and pan[1] for high byte + */ +void mrf24j40_set_pan(uint8_t *pan) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_PANIDL, pan[0]); + mrf24j40_write_short_ctrl_reg(MRF24J40_PANIDH, pan[1]); +} + +/** + * \brief Set short address in SADRL and SADRH + * \param *addr Pointer of short address, addr[0] for low byte and addr[1] for high byte + */ +void mrf24j40_set_short_addr(uint8_t *addr) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_SADRL, addr[0]); + mrf24j40_write_short_ctrl_reg(MRF24J40_SADRH, addr[1]); +} + +/** + * \brief Set extended address from EADR0 to EADR7 + * \param *addr Pointer of extended address, eui[0] to eui[7] + */ +/* Modified for embARC */ +void mrf24j40_set_eui(uint8_t *eui) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR0, eui[0]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR1, eui[1]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR2, eui[2]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR3, eui[3]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR4, eui[4]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR5, eui[5]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR6, eui[6]); + mrf24j40_write_short_ctrl_reg(MRF24J40_EADR7, eui[7]); +} + +/** + * \brief Set associated coordinator short address in ASSOSADR0 and ASSOSADR1 + * \param *addr Pointer of associated coordinator short address + */ +/* Modified for embARC */ +void mrf24j40_set_coordinator_short_addr(uint8_t *addr) +{ + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOSADR0, addr[0]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOSADR1, addr[1]); +} + +/** + * \brief Set associated coordinator extended address from ASSOEADR0 to ASSOEADR7 + * \param *addr Pointer of associated coordinator extended address, eui[0] to eui[7] + */ +/* Modified for embARC */ +void mrf24j40_set_coordinator_eui(uint8_t *eui) +{ + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR0, eui[0]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR1, eui[1]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR2, eui[2]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR3, eui[3]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR4, eui[4]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR5, eui[5]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR6, eui[6]); + mrf24j40_write_long_ctrl_reg(MRF24J40_ASSOEADR7, eui[7]); +} + +/** + * \brief Set key in address for SECKTXNFIFO and SECKRXFIFO + * \param address TX normal FIFO security key (0x280) and RX FIFO security key (0x2B0) + * \param *key Pointer of security key (16 bytes) + */ +/* Modified for embARC */ +void mrf24j40_set_key(uint16_t address, uint8_t *key) +{ + pmrf_set_key(address, key); +} + +/** + * \brief Perform hardware Reset by asserting RESET pin + * \details The MRF24J40 will be released from Reset approximately 250 us after the RESET pin is released. + */ +void mrf24j40_hard_reset() +{ + mrf24j40_reset_pin(0); + + mrf24j40_delay_us(500); + mrf24j40_reset_pin(1); + mrf24j40_delay_us(500); +} + +/** + * \brief Initialize MRF24J40 + */ +/* Modified for embARC */ +void mrf24j40_initialize() +{ + + uint8_t softrst_status; + uint8_t rf_state; + + pmrf_all_install(); + + //mrf24j40_cs_pin(1); + //mrf24j40_wake_pin(1); + mrf24j40_wake_pin(1); + + mrf24j40_hard_reset(); + mrf24j40_write_short_ctrl_reg(MRF24J40_SOFTRST, (MRF24J40_RSTPWR | MRF24J40_RSTBB | MRF24J40_RSTMAC)); + mrf24j40_delay_us(500); + + do + { + softrst_status = mrf24j40_read_short_ctrl_reg(MRF24J40_SOFTRST); + } + while ((softrst_status & (MRF24J40_RSTPWR | MRF24J40_RSTBB | MRF24J40_RSTMAC)) != 0); + + mrf24j40_write_short_ctrl_reg(MRF24J40_PACON2, MRF24J40_FIFOEN | MRF24J40_TXONTS(0x18)); + mrf24j40_write_short_ctrl_reg(MRF24J40_TXSTBL, MRF24J40_RFSTBL(9) | MRF24J40_MSIFS(5)); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON0, MRF24J40_CHANNEL(0) | MRF24J40_RFOPT(0x03)); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON1, MRF24J40_VCOOPT(0x02)); // Initialize VCOOPT = 0x02 + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON2, MRF24J40_PLLEN); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON6, (MRF24J40_TXFIL | MRF24J40__20MRECVR)); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON7, MRF24J40_SLPCLKSEL(0x02)); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON8, MRF24J40_RFVCO); + mrf24j40_write_long_ctrl_reg(MRF24J40_SLPCON1, MRF24J40_SLPCLKDIV(1) | MRF24J40_CLKOUTDIS); + + mrf24j40_write_short_ctrl_reg(MRF24J40_RXFLUSH, (MRF24J40_WAKEPAD | MRF24J40_WAKEPOL)); + + mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) & (~MRF24J40_NOACKRSP)); + // mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) | MRF24J40_PANCOORD); + // mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) | (MRF24J40_NOACKRSP)); + // mrf24j40_write_short_ctrl_reg(MRF24J40_ACKTMOUT, mrf24j40_read_short_ctrl_reg(MRF24J40_ACKTMOUT) | 0x7f); + mrf24j40_write_short_ctrl_reg(MRF24J40_TXMCR, 0b00011100); + // mrf24j40_set_coordinator(); + mrf24j40_write_short_ctrl_reg(MRF24J40_ORDER, 0xFF); + + mrf24j40_write_short_ctrl_reg(MRF24J40_BBREG1, 0x0); + mrf24j40_write_short_ctrl_reg(MRF24J40_BBREG2, MRF24J40_CCAMODE(0x02) | MRF24J40_CCASTH(0x00)); + mrf24j40_write_short_ctrl_reg(MRF24J40_CCAEDTH, 0x60); + mrf24j40_write_short_ctrl_reg(MRF24J40_BBREG6, MRF24J40_RSSIMODE2); + + // TURNTIME Defaule value: 0x4 and TURNTIME=0x3 + mrf24j40_write_short_ctrl_reg(MRF24J40_TXTIME, 0x30); + + //mrf24j40_write_short_ctrl_reg(MRF24J40_TXPEND, mrf24j40_read_short_ctrl_reg(MRF24J40_TXPEND) & MRF24J40_FPACK); + + //mrf24j40_write_long_ctrl_reg(MRF24J40_SLPCON0, MRF24J40_SLPCLKEN); + + // mrf24j40_write_short_ctrl_reg(MRF24J40_ACKTMOUT, mrf24j40_read_short_ctrl_reg(MRF24J40_ACKTMOUT) | MRF24J40_DRPACK); + + // mrf24j40_write_short_ctrl_reg(MRF24J40_RXMCR, mrf24j40_read_short_ctrl_reg(MRF24J40_RXMCR) | MRF24J40_PROMI); + + mrf24j40_ie(); + mrf24j40_write_long_ctrl_reg(MRF24J40_RFCON3, 0x0); + + mrf24j40_rf_reset(); + + do + { + rf_state = mrf24j40_read_long_ctrl_reg(MRF24J40_RFSTATE); + } + while (((rf_state >> 5) & 0x05) != 0x05); + + mrf24j40_rxfifo_flush(); + +} + +/** + * \brief Set low-current Sleep mode + */ +void mrf24j40_sleep() +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_WAKECON, MRF24J40_IMMWAKE); + + uint8_t r = mrf24j40_read_short_ctrl_reg(MRF24J40_SLPACK); + mrf24j40_wake_pin(0); + + mrf24j40_pwr_reset(); + mrf24j40_write_short_ctrl_reg(MRF24J40_SLPACK, r | MRF24J40__SLPACK); +} + +/** + * \brief Set wake-up from Sleep mode + */ +void mrf24j40_wakeup() +{ + mrf24j40_wake_pin(1); + mrf24j40_rf_reset(); +} + +/** + * \brief Enable and transmit frame in TX Normal FIFO + * \param *frame Pointer of the TX frame + * \param hdr_len Header Legnth of the transmission packet + * \param sec_hdr_len Security header Legnth of the transmission packet + * \param payload_len Data payload of the transmission packet + */ +/* Modified for embARC */ +void mrf24j40_txpkt(uint8_t *frame, int16_t hdr_len, int16_t sec_hdr_len, int16_t payload_len) +{ + int16_t frame_len = hdr_len + sec_hdr_len + payload_len; + + uint8_t w = mrf24j40_read_short_ctrl_reg(MRF24J40_TXNCON); + w &= ~(MRF24J40_TXNSECEN); + + if (IEEE_802_15_4_HAS_SEC(frame[0])) + { + w |= MRF24J40_TXNSECEN; + } + + if (IEEE_802_15_4_WANTS_ACK(frame[0])) + { + w |= MRF24J40_TXNACKREQ; + } + + pmrf_txpkt_frame_write(frame, hdr_len, frame_len); + + mrf24j40_write_short_ctrl_reg(MRF24J40_TXNCON, w | MRF24J40_TXNTRIG); +} + +/** + * \brief Set RXCIPHER and TXNCIPHER in SECCON0: Security Control 0 Register + * \param rxcipher RX FIFO security suite select bits + * \param txcipher TX normal FIFO security suite select bits + * \details 111 = AES-CBC-MAC-32 + * 110 = AES-CBC-MAC-64 + * 101 = AES-CBC-MAC-128 + * 100 = AES-CMM-32 + * 011 = AES-CMM-64 + * 010 = AES-CMM-128 + * 001 = AES-CTR + * 000 = None (default) + */ +void mrf24j40_set_cipher(uint8_t rxcipher, uint8_t txcipher) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_SECCON0, MRF24J40_RXCIPHER(rxcipher) | MRF24J40_TXNCIPHER(txcipher)); +} + +/** + * \brief Read SECDECERR in RXSR: RX MAC Status Register + * \details Read security decryption error bit + * \retval 0 Security decryption error occurred + * \retval 1 Security decryption error did not occur + */ +// Should be tested +bool mrf24j40_rx_sec_fail() +{ + bool rx_sec_fail = (mrf24j40_read_short_ctrl_reg(MRF24J40_RXSR) >> 2) & 0x01; + mrf24j40_write_short_ctrl_reg(MRF24J40_RXSR, 0x00); + return rx_sec_fail; +} + +/** + * \brief Set SECIGNORE/SECSTART in SECCON0: Security Control 0 Register + * \details Set RX security decryption ignore/start bit + * \param accept 1: start decryption process, 0: ignore decryption process + */ +void mrf24j40_sec_intcb(bool accept) +{ + uint8_t w = mrf24j40_read_short_ctrl_reg(MRF24J40_SECCON0); + + w |= accept ? MRF24J40_SECSTART : MRF24J40_SECIGNORE; + mrf24j40_write_short_ctrl_reg(MRF24J40_SECCON0, w); +} + +/** + * \brief Read TX normal FIFO release status bit in TXSTAT: TX MAC Status Register + * \retval MRF24J40_EBUSY Failed, channel busy + * \retval MRF24J40_EIO Failed, channel idle + * \retval 0 Succeeded + */ +int16_t mrf24j40_txpkt_intcb(void) +{ + uint8_t stat = mrf24j40_read_short_ctrl_reg(MRF24J40_TXSTAT); + + if (stat & MRF24J40_TXNSTAT) + { + if (stat & MRF24J40_CCAFAIL) + { + return MRF24J40_EBUSY; + } + else + { + return MRF24J40_EIO; + } + } + else + { + return 0; + } +} + +/** + * \brief Send RX packet in RX FIFO + * \param *buf Pointer of RX buffer in RX FIFO + * \param *plqi Pointer of LQI in RX FIFO + * \param *prssi Pointer of RSSI in RX FIFO + * \returns Frame length in RX FIFO + */ +/* Modified for embARC */ +int16_t mrf24j40_rxpkt_intcb(uint8_t *buf, uint8_t *plqi, uint8_t *prssi) +{ + mrf24j40_write_short_ctrl_reg(MRF24J40_BBREG1, mrf24j40_read_short_ctrl_reg(MRF24J40_BBREG1) | MRF24J40_RXDECINV); + + /* Packet Reception + * Frame Length -- Header -- Data Payload -- FCS -- LQI -- RSSI + */ + uint8_t flen = mrf24j40_read_long_ctrl_reg(MRF24J40_RXFIFO); + + if (flen > (MRF24J40_RXFIFO_SIZE - 3)) + { + flen = MRF24J40_RXFIFO_SIZE - 3; + } + + pmrf_rxpkt_intcb_frame_read(buf, flen); + + uint8_t lqi = mrf24j40_read_long_ctrl_reg(MRF24J40_RXFIFO + flen + 1); + uint8_t rssi = mrf24j40_read_long_ctrl_reg(MRF24J40_RXFIFO + flen + 2); + + if (plqi != NULL) + { + *plqi = lqi; + } + + if (prssi != NULL) + { + *prssi = rssi; + } + + mrf24j40_rxfifo_flush(); + mrf24j40_write_short_ctrl_reg(MRF24J40_BBREG1, mrf24j40_read_short_ctrl_reg(MRF24J40_BBREG1) & ~MRF24J40_RXDECINV); + + return (int16_t)flen; +} + +/** + * \brief Read SECIF, TXNIF and RXIF in INTSTAT: Interrupt Status Register + * \details Read security key request interrupt bit, TX normal FIFO release interrupt bit + * and RX FIFO reception interrupt bit + * \returns Interrupt status + */ +int16_t mrf24j40_int_tasks(void) +{ + int16_t ret = 0; + + uint8_t stat = mrf24j40_read_short_ctrl_reg(MRF24J40_INTSTAT); + + if (stat & MRF24J40_RXIF) + { + ret |= MRF24J40_INT_RX; + } + + if (stat & MRF24J40_TXNIF) + { + ret |= MRF24J40_INT_TX; + } + + if (stat & MRF24J40_SECIF) + { + ret |= MRF24J40_INT_SEC; + } + + return ret; +} + +/** + * \brief Write TX FIFO + * \param address FIFO Address (TX Normal FIFO) + * \param *data Pointer of data for TX FIFO + * \param hdr_len Header legnth for TX FIFO + * \param len Frame length for TX FIFO + */ +void mrf24j40_txfifo_write(uint16_t address, uint8_t *data, uint8_t hdr_len, uint8_t len) +{ + pmrf_txfifo_write(address, data, hdr_len, len); +} + +/** + * \brief Set TXNTRIG in TXNCON: Transmit normal FIFO control register + * \details Transmit frame in TX normal FIFO bit + */ +void mrf24j40_transmit(void) +{ + uint8_t reg = pmrf_read_short_ctrl_reg(MRF24J40_TXNCON) | MRF24J40_TXNTRIG; + + pmrf_write_short_ctrl_reg(MRF24J40_TXNCON, reg); +} + +/** @} end of group BOARD_EMSK_DRV_RF_MRF24J40 */ \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.h new file mode 100644 index 000000000..779020a0d --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/mrf24j40.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2014, Michele Balistreri + * + * Derived from code originally Copyright (C) 2011, Alex Hornung + * + * 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. + * + * Modified by Qiang Gu(Qiang.Gu@synopsys.com) for embARC + * \version 2017.03 + * \date 2016-07-29 + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_RF_MRF24J40 + * \brief RF MRF24J40 driver + * \details implement MRF24J40 driver header file + */ + +#ifndef _MRF24J40_H_ +#define _MRF24J40_H_ + +#include +#include + +#define MRF24J40_RXFIFO_SIZE 144 + +/* Return values */ +#define MRF24J40_INT_RX 0x01 +#define MRF24J40_INT_TX 0x02 +#define MRF24J40_INT_SEC 0x04 +#define MRF24J40_INT_SLP 0x08 +#define MRF24J40_INT_ENC 0x10 +#define MRF24J40_INT_DEC 0x20 + +#define MRF24J40_EIO 1 +#define MRF24J40_EBUSY 2 + +/* IEEE 802.15.4 constants needed for some flags */ +#define IEEE_802_15_4_HAS_SEC(x) ((x >> 3) & 0x01) +#define IEEE_802_15_4_WANTS_ACK(x) ((x >> 5) & 0x01) + +/* enc dec parameters */ +#define MRF24J40_TX_KEY 0x01 +#define MRF24J40_RX_KEY 0x02 +#define MRF24J40_UP_KEY MRF24J40_TX_KEY + +#define MRF24J40_AES_CBC_MAC32 0x07 +#define MRF24J40_AES_CBC_MAC64 0x06 +#define MRF24J40_AES_CBC_MAC128 0x05 +#define MRF24J40_AES_CCM32 0x04 +#define MRF24J40_AES_CCM64 0x03 +#define MRF24J40_AES_CCM128 0x02 +#define MRF24J40_AES_CTR 0x01 +#define MRF24J40_ALGO_NONE 0x00 + +/* Short Address Control Register Map */ +#define MRF24J40_RXMCR 0x00 +#define MRF24J40_PANIDL 0x01 +#define MRF24J40_PANIDH 0x02 +#define MRF24J40_SADRL 0x03 +#define MRF24J40_SADRH 0x04 +#define MRF24J40_EADR0 0x05 +#define MRF24J40_EADR1 0x06 +#define MRF24J40_EADR2 0x07 +#define MRF24J40_EADR3 0x08 +#define MRF24J40_EADR4 0x09 +#define MRF24J40_EADR5 0x0A +#define MRF24J40_EADR6 0x0B +#define MRF24J40_EADR7 0x0C +#define MRF24J40_RXFLUSH 0x0D + +#define MRF24J40_ORDER 0x10 +#define MRF24J40_TXMCR 0x11 +#define MRF24J40_ACKTMOUT 0x12 +#define MRF24J40_ESLOTG1 0x13 +#define MRF24J40_SYMTICKL 0x14 +#define MRF24J40_SYMTICKH 0x15 +#define MRF24J40_PACON0 0x16 +#define MRF24J40_PACON1 0x17 +#define MRF24J40_PACON2 0x18 +#define MRF24J40_TXBCON0 0x1A +#define MRF24J40_TXNCON 0x1B +#define MRF24J40_TXG1CON 0x1C +#define MRF24J40_TXG2CON 0x1D +#define MRF24J40_ESLOTG23 0x1E +#define MRF24J40_ESLOTG45 0x1F + +#define MRF24J40_ESLOTG67 0x20 +#define MRF24J40_TXPEND 0x21 +#define MRF24J40_WAKECON 0x22 +#define MRF24J40_FRMOFFSET 0x23 +#define MRF24J40_TXSTAT 0x24 +#define MRF24J40_TXBCON1 0x25 +#define MRF24J40_GATECLK 0x26 +#define MRF24J40_TXTIME 0x27 +#define MRF24J40_HSYMTMRL 0x28 +#define MRF24J40_HSYMTMRH 0x29 +#define MRF24J40_SOFTRST 0x2A +#define MRF24J40_SECCON0 0x2c +#define MRF24J40_SECCON1 0x2d +#define MRF24J40_TXSTBL 0x2e + +#define MRF24J40_RXSR 0x30 +#define MRF24J40_INTSTAT 0x31 +#define MRF24J40_INTCON 0x32 +#define MRF24J40_GPIO 0x33 +#define MRF24J40_TRISGPIO 0x34 +#define MRF24J40_SLPACK 0x35 +#define MRF24J40_RFCTL 0x36 +#define MRF24J40_SECCR2 0x37 +#define MRF24J40_BBREG0 0x38 +#define MRF24J40_BBREG1 0x39 +#define MRF24J40_BBREG2 0x3A +#define MRF24J40_BBREG3 0x3B +#define MRF24J40_BBREG4 0x3C +#define MRF24J40_BBREG6 0x3E +#define MRF24J40_CCAEDTH 0x3F + +/* Long Address Control Register Map */ +#define MRF24J40_RFCON0 0x200 +#define MRF24J40_RFCON1 0x201 +#define MRF24J40_RFCON2 0x202 +#define MRF24J40_RFCON3 0x203 +#define MRF24J40_RFCON5 0x205 +#define MRF24J40_RFCON6 0x206 +#define MRF24J40_RFCON7 0x207 +#define MRF24J40_RFCON8 0x208 +#define MRF24J40_RFSTATE 0x20F + +#define MRF24J40_RSSI 0x210 +#define MRF24J40_SLPCON0 0x211 +#define MRF24J40_SLPCON1 0x220 + +#define MRF24J40_WAKETIMEL 0x222 +#define MRF24J40_WAKETIMEH 0x223 + +#define MRF24J40_AINCNT0 0x226 +#define MRF24J40_AINCNT1 0x227 +#define MRF24J40_AINCNT2 0x228 +#define MRF24J40_AINCNT3 0x229 + +#define MRF24J40_ASSOEADR0 0x230 +#define MRF24J40_ASSOEADR1 0x231 +#define MRF24J40_ASSOEADR2 0x232 +#define MRF24J40_ASSOEADR3 0x233 +#define MRF24J40_ASSOEADR4 0x234 +#define MRF24J40_ASSOEADR5 0x235 +#define MRF24J40_ASSOEADR6 0x236 +#define MRF24J40_ASSOEADR7 0x237 + +#define MRF24J40_ASSOSADR0 0x238 +#define MRF24J40_ASSOSADR1 0x239 + +#define MRF24J40_UPNONCE0 0x240 +#define MRF24J40_UPNONCE1 0x241 +#define MRF24J40_UPNONCE2 0x242 +#define MRF24J40_UPNONCE3 0x243 +#define MRF24J40_UPNONCE4 0x244 +#define MRF24J40_UPNONCE5 0x245 +#define MRF24J40_UPNONCE6 0x246 +#define MRF24J40_UPNONCE7 0x247 +#define MRF24J40_UPNONCE8 0x248 +#define MRF24J40_UPNONCE9 0x249 +#define MRF24J40_UPNONCE10 0x24A +#define MRF24J40_UPNONCE11 0x24B +#define MRF24J40_UPNONCE12 0x24C + +/* Long Address Memory Map */ +#define MRF24J40_TXNFIFO 0x000 /* - 0x07F, 128 bytes */ +#define MRF24J40_TXBFIFO 0x080 /* - 0x0FF, 128 bytes */ +#define MRF24J40_TXG1FIFO 0x100 /* - 0x17F, 128 bytes */ +#define MRF24J40_TXG2FIFO 0x180 /* - 0x1FF, 128 bytes */ +#define MRF24J40_SECKFIFO 0x280 /* - 0x2BF, 64 bytes */ +#define MRF24J40_SECKTXNFIFO 0x280 /* - 0x28F, 16 bytes */ +#define MRF24J40_SECKRXFIFO 0x2B0 /* - 0x2BF, 16 bytes */ +#define MRF24J40_RXFIFO 0x300 /* - 0x38F, 144 bytes */ + + +/* RXMCR */ +#define MRF24J40_NOACKRSP (1<<5) +#define MRF24J40_PANCOORD (1<<3) +#define MRF24J40_COORD (1<<2) +#define MRF24J40_ERRPKT (1<<1) +#define MRF24J40_PROMI (1) + +/* RXFLUSH */ +#define MRF24J40_WAKEPOL (1<<6) +#define MRF24J40_WAKEPAD (1<<5) +#define MRF24J40_CMDONLY (1<<3) +#define MRF24J40_DATAONLY (1<<2) +#define MRF24J40_BCNONLY (1<<1) +#define MRF24J40__RXFLUSH (1) + +/* TXMCR */ +#define MRF24J40_NOCSMA (1<<7) +#define MRF24J40_BATLIFEXT (1<<6) +#define MRF24J40_SLOTTED (1<<5) +#define MRF24J40_MACMINBE(x) ((x & 0x03)<<3) +#define MRF24J40_CSMABF(x) (x & 0x07) + +/* ACKTMOUT */ +#define MRF24J40_DRPACK (1<<7) + +/* PACON2 */ +#define MRF24J40_FIFOEN (1<<7) +#define MRF24J40_TXONTS(x) (x & 0x3F) + +/* TXNCON */ +#define MRF24J40_FPSTAT (1<<4) +#define MRF24J40_INDIRECT (1<<3) +#define MRF24J40_TXNACKREQ (1<<2) +#define MRF24J40_TXNSECEN (1<<1) +#define MRF24J40_TXNTRIG (1) + +/* TXPEND */ +#define MRF24J40_FPACK (1) + +/* WAKECON */ +#define MRF24J40_IMMWAKE (1<<7) +#define MRF24J40_REGWAKE (1<<6) + +/* TXSTAT */ +#define MRF24J40_CCAFAIL (1<<5) +#define MRF24J40_TXNSTAT (1) + +/* SOFTRST */ +#define MRF24J40_RSTPWR (1<<2) +#define MRF24J40_RSTBB (1<<1) +#define MRF24J40_RSTMAC (1) + +/* SECCON0 */ +#define MRF24J40_SECIGNORE (1<<7) +#define MRF24J40_SECSTART (1<<6) +#define MRF24J40_RXCIPHER(x) ((x & 0x07) << 3) +#define MRF24J40_TXNCIPHER(x) ((x & 0x07)) + +/* SECCON1 */ +#define MRF24J40_DISDEC (1<<1) +#define MRF24J40_DISENC (1) + +/* TXSTBL */ +#define MRF24J40_RFSTBL(x) ((x & 0x0f) << 4) +#define MRF24J40_MSIFS(x) ((x & 0x0f)) + +/* RXSR */ +#define MRF24J40_UPSECERR (1<<6) +#define MRF24J40_SECDECERR (1<<2) + +/* INTSTAT */ +#define MRF24J40_SLPIF (1<<7) +#define MRF24J40_WAKEIF (1<<6) +#define MRF24J40_HSYMTMRIF (1<<5) +#define MRF24J40_SECIF (1<<4) +#define MRF24J40_RXIF (1<<3) +#define MRF24J40_TXG2IF (1<<2) +#define MRF24J40_TXG1IF (1<<1) +#define MRF24J40_TXNIF (1) + +/* INTCON */ +#define MRF24J40_SLPIE (1<<7) +#define MRF24J40_WAKEIE (1<<6) +#define MRF24J40_HSYMTMRIE (1<<5) +#define MRF24J40_SECIE (1<<4) +#define MRF24J40_RXIE (1<<3) +#define MRF24J40_TXG2IE (1<<2) +#define MRF24J40_TXG1IE (1<<1) +#define MRF24J40_TXNIE (1) + +/* SLPACK */ +#define MRF24J40__SLPACK (1<<7) +#define MRF24J40_WAKECNT_L(x) (x & 0x03F) + +/* RFCTL */ +#define MRF24J40_WAKECNT_H(x) ((x & 0x03) << 3) +#define MRF24J40_RFRST (1<<2) +#define MRF24J40_RFTXMODE (1<<1) +#define MRF24J40_RFRXMODE (1) + +/* SECCR2 */ +#define MRF24J40_UPDEC (1<<7) +#define MRF24J40_UPENC (1<<6) + +/* BBREG0 */ +#define MRF24J40_TURBO (1) + +/* BBREG1 */ +#define MRF24J40_RXDECINV (1<<2) + +/* BBREG2 */ +#define MRF24J40_CCAMODE(x) ((x & 0x03) <<6) +#define MRF24J40_CCASTH(x) ((x & 0x0F) <<2) + +/* BBREG3 */ +#define MRF24J40_PREVALIDTH(x) ((x & 0x0F) <<4) + +/* BBREG4 */ +#define MRF24J40_CSTH(x) ((x & 0x07) << 5) + +/* BBREG6 */ +#define MRF24J40_RSSIMODE1 (1 << 7) +#define MRF24J40_RSSIMODE2 (1<<6) +#define MRF24J40_RSSIRDY (1) + +/* RFCON0 */ +#define MRF24J40_CHANNEL(x) ((x & 0x0F) << 4) +#define MRF24J40_RFOPT(x) ((x & 0x0F)) + +/* RFCON1 */ +#define MRF24J40_VCOOPT(x) ((x & 0xFF)) + +/* RFCON2 */ +#define MRF24J40_PLLEN (1<<7) + +/* RFCON3 */ +#define MRF24J40_TXPWRL(x) ((x & 0x03) << 6) +#define MRF24J40_TXPWRS(x) ((x & 0x07) << 3) + +/* RFCON6 */ +#define MRF24J40_TXFIL (1 << 7) +#define MRF24J40__20MRECVR (1 << 4) +#define MRF24J40_BATEN (1 << 3) + +/* RFCON 7 */ +#define MRF24J40_SLPCLKSEL(x) ((x & 0x03) << 6) +#define MRF24J40_SLPCLKSEL_100k (MRF24J40_SLPCLKSEL(0x02)) +#define MRF24J40_SLPCLKSEL_32k (MRF24J40_SLPCLKSEL(0x01)) + +/* RFCON8 */ +#define MRF24J40_RFVCO (1 << 4) + +/* SLPCON0 */ +#define MRF24J40_SLPCLKEN (1) + +/* SLPCON1 */ +#define MRF24J40_CLKOUTDIS (1 << 5) /* CLKOUTEN' */ +#define MRF24J40_SLPCLKDIV(x) ((x & 0x1F)) /* division ratio: 2^(SLPCLKDIV) */ + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t mrf24j40_read_long_ctrl_reg(uint16_t addr); +uint8_t mrf24j40_read_short_ctrl_reg(uint8_t addr); +void mrf24j40_write_long_ctrl_reg(uint16_t addr, uint8_t value); +void mrf24j40_write_short_ctrl_reg(uint8_t addr, uint8_t value); +void mrf24j40_rxfifo_flush(void); +uint8_t mrf24j40_get_pending_frame(void); +void mrf24j40_hard_reset(void); +void mrf24j40_initialize(void); +void mrf24j40_sleep(); +void mrf24j40_wakeup(); +void mrf24j40_set_short_addr(uint8_t *addr); +void mrf24j40_set_coordinator_short_addr(uint8_t *addr); +void mrf24j40_set_coordinator_eui(uint8_t *eui); +void mrf24j40_set_eui(uint8_t *eui); +void mrf24j40_set_pan(uint8_t *pan); +void mrf24j40_set_key(uint16_t address, uint8_t *key); +#define mrf24j40_tx_key(key) mrf24j40_set_key(SECKTXNFIFO, key); +#define mrf24j40_rx_key(key) mrf24j40_set_key(SECKRXFIFO, key); +void mrf24j40_set_channel(int16_t ch); +void mrf24j40_set_promiscuous(bool crc_check); +void mrf24j40_set_coordinator(void); +void mrf24j40_clear_coordinator(void); +void mrf24j40_txpkt(uint8_t *frame, int16_t hdr_len, int16_t sec_hdr_len, int16_t payload_len); +void mrf24j40_set_cipher(uint8_t rxcipher, uint8_t txcipher); +bool mrf24j40_rx_sec_fail(); +uint8_t mrf24j40_get_channel(void); +int16_t mrf24j40_int_tasks(void); +int16_t mrf24j40_rxpkt_intcb(uint8_t *buf, uint8_t *plqi, uint8_t *prssi); +int16_t mrf24j40_txpkt_intcb(void); +void mrf24j40_sec_intcb(bool accept); + +void mrf24j40_txfifo_write(uint16_t address, uint8_t *data, uint8_t hdr_len, uint8_t len); +void mrf24j40_transmit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _MRF24J40_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.c new file mode 100644 index 000000000..150537f32 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.c @@ -0,0 +1,373 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-07-18 + * \author Qiang Gu(Qiang.Gu@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup BOARD_EMSK_DRV_PMODRF EMSK PMOD RF Driver + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Pmod RF Driver + * \details + * Realize the EMSK board PMOD RF driver + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_PMODRF + * \brief Pmod RF driver for emsk board + */ + +/** + * \addtogroup BOARD_EMSK_DRV_PMODRF + * @{ + */ +#include +#include + +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" +#include "inc/arc/arc_exception.h" + +#include "board/board.h" + +#include "device/device_hal/inc/dev_gpio.h" +#include "device/device_hal/inc/dev_spi.h" + +#include "board/emsk/pmrf/pmrf.h" + +#define EMSK_PMRF_0_SPI_CPULOCK_ENABLE + +static DEV_SPI_PTR pmrf_spi_ptr; +static DEV_GPIO_PTR pmrf_gpio_ptr; +static uint32_t cs_line = EMSK_PMRF_0_SPI_LINE; + +void pmrf_wake_pin(uint32_t flag) +{ + if (flag == 1) + { + pmrf_gpio_ptr->gpio_write(MRF24J40_WAKE_ON, MRF24J40_WAKE_PIN); + } + else + { + pmrf_gpio_ptr->gpio_write(MRF24J40_WAKE_OFF, MRF24J40_WAKE_PIN); + } +} + +void pmrf_cs_pin(uint32_t flag) +{ + uint32_t cpu_status; + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + + if (flag == 1) + { + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); + + } + else + { + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + } + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif +} + +void pmrf_reset_pin(uint32_t flag) +{ + if (flag == 1) + { + pmrf_gpio_ptr->gpio_write(MRF24J40_RST_HIGH, MRF24J40_RST_PIN); + } + else + { + pmrf_gpio_ptr->gpio_write(MRF24J40_RST_LOW, MRF24J40_RST_PIN); + } +} + +uint8_t pmrf_read_long_ctrl_reg(uint16_t addr) +{ + uint8_t msg[2]; + uint8_t ret_val; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + + msg[0] = (uint8_t)(((addr >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)((addr << 5) & 0xE0); + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, 2); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, &ret_val, 2, 1); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif + + return ret_val; +} + +uint8_t pmrf_read_short_ctrl_reg(uint8_t addr) +{ + uint8_t msg; + uint8_t ret_val; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + + msg = (((addr << 1) & 0x7E) | 0); + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, &msg, 0, 1); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, &ret_val, 1, 1); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif + + return ret_val; + +} + +void pmrf_write_long_ctrl_reg(uint16_t addr, uint8_t value) +{ + uint8_t msg[4]; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + + msg[0] = (uint8_t)(((addr >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)(((addr << 5) & 0xE0) | (1 << 4)); + msg[2] = value; + msg[3] = 0x0; /* have to write 1 more byte, why ?*/ + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, 4); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, NULL, 4, 0); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif +} + +void pmrf_write_short_ctrl_reg(uint8_t addr, uint8_t value) +{ + DEV_SPI_TRANSFER pmrf_xfer; + uint8_t msg[3]; + uint32_t cpu_status; + + msg[0] = (((addr << 1) & 0x7E) | 1); + msg[1] = value; + msg[2] = 0x0; /* have to write 1 more byte, why ?*/ + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, 3); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, NULL, 3, 0); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif + +} + +void pmrf_delay_us(uint32_t us) +{ + uint64_t start_us, us_delayed; + + us_delayed = (uint64_t)us; + start_us = board_get_cur_us(); + + while ((board_get_cur_us() - start_us) < us_delayed); +} + +void pmrf_delay_ms(uint32_t ms) +{ + board_delay_ms(ms, OSP_DELAY_OS_COMPAT_DISABLE); +} + +/* need test */ +void pmrf_set_key(uint16_t addr, uint8_t *key) +{ + uint8_t msg[16 + 2]; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + uint8_t i; + + msg[0] = (uint8_t)(((addr >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)(((addr << 5) & 0xE0) | (1 << 4)); + + for (i = 0; i < 16; i++) + { + msg[i + 2] = key[0]; + } + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, 18); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, NULL, 18, 0); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif +} + +/* need test */ +void pmrf_txpkt_frame_write(uint8_t *frame, int16_t hdr_len, int16_t frame_len) +{ + uint8_t msg[frame_len + 2 + 2]; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + uint8_t i = 0; + + msg[0] = (uint8_t)(((MRF24J40_TXNFIFO >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)(((MRF24J40_TXNFIFO << 5) & 0xE0) | (1 << 4)); + msg[2] = (uint8_t)hdr_len; + msg[3] = (uint8_t)frame_len; + + for (i = 0; i < frame_len; i++) + { + msg[i + 4] = *frame; + frame++; + } + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, frame_len + 2 + 2); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, NULL, frame_len + 2 + 2, 0); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif +} + +/* need test */ +void pmrf_rxpkt_intcb_frame_read(uint8_t *buf, uint8_t length) +{ + uint8_t msg[length]; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + + msg[0] = (uint8_t)((((MRF24J40_RXFIFO + 1) >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)(((MRF24J40_RXFIFO + 1) << 5) & 0xE0); + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, 2); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, buf, 2, length); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif + +} + +void pmrf_all_install(void) +{ + pmrf_spi_ptr = spi_get_dev(EMSK_PMRF_0_SPI_ID); + pmrf_gpio_ptr = gpio_get_dev(EMSK_PMRF_0_GPIO_ID); +} + +void pmrf_txfifo_write(uint16_t address, uint8_t *data, uint8_t hdr_len, uint8_t len) +{ + uint8_t msg[len + 4]; + DEV_SPI_TRANSFER pmrf_xfer; + uint32_t cpu_status; + uint8_t i = 0; + + msg[0] = (uint8_t)(((address >> 3) & 0x7F) | 0x80); + msg[1] = (uint8_t)(((address << 5) & 0xE0) | (1 << 4)); + msg[2] = hdr_len; + msg[3] = len; + + for (i = 0; i < len; i++) + { + msg[i + 4] = *(data + i); + } + + DEV_SPI_XFER_SET_TXBUF(&pmrf_xfer, msg, 0, len + 4); + DEV_SPI_XFER_SET_RXBUF(&pmrf_xfer, NULL, len + 4, 0); + DEV_SPI_XFER_SET_NEXT(&pmrf_xfer, NULL); + + +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_status = cpu_lock_save(); +#endif + pmrf_spi_ptr->spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_line)); + pmrf_spi_ptr->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(&pmrf_xfer)); + pmrf_spi_ptr->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_line)); +#ifdef EMSK_PMRF_0_SPI_CPULOCK_ENABLE + cpu_unlock_restore(cpu_status); +#endif + +} + +/** @} end of group BOARD_EMSK_DRV_PMODRF */ \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.h new file mode 100644 index 000000000..4b1622d18 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/pmrf/pmrf.h @@ -0,0 +1,110 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-07-18 + * \author Qiang Gu(Qiang.Gu@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_PMODRF + * \brief header file of Pmod MRF24J40MA driver for EMSK board + */ + +/** + * \addtogroup BOARD_EMSK_DRV_PMODRF + * @{ + */ + +#ifndef _PMRF_H_ +#define _PMRF_H_ + +/** MRF24J40 Functions */ + +#define mrf24j40_reset_pin(val) pmrf_reset_pin(val) +#define mrf24j40_wake_pin(val) pmrf_wake_pin(val) +#define mrf24j40_cs_pin(val) pmrf_cs_pin(val) + +#define mrf24j40_delay_us(val) pmrf_delay_us(val) +#define mrf24j40_delay_ms(val) pmrf_delay_ms(val) + + +/** PMOD RF SPI FREQ & CLK MODE SETTINGS */ +#define EMSK_PMRF_0_SPIFREQ BOARD_SPI_FREQ +#define EMSK_PMRF_0_SPICLKMODE BOARD_SPI_CLKMODE + +/** PMOD RF SPI ID */ +#define EMSK_PMRF_0_SPI_ID DW_SPI_0_ID + +/** Use J6 by default, MRF24J40 PIN */ +#define EMSK_PMRF_0_SPI_LINE EMSK_SPI_LINE_0 +#define EMSK_PMRF_0_GPIO_ID EMSK_GPIO_PORT_A +#define MRF24J40_WAKE_PIN (1 << 30) +#define MRF24J40_RST_PIN (1 << 29) +#define MRF24J40_INT_PIN (1 << 28) + +#define MRF24J40_WAKE_OFF (0 << 30) +#define MRF24J40_WAKE_ON (1 << 30) + +#define MRF24J40_RST_LOW (0 << 29) +#define MRF24J40_RST_HIGH (1 << 29) + +#define MRF24J40_INT_PIN_OFS (28) + +#ifdef __cplusplus +extern "C" { +#endif + +extern void pmrf_reset_pin(uint32_t flag); +extern void pmrf_wake_pin(uint32_t flag); +extern void pmrf_cs_pin(uint32_t flag); + +extern uint8_t pmrf_read_long_ctrl_reg(uint16_t addr); +extern uint8_t pmrf_read_short_ctrl_reg(uint8_t addr); +extern void pmrf_write_long_ctrl_reg(uint16_t addr, uint8_t value); +extern void pmrf_write_short_ctrl_reg(uint8_t addr, uint8_t value); +extern void pmrf_spi_write(uint8_t data); +extern void pmrf_delay_us(uint32_t us); +extern void pmrf_delay_ms(uint32_t ms); + +extern void pmrf_set_key(uint16_t address, uint8_t *key); +extern void pmrf_txpkt_frame_write(uint8_t *frame, int16_t hdr_len, int16_t frame_len); +extern void pmrf_rxpkt_intcb_frame_read(uint8_t *buf, uint8_t length); + +extern void pmrf_all_install(void); + +extern void pmrf_txfifo_write(uint16_t address, uint8_t *data, uint8_t hdr_len, uint8_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _PMRF_H_ */ + +/** @} end of group BOARD_EMSK_DRV_PMODRF */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.c new file mode 100644 index 000000000..f51675d40 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.c @@ -0,0 +1,333 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-07-03 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup BOARD_EMSK_DRV_DW_SPI_OBJ EMSK DW SPI Object + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Designware SPI Objects + * \details + * realize the EMSK board spi object using designware spi device driver, + * only need to realize some designware spi structures combine with EMSK spi + * hardware resource. just like cpp class instantiation. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_SPI_OBJ + * \brief designware spi object instantiation on emsk + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_SPI_OBJ + * @{ + */ +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" +#include "inc/arc/arc_exception.h" + +#include "device/designware/spi/dw_spi.h" +#include "board/emsk/spi/dw_spi_obj.h" + +#include "board/emsk/emsk.h" + +#ifdef ARC_FEATURE_DMP_PERIPHERAL +#define PERIPHERAL_BASE ARC_FEATURE_DMP_PERIPHERAL +#else +#define PERIPHERAL_BASE _arc_aux_read(AUX_DMP_PERIPHERAL) +#endif + +/** + * \name EMSK DesignWare SPI 0 Object Instantiation + * @{ + */ +#if (USE_DW_SPI_0) +static void dw_spi_0_isr(void *ptr); +#define DW_SPI_0_RELBASE (REL_REGBASE_SPI0) /*!< designware spi 0 relative baseaddr */ +#define DW_SPI_0_INTNO (INTNO_SPI_MASTER) /*!< designware spi 0 interrupt number */ + +#define DW_SPI_0_TX_FIFO_LEN (32) +#define DW_SPI_0_RX_FIFO_LEN (32) + +#define DW_SPI_0_SUPPORTED_MODE DW_SPI_MASTER_SUPPORTED + +DEV_SPI dw_spi_0; /*!< designware spi object */ +DW_SPI_CTRL dw_spi_0_ctrl; /*!< designware spi 0 ctrl */ +#if HW_VERSION >= 22 +static uint32_t spi_mst_cs_ctrl_creg = 0; +#endif + +/** designware spi 0 open */ +static int32_t dw_spi_0_open(uint32_t mode, uint32_t param) +{ + return dw_spi_open(&dw_spi_0, mode, param); +} +/** designware spi 0 close */ +static int32_t dw_spi_0_close(void) +{ + return dw_spi_close(&dw_spi_0); +} +/** designware spi 0 control */ +static int32_t dw_spi_0_control(uint32_t ctrl_cmd, void *param) +{ +#if HW_VERSION >= 22 + int32_t ercd; + ercd = dw_spi_control(&dw_spi_0, ctrl_cmd, param); + + if (ctrl_cmd == SPI_CMD_MST_SEL_DEV) + { + _arc_write_uncached_32((void *)spi_mst_cs_ctrl_creg, 1 << ((uint32_t)param)); + } + else if (ctrl_cmd == SPI_CMD_MST_DSEL_DEV) + { + _arc_write_uncached_32((void *)spi_mst_cs_ctrl_creg, 0); + } + + return ercd; +#else + return dw_spi_control(&dw_spi_0, ctrl_cmd, param); +#endif +} +/** designware spi 0 write */ +static int32_t dw_spi_0_write(const void *data, uint32_t len) +{ + return dw_spi_write(&dw_spi_0, data, len); +} +/** designware spi 0 close */ +static int32_t dw_spi_0_read(void *data, uint32_t len) +{ + return dw_spi_read(&dw_spi_0, data, len); +} +/** designware spi 0 interrupt routine */ +static void dw_spi_0_isr(void *ptr) +{ + dw_spi_isr(&dw_spi_0, ptr); +} +/** install designware spi 0 to system */ +static void dw_spi_0_install(void) +{ + uint32_t spi_abs_base = 0; + DEV_SPI *dw_spi_ptr = &dw_spi_0; + DEV_SPI_INFO *dw_spi_info_ptr = &(dw_spi_0.spi_info); + DW_SPI_CTRL *dw_spi_ctrl_ptr = &dw_spi_0_ctrl; + DW_SPI_REG *dw_spi_reg_ptr; + + /** + * get absolute designware base address + */ + spi_abs_base = (uint32_t)PERIPHERAL_BASE + DW_SPI_0_RELBASE; + +#if HW_VERSION >= 22 + spi_mst_cs_ctrl_creg = spi_abs_base + REL_REGBASE_SPI_MST_CS_CTRL; +#endif + + dw_spi_reg_ptr = (DW_SPI_REG *)spi_abs_base; + + /** spi info init */ + dw_spi_info_ptr->spi_ctrl = (void *)dw_spi_ctrl_ptr; + dw_spi_info_ptr->status = DEV_DISABLED; + dw_spi_info_ptr->freq = 1000; + dw_spi_info_ptr->opn_cnt = 0; + dw_spi_info_ptr->mode = DEV_MASTER_MODE; + dw_spi_info_ptr->clk_mode = SPI_CLK_MODE_DEFAULT; + dw_spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED; + dw_spi_info_ptr->dfs = SPI_DFS_DEFAULT; + dw_spi_info_ptr->dummy = 0xff; + + /* spi ctrl init */ + /* Variables which should be set during object implementation */ + dw_spi_ctrl_ptr->dw_spi_regs = dw_spi_reg_ptr; + dw_spi_ctrl_ptr->intno = DW_SPI_0_INTNO; + dw_spi_ctrl_ptr->support_modes = DW_SPI_0_SUPPORTED_MODE; + dw_spi_ctrl_ptr->tx_fifo_len = DW_SPI_0_TX_FIFO_LEN; + dw_spi_ctrl_ptr->rx_fifo_len = DW_SPI_0_TX_FIFO_LEN; + dw_spi_ctrl_ptr->dw_apb_bus_freq = CLK_BUS_APB; + dw_spi_ctrl_ptr->dw_spi_int_handler = dw_spi_0_isr; + /* Variables which always change during spi operation */ + dw_spi_ctrl_ptr->int_status = 0; + + /** spi dev init */ + dw_spi_ptr->spi_open = dw_spi_0_open; + dw_spi_ptr->spi_close = dw_spi_0_close; + dw_spi_ptr->spi_control = dw_spi_0_control; + dw_spi_ptr->spi_write = dw_spi_0_write; + dw_spi_ptr->spi_read = dw_spi_0_read; +} +#endif /* USE_DW_SPI_0 */ +/** @} end of name */ + +/** + * \name EMSK DesignWare SPI 1 Object Instantiation + * @{ + */ +#if (USE_DW_SPI_1) +static void dw_spi_1_isr(void *ptr); +#define DW_SPI_1_RELBASE (REL_REGBASE_SPI1) /*!< designware spi 1 relative baseaddr */ +#define DW_SPI_1_INTNO (INTNO_SPI_SLAVE) /*!< designware spi 1 interrupt number */ + +#define DW_SPI_1_TX_FIFO_LEN (32) +#define DW_SPI_1_RX_FIFO_LEN (32) + +#define DW_SPI_1_SUPPORTED_MODE DW_SPI_SLAVE_SUPPORTED + +DEV_SPI dw_spi_1; /*!< designware spi 1 object */ +DW_SPI_CTRL dw_spi_1_ctrl; /*!< designware spi 1 ctrl */ + +/** designware spi 1 open */ +static int32_t dw_spi_1_open(uint32_t mode, uint32_t param) +{ + return dw_spi_open(&dw_spi_1, mode, param); +} +/** designware spi 1 close */ +static int32_t dw_spi_1_close(void) +{ + return dw_spi_close(&dw_spi_1); +} +/** designware spi 1 control */ +static int32_t dw_spi_1_control(uint32_t ctrl_cmd, void *param) +{ + return dw_spi_control(&dw_spi_1, ctrl_cmd, param); +} +/** designware spi 1 write */ +static int32_t dw_spi_1_write(const void *data, uint32_t len) +{ + return dw_spi_write(&dw_spi_1, data, len); +} +/** designware spi 1 close */ +static int32_t dw_spi_1_read(void *data, uint32_t len) +{ + return dw_spi_read(&dw_spi_1, data, len); +} +/** designware spi 1 interrupt routine */ +static void dw_spi_1_isr(void *ptr) +{ + dw_spi_isr(&dw_spi_1, ptr); +} +/** install designware spi 1 to system */ +static void dw_spi_1_install(void) +{ + uint32_t spi_abs_base = 0; + DEV_SPI *dw_spi_ptr = &dw_spi_1; + DEV_SPI_INFO *dw_spi_info_ptr = &(dw_spi_1.spi_info); + DW_SPI_CTRL *dw_spi_ctrl_ptr = &dw_spi_1_ctrl; + DW_SPI_REG *dw_spi_reg_ptr; + + /** + * get absolute designware base address + */ + spi_abs_base = (uint32_t)PERIPHERAL_BASE + DW_SPI_1_RELBASE; + dw_spi_reg_ptr = (DW_SPI_REG *)spi_abs_base; + + /** spi info init */ + dw_spi_info_ptr->spi_ctrl = (void *)dw_spi_ctrl_ptr; + dw_spi_info_ptr->status = DEV_DISABLED; + dw_spi_info_ptr->freq = 1000; + dw_spi_info_ptr->opn_cnt = 0; + dw_spi_info_ptr->mode = DEV_SLAVE_MODE; + dw_spi_info_ptr->clk_mode = SPI_CLK_MODE_DEFAULT; + dw_spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED; + dw_spi_info_ptr->dfs = SPI_DFS_DEFAULT; + dw_spi_info_ptr->dummy = 0xff; + + /* spi ctrl init */ + /* Variables which should be set during object implementation */ + dw_spi_ctrl_ptr->dw_spi_regs = dw_spi_reg_ptr; + dw_spi_ctrl_ptr->intno = DW_SPI_1_INTNO; + dw_spi_ctrl_ptr->support_modes = DW_SPI_1_SUPPORTED_MODE; + dw_spi_ctrl_ptr->tx_fifo_len = DW_SPI_1_TX_FIFO_LEN; + dw_spi_ctrl_ptr->rx_fifo_len = DW_SPI_1_TX_FIFO_LEN; + dw_spi_ctrl_ptr->dw_apb_bus_freq = CLK_BUS_APB; + dw_spi_ctrl_ptr->dw_spi_int_handler = dw_spi_1_isr; + /* Variables which always change during spi operation */ + dw_spi_ctrl_ptr->int_status = 0; + + /** spi dev init */ + dw_spi_ptr->spi_open = dw_spi_1_open; + dw_spi_ptr->spi_close = dw_spi_1_close; + dw_spi_ptr->spi_control = dw_spi_1_control; + dw_spi_ptr->spi_write = dw_spi_1_write; + dw_spi_ptr->spi_read = dw_spi_1_read; +} +#endif /* USE_DW_SPI_1 */ +/** @} end of name */ + +/** get one designware device structure */ +DEV_SPI_PTR spi_get_dev(int32_t spi_id) +{ + static uint32_t install_flag = 0; + + /* install device objects */ + if (install_flag == 0) + { + install_flag = 1; + dw_spi_all_install(); + } + + switch (spi_id) + { +#if (USE_DW_SPI_0) + + case DW_SPI_0_ID: + return &dw_spi_0; + break; +#endif +#if (USE_DW_SPI_1) + + case DW_SPI_1_ID: + return &dw_spi_1; + break; +#endif + + default: + break; + } + + return NULL; +} + +/** + * \brief install all spi objects + * \note \b MUST be called during system init + */ +void dw_spi_all_install(void) +{ +#if (USE_DW_SPI_0) + dw_spi_0_install(); +#endif +#if (USE_DW_SPI_1) + dw_spi_1_install(); +#endif +} + +/** @} end of group BOARD_EMSK_DRV_DW_SPI_OBJ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.h new file mode 100644 index 000000000..f363c41ff --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spi/dw_spi_obj.h @@ -0,0 +1,82 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-07-03 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_SPI_OBJ + * \brief header file of designware spi object instantiation on emsk + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_SPI_OBJ + * @{ + */ +#ifndef _DW_SPI_OBJ_H_ +#define _DW_SPI_OBJ_H_ + +#include "device/device_hal/inc/dev_spi.h" + +/** + * \name DesignWare SPI Object Number + * @{ + */ +#define DW_SPI_NUM (2) /*!< DesignWare SPI valid number */ +/** @} end of name */ + +/** + * \name Designware SPI Object ID Macros + * @{ + */ +#define DW_SPI_0_ID 0 /*!< SPI 0 id macro (master node) */ +#define DW_SPI_1_ID 1 /*!< SPI 1 id macro (slave node) */ +/** @} end of name */ + +/** + * \name Designware SPI Object Control Macros + * @{ + */ +#define USE_DW_SPI_0 1 /*!< enable use designware SPI 0 */ +#define USE_DW_SPI_1 1 /*!< enable use designware SPI 1 */ +/** @} end of name */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void dw_spi_all_install(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DW_SPI_OBJ_H_ */ +/** @} end of group BOARD_EMSK_DRV_DW_SPI_OBJ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.c new file mode 100644 index 000000000..e05f17cda --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.c @@ -0,0 +1,449 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-07-17 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup BOARD_EMSK_DRV_SPIFLASH EMSK SPI Flash Driver + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK On-board SPI Flash Driver + * \details + * Realize driver for on-board W25Q128BV spi flash using Designware spi driver. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_SPIFLASH + * \brief emsk on-board W25Q128BV spi flash driver + */ + +/** + * \addtogroup BOARD_EMSK_DRV_SPIFLASH + * @{ + */ +#include "board/emsk/spiflash/spiflash.h" + +#include "inc/embARC_error.h" +#include "board/emsk/emsk.h" +#include "device/device_hal/inc/dev_spi.h" +#include "inc/arc/arc_exception.h" + +/** + * \name SPI Flash Commands + * @{ + */ +#define RDID 0x9F /*!spi_control(SPI_CMD_MST_SEL_DEV, CONV2VOID(cs_flash)); + SPIFLASH_CHECK_EXP(ercd == E_OK, -1); + ercd = spi_flash->spi_control(SPI_CMD_TRANSFER_POLLING, CONV2VOID(xfer)); + /* deselect device */ + spi_flash->spi_control(SPI_CMD_MST_DSEL_DEV, CONV2VOID(cs_flash)); + SPIFLASH_CHECK_EXP(ercd == E_OK, -1); + + cpu_unlock_restore(cpu_status); + + if (ercd == E_OK) { ercd = 0; } + +error_exit: + return ercd; +} + +/** + * \brief init spi flash related interface + * \retval 0 success + * \retval -1 fail + */ +int32_t flash_init(void) +{ + int32_t ercd = 0; + + spi_flash = spi_get_dev(SPI_ID_SFLASH); + ercd = spi_flash->spi_open(DEV_MASTER_MODE, SPI_FLASH_FREQ); + spi_flash->spi_control(SPI_CMD_MST_SET_FREQ, CONV2VOID(SPI_FLASH_FREQ)); + spi_flash->spi_control(SPI_CMD_SET_DUMMY_DATA, CONV2VOID(0xFF)); + spi_flash->spi_control(SPI_CMD_SET_CLK_MODE, CONV2VOID(SPI_FLASH_CLKMODE)); + + if (ercd == E_OK) { ercd = 0; } + +error_exit: + return ercd; +} + +int32_t flash_change_freq(uint32_t freq) +{ + spi_flash = spi_get_dev(SPI_ID_SFLASH); + int32_t ercd = spi_flash->spi_control(SPI_CMD_MST_SET_FREQ, CONV2VOID(freq)); + return ercd; +} + +/** + * \brief read spi flash identification ID + * \return the id of the spi flash + */ +uint32_t flash_read_id(void) +{ + uint32_t id = 0; + uint8_t local_buf[4]; + DEV_SPI_TRANSFER cmd_xfer; + + local_buf[0] = RDID; + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 1); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, local_buf, 1, 3); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) == 0) + { + id = (local_buf[0] << 16) | (local_buf[1] << 8) | local_buf[2]; + } + else + { + id = SPI_FLASH_NOT_VALID; + } + + return id; +} + +/** + * \brief read the status of spi flash + * \return current status of spi flash + */ +uint32_t flash_read_status(void) +{ + + uint8_t local_buf[2]; + DEV_SPI_TRANSFER cmd_xfer; + + local_buf[0] = RDSR; + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 1); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, local_buf, 1, 1); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) == 0) + { + return (uint32_t)local_buf[0]; + } + else + { + return SPI_FLASH_NOT_VALID; + } +} + +/** + * \brief read data from flash + * \param[in] address read start address of spi flash + * \param[in] size read size of spi flash + * \param[out] data data to store the return data + * + * \retval -1 failed in read operation + * \retval >=0 data size of data read + */ +int32_t flash_read(uint32_t address, uint32_t size, void *data) +{ + + uint8_t local_buf[4]; + DEV_SPI_TRANSFER cmd_xfer; + + local_buf[0] = READ; + local_buf[1] = (address >> 16) & 0xff; + local_buf[2] = (address >> 8) & 0xff; + local_buf[3] = address & 0xff; + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 4); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, data, 4, size); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) == 0) + { + return size; + } + else + { + return -1; + } +} + +/** + * \brief Read status and wait while busy flag is set + * \retval 0 success + * \retval -1 fail + */ +int32_t flash_wait_ready(void) +{ + uint32_t status = 0x01; + + do + { + status = flash_read_status(); + + if (status == SPI_FLASH_NOT_VALID) + { + return -1; + } + } + while (status & 0x01); + + return 0; +} + +/** + * \brief enable to write flash + * \retval 0 success + * \retval -1 fail + */ +int32_t flash_write_enable(void) +{ + uint8_t local_buf[3]; + DEV_SPI_TRANSFER cmd_xfer; + + uint32_t status = 0; + + do + { + local_buf[0] = WREN; + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 1); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) != 0) + { + return -1; + } + + status = flash_read_status(); + + if (status == SPI_FLASH_NOT_VALID) + { + return -1; + } + + // clear protection bits + // Write Protect. and Write Enable. + if ((status & 0xfc) && (status & 0x02)) + { + local_buf[0] = WRSR; // write status + local_buf[1] = 0x00; // write status + local_buf[2] = 0x00; // write status + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 3); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) != 0) + { + return -1; + } + + status = 0; + } + } + while (status != 0x02); + + return 0; +} + + +/** + * \brief flash erase in sectors + * + * \param[in] address erase start address of spi flash + * \param[in] size erase size + * + * \retval -1 failed in erase operation + * \retval >=0 sector count erased + */ +int32_t flash_erase(uint32_t address, uint32_t size) +{ + uint32_t last_address; + uint32_t count = 0; + uint8_t local_buf[4]; + DEV_SPI_TRANSFER cmd_xfer; + + // start address of last sector + last_address = (address + size) & (~(FLASH_SECTOR_SIZE - 1)); + + // start address of first sector + address &= ~(FLASH_SECTOR_SIZE - 1); + + do + { + if (flash_write_enable() != 0) + { + return -1; + } + + if (flash_wait_ready() != 0) + { + return -1; + } + + local_buf[0] = SE; + local_buf[1] = (address >> 16) & 0xff; + local_buf[2] = (address >> 8) & 0xff; + local_buf[3] = address & 0xff; + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 4); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, NULL); + + if (spi_send_cmd(&cmd_xfer) != 0) + { + return -1; + } + + address += FLASH_SECTOR_SIZE; + count++; + } + while (address <= last_address); + + if (flash_wait_ready() != 0) + { + return -1; + } + + return (int32_t)count; +} + +/** + * \brief write data to spi flash + * + * \param[in] address start address + * \param[in] size data size + * \param[in] data pointer to data + * + * \retval >=0 written bytes number + * \retval <0 error + */ +int32_t flash_write(uint32_t address, uint32_t size, const void *data) +{ + + uint8_t local_buf[4]; + DEV_SPI_TRANSFER cmd_xfer; + DEV_SPI_TRANSFER data_xfer; + + uint32_t first = 0; + uint32_t size_orig = size; + + if (flash_wait_ready() != 0) + { + return -1; + } + + first = FLASH_PAGE_SIZE - (address & (FLASH_PAGE_SIZE - 1)); + + do + { + // send write enable command to flash + if (flash_write_enable() != 0) + { + return -1; + } + + if (flash_wait_ready() != 0) + { + return -1; + } + + first = first < size ? first : size; + + local_buf[0] = PP; + local_buf[1] = (address >> 16) & 0xff; + local_buf[2] = (address >> 8) & 0xff; + local_buf[3] = address & 0xff; + + DEV_SPI_XFER_SET_TXBUF(&data_xfer, data, 0, first); + DEV_SPI_XFER_SET_RXBUF(&data_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(&data_xfer, NULL); + + DEV_SPI_XFER_SET_TXBUF(&cmd_xfer, local_buf, 0, 4); + DEV_SPI_XFER_SET_RXBUF(&cmd_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(&cmd_xfer, &data_xfer); + + if (spi_send_cmd(&cmd_xfer) != 0) + { + return -1; + } + + size -= first; + address += first; + data += first; + first = FLASH_PAGE_SIZE; + + } + while (size); + + if (flash_wait_ready() != 0) + { + return -1; + } + + return (int32_t)(size_orig); +} + +/** @} end of group BOARD_EMSK_DRV_SPIFLASH */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.h new file mode 100644 index 000000000..c4c6e7895 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/spiflash/spiflash.h @@ -0,0 +1,83 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-07-17 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_SPIFLASH + * \brief header file of emsk onbard W25Q128BV spi flash driver + */ + +/** + * \addtogroup BOARD_EMSK_DRV_SPIFLASH + * @{ + */ +#ifndef _EMSK_SPIFLASH_H_ +#define _EMSK_SPIFLASH_H_ + +#define FLASH_PAGE_SIZE 0x100 +#define FLASH_SECTOR_SIZE 0x1000 + +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" + +typedef struct +{ + uint32_t head; /*!< 0x68656164 ='head' */ + uint32_t cpu_type; /*!< = 0 - all images, reserved for future */ + uint32_t start; /*!< start address of application image in spi flash */ + uint32_t size; /*!< size of image in bytes */ + uint32_t ramaddr; /*!< address of ram for loading image */ + uint32_t ramstart; /*!< start address of application in RAM !!!! */ + uint32_t checksum; /*!< checksum of all bytes in image */ +} image_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t flash_read_id(void); +extern uint32_t flash_read_status(void); +extern int32_t flash_read(uint32_t address, uint32_t size, void *data); +extern int32_t flash_write_enable(void); +extern int32_t flash_wait_ready(void); +extern int32_t flash_erase(uint32_t address, uint32_t size); +extern int32_t flash_write(uint32_t address, uint32_t size, const void *data); +extern int32_t flash_init(void); +extern int32_t flash_change_freq(uint32_t freq); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMSK_SPIFLASH_H_ */ + +/** @} end of group BOARD_EMSK_DRV_SPIFLASH */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.c b/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.c new file mode 100644 index 000000000..530ac1454 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.c @@ -0,0 +1,274 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-03 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup BOARD_EMSK_DRV_DW_UART_OBJ EMSK DW UART Object + * \ingroup BOARD_EMSK_DRIVER + * \brief EMSK Designware UART Objects + * \details + * Realize the EMSK board uart object using Designware uart device driver, + * only need to realize some Designware uart structures combine with EMSK uart + * hardware resource. just like cpp class instantiation. + */ + +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_UART_OBJ + * \brief designware uart object instantiation on emsk + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_UART_OBJ + * @{ + */ +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" + +#include "inc/arc/arc_exception.h" +#include "device/designware/uart/dw_uart.h" +#include "board/emsk/uart/dw_uart_obj.h" + +#include "board/emsk/emsk.h" + +#ifdef ARC_FEATURE_DMP_PERIPHERAL +#define PERIPHERAL_BASE ARC_FEATURE_DMP_PERIPHERAL +#else +#define PERIPHERAL_BASE _arc_aux_read(AUX_DMP_PERIPHERAL) +#endif + +#define DW_UART_FIFO_LEN 32 + +/** + * \name EMSK DesignWare UART 0 Object Instantiation + * @{ + */ +#if (USE_DW_UART_0) +static void dw_uart_0_isr(void *ptr); +#define DW_UART_0_RELBASE (REL_REGBASE_UART0) /*!< designware uart 0 relative baseaddr */ +#define DW_UART_0_INTNO (INTNO_UART0) /*!< designware uart 0 interrupt number */ + +DEV_UART dw_uart_0; /*!< designware uart object */ +DW_UART_CTRL dw_uart_0_ctrl = /*!< designware uart 0 ctrl */ +{ + 0, CLK_BUS_APB, DW_UART_0_INTNO, (INT_HANDLER)dw_uart_0_isr, + DW_UART_FIFO_LEN, DW_UART_FIFO_LEN, 0 +}; + +/** designware uart 0 open */ +static int32_t dw_uart_0_open(uint32_t baud) +{ + return dw_uart_open(&dw_uart_0, baud); +} +/** designware uart 0 close */ +static int32_t dw_uart_0_close(void) +{ + return dw_uart_close(&dw_uart_0); +} +/** designware uart 0 control */ +static int32_t dw_uart_0_control(uint32_t ctrl_cmd, void *param) +{ + return dw_uart_control(&dw_uart_0, ctrl_cmd, param); +} +/** designware uart 0 write */ +static int32_t dw_uart_0_write(const void *data, uint32_t len) +{ + return dw_uart_write(&dw_uart_0, data, len); +} +/** designware uart 0 close */ +static int32_t dw_uart_0_read(void *data, uint32_t len) +{ + return dw_uart_read(&dw_uart_0, data, len); +} +/** designware uart 0 interrupt rountine */ +static void dw_uart_0_isr(void *ptr) +{ + dw_uart_isr(&dw_uart_0, ptr); +} +/** install designware uart 0 to system */ +static void dw_uart_0_install(void) +{ + uint32_t uart_abs_base = 0; + DEV_UART *dw_uart_ptr = &dw_uart_0; + DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_0.uart_info); + DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_0_ctrl; + + /** + * get absolute designware base address + */ + uart_abs_base = (uint32_t)PERIPHERAL_BASE + DW_UART_0_RELBASE; + dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base; + + /** uart info init */ + dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr; + dw_uart_info_ptr->opn_cnt = 0; + dw_uart_info_ptr->status = 0; + dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200; /* default 115200bps */ + + /** uart dev init */ + dw_uart_ptr->uart_open = dw_uart_0_open; + dw_uart_ptr->uart_close = dw_uart_0_close; + dw_uart_ptr->uart_control = dw_uart_0_control; + dw_uart_ptr->uart_write = dw_uart_0_write; + dw_uart_ptr->uart_read = dw_uart_0_read; + +} +#endif /* USE_DW_UART_0 */ +/** @} end of name */ + +/** + * \name EMSK DesignWare UART 1 Object Instantiation + * @{ + */ +#if (USE_DW_UART_1) +static void dw_uart_1_isr(void *ptr); +#define DW_UART_1_RELBASE (REL_REGBASE_UART1) /*!< designware uart 1 relative baseaddr */ +#define DW_UART_1_INTNO (INTNO_UART1) /*!< designware uart 1 interrupt number */ + +DEV_UART dw_uart_1; /*!< designware uart 1 object */ +DW_UART_CTRL dw_uart_1_ctrl = /*!< designware uart 1 ctrl */ +{ + 0, CLK_BUS_APB, DW_UART_1_INTNO, (INT_HANDLER)dw_uart_1_isr, + DW_UART_FIFO_LEN, DW_UART_FIFO_LEN, 0 +}; + +/** designware uart 1 open */ +static int32_t dw_uart_1_open(uint32_t baud) +{ + return dw_uart_open(&dw_uart_1, baud); +} +/** designware uart 1 close */ +static int32_t dw_uart_1_close(void) +{ + return dw_uart_close(&dw_uart_1); +} +/** designware uart 1 control */ +static int32_t dw_uart_1_control(uint32_t ctrl_cmd, void *param) +{ + return dw_uart_control(&dw_uart_1, ctrl_cmd, param); +} +/** designware uart 1 write */ +static int32_t dw_uart_1_write(const void *data, uint32_t len) +{ + return dw_uart_write(&dw_uart_1, data, len); +} +/** designware uart 1 close */ +static int32_t dw_uart_1_read(void *data, uint32_t len) +{ + return dw_uart_read(&dw_uart_1, data, len); +} +/** designware uart 1 interrupt routine */ +static void dw_uart_1_isr(void *ptr) +{ + dw_uart_isr(&dw_uart_1, ptr); +} +/** install designware uart 1 to system */ +static void dw_uart_1_install(void) +{ + uint32_t uart_abs_base = 0; + DEV_UART *dw_uart_ptr = &dw_uart_1; + DEV_UART_INFO *dw_uart_info_ptr = &(dw_uart_1.uart_info); + DW_UART_CTRL *dw_uart_ctrl_ptr = &dw_uart_1_ctrl; + + /** + * get absolute designware base address + */ + uart_abs_base = (uint32_t)PERIPHERAL_BASE + DW_UART_1_RELBASE; + dw_uart_ctrl_ptr->dw_uart_regbase = uart_abs_base; + + /** uart info init */ + dw_uart_info_ptr->uart_ctrl = (void *)dw_uart_ctrl_ptr; + dw_uart_info_ptr->opn_cnt = 0; + dw_uart_info_ptr->status = 0; + dw_uart_info_ptr->baudrate = UART_BAUDRATE_115200; /* default 115200bps */ + + /** uart dev init */ + dw_uart_ptr->uart_open = dw_uart_1_open; + dw_uart_ptr->uart_close = dw_uart_1_close; + dw_uart_ptr->uart_control = dw_uart_1_control; + dw_uart_ptr->uart_write = dw_uart_1_write; + dw_uart_ptr->uart_read = dw_uart_1_read; +} +#endif /* USE_DW_UART_1 */ +/** @} end of name */ + +/** get one designware device structure */ +DEV_UART_PTR uart_get_dev(int32_t uart_id) +{ + static uint32_t install_flag = 0; + + /* intall device objects */ + if (install_flag == 0) + { + install_flag = 1; + dw_uart_all_install(); + } + + switch (uart_id) + { +#if (USE_DW_UART_0) + + case DW_UART_0_ID: + return &dw_uart_0; + break; +#endif +#if (USE_DW_UART_1) + + case DW_UART_1_ID: + return &dw_uart_1; + break; +#endif + + default: + break; + } + + return NULL; +} + +/** + * \brief install all uart objects + * \note \b MUST be called during system init + */ +void dw_uart_all_install(void) +{ +#if (USE_DW_UART_0) + dw_uart_0_install(); +#endif +#if (USE_DW_UART_1) + dw_uart_1_install(); +#endif +} + +/** @} end of group BOARD_EMSK_DRV_DW_UART_OBJ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.h b/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.h new file mode 100644 index 000000000..8053f93c8 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/board/emsk/uart/dw_uart_obj.h @@ -0,0 +1,89 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-03 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +/** + * \file + * \ingroup BOARD_EMSK_DRV_DW_UART_OBJ + * \brief header file of designware uart object instantiation on emsk + */ + +/** + * \addtogroup BOARD_EMSK_DRV_DW_UART_OBJ + * @{ + */ +#ifndef _DW_UART_OBJ_H_ +#define _DW_UART_OBJ_H_ + +#include "device/device_hal/inc/dev_uart.h" + +/** + * \name DesignWare UART Object Number + * @{ + */ +#define DW_UART_NUM (2) /*!< DesignWare UART valid number */ +/** @} end of name */ + +/** + * \name Designware UART Object ID Macros + * @{ + */ +#define DW_UART_0_ID 0 /*!< uart 0 id macro */ +#define DW_UART_1_ID 1 /*!< uart 1 id macro */ +/** @} end of name */ + +/** + * \name Designware UART Object Control Macros + * @{ + */ +#define USE_DW_UART_0 1 /*!< enable use designware uart 0 */ +#define USE_DW_UART_1 1 /*!< enable use designware uart 1 */ +/** @} end of name */ + +/** + * \name Designware UART Ringbuffer Size Control Macros + * @{ + */ +#define MAX_SNDBUF_SIZE 256 /*!< max size of uart send buffer */ +#define MAX_RCVBUF_SIZE 10 /*!< max size of uart recv buffer */ +/** @} end of name */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void dw_uart_all_install(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DW_UART_OBJ_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/common/console_io.c b/third_party/synopsys/embarc_emsk_bsp/common/console_io.c new file mode 100644 index 000000000..c453ed70f --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/common/console_io.c @@ -0,0 +1,172 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-23 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \brief common io implementation + */ +#include + +#include "device/device_hal/inc/dev_uart.h" +#include "common/console_io.h" +#include "inc/arc/arc_builtin.h" +#include "common/xprintf/xprintf.h" + +/*!< to indicate xprintf setup state(0 for not setup) */ +static int xprintf_setup_flag = 0; +static DEV_UART *console_uart; /*!< console uart device pointer */ + +/** put one char */ +int console_putchar(unsigned char chr) +{ + if (console_uart == NULL) + { + return -1; + } + + console_uart->uart_write((const void *)(&chr), 1); + return 0; +} + +/** put string */ +int console_putstr(const char *str, unsigned int len) +{ + if (console_uart == NULL) + { + return -1; + } + + return (int)console_uart->uart_write((const void *)(str), len); +} + +/** get one char*/ +int console_getchar(void) +{ + unsigned char data; + + if (console_uart == NULL) + { + return -1; + } + + while (!console_uart->uart_read((void *)(&data), 1)); + + return (int)data; +} + +/** get string */ +int console_getstr(char *str, unsigned int len) +{ + if (console_uart == NULL) + { + return -1; + } + + return (int)console_uart->uart_read((void *)(str), len); +} + +#ifndef ENABLE_BANNER +#define ENABLE_BANNER 1 +#endif + +#ifndef EMBARC_BANNER_TYPE +#define EMBARC_BANNER_TYPE 1 +#endif + +static const char *embarc_banner = +#if EMBARC_BANNER_TYPE == 1 + "----------------------------------------------------------- \r\n\ + ____ _ ____ \r\n\ +| _ \\ _____ _____ _ __ ___ __| | __ ) _ _ \r\n\ +| |_) / _ \\ \\ /\\ / / _ \\ '__/ _ \\/ _` | _ \\| | | | \r\n\ +| __/ (_) \\ V V / __/ | | __/ (_| | |_) | |_| | \r\n\ +|_| \\___/ \\_/\\_/ \\___|_| \\___|\\__,_|____/ \\__, | \r\n\ + |___/ \r\n\ + _ _ ____ ____ \r\n\ + ___ _ __ ___ | |__ / \\ | _ \\ / ___| \r\n\ + / _ \\ '_ ` _ \\| '_ \\ / _ \\ | |_) | | \r\n\ + | __/ | | | | | |_) / ___ \\| _ <| |___ \r\n\ + \\___|_| |_| |_|_.__/_/ \\_\\_| \\_\\\\____| \r\n\ +------------------------------------------------------------ \r\n\ +"; +#else + "-----------------------------------------------------------------------------------------------\r\n\ + _/_/_/ _/ _/_/_/ \r\n\ + _/ _/ _/_/ _/ _/ _/ _/_/ _/ _/_/ _/_/ _/_/_/ _/ _/ _/ _/ \r\n\ + _/_/_/ _/ _/ _/ _/ _/ _/_/_/_/ _/_/ _/_/_/_/ _/ _/ _/_/_/ _/ _/ \r\n\ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ \r\n\ + _/ _/_/ _/ _/ _/_/_/ _/ _/_/_/ _/_/_/ _/_/_/ _/_/_/ \r\n\ + _/ \r\n\ + _/_/ \r\n\ + _/ _/_/ _/_/_/ _/_/_/ \r\n\ + _/_/ _/_/_/ _/_/ _/_/_/ _/ _/ _/ _/ _/ \r\n\ + _/_/_/_/ _/ _/ _/ _/ _/ _/_/_/_/ _/_/_/ _/ \r\n\ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ \r\n\ + _/_/_/ _/ _/ _/ _/_/_/ _/ _/ _/ _/ _/_/_/ \r\n\ +------------------------------------------------------------------------------------------------\r\n\ +"; +#endif + +static void embarc_print_banner(void) +{ + xprintf("%s\r\n", embarc_banner); +} + +/** xprintf need functions api setup */ +void xprintf_setup(void) +{ + if (xprintf_setup_flag) + { + return; + } + + console_uart = uart_get_dev(CONSOLE_UART_ID); + console_uart->uart_open(BOARD_CONSOLE_UART_BAUD); + + xdev_in(console_getchar); + xdev_out(console_putchar); + +#if ENABLE_BANNER == 1 + embarc_print_banner(); +#endif + + xprintf("embARC Build Time: %s, %s\r\n", __DATE__, __TIME__); +#if defined(__GNU__) + xprintf("Compiler Version: ARC GNU, %s\r\n", __VERSION__); +#else + xprintf("Compiler Version: Metaware, %s\r\n", __VERSION__); +#endif + + xprintf_setup_flag = 1; +} + diff --git a/third_party/synopsys/embarc_emsk_bsp/common/console_io.h b/third_party/synopsys/embarc_emsk_bsp/common/console_io.h new file mode 100644 index 000000000..1603774cd --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/common/console_io.h @@ -0,0 +1,59 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-23 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \brief common io implementation + */ +#ifndef _CONSOLE_IO_H_ +#define _CONSOLE_IO_H_ +#include "inc/embARC_toolchain.h" +#include "board/board.h" + +#define CONSOLE_UART_ID BOARD_CONSOLE_UART_ID /*!< console uart id */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int console_putchar(unsigned char chr); +extern int console_putstr(const char *str, unsigned int len); +extern int console_getchar(void); +extern int console_getstr(char *str, unsigned int len); +extern void xprintf_setup(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSOLE_IO_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.c b/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.c new file mode 100644 index 000000000..8a9cbac8a --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.c @@ -0,0 +1,510 @@ +/*------------------------------------------------------------------------/ +/ Universal string handler for user console interface +/-------------------------------------------------------------------------/ +/ +/ Copyright (C) 2011, ChaN, all right reserved. +/ +/ * This software is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-------------------------------------------------------------------------*/ + +#include "common/xprintf/xprintf.h" + + +#if _USE_XFUNC_OUT +#include +void (*xfunc_out)(unsigned char); /* Pointer to the output stream */ +static char *outptr; + +/*----------------------------------------------*/ +/* Put a character */ +/*----------------------------------------------*/ + +void xputc(char c) +{ + if (_CR_CRLF && c == '\n') { xputc('\r'); } /* CR -> CRLF */ + + if (outptr) + { + *outptr++ = (unsigned char)c; + return; + } + + if (xfunc_out) { xfunc_out((unsigned char)c); } +} + + + +/*----------------------------------------------*/ +/* Put a null-terminated string */ +/*----------------------------------------------*/ + +void xputs( /* Put a string to the default device */ + const char *str /* Pointer to the string */ +) +{ + while (*str) + { + xputc(*str++); + } +} + + +void xfputs( /* Put a string to the specified device */ + void(*func)(unsigned char), /* Pointer to the output function */ + const char *str /* Pointer to the string */ +) +{ + void (*pf)(unsigned char); + + + pf = xfunc_out; /* Save current output device */ + xfunc_out = func; /* Switch output to specified device */ + + while (*str) /* Put the string */ + { + xputc(*str++); + } + + xfunc_out = pf; /* Restore output device */ +} + + + +/*----------------------------------------------*/ +/* Formatted string output */ +/*----------------------------------------------*/ +/* xprintf("%d", 1234); "1234" + xprintf("%6d,%3d%%", -200, 5); " -200, 5%" + xprintf("%-6u", 100); "100 " + xprintf("%ld", 12345678L); "12345678" + xprintf("%04x", 0xA3); "00a3" + xprintf("%08LX", 0x123ABC); "00123ABC" + xprintf("%016b", 0x550F); "0101010100001111" + xprintf("%s", "String"); "String" + xprintf("%-4s", "abc"); "abc " + xprintf("%4s", "abc"); " abc" + xprintf("%c", 'a'); "a" + xprintf("%f", 10.0); +*/ + +void xvprintf( + const char *fmt, /* Pointer to the format string */ + va_list arp /* Pointer to arguments */ +) +{ + unsigned int r, i, j, w, f; + unsigned long v; + char s[16], c, d, *p; + + + for (;;) + { + c = *fmt++; /* Get a char */ + + if (!c) { break; } /* End of format? */ + + if (c != '%') /* Pass through it if not a % sequense */ + { + xputc(c); + continue; + } + + f = 0; + c = *fmt++; /* Get first char of the sequense */ + + if (c == '0') /* Flag: '0' padded */ + { + f = 1; + c = *fmt++; + } + else + { + if (c == '-') /* Flag: left justified */ + { + f = 2; + c = *fmt++; + } + } + + for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */ + { + w = w * 10 + c - '0'; + } + + if (c == 'l' || c == 'L') /* Prefix: Size is long int */ + { + f |= 4; + c = *fmt++; + } + + if (!c) { break; } /* End of format? */ + + d = c; + + if (d >= 'a') { d -= 0x20; } + + switch (d) /* Type is... */ + { + case 'S' : /* String */ + p = va_arg(arp, char *); + + for (j = 0; p[j]; j++) ; + + while (!(f & 2) && j++ < w) { xputc(' '); } + + xputs(p); + + while (j++ < w) { xputc(' '); } + + continue; + + case 'C' : /* Character */ + xputc((char)va_arg(arp, int)); + continue; + + case 'B' : /* Binary */ + r = 2; + break; + + case 'O' : /* Octal */ + r = 8; + break; + + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; + break; + + case 'X' : /* Hexdecimal */ + r = 16; + break; + + default: /* Unknown type (passthrough) */ + xputc(c); + continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int)); + + if (d == 'D' && (v & 0x80000000)) + { + v = 0 - v; + f |= 8; + } + + i = 0; + + do + { + d = (char)(v % r); + v /= r; + + if (d > 9) { d += (c == 'x') ? 0x27 : 0x07; } + + s[i++] = d + '0'; + } + while (v && i < sizeof(s)); + + if ((f & 8) && (i < sizeof(s))) { s[i++] = '-'; } + + j = i; + d = (f & 1) ? '0' : ' '; + + while (!(f & 2) && j++ < w) { xputc(d); } + + do { xputc(s[--i]); } + while (i); + + while (j++ < w) { xputc(' '); } + } +} + + +void xprintf( /* Put a formatted string to the default device */ + const char *fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + + + va_start(arp, fmt); + xvprintf(fmt, arp); + va_end(arp); +} + + +void xsprintf( /* Put a formatted string to the memory */ + char *buff, /* Pointer to the output buffer */ + const char *fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + + + outptr = buff; /* Switch destination for memory */ + + va_start(arp, fmt); + xvprintf(fmt, arp); + va_end(arp); + + *outptr = 0; /* Terminate output string with a \0 */ + outptr = 0; /* Switch destination for device */ +} + + +void xfprintf( /* Put a formatted string to the specified device */ + void(*func)(unsigned char), /* Pointer to the output function */ + const char *fmt, /* Pointer to the format string */ + ... /* Optional arguments */ +) +{ + va_list arp; + void (*pf)(unsigned char); + + + pf = xfunc_out; /* Save current output device */ + xfunc_out = func; /* Switch output to specified device */ + + va_start(arp, fmt); + xvprintf(fmt, arp); + va_end(arp); + + xfunc_out = pf; /* Restore output device */ +} + + + +/*----------------------------------------------*/ +/* Dump a line of binary dump */ +/*----------------------------------------------*/ + +void put_dump( + const void *buff, /* Pointer to the array to be dumped */ + unsigned long addr, /* Heading address value */ + int len, /* Number of items to be dumped */ + int width /* Size of the items (DF_CHAR, DF_SHORT, DF_LONG) */ +) +{ + int i; + const unsigned char *bp; + const unsigned short *sp; + const unsigned long *lp; + + + xprintf("%08lX ", addr); /* address */ + + switch (width) + { + case DW_CHAR: + bp = buff; + + for (i = 0; i < len; i++) /* Hexdecimal dump */ + { + xprintf(" %02X", bp[i]); + } + + xputc(' '); + + for (i = 0; i < len; i++) /* ASCII dump */ + { + xputc((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.'); + } + + break; + + case DW_SHORT: + sp = buff; + + do /* Hexdecimal dump */ + { + xprintf(" %04X", *sp++); + } + while (--len); + + break; + + case DW_LONG: + lp = buff; + + do /* Hexdecimal dump */ + { + xprintf(" %08LX", *lp++); + } + while (--len); + + break; + } + + xputc('\n'); +} + +#endif /* _USE_XFUNC_OUT */ + + + +#if _USE_XFUNC_IN +unsigned char (*xfunc_in)(void); /* Pointer to the input stream */ + +/*----------------------------------------------*/ +/* Get a line from the input */ +/*----------------------------------------------*/ + +int xgets( /* 0:End of stream, 1:A line arrived */ + char *buff, /* Pointer to the buffer */ + int len /* Buffer length */ +) +{ + int c, i; + + + if (!xfunc_in) { return 0; } /* No input function specified */ + + i = 0; + + for (;;) + { + c = xfunc_in(); /* Get a char from the incoming stream */ + + if (!c) { return 0; } /* End of stream? */ + + if (c == '\r') { break; } /* End of line? */ + + if (c == '\b' && i) /* Back space? */ + { + i--; + + if (_LINE_ECHO) { xputc(c); } + + continue; + } + + if (c >= ' ' && i < len - 1) /* Visible chars */ + { + buff[i++] = c; + + if (_LINE_ECHO) { xputc(c); } + } + } + + buff[i] = 0; /* Terminate with a \0 */ + + if (_LINE_ECHO) { xputc('\n'); } + + return 1; +} + + +int xfgets( /* 0:End of stream, 1:A line arrived */ + unsigned char (*func)(void), /* Pointer to the input stream function */ + char *buff, /* Pointer to the buffer */ + int len /* Buffer length */ +) +{ + unsigned char (*pf)(void); + int n; + + + pf = xfunc_in; /* Save current input device */ + xfunc_in = func; /* Switch input to specified device */ + n = xgets(buff, len); /* Get a line */ + xfunc_in = pf; /* Restore input device */ + + return n; +} + + +/*----------------------------------------------*/ +/* Get a value of the string */ +/*----------------------------------------------*/ +/* "123 -5 0x3ff 0b1111 0377 w " + ^ 1st call returns 123 and next ptr + ^ 2nd call returns -5 and next ptr + ^ 3rd call returns 1023 and next ptr + ^ 4th call returns 15 and next ptr + ^ 5th call returns 255 and next ptr + ^ 6th call fails and returns 0 +*/ + +int xatoi( /* 0:Failed, 1:Successful */ + char **str, /* Pointer to pointer to the string */ + long *res /* Pointer to the valiable to store the value */ +) +{ + unsigned long val; + unsigned char c, r, s = 0; + + + *res = 0; + + while ((c = **str) == ' ') { (*str)++; } /* Skip leading spaces */ + + if (c == '-') /* negative? */ + { + s = 1; + c = *(++(*str)); + } + + if (c == '0') + { + c = *(++(*str)); + + switch (c) + { + case 'x': /* hexdecimal */ + r = 16; + c = *(++(*str)); + break; + + case 'b': /* binary */ + r = 2; + c = *(++(*str)); + break; + + default: + if (c <= ' ') { return 1; } /* single zero */ + + if (c < '0' || c > '9') { return 0; } /* invalid char */ + + r = 8; /* octal */ + } + } + else + { + if (c < '0' || c > '9') { return 0; } /* EOL or invalid char */ + + r = 10; /* decimal */ + } + + val = 0; + + while (c > ' ') + { + if (c >= 'a') { c -= 0x20; } + + c -= '0'; + + if (c >= 17) + { + c -= 7; + } + + if (c >= r) { return 0; } /* invalid char for current radix */ + + val = val * r + c; + c = *(++(*str)); + } + + if (s) { val = 0 - val; } /* apply sign if needed */ + + *res = val; + return 1; +} + +#endif /* _USE_XFUNC_IN */ diff --git a/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.h b/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.h new file mode 100644 index 000000000..94bc17722 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/common/xprintf/xprintf.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------*/ +/* Universal string handler for user console interface (C)ChaN, 2011 */ +/*------------------------------------------------------------------------*/ + +#ifndef _STRFUNC +#define _STRFUNC + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define _USE_XFUNC_OUT 1 /* 1: Use output functions */ +#define _CR_CRLF 1 /* 1: Convert \n ==> \r\n in the output char */ + +#define _USE_XFUNC_IN 1 /* 1: Use input function */ +#define _LINE_ECHO 1 /* 1: Echo back input chars in xgets function */ + +#if _USE_XFUNC_OUT +#define xdev_out(func) xfunc_out = (void(*)(unsigned char))(func) +extern void (*xfunc_out)(unsigned char); +extern void xputc(char c); +extern void xputs(const char *str); +extern void xfputs(void (*func)(unsigned char), const char *str); +extern void xvprintf(const char *fmt, va_list arp); +extern void xprintf(const char *fmt, ...); +extern void xsprintf(char *buff, const char *fmt, ...); +extern void xfprintf(void (*func)(unsigned char), const char *fmt, ...); +extern void put_dump(const void *buff, unsigned long addr, int len, int width); +#define DW_CHAR sizeof(char) +#define DW_SHORT sizeof(short) +#define DW_LONG sizeof(long) +#endif + +#if _USE_XFUNC_IN +#define xdev_in(func) xfunc_in = (unsigned char(*)(void))(func) +extern unsigned char (*xfunc_in)(void); +extern int xgets(char *buff, int len); +extern int xfgets(unsigned char (*func)(void), char *buff, int len); +extern int xatoi(char **str, long *res); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.c b/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.c new file mode 100644 index 000000000..ac74c8409 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.c @@ -0,0 +1,534 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-22 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_DW_GPIO Designware GPIO Driver + * \ingroup DEVICE_DW + * \brief Designware GPIO Driver Implementation + */ + +/** + * \file + * \brief designware gpio driver + * \ingroup DEVICE_DW_GPIO + * \brief Designware GPIO driver + */ +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" +#include "inc/arc/arc_exception.h" + +#include "device/designware/gpio/dw_gpio.h" + +/** check expressions used in DesignWare GPIO driver implementation */ +#define DW_GPIO_CHECK_EXP(EXPR, ERROR_CODE) CHECK_EXP(EXPR, ercd, ERROR_CODE, error_exit) + +#ifndef DISABLE_DEVICE_OBJECT_VALID_CHECK +/** valid check of uart info object */ +#define VALID_CHK_GPIO_INFO_OBJECT(gpioinfo_obj_ptr) { \ + DW_GPIO_CHECK_EXP((gpioinfo_obj_ptr)!=NULL, E_OBJ); \ + DW_GPIO_CHECK_EXP(((gpioinfo_obj_ptr)->gpio_ctrl)!=NULL, E_OBJ); \ + } +#endif + +/** + * \defgroup DEVICE_DW_GPIO_STATIC DesignWare GPIO Driver Static Functions + * \ingroup DEVICE_DW_GPIO + * \brief Static or inline functions, variables for DesignWare GPIO handle gpio operations, + * only used in this file + * @{ + */ +Inline uint32_t dw_gpio_read_ext(DW_GPIO_PORT_PTR port) +{ + return port->regs->EXT_PORTS[port->no]; +} + +Inline uint32_t dw_gpio_read_dir(DW_GPIO_PORT_PTR port) +{ + return port->regs->SWPORTS[port->no].DDR; +} + +Inline uint32_t dw_gpio_read_dr(DW_GPIO_PORT_PTR port) +{ + return port->regs->SWPORTS[port->no].DR; +} + +Inline uint32_t dw_gpio_read_mthd(DW_GPIO_PORT_PTR port) +{ + return port->regs->INTEN; +} + +Inline void dw_gpio_int_enable(DW_GPIO_PORT_PTR port, uint32_t bit_mask) +{ + port->regs->INTEN |= bit_mask; +} + +Inline void dw_gpio_int_disable(DW_GPIO_PORT_PTR port, uint32_t bit_mask) +{ + port->regs->INTEN &= (~bit_mask); +} + +Inline void dw_gpio_int_mask(DW_GPIO_PORT_PTR port, uint32_t bit_mask) +{ + port->regs->INTMASK |= bit_mask; +} + +Inline void dw_gpio_int_unmask(DW_GPIO_PORT_PTR port, uint32_t bit_mask) +{ + port->regs->INTMASK &= (~bit_mask); +} + +Inline uint32_t dw_gpio_int_read_level(DW_GPIO_PORT_PTR port) +{ + return port->regs->INTTYPE_LEVEL; +} + +Inline uint32_t dw_gpio_int_read_polarity(DW_GPIO_PORT_PTR port) +{ + return port->regs->INT_POLARITY; +} + +Inline uint32_t dw_gpio_int_read_debounce(DW_GPIO_PORT_PTR port) +{ + return port->regs->DEBOUNCE; +} + +Inline uint32_t dw_gpio_int_read_status(DW_GPIO_PORT_PTR port) +{ + return port->regs->INTSTATUS; +} + +Inline void dw_gpio_int_clear(DW_GPIO_PORT_PTR port, uint32_t bit_mask) +{ + port->regs->PORTA_EOI = bit_mask; +} + +static void dw_gpio_int_write_level(DW_GPIO_PORT_PTR port, uint32_t bit_mask, uint32_t bit_level) +{ + uint32_t reg_val; + + reg_val = port->regs->INTTYPE_LEVEL; + reg_val &= (~bit_mask); + bit_level &= bit_mask; + reg_val |= bit_level; + + port->regs->INTTYPE_LEVEL = reg_val; +} + +static void dw_gpio_int_write_polarity(DW_GPIO_PORT_PTR port, uint32_t bit_mask, uint32_t bit_polarity) +{ + uint32_t reg_val; + + reg_val = port->regs->INT_POLARITY; + + reg_val &= (~bit_mask); + bit_polarity &= bit_mask; + reg_val |= bit_polarity; + + port->regs->INT_POLARITY = reg_val; +} + +static void dw_gpio_int_write_debounce(DW_GPIO_PORT_PTR port, uint32_t bit_mask, uint32_t bit_debounce) +{ + uint32_t reg_val; + + reg_val = port->regs->DEBOUNCE; + + reg_val &= (~bit_mask); + bit_debounce &= bit_mask; + reg_val |= bit_debounce; + + port->regs->DEBOUNCE = reg_val; +} + +static void dw_gpio_set_int_cfg(DW_GPIO_PORT_PTR port, DEV_GPIO_INT_CFG *int_cfg) +{ + dw_gpio_int_write_level(port, int_cfg->int_bit_mask, int_cfg->int_bit_type); + dw_gpio_int_write_polarity(port, int_cfg->int_bit_mask, int_cfg->int_bit_polarity); + dw_gpio_int_write_debounce(port, int_cfg->int_bit_mask, int_cfg->int_bit_debounce); +} + +static void dw_gpio_get_int_cfg(DW_GPIO_PORT_PTR port, DEV_GPIO_INT_CFG *int_cfg) +{ + int_cfg->int_bit_type = dw_gpio_int_read_level(port) & int_cfg->int_bit_mask; + int_cfg->int_bit_polarity = dw_gpio_int_read_polarity(port) & int_cfg->int_bit_mask; + int_cfg->int_bit_debounce = dw_gpio_int_read_debounce(port) & int_cfg->int_bit_mask; +} + +static void dw_gpio_write_dr(DW_GPIO_PORT_PTR port, uint32_t bit_mask, uint32_t val) +{ + uint32_t temp_reg; + + temp_reg = port->regs->SWPORTS[port->no].DR; + temp_reg &= ~bit_mask; + val &= bit_mask; + temp_reg |= val; + + port->regs->SWPORTS[port->no].DR = temp_reg; +} + +static void dw_gpio_write_dir(DW_GPIO_PORT_PTR port, uint32_t bit_mask, uint32_t val) +{ + uint32_t temp_reg; + + temp_reg = port->regs->SWPORTS[port->no].DDR; + temp_reg &= ~bit_mask; + val &= bit_mask; + temp_reg |= val; + + port->regs->SWPORTS[port->no].DDR = temp_reg; +} + +static uint32_t dw_gpio_read_val(DW_GPIO_PORT_PTR port) +{ + uint32_t val; + + val = dw_gpio_read_ext(port) & (~dw_gpio_read_dir(port)); + val |= dw_gpio_read_dr(port) & dw_gpio_read_dir(port); + + return val; +} + +/** @} end of group DEVICE_DW_GPIO_STATIC */ + +/* interface for DEV_GPIO */ +/** Open designware gpio device with specified io direction configuration */ +int32_t dw_gpio_open(DEV_GPIO *gpio_obj, uint32_t dir) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no <= DW_GPIO_PORT_D, E_OBJ); + + port_info_ptr->opn_cnt ++; + + if (port_info_ptr->opn_cnt > 1) /* opened before */ + { + if (dir == port_info_ptr->direction) /* direction is the same */ + { + return E_OK; + } + else /* open with different direction */ + { + return E_OPNED; + } + } + + dw_gpio_write_dir(port, port->valid_bit_mask, dir); + + if (port->no == DW_GPIO_PORT_A) + { + dw_gpio_int_clear(port, DW_GPIO_MASK_ALL); + dw_gpio_int_disable(port, DW_GPIO_MASK_ALL); + dw_gpio_int_unmask(port, DW_GPIO_MASK_ALL); + /* install gpio interrupt handler */ + int_handler_install(port->intno, port->int_handler); + int_disable(port->intno); + /** Set int type, int polarity and debounce configuration to default settings of device gpio */ + dw_gpio_set_int_cfg(port, (DEV_GPIO_INT_CFG *)(&gpio_int_cfg_default)); + port_info_ptr->method = dw_gpio_read_mthd(port); + } + else + { + port_info_ptr->method = DEV_GPIO_BITS_MTHD_DEFAULT; + } + + dw_gpio_write_dr(port, port->valid_bit_mask, 0); + + port_info_ptr->direction = dir; + port_info_ptr->extra = NULL; + +error_exit: + return ercd; +} + +/** Close designware gpio device */ +int32_t dw_gpio_close(DEV_GPIO *gpio_obj) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no <= DW_GPIO_PORT_D, E_OBJ); + + DW_GPIO_CHECK_EXP(port_info_ptr->opn_cnt > 0, E_OK); + + port_info_ptr->opn_cnt --; + + if (port_info_ptr->opn_cnt == 0) + { + dw_gpio_write_dr(port, port->valid_bit_mask, 0); + dw_gpio_write_dir(port, port->valid_bit_mask, 0); + + if (port->no == DW_GPIO_PORT_A) + { + dw_gpio_int_clear(port, DW_GPIO_MASK_ALL); + dw_gpio_int_disable(port, DW_GPIO_MASK_ALL); + int_disable(port->intno); + } + + port_info_ptr->direction = 0; + port_info_ptr->method = 0; + port_info_ptr->extra = NULL; + } + else + { + ercd = E_OPNED; + } + +error_exit: + return ercd; +} + +/** Read designware gpio device value */ +int32_t dw_gpio_read(DEV_GPIO *gpio_obj, uint32_t *val, uint32_t mask) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no <= DW_GPIO_PORT_D, E_OBJ); + DW_GPIO_CHECK_EXP(port_info_ptr->opn_cnt > 0, E_CLSED); + + DW_GPIO_CHECK_EXP(val != NULL, E_PAR); + + //*val = dw_gpio_read_ext(port) & mask; + *val = dw_gpio_read_val(port) & mask; + +error_exit: + return ercd; +} + +/** Write designware gpio device value */ +int32_t dw_gpio_write(DEV_GPIO *gpio_obj, uint32_t val, uint32_t mask) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no <= DW_GPIO_PORT_D, E_OBJ); + DW_GPIO_CHECK_EXP(port_info_ptr->opn_cnt > 0, E_CLSED); + + dw_gpio_write_dr(port, mask, val); + +error_exit: + return ercd; +} + +/** Control designware gpio device */ +int32_t dw_gpio_control(DEV_GPIO *gpio_obj, uint32_t ctrl_cmd, void *param) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no <= DW_GPIO_PORT_D, E_OBJ); + DW_GPIO_CHECK_EXP(port_info_ptr->opn_cnt > 0, E_CLSED); + + uint32_t val32; /** to receive unsigned int value */ + + if (ctrl_cmd == GPIO_CMD_SET_BIT_DIR_INPUT) + { + val32 = (uint32_t)param; + dw_gpio_write_dir(port, val32, DW_GPIO_INPUT_ALL); + port_info_ptr->direction = dw_gpio_read_dir(port); + } + else if (ctrl_cmd == GPIO_CMD_SET_BIT_DIR_OUTPUT) + { + val32 = (uint32_t)param; + dw_gpio_write_dir(port, val32, DW_GPIO_OUTPUT_ALL); + port_info_ptr->direction = dw_gpio_read_dir(port); + } + else if (ctrl_cmd == GPIO_CMD_GET_BIT_DIR) + { + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + port_info_ptr->direction = dw_gpio_read_dir(port); + *((int32_t *)param) = port_info_ptr->direction; + } + else + { + DW_GPIO_CHECK_EXP(port->no == DW_GPIO_PORT_A, E_NOSPT); + /* output pin cannot be used as interrupt */ + DEV_GPIO_INT_CFG *gpio_int_cfg; + DEV_GPIO_BIT_ISR *port_bit_isr; + + switch (ctrl_cmd) + { + case GPIO_CMD_SET_BIT_INT_CFG: + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + gpio_int_cfg = (DEV_GPIO_INT_CFG *)param; + dw_gpio_set_int_cfg(port, gpio_int_cfg); + break; + + case GPIO_CMD_GET_BIT_INT_CFG: + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + gpio_int_cfg = (DEV_GPIO_INT_CFG *)param; + /** read configuration, each bit stands for different configuration */ + dw_gpio_get_int_cfg(port, gpio_int_cfg); + break; + + case GPIO_CMD_SET_BIT_ISR: + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + port_bit_isr = (DEV_GPIO_BIT_ISR *)param; + + if (port_bit_isr->int_bit_ofs < port->gpio_bit_isr->int_bit_max_cnt) + { + port->gpio_bit_isr->int_bit_handler_ptr[port_bit_isr->int_bit_ofs] = port_bit_isr->int_bit_handler; + } + else + { + ercd = E_PAR; + } + + break; + + case GPIO_CMD_GET_BIT_ISR: + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + port_bit_isr = (DEV_GPIO_BIT_ISR *)param; + + if (port_bit_isr->int_bit_ofs < port->gpio_bit_isr->int_bit_max_cnt) + { + port_bit_isr->int_bit_handler = port->gpio_bit_isr->int_bit_handler_ptr[port_bit_isr->int_bit_ofs]; + } + else + { + ercd = E_PAR; + } + + break; + + case GPIO_CMD_ENA_BIT_INT: + val32 = (uint32_t)param; + dw_gpio_int_enable(port, val32); + port_info_ptr->method = dw_gpio_read_mthd(port); + + if (port_info_ptr->method) + { + int_enable(port->intno); + } + + break; + + case GPIO_CMD_DIS_BIT_INT: + val32 = (uint32_t)param; + dw_gpio_int_disable(port, val32); + port_info_ptr->method = dw_gpio_read_mthd(port); + + if (port_info_ptr->method == 0) + { + int_disable(port->intno); + } + + break; + + case GPIO_CMD_GET_BIT_MTHD: + DW_GPIO_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + port_info_ptr->method = dw_gpio_read_mthd(port); + *((int32_t *)param) = port_info_ptr->method; + break; + + default: + ercd = E_NOSPT; + break; + } + } + +error_exit: + return ercd; +} + +/** designware gpio interrupt process */ +int32_t dw_gpio_isr_handler(DEV_GPIO *gpio_obj, void *ptr) +{ + int32_t ercd = E_OK; + DEV_GPIO_INFO_PTR port_info_ptr = &(gpio_obj->gpio_info); + + /* START ERROR CHECK */ + VALID_CHK_GPIO_INFO_OBJECT(port_info_ptr); + /* END OF ERROR CHECK */ + + DW_GPIO_PORT_PTR port = (DW_GPIO_PORT_PTR)(port_info_ptr->gpio_ctrl); + DW_GPIO_CHECK_EXP(port->no == DW_GPIO_PORT_A, E_NOSPT); + + uint32_t i, gpio_bit_isr_state; + uint32_t max_int_bit_count = 0; + + /** read interrupt status */ + gpio_bit_isr_state = dw_gpio_int_read_status(port); + + if (port->gpio_bit_isr) + { + max_int_bit_count = (port->gpio_bit_isr->int_bit_max_cnt); + } + else + { + dw_gpio_int_clear(port, gpio_bit_isr_state); + } + + for (i = 0; i < max_int_bit_count; i++) + { + if (gpio_bit_isr_state & (1 << i)) + { + /* this bit interrupt enabled */ + if (port->gpio_bit_isr->int_bit_handler_ptr[i]) + { + port->gpio_bit_isr->int_bit_handler_ptr[i](gpio_obj); + } + + dw_gpio_int_clear(port, (1 << i)); /** clear this bit interrupt */ + } + } + +error_exit: + return ercd; +} diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.h new file mode 100644 index 000000000..2dbcb8e74 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/gpio/dw_gpio.h @@ -0,0 +1,149 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-22 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \brief designware gpio driver + * \ingroup DEVICE_DW_GPIO + * \brief Designware GPIO driver header file + */ + +#ifndef _DW_GPIO_H_ +#define _DW_GPIO_H_ + +#include "device/device_hal/inc/dev_gpio.h" + +#include "inc/arc/arc_exception.h" + +#define DW_GPIO_PORT_A (0x00) +#define DW_GPIO_PORT_B (0x01) +#define DW_GPIO_PORT_C (0x02) +#define DW_GPIO_PORT_D (0x03) + +#define DW_GPIO_INT_ACT_LOW GPIO_INT_ACTIVE_LOW +#define DW_GPIO_INT_ACT_HIGH GPIO_INT_ACTIVE_HIGH + +#define DW_GPIO_INT_LEVEL_TRIG GPIO_INT_LEVEL_TRIG +#define DW_GPIO_INT_EDGE_TRIG GPIO_INT_EDGE_TRIG + +#define DW_GPIO_INT_NO_DEBOUNCE GPIO_INT_NO_DEBOUNCE +#define DW_GPIO_INT_DEBOUNCE GPIO_INT_DEBOUNCE + +#define DW_GPIO_ALL_ZERO (0x0) +#define DW_GPIO_ALL_ONE (0xffffffff) +#define DW_GPIO_MASK_ALL (0xffffffff) +#define DW_GPIO_INPUT_ALL (0x0) +#define DW_GPIO_OUTPUT_ALL (0xffffffff) + +/** + * \name DesignWare GPIO Register Structure + * \brief contains definitions of DesignWare GPIO register structure. + * @{ + */ +typedef struct port_ctrl +{ + uint32_t DR; + uint32_t DDR; + uint32_t CTRL; +} PORT_CTRL; + +/* DW GPIO PORTS Registers */ +typedef volatile struct dw_gpio_reg +{ + PORT_CTRL SWPORTS[4]; + uint32_t INTEN; /*!< (0x30) */ + uint32_t INTMASK; /*!< (0x34) */ + uint32_t INTTYPE_LEVEL; /*!< (0x38) */ + uint32_t INT_POLARITY; /*!< (0x3c) */ + uint32_t INTSTATUS; /*!< (0x40) */ + uint32_t RAW_INTSTATUS; /*!< (0x44) */ + uint32_t DEBOUNCE; /*!< (0x48) */ + uint32_t PORTA_EOI; /*!< (0x4c) */ + uint32_t EXT_PORTS[4]; /*!< (0x50) -A + (0x54) -B + (0x58) -C + (0x5c) -D */ + uint32_t LS_SYNC; /*!< (0x60) */ + uint32_t ID_CODE; /*!< (0x64) */ + uint32_t RESERVED_3; /*!< (0x68) */ + uint32_t VER_ID_CODE; /*!< (0x6c) */ + uint32_t CONFIG_REG2; /*!< (0x70) */ + uint32_t CONFIG_REG1; /*!< (0x74) */ +} DW_GPIO_REG, *DW_GPIO_REG_PTR; +/** @} */ + +/** interrupt handler for each port bit */ +typedef struct dw_gpio_bit_isr +{ + uint32_t int_bit_max_cnt; /*!< max bit count for each port */ + DEV_GPIO_HANDLER *int_bit_handler_ptr; /*!< interrupt handler pointer */ +} DW_GPIO_BIT_ISR, * DW_GPIO_BIT_ISR_PTR; + +/** + * \brief DesignWare GPIO control structure definition + * \details implement of dev_gpio_info::gpio_ctrl + */ +typedef struct dw_gpio_port +{ + uint32_t no; /*!< gpio port number */ + DW_GPIO_REG_PTR regs; /*!< gpio port register */ + uint32_t intno; /*!< gpio interrupt vector number */ + uint32_t valid_bit_mask; /*!< valid bit mask of gpio port */ + INT_HANDLER int_handler; /*!< gpio interrupt handler */ + DW_GPIO_BIT_ISR_PTR gpio_bit_isr; /*!< gpio bit handler struct */ +} DW_GPIO_PORT, *DW_GPIO_PORT_PTR; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name DesignWare GPIO Function Declaration + * \brief contains declarations of designware gpio functions. + * \details This are only used in gpio object implementation source file + * @{ + */ +extern int32_t dw_gpio_open(DEV_GPIO *gpio_obj, uint32_t dir); +extern int32_t dw_gpio_close(DEV_GPIO *gpio_obj); +extern int32_t dw_gpio_read(DEV_GPIO *gpio_obj, uint32_t *val, uint32_t mask); +extern int32_t dw_gpio_write(DEV_GPIO *gpio_obj, uint32_t val, uint32_t mask); +extern int32_t dw_gpio_control(DEV_GPIO *gpio_obj, uint32_t ctrl_cmd, void *param); +extern int32_t dw_gpio_isr_handler(DEV_GPIO *gpio_obj, void *ptr); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* _DW_GPIO_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.c b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.c new file mode 100644 index 000000000..38b7bea11 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.c @@ -0,0 +1,1579 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-06-25 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_DW_SPI Designware SPI Driver + * \ingroup DEVICE_DW + * \brief Designware SPI Driver Implementation + */ + +/** + * \file + * \brief DesignWare SPI driver implementation based on device hal layer definition (\ref dev_spi.h) + * \ingroup DEVICE_DW_SPI + */ +#include + +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" + +#include "inc/arc/arc_exception.h" + +#include "device/designware/spi/dw_spi_hal.h" +#include "device/designware/spi/dw_spi.h" + +/** + * \defgroup DEVICE_DW_SPI_DEFINES DesignWare SPI Driver Macros + * \ingroup DEVICE_DW_SPI + * \brief DesignWare SPI driver macros used in spi driver + * @{ + */ +/** check expressions used in DesignWare SPI driver implementation */ +#define DW_SPI_CHECK_EXP(EXPR, ERROR_CODE) CHECK_EXP(EXPR, ercd, ERROR_CODE, error_exit) + +/** convert DesignWare frequence to divisor */ +#define DW_SPI_FREQ2DV(perifreq, spifreq) ((perifreq) / (spifreq)) + +#ifndef DISABLE_DEVICE_OBJECT_VALID_CHECK +/** valid check of spi info object */ +#define VALID_CHK_SPI_INFO_OBJECT(spiinfo_obj_ptr) { \ + DW_SPI_CHECK_EXP((spiinfo_obj_ptr)!=NULL, E_OBJ); \ + DW_SPI_CHECK_EXP(((spiinfo_obj_ptr)->spi_ctrl)!=NULL, E_OBJ); \ + } +#endif + +/** + * \defgroup DEVICE_DW_SPI_DEF_CBR DesignWare SPI Interrupt Callback Routine Select Marcos + * \ingroup DEVICE_DW_SPI_DEFINES + * \brief DesignWare SPI interrupt callback routines select macros definitions + * @{ + */ +#define DW_SPI_RDY_SND (1U) /*!< ready to send callback */ +#define DW_SPI_RDY_RCV (2U) /*!< ready to receive callback */ +#define DW_SPI_RDY_XFER (3U) /*!< ready to transfer callback */ +/** @} */ + +/** @} */ + +/** + * \defgroup DEVICE_DW_SPI_STATIC DesignWare SPI Driver Static Functions + * \ingroup DEVICE_DW_SPI + * \brief Static or inline functions, variables for DesignWare SPI handle spi operations, + * only used in this file. + * @{ + */ + +/** Disable designware spi device */ +Inline void dw_spi_disable(DW_SPI_REG *spi_reg_ptr) +{ + /** disable spi operations, then program spi control regs is possible */ + spi_reg_ptr->SSIENR = DW_SPI_SSI_DISABLE; +} +/** Enable designware spi device */ +Inline void dw_spi_enable(DW_SPI_REG *spi_reg_ptr) +{ + spi_reg_ptr->SSIENR = DW_SPI_SSI_ENABLE; +} + +/** Clear all designware spi interrupt */ +Inline void dw_spi_clear_interrupt_all(DW_SPI_REG *spi_reg_ptr) +{ + (void)spi_reg_ptr->ICR; +} + +/** test whether spi is busy, busy return 1, else 0 */ +Inline int32_t dw_spi_busy(DW_SPI_REG *spi_reg_ptr) +{ + return ((spi_reg_ptr->SR & DW_SPI_SR_BUSY) != 0); +} +/** test whether spi is ready to send, 1 ready, 0 not ready */ +Inline int32_t dw_spi_putready(DW_SPI_REG *spi_reg_ptr) +{ + return ((spi_reg_ptr->SR & DW_SPI_SR_TFNF) != 0); +} +/** test whether spi is read to receive, 1 ready, 0 not ready */ +Inline int32_t dw_spi_getready(DW_SPI_REG *spi_reg_ptr) +{ + return ((spi_reg_ptr->SR & DW_SPI_SR_RFNE) != 0); +} +/** write data to spi send fifo */ +Inline void dw_spi_putdata(DW_SPI_REG *spi_reg_ptr, int32_t data) +{ + spi_reg_ptr->DATAREG = (uint32_t)data; +} +/** read data from spi receive fifo, return data received */ +Inline int32_t dw_spi_getdata(DW_SPI_REG *spi_reg_ptr) +{ + return (int32_t)spi_reg_ptr->DATAREG; +} +/** + * \brief send data by spi when available, + * mostly used in interrupt method, non-blocked function + * \param[in] spi_reg_ptr spi register structure pointer + * \param[in] data data to be sent + * \retval E_OK send successfully + * \retval E_OBJ not ready to send data + */ +Inline int32_t dw_spi_snd_dat(DW_SPI_REG *spi_reg_ptr, int32_t data) +{ + if (dw_spi_putready(spi_reg_ptr)) + { + dw_spi_putdata(spi_reg_ptr, data); + return E_OK; + } + + return E_OBJ; +} +/** + * \brief receive one char from spi, + * mostly used in interrupt routine, non-blocked function + * \param[in] spi_reg_ptr spi register structure pointer + * \return data received by the spi + */ +Inline int32_t dw_spi_rcv_dat(DW_SPI_REG *spi_reg_ptr) +{ + return dw_spi_getdata(spi_reg_ptr); +} +/** + * \brief send char by spi in poll method, blocked function + * \param[in] spi_reg_ptr spi register structure pointer + * \param[in] data data to be sent + */ +Inline void dw_spi_psnd_dat(DW_SPI_REG *spi_reg_ptr, int32_t data) +{ + /** wait until spi is ready to send */ + while (!dw_spi_putready(spi_reg_ptr)); /* blocked */ + + /** send char */ + dw_spi_putdata(spi_reg_ptr, data); +} +/** + * \brief receive one char from spi in poll method, blocked function + * \param[in] spi_reg_ptr spi register structure pointer + * \return data received by the spi + */ +Inline int32_t dw_spi_prcv_dat(DW_SPI_REG *spi_reg_ptr) +{ + /** wait until spi is ready to receive */ + while (!dw_spi_getready(spi_reg_ptr)); /* blocked */ + + /** receive data */ + return dw_spi_getdata(spi_reg_ptr); +} + +/** Reset designware FIFO by disable spi device, then enable device */ +Inline void dw_spi_reset_fifo(DW_SPI_REG *spi_reg_ptr) +{ + dw_spi_disable(spi_reg_ptr); + dw_spi_enable(spi_reg_ptr); +} + +/** Enable designware spi bit interrupt with mask */ +Inline void dw_spi_unmask_interrupt(DW_SPI_REG *spi_reg_ptr, uint32_t mask) +{ + spi_reg_ptr->IMR |= mask; +} + +/** Disable designware spi bit interrupt with mask */ +Inline void dw_spi_mask_interrupt(DW_SPI_REG *spi_reg_ptr, uint32_t mask) +{ + spi_reg_ptr->IMR &= ~mask; +} + +/** Set designware spi device frequency */ +Inline void dw_spi_set_freq(DW_SPI_CTRL *spi_ctrl_ptr, uint32_t freq) +{ + uint32_t sck_divisor; + DW_SPI_REG *spi_reg_ptr = spi_ctrl_ptr->dw_spi_regs; + + dw_spi_disable(spi_reg_ptr); + + sck_divisor = DW_SPI_FREQ2DV(spi_ctrl_ptr->dw_apb_bus_freq, freq); + spi_reg_ptr->BAUDR = sck_divisor; + dw_spi_enable(spi_reg_ptr); +} + +/** Set designware spi device data frame size */ +static int32_t dw_spi_set_dfs(DW_SPI_REG *spi_reg_ptr, uint32_t dfs) +{ + uint32_t ctrl0_reg; + + if ((dfs <= 3) || (dfs > 16)) { return -1; } + + dw_spi_disable(spi_reg_ptr); + ctrl0_reg = spi_reg_ptr->CTRLR0; + ctrl0_reg &= ~(DW_SPI_CTRLR0_DFS_MASK); + spi_reg_ptr->CTRLR0 = ctrl0_reg | (dfs - 1); + dw_spi_enable(spi_reg_ptr); + + return 0; +} + +/** Choose proper designware spi clock mode setting value */ +Inline uint32_t dw_spi_select_clockmode(uint32_t clk_mode) +{ + return (clk_mode << DW_SPI_CTRLR0_SC_OFS); +} + +/** Set designware spi clock mode */ +Inline int32_t dw_spi_set_clockmode(DW_SPI_REG *spi_reg_ptr, uint32_t clk_mode) +{ + if (clk_mode > SPI_CPOL_1_CPHA_1) + { + return -1; + } + + dw_spi_disable(spi_reg_ptr); + spi_reg_ptr->CTRLR0 &= ~(DW_SPI_CTRLR0_SC_MASK); + spi_reg_ptr->CTRLR0 |= dw_spi_select_clockmode(clk_mode); + dw_spi_enable(spi_reg_ptr); + return 0; +} + +/** Select a spi slave with slv_line */ +Inline int32_t dw_spi_select_slave(DW_SPI_REG *spi_reg_ptr, uint32_t slv_line) +{ + /* check if spi busy */ + if (dw_spi_busy(spi_reg_ptr)) { return -1; } + + spi_reg_ptr->SER = 1 << slv_line; + return 0; +} + +/** Deselect a spi device */ +Inline int32_t dw_spi_deselect_slave(DW_SPI_REG *spi_reg_ptr, uint32_t slv_line) +{ + /* check if spi busy */ + if (dw_spi_busy(spi_reg_ptr)) { return -1; } + + spi_reg_ptr->SER = 0; + return 0; +} + +Inline void dw_spi_flush_tx(DW_SPI_REG *spi_reg_ptr) +{ + dw_spi_reset_fifo(spi_reg_ptr); +} + +Inline void dw_spi_flush_rx(DW_SPI_REG *spi_reg_ptr) +{ + dw_spi_reset_fifo(spi_reg_ptr); +} + +/** Get TX FIFO Length. + * calculate spi fifo length using fifo threshold method + * If you attempt to set bits [7:0] of this register to + * a value greater than or equal to the depth of the FIFO, + * this field is not written and retains its current value. + */ +static uint32_t dw_spi_get_txfifo_len(DW_SPI_REG *spi_reg_ptr) +{ + uint32_t fifo_thr_lev_tmp, left, right, i; + + fifo_thr_lev_tmp = spi_reg_ptr->TXFTLR; + + if (fifo_thr_lev_tmp != 0) + { + left = fifo_thr_lev_tmp; + } + else + { + left = DW_SPI_MIN_FIFO_LENGTH; + } + + right = DW_SPI_MAX_FIFO_LENGTH + 1; + + for (i = left; i <= right; i++) + { + spi_reg_ptr->TXFTLR = i; + + if (spi_reg_ptr->TXFTLR != i) + { + break; + } + } + + spi_reg_ptr->TXFTLR = fifo_thr_lev_tmp; /* restore old fifo threshold */ + + return (i); +} + +/** Get RX FIFO Length */ +static uint32_t dw_spi_get_rxfifo_len(DW_SPI_REG *spi_reg_ptr) +{ + uint32_t fifo_thr_lev_tmp, left, right, i; + + fifo_thr_lev_tmp = spi_reg_ptr->RXFTLR; + + if (fifo_thr_lev_tmp != 0) + { + left = fifo_thr_lev_tmp; + } + else + { + left = DW_SPI_MIN_FIFO_LENGTH; + } + + right = DW_SPI_MAX_FIFO_LENGTH + 1; + + for (i = left; i <= right; i++) + { + spi_reg_ptr->RXFTLR = i; + + if (spi_reg_ptr->RXFTLR != i) + { + break; + } + } + + spi_reg_ptr->RXFTLR = fifo_thr_lev_tmp; /* restore old fifo threshold */ + + return (i); +} + +/** Init Designware SPI Hardware */ +static void dw_spi_hw_init(DW_SPI_CTRL *spi_ctrl_ptr, uint32_t clk_mode, uint32_t dfs) +{ + uint32_t ctrl0_reg = 0; + DW_SPI_REG *spi_reg_ptr = spi_ctrl_ptr->dw_spi_regs; + + dw_spi_disable(spi_reg_ptr); + + /* Clear interrupts */ + ctrl0_reg = spi_reg_ptr->ICR; + /* Mask all interrupts */ + spi_reg_ptr->IMR = 0; + + ctrl0_reg = DW_SPI_CTRLR0_FRF_MOTOROLA | DW_SPI_TMOD_TRANSMIT_RECEIVE \ + | dw_spi_select_clockmode(clk_mode) | (dfs - 1) | DW_SPI_CTRLR0_SLV_OE_ENABLE; + spi_reg_ptr->CTRLR0 = ctrl0_reg; + spi_reg_ptr->CTRLR1 = 0; + + /* deselect slaves */ + spi_reg_ptr->SER = 0; + + /* Set threshold values for both tx and rx */ + spi_reg_ptr->TXFTLR = 0; + spi_reg_ptr->RXFTLR = 0; + + dw_spi_enable(spi_reg_ptr); +} + +/** enable designware spi */ +static void dw_spi_enable_device(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + + if ((spi_info_ptr->status & DEV_ENABLED) == 0) + { + dw_spi_enable(spi_reg_ptr); + spi_info_ptr->status |= DEV_ENABLED; + } +} + +/** disable designware spi */ +static void dw_spi_disable_device(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + + dw_spi_disable(spi_reg_ptr); + spi_info_ptr->status &= ~DEV_ENABLED; +} + + +/** + * \brief disable designware spi send or receive interrupt + * \param[in] DEV_SPI_INFO *spi_info_ptr + * \param[in] cbrtn control code of callback routine of send or receive + */ +static int32_t dw_spi_dis_cbr(DEV_SPI_INFO *spi_info_ptr, uint32_t cbrtn) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + int32_t ercd = E_OK; + + if ((spi_info_ptr->status & DW_SPI_IN_XFER) != 0) /* only in transfer need do check */ + { + switch (cbrtn) + { + case DW_SPI_RDY_SND: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX, E_CTX); + spi_info_ptr->status &= ~(DW_SPI_IN_TX); + break; + + case DW_SPI_RDY_RCV: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX, E_CTX); + spi_info_ptr->status &= ~(DW_SPI_IN_RX); + break; + + case DW_SPI_RDY_XFER: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER, E_CTX); + spi_info_ptr->status &= ~(DW_SPI_IN_XFER); + break; + + default: + break; + } + } + + dw_spi_mask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER); + + if (spi_ctrl_ptr->int_status & DW_SPI_GINT_ENABLE) + { + int_disable(spi_ctrl_ptr->intno); + spi_ctrl_ptr->int_status &= ~DW_SPI_GINT_ENABLE; + } + +error_exit: + return ercd; +} + +/** + * \brief enable DesignWare SPI send or receive interrupt + * \param[in] DEV_SPI_INFO *spi_info_ptr + * \param[in] cbrtn control code of callback routine of send or receive + */ +static int32_t dw_spi_ena_cbr(DEV_SPI_INFO *spi_info_ptr, uint32_t cbrtn) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + int32_t ercd = E_OK; + + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == 0, E_CTX); + + switch (cbrtn) + { + case DW_SPI_RDY_SND: + spi_info_ptr->status |= DW_SPI_IN_TX; + break; + + case DW_SPI_RDY_RCV: + spi_info_ptr->status |= DW_SPI_IN_RX; + break; + + case DW_SPI_RDY_XFER: + spi_info_ptr->status |= DW_SPI_IN_XFER; + break; + + default: + break; + } + + dw_spi_unmask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER); + + if ((spi_ctrl_ptr->int_status & DW_SPI_GINT_ENABLE) == 0) + { + spi_ctrl_ptr->int_status |= DW_SPI_GINT_ENABLE; + int_enable(spi_ctrl_ptr->intno); + } + +error_exit: + return ercd; +} + +/** + * \brief enable designware spi interrupt + * \param spi_info_ptr spi information structure pointer + */ +static void dw_spi_enable_interrupt(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + + int_handler_install(spi_ctrl_ptr->intno, spi_ctrl_ptr->dw_spi_int_handler); + spi_ctrl_ptr->int_status |= DW_SPI_GINT_ENABLE; + int_enable(spi_ctrl_ptr->intno); /** enable spi interrupt */ +} +/** + * \brief disable designware spi interrupt + * \param spi_info_ptr spi information structure pointer + */ +static void dw_spi_disable_interrupt(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + + /** disable spi send&receive interrupt after disable spi interrupt */ + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND); + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV); + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER); + /* disable spi interrupt */ + dw_spi_mask_interrupt(spi_ctrl_ptr->dw_spi_regs, DW_SPI_IMR_XFER); + spi_info_ptr->status &= ~DW_SPI_IN_XFER; + int_disable(spi_ctrl_ptr->intno); + spi_ctrl_ptr->int_status &= ~(DW_SPI_GINT_ENABLE); +} + +static void dw_spi_reset_device(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + + dw_spi_disable_device(spi_info_ptr); + dw_spi_disable_interrupt(spi_info_ptr); + dw_spi_clear_interrupt_all(spi_reg_ptr); + dw_spi_enable_device(spi_info_ptr); +} + +/** abort current interrupt transmit transfer */ +static int32_t dw_spi_abort_tx(DEV_SPI *spi_obj) +{ + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + int32_t ercd = E_OK; + + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX, E_CTX); + + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND); + spi_info_ptr->status |= DEV_IN_TX_ABRT; + + if (spi_info_ptr->spi_cbs.tx_cb != NULL) + { + spi_info_ptr->spi_cbs.tx_cb(spi_obj); + } + + spi_info_ptr->status &= ~(DEV_IN_TX_ABRT); + +error_exit: + return ercd; +} + +/** abort current interrupt receive transfer */ +static int32_t dw_spi_abort_rx(DEV_SPI *spi_obj) +{ + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + int32_t ercd = E_OK; + + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX, E_CTX); + + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV); + spi_info_ptr->status |= DEV_IN_RX_ABRT; + + if (spi_info_ptr->spi_cbs.rx_cb != NULL) + { + spi_info_ptr->spi_cbs.rx_cb(spi_obj); + } + + spi_info_ptr->status &= ~(DEV_IN_RX_ABRT); + +error_exit: + return ercd; +} + +/** abort current interrupt transfer */ +static int32_t dw_spi_abort_xfer(DEV_SPI *spi_obj) +{ + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + int32_t ercd = E_OK; + + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) != 0, E_OK); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER, E_CTX); + + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER); + spi_info_ptr->status |= DEV_IN_XFER_ABRT; + + if (spi_info_ptr->spi_cbs.xfer_cb != NULL) + { + spi_info_ptr->spi_cbs.xfer_cb(spi_obj); + } + + spi_info_ptr->status &= ~(DEV_IN_XFER_ABRT); + +error_exit: + return ercd; +} + +/** Get available transmit fifo count */ +static int32_t dw_spi_get_txavail(DW_SPI_CTRL *spi_ctrl_ptr) +{ + int32_t tx_avail = 0; + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + +#if DW_SPI_CALC_FIFO_LEN_ENABLE + + if (spi_ctrl_ptr->tx_fifo_len <= 1) + { + if (dw_spi_putready(spi_reg_ptr) == 1) + { + tx_avail = 1; + } + else + { + tx_avail = 0; + } + } + else +#endif + { + tx_avail = spi_ctrl_ptr->tx_fifo_len - spi_reg_ptr->TXFLR; + } + + return tx_avail; +} + +/** Get available receive fifo count */ +static int32_t dw_spi_get_rxavail(DW_SPI_CTRL *spi_ctrl_ptr) +{ + int32_t rx_avail = 0; + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + +#if DW_SPI_CALC_FIFO_LEN_ENABLE + + if (spi_ctrl_ptr->rx_fifo_len <= 1) + { + if (dw_spi_getready(spi_reg_ptr) == 1) + { + rx_avail = 1; + } + else + { + rx_avail = 0; + } + } + else +#endif + { + rx_avail = spi_reg_ptr->RXFLR; + } + + return rx_avail; +} + +static uint32_t dw_spi_tx_max(DW_SPI_CTRL *spi_ctrl_ptr) +{ + uint32_t tx_left, tx_room; + DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer); + + tx_left = (xfer->xfer_len - xfer->tx_idx) / xfer->nbytes; + tx_room = dw_spi_get_txavail(spi_ctrl_ptr); + + return (tx_left < tx_room) ? tx_left : tx_room; +} + +static uint32_t dw_spi_rx_max(DW_SPI_CTRL *spi_ctrl_ptr) +{ + uint32_t rx_left, rx_room; + DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer); + + rx_left = (xfer->xfer_len - xfer->rx_idx) / xfer->nbytes; + rx_room = dw_spi_get_rxavail(spi_ctrl_ptr); + + return (rx_left < rx_room) ? rx_left : rx_room; +} + +Inline int32_t dw_spi_rx_end(DW_SPI_CTRL *spi_ctrl_ptr) +{ + DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer); + + return (xfer->rx_idx >= xfer->xfer_len); +} + +Inline int32_t dw_spi_tx_end(DW_SPI_CTRL *spi_ctrl_ptr) +{ + DW_SPI_TRANSFER *xfer = &(spi_ctrl_ptr->dw_xfer); + + return (xfer->tx_idx >= xfer->xfer_len); +} + +/** 1 for end, 0 for not end */ +Inline int32_t dw_spi_xfer_end(DW_SPI_CTRL *spi_ctrl_ptr) +{ + return (dw_spi_tx_end(spi_ctrl_ptr) && dw_spi_rx_end(spi_ctrl_ptr)); +} + +static int32_t dw_spi_writer(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + DW_SPI_TRANSFER *dw_xfer = &(spi_ctrl_ptr->dw_xfer); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + uint32_t tx_max = dw_spi_tx_max(spi_ctrl_ptr); + int32_t tx_w; + uint32_t tx_cnt = tx_max; + + if (dw_xfer->tx_xfer == NULL) + { + return 0; + } + + while (tx_max) + { + if (dw_xfer->tx_xfer->tx_idx >= dw_xfer->tx_xfer->tot_len) + { + dw_xfer->tx_xfer = dw_xfer->tx_xfer->next; + + if (dw_xfer->tx_xfer == NULL) + { + break; + } + } + + if ((dw_xfer->tx_xfer->tx_idx >= dw_xfer->tx_xfer->tx_ofs) \ + && (dw_xfer->tx_xfer->tx_idx < dw_xfer->tx_xfer->tx_totlen)) + { + if (dw_xfer->nbytes == 1) + { + tx_w = (int32_t)(*(int8_t *)(dw_xfer->tx_xfer->tx_buf)); + } + else + { + tx_w = (int32_t)(*(int16_t *)(dw_xfer->tx_xfer->tx_buf)); + } + + dw_xfer->tx_xfer->tx_buf += dw_xfer->nbytes; + } + else + { + tx_w = spi_info_ptr->dummy; + } + + dw_spi_putdata(spi_reg_ptr, tx_w); + dw_xfer->tx_xfer->tx_idx += dw_xfer->nbytes; + dw_xfer->tx_idx += dw_xfer->nbytes; + tx_max --; + } + + return ((tx_cnt - tx_max) * dw_xfer->nbytes); +} + +static int32_t dw_spi_reader(DEV_SPI_INFO *spi_info_ptr) +{ + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + DW_SPI_TRANSFER *dw_xfer = &(spi_ctrl_ptr->dw_xfer); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + uint32_t rx_max = dw_spi_rx_max(spi_ctrl_ptr); + int32_t rx_w; + uint32_t rx_cnt = rx_max; + + if (dw_xfer->rx_xfer == NULL) + { + return 0; + } + + while (rx_max) + { + if (dw_xfer->rx_xfer->rx_idx >= dw_xfer->rx_xfer->tot_len) + { + dw_xfer->rx_xfer = dw_xfer->rx_xfer->next; + + if (dw_xfer->rx_xfer == NULL) + { + break; + } + } + + rx_w = dw_spi_getdata(spi_reg_ptr); + + if ((dw_xfer->rx_xfer->rx_idx >= dw_xfer->rx_xfer->rx_ofs) \ + && (dw_xfer->rx_xfer->rx_idx < dw_xfer->rx_xfer->rx_totlen)) + { + if (dw_xfer->nbytes == 1) + { + *(int8_t *)(dw_xfer->rx_xfer->rx_buf) = rx_w; + } + else + { + *(int16_t *)(dw_xfer->rx_xfer->rx_buf) = rx_w; + } + + dw_xfer->rx_xfer->rx_buf += dw_xfer->nbytes; + } + + dw_xfer->rx_xfer->rx_idx += dw_xfer->nbytes; + dw_xfer->rx_idx += dw_xfer->nbytes; + rx_max --; + } + + return ((rx_cnt - rx_max) * dw_xfer->nbytes); +} + +Inline uint32_t dw_spi_nbytes(uint32_t dfs) +{ + uint32_t nbytes = 1; + + if (dfs > 8) { nbytes = 2; } + + return nbytes; +} + +static void dw_spi_init_transfer(DW_SPI_CTRL *spi_ctrl_ptr, DEV_SPI_TRANSFER *xfer, uint32_t dfs) +{ + DW_SPI_TRANSFER *dw_xfer = &(spi_ctrl_ptr->dw_xfer); + uint32_t tot_len = 0; + + dw_xfer->tx_xfer = xfer; + dw_xfer->rx_xfer = xfer; + dw_xfer->tx_idx = 0; + dw_xfer->rx_idx = 0; + dw_xfer->nbytes = dw_spi_nbytes(dfs); + + /** Calculate all transfer length */ + while (xfer) + { + DEV_SPI_XFER_INIT(xfer); + tot_len += xfer->tot_len; + xfer = xfer->next; + } + + dw_xfer->xfer_len = tot_len; +} + +/* Check buffer align status, 0 for aligned, -1 for not-aligned */ +static int32_t dw_spi_chk_xfer_aligned(DEV_SPI_TRANSFER *xfer, uint32_t dfs) +{ + uint32_t align_bytes = 1; + + if (xfer == NULL) { return -1; } + + if (dfs > 8) + { + align_bytes = 2; + } + else + { + return 0; + } + + while (xfer) + { + /* check tx buffer align status */ + if (xfer->tx_len != 0) + { + if (xfer->tx_len % align_bytes) { return -1; } + + if (xfer->tx_ofs % align_bytes) { return -1; } + + if (!CHECK_ALIGN_BYTES(xfer->tx_buf, align_bytes)) { return -1; } + } + + /* check tx buffer align status */ + if (xfer->rx_len != 0) + { + if (xfer->rx_len % align_bytes) { return -1; } + + if (xfer->rx_ofs % align_bytes) { return -1; } + + if (!CHECK_ALIGN_BYTES(xfer->rx_buf, align_bytes)) { return -1; } + } + + xfer = xfer->next; + } + + return 0; +} + +static uint32_t dw_spi_poll_transfer(DEV_SPI_INFO *spi_info_ptr) +{ + uint32_t len = 0; + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + + spi_info_ptr->status |= DEV_IN_XFER; + + while (!dw_spi_xfer_end(spi_ctrl_ptr)) + { + len += dw_spi_writer(spi_info_ptr); + len += dw_spi_reader(spi_info_ptr); + } + + spi_info_ptr->status &= ~DEV_IN_XFER; + + return len >> 1; +} + +/** @} */ + +/** + * \brief open a designware spi device + * \param[in] spi_obj spi object pointer + * \param[in] mode spi working mode (master or slave) + * \param[in] param parameter, for master, param is the freq, for slave, param is dfs + * \retval E_OK Open successfully without any issues + * \retval E_OPNED If device was opened before with different parameters, + * then just increase the \ref dev_spi_info::opn_cnt "opn_cnt" and return \ref E_OPNED + * \retval E_OBJ Device object is not valid + * \retval E_SYS Device is opened for different mode before, if you want to open it with different mode, you need to fully close it first. + * \retval E_PAR Parameter is not valid + * \retval E_NOSPT Open settings are not supported + */ +int32_t dw_spi_open(DEV_SPI *spi_obj, uint32_t mode, uint32_t param) +{ + int32_t ercd = E_OK; + uint32_t param2check; + uint32_t clk_mode, dfs_val; + uint32_t support_modes; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + DW_SPI_CHECK_EXP((mode == DEV_MASTER_MODE) || (mode == DEV_SLAVE_MODE), E_PAR); + + if (mode == DEV_SLAVE_MODE) /* clock mode should be in the enum structure */ + { + DW_SPI_CHECK_EXP((param >= SPI_CPOL_0_CPHA_0) && (param <= SPI_CPOL_1_CPHA_1), E_PAR); + } + else /* frequence should > 0 */ + { + DW_SPI_CHECK_EXP(param > 0, E_PAR); + } + + /* END OF ERROR CHECK */ + + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + + /* Check supported modes, master or slave */ + support_modes = spi_ctrl_ptr->support_modes; + DW_SPI_CHECK_EXP((((support_modes)&DW_SPI_MASTER_SUPPORTED) && (mode == DEV_MASTER_MODE)) || \ + (((support_modes)&DW_SPI_SLAVE_SUPPORTED) && (mode == DEV_SLAVE_MODE)), E_NOSPT); + + /** Check opened before use case */ + if (spi_info_ptr->opn_cnt > 0) + { + if (mode != spi_info_ptr->mode) + { + /* current working mode is different from passing mode */ + return E_SYS; + } + + if (mode == DEV_MASTER_MODE) /* param is freq when as master */ + { + param2check = spi_info_ptr->freq; + } + else /* param is clk_mode when as slave */ + { + param2check = spi_info_ptr->clk_mode; + } + + spi_info_ptr->opn_cnt ++; + + if (param != param2check) /* open with different speed mode */ + { + return E_OPNED; + } + else + { + return E_OK; + } + } + + /* auto increase open count */ + spi_info_ptr->opn_cnt ++; + + /* Do FIFO Length get before init */ +#if DW_SPI_CALC_FIFO_LEN_ENABLE + spi_ctrl_ptr->tx_fifo_len = dw_spi_get_txfifo_len(spi_ctrl_ptr->dw_spi_regs); + spi_ctrl_ptr->rx_fifo_len = dw_spi_get_rxfifo_len(spi_ctrl_ptr->dw_spi_regs); +#endif + /* hardware init */ + spi_info_ptr->mode = mode; + clk_mode = SPI_CLK_MODE_DEFAULT; + dfs_val = SPI_DFS_DEFAULT; + + if (mode == DEV_SLAVE_MODE) + { + clk_mode = param; + } + + spi_info_ptr->dfs = dfs_val; + spi_info_ptr->clk_mode = clk_mode; + dw_spi_hw_init(spi_ctrl_ptr, clk_mode, dfs_val); + + if (mode == DEV_MASTER_MODE) /* Deselect all slaves, and set frequence */ + { + dw_spi_deselect_slave(spi_ctrl_ptr->dw_spi_regs, 0); + dw_spi_set_freq(spi_ctrl_ptr, param); + spi_info_ptr->freq = param; + } + + spi_info_ptr->status = DEV_ENABLED; + spi_info_ptr->extra = NULL; + spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED; + spi_info_ptr->dummy = 0xff; + + spi_ctrl_ptr->int_status = 0; + dw_spi_init_transfer(spi_ctrl_ptr, NULL, dfs_val); + + /** install spi interrupt into system */ + dw_spi_disable_interrupt(spi_info_ptr); + int_handler_install(spi_ctrl_ptr->intno, spi_ctrl_ptr->dw_spi_int_handler); + memset(&(spi_info_ptr->xfer), 0, sizeof(DEV_SPI_TRANSFER)); + memset(&(spi_info_ptr->spi_cbs), 0, sizeof(DEV_SPI_CBS)); + +error_exit: + return ercd; +} + +/** + * \brief close a DesignWare SPI device + * \param[in] spi_obj spi object pointer + * \retval E_OK Close successfully without any issues(including scenario that device is already closed) + * \retval E_OPNED Device is still opened, the device \ref dev_spi_info::opn_cnt "opn_cnt" decreased by 1 + * \retval E_OBJ Device object is not valid + */ +int32_t dw_spi_close(DEV_SPI *spi_obj) +{ + int32_t ercd = E_OK; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_OK); + /* END OF ERROR CHECK */ + + spi_info_ptr->opn_cnt --; + + if (spi_info_ptr->opn_cnt == 0) + { + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + + dw_spi_disable_interrupt(spi_info_ptr); + dw_spi_abort_tx(spi_obj); + dw_spi_abort_rx(spi_obj); + memset(&(spi_info_ptr->xfer), 0, sizeof(DEV_SPI_TRANSFER)); + memset(&(spi_info_ptr->spi_cbs), 0, sizeof(DEV_SPI_CBS)); + memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER)); + dw_spi_disable_device(spi_info_ptr); + spi_info_ptr->status = DEV_DISABLED; + spi_info_ptr->extra = NULL; + } + else + { + ercd = E_OPNED; + } + +error_exit: + return ercd; +} + +/** + * \brief control spi by ctrl command + * \param[in] spi_obj spi object pointer + * \param[in] ctrl_cmd control command code to do specific spi work + * \param[in,out] param parameters used to control spi or return something + * \retval E_OK Control device successfully + * \retval E_CLSED Device is not opened + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Control device failed, due to hardware issues, such as device is disabled + * \retval E_CTX Control device failed, due to different reasons like in transfer state + * \retval E_NOSPT Control command is not supported or not valid + */ +int32_t dw_spi_control(DEV_SPI *spi_obj, uint32_t ctrl_cmd, void *param) +{ + int32_t ercd = E_OK; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED); + /* END OF ERROR CHECK */ + + uint32_t val32; /** to receive unsigned int value */ + DEV_BUFFER *devbuf; + + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL *)(spi_info_ptr->spi_ctrl); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + DEV_SPI_TRANSFER *spi_xfer = &(spi_info_ptr->xfer); + + /* check whether current device is disabled */ + if ((spi_info_ptr->status & DEV_ENABLED) == 0) + { + /** When device is disabled, + * only SPI_CMD_ENA_DEV, SPI_CMD_DIS_DEV, SPI_CMD_GET_STATUS, SPI_CMD_RESET + * are available, other commands will return E_SYS + */ + if ((ctrl_cmd != SPI_CMD_ENA_DEV) && \ + (ctrl_cmd != SPI_CMD_DIS_DEV) && \ + (ctrl_cmd != SPI_CMD_GET_STATUS) && \ + (ctrl_cmd != SPI_CMD_RESET)) + { + return E_SYS; + } + } + + switch (ctrl_cmd) + { + /* Commmon commands for both master and slave mode */ + case SPI_CMD_GET_STATUS: + DW_SPI_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = spi_info_ptr->status; + break; + + case SPI_CMD_SET_CLK_MODE: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + val32 = (uint32_t)param; + DW_SPI_CHECK_EXP((val32 >= SPI_CPOL_0_CPHA_0) && (val32 <= SPI_CPOL_1_CPHA_1), E_PAR); + + if (dw_spi_set_clockmode(spi_reg_ptr, val32) == 0) + { + spi_info_ptr->clk_mode = val32; + } + else + { + ercd = E_SYS; + } + + break; + + case SPI_CMD_ENA_DEV: + dw_spi_enable_device(spi_info_ptr); + break; + + case SPI_CMD_DIS_DEV: + dw_spi_disable_device(spi_info_ptr); + break; + + case SPI_CMD_RESET: + dw_spi_reset_device(spi_info_ptr); + break; + + case SPI_CMD_FLUSH_TX: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + dw_spi_flush_tx(spi_reg_ptr); + break; + + case SPI_CMD_FLUSH_RX: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + dw_spi_flush_rx(spi_reg_ptr); + break; + + case SPI_CMD_SET_DFS: + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + val32 = (uint32_t)param; + DW_SPI_CHECK_EXP(val32 > 0, E_PAR); + + if (dw_spi_set_dfs(spi_reg_ptr, val32) == 0) + { + spi_info_ptr->dfs = val32; + } + else + { + ercd = E_SYS; + } + + break; + + case SPI_CMD_SET_DUMMY_DATA: + val32 = (uint32_t)param; + spi_info_ptr->dummy = val32; + break; + + case SPI_CMD_GET_RXAVAIL: /* Notice in bytes unit */ + DW_SPI_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = dw_spi_get_rxavail(spi_ctrl_ptr) * dw_spi_nbytes(spi_info_ptr->dfs); + break; + + case SPI_CMD_GET_TXAVAIL: /* Notice in bytes unit */ + DW_SPI_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = dw_spi_get_txavail(spi_ctrl_ptr) * dw_spi_nbytes(spi_info_ptr->dfs); + break; + + case SPI_CMD_SET_TXCB: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + spi_info_ptr->spi_cbs.tx_cb = param; + break; + + case SPI_CMD_SET_RXCB: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + spi_info_ptr->spi_cbs.rx_cb = param; + break; + + case SPI_CMD_SET_XFERCB: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + spi_info_ptr->spi_cbs.xfer_cb = param; + break; + + case SPI_CMD_SET_ERRCB: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + spi_info_ptr->spi_cbs.err_cb = param; + break; + + case SPI_CMD_ABORT_TX: + ercd = dw_spi_abort_tx(spi_obj); + break; + + case SPI_CMD_ABORT_RX: + ercd = dw_spi_abort_rx(spi_obj); + break; + + case SPI_CMD_ABORT_XFER: + ercd = dw_spi_abort_xfer(spi_obj); + break; + + case SPI_CMD_SET_TXINT: + val32 = (uint32_t)param; + + if (val32 == 0) + { + ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND); + } + else + { + ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_SND); + } + + break; + + case SPI_CMD_SET_RXINT: + val32 = (uint32_t)param; + + if (val32 == 0) + { + ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV); + } + else + { + ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_RCV); + } + + break; + + case SPI_CMD_SET_TXINT_BUF: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + + if (param != NULL) + { + devbuf = (DEV_BUFFER *)param; + DEV_SPI_XFER_SET_TXBUF(spi_xfer, devbuf->buf, 0, devbuf->len); + DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, devbuf->len, 0); + DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL); + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(spi_xfer, spi_info_ptr->dfs) == 0, E_PAR); + dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs); + } + else + { + DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL); + dw_spi_init_transfer(spi_ctrl_ptr, NULL, spi_info_ptr->dfs); + } + + break; + + case SPI_CMD_SET_RXINT_BUF: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + + if (param != NULL) + { + devbuf = (DEV_BUFFER *)param; + DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, devbuf->len, 0); + DEV_SPI_XFER_SET_RXBUF(spi_xfer, devbuf->buf, 0, devbuf->len); + DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL); + /* Check transfer align */ + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(spi_xfer, spi_info_ptr->dfs) == 0, E_PAR); + dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs); + } + else + { + DEV_SPI_XFER_SET_TXBUF(spi_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_RXBUF(spi_xfer, NULL, 0, 0); + DEV_SPI_XFER_SET_NEXT(spi_xfer, NULL); + dw_spi_init_transfer(spi_ctrl_ptr, NULL, spi_info_ptr->dfs); + } + + break; + + case SPI_CMD_TRANSFER_POLLING: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + + if (param != NULL) + { + /* Check transfer align */ + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned((DEV_SPI_TRANSFER *)param, spi_info_ptr->dfs) == 0, E_PAR); + *spi_xfer = *((DEV_SPI_TRANSFER *)param); + dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs); + /* Transfer data by poll */ + dw_spi_poll_transfer(spi_info_ptr); + } + else + { + ercd = E_PAR; + } + + break; + + case SPI_CMD_TRANSFER_INT: + DW_SPI_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + + if (param != NULL) + { + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + /* Check transfer align */ + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned((DEV_SPI_TRANSFER *)param, spi_info_ptr->dfs) == 0, E_PAR); + *spi_xfer = *((DEV_SPI_TRANSFER *)param); + dw_spi_init_transfer(spi_ctrl_ptr, spi_xfer, spi_info_ptr->dfs); + /* Transfer data by interrupt */ + ercd = dw_spi_ena_cbr(spi_info_ptr, DW_SPI_RDY_XFER); + } + else + { + ercd = dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER); + } + + break; + + /* Master mode only commands */ + case SPI_CMD_MST_SET_FREQ: + DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + val32 = (uint32_t)param; + DW_SPI_CHECK_EXP(val32 > 0, E_PAR); + dw_spi_set_freq(spi_ctrl_ptr, val32); + spi_info_ptr->freq = val32; + break; + + case SPI_CMD_MST_SEL_DEV: + DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + val32 = (uint32_t)param; + + if (dw_spi_select_slave(spi_reg_ptr, val32) == 0) + { + spi_info_ptr->slave = val32; + } + else + { + ercd = E_SYS; + } + + break; + + case SPI_CMD_MST_DSEL_DEV: + DW_SPI_CHECK_EXP(spi_info_ptr->mode == DEV_MASTER_MODE, E_NOSPT); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + val32 = (uint32_t)param; + + if (dw_spi_deselect_slave(spi_reg_ptr, val32) == 0) + { + spi_info_ptr->slave = SPI_SLAVE_NOT_SELECTED; + } + else + { + ercd = E_SYS; + } + + break; + + /* Slave mode only commands */ + + + default: + ercd = E_NOSPT; + break; + } + +error_exit: + return ercd; +} + +/** + * \brief send data through DesignWare SPI + * \param[in] spi_obj spi object pointer + * \param[in] data pointer to data need to send by spi + * \param[in] len length of data to be sent + * \retval >0 Byte count that was successfully sent for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + * \retval E_CTX Device is still in transfer state + * \retval E_SYS Can't write data to hardware due to hardware issues, such as device is disabled + */ +int32_t dw_spi_write(DEV_SPI *spi_obj, const void *data, uint32_t len) +{ + int32_t ercd = E_OK; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED); + DW_SPI_CHECK_EXP(spi_info_ptr->status & DEV_ENABLED, E_SYS); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + DW_SPI_CHECK_EXP(data != NULL, E_PAR); + DW_SPI_CHECK_EXP(len > 0, E_PAR); + /* END OF ERROR CHECK */ + + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + DEV_SPI_TRANSFER spi_xfer; + + /* Master and Slave transmit */ + DEV_SPI_XFER_SET_TXBUF(&spi_xfer, data, 0, len); + DEV_SPI_XFER_SET_RXBUF(&spi_xfer, NULL, len, 0); + DEV_SPI_XFER_SET_NEXT(&spi_xfer, NULL); + + /* Check transfer align */ + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(&spi_xfer, spi_info_ptr->dfs) == 0, E_PAR); + + dw_spi_init_transfer(spi_ctrl_ptr, &spi_xfer, spi_info_ptr->dfs); + + ercd = dw_spi_poll_transfer(spi_info_ptr); + +error_exit: + return ercd; +} + +/** + * \brief read data through DesignWare SPI + * \param[in] spi_info_ptr spi information structure pointer + * \param[out] data data that need to read (data must be char type) + * \param[in] len data count need to read + * \retval >=0 data have been read + * \retval E_PAR arguments passed was wrong + * \retval E_OBJ spi has something error, nothing can be done + * \retval E_CLSED spi was closed, not available for control + * \retval <0 other error code not defined here + */ +int32_t dw_spi_read(DEV_SPI *spi_obj, void *data, uint32_t len) +{ + int32_t ercd = E_OK; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + DW_SPI_CHECK_EXP(spi_info_ptr->opn_cnt > 0, E_CLSED); + DW_SPI_CHECK_EXP(spi_info_ptr->status & DEV_ENABLED, E_SYS); + DW_SPI_CHECK_EXP((spi_info_ptr->status & DEV_IN_XFER) == 0, E_CTX); + DW_SPI_CHECK_EXP(data != NULL, E_PAR); + DW_SPI_CHECK_EXP(len > 0, E_PAR); + /* END OF ERROR CHECK */ + + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + DEV_SPI_TRANSFER spi_xfer; + + /* Master and Slave transmit */ + DEV_SPI_XFER_SET_TXBUF(&spi_xfer, NULL, len, 0); + DEV_SPI_XFER_SET_RXBUF(&spi_xfer, data, 0, len); + DEV_SPI_XFER_SET_NEXT(&spi_xfer, NULL); + + /* Check transfer align */ + DW_SPI_CHECK_EXP(dw_spi_chk_xfer_aligned(&spi_xfer, spi_info_ptr->dfs) == 0, E_PAR); + + dw_spi_init_transfer(spi_ctrl_ptr, &spi_xfer, spi_info_ptr->dfs); + + ercd = dw_spi_poll_transfer(spi_info_ptr); + +error_exit: + return ercd; +} + +/** + * \brief DesignWare SPI interrupt processing routine + * \param[in] spi_info_ptr DEV_SPI_INFO *spi_info_ptr + * \param[in] ptr extra information + */ +void dw_spi_isr(DEV_SPI *spi_obj, void *ptr) +{ + int32_t ercd = E_OK; + DEV_SPI_INFO *spi_info_ptr = &(spi_obj->spi_info); + + /* START ERROR CHECK */ + VALID_CHK_SPI_INFO_OBJECT(spi_info_ptr); + /* END OF ERROR CHECK */ + + DW_SPI_CTRL *spi_ctrl_ptr = (DW_SPI_CTRL_PTR)(spi_info_ptr->spi_ctrl); + DW_SPI_REG *spi_reg_ptr = (DW_SPI_REG *)(spi_ctrl_ptr->dw_spi_regs); + + uint32_t isr_status; + + isr_status = spi_reg_ptr->ISR; + + if (!isr_status) { return; } + + if (spi_ctrl_ptr->dw_xfer.xfer_len == 0) + { + dw_spi_disable_interrupt(spi_info_ptr); + } + else + { + if (isr_status & (DW_SPI_IMR_TXOIM | DW_SPI_IMR_RXOIM | DW_SPI_IMR_RXUIM)) + { + dw_spi_clear_interrupt_all(spi_reg_ptr); + dw_spi_disable_interrupt(spi_info_ptr); + + if (spi_info_ptr->spi_cbs.err_cb) + { + spi_info_ptr->spi_cbs.err_cb(spi_obj); + } + + memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER)); + } + + dw_spi_reader(spi_info_ptr); + + if (isr_status & DW_SPI_IMR_TXEIM) + { + dw_spi_writer(spi_info_ptr); + } + + if (dw_spi_xfer_end(spi_ctrl_ptr)) + { + if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_TX) + { + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_SND); + + if (spi_info_ptr->spi_cbs.tx_cb) + { + spi_info_ptr->spi_cbs.tx_cb(spi_obj); + } + } + else if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_RX) + { + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_RCV); + + if (spi_info_ptr->spi_cbs.rx_cb) + { + spi_info_ptr->spi_cbs.rx_cb(spi_obj); + } + } + else if ((spi_info_ptr->status & DW_SPI_IN_XFER) == DW_SPI_IN_XFER) + { + dw_spi_dis_cbr(spi_info_ptr, DW_SPI_RDY_XFER); + + if (spi_info_ptr->spi_cbs.xfer_cb) + { + spi_info_ptr->spi_cbs.xfer_cb(spi_obj); + } + } + else + { + dw_spi_disable_interrupt(spi_info_ptr); + } + + memset(&(spi_ctrl_ptr->dw_xfer), 0, sizeof(DW_SPI_TRANSFER)); + } + } + +error_exit: + return; +} +/** @} */ /* DEVICE_DW_SPI_IMPLEMENT */ + +/** @} */ /* DEVICE_DW_SPI */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.h new file mode 100644 index 000000000..1e011805c --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi.h @@ -0,0 +1,192 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-06-25 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \brief DesignWare SPI driver header file + * \ingroup DEVICE_DW_SPI + */ + +#ifndef _DEVICE_DW_SPI_H_ +#define _DEVICE_DW_SPI_H_ + +#include "device/device_hal/inc/dev_spi.h" + +/** + * if this header file is included, + * will indicate that this designware spi device + * is used + */ +#define DEVICE_USE_DESIGNWARE_SPI + +#define DW_SPI_IN_FREE (0) /*!< Currently not in spi transfer */ +#define DW_SPI_IN_XFER (DEV_IN_TX|DEV_IN_RX|DEV_IN_XFER) /*!< Currently in spi transfer */ +#define DW_SPI_IN_TX (DEV_IN_TX|DEV_IN_XFER) /*!< Currently in spi tx */ +#define DW_SPI_IN_RX (DEV_IN_RX|DEV_IN_XFER) /*!< Currently in spi rx */ + +#define DW_SPI_GINT_DISABLED (0) /*!< designware interrupt disabled for control iic irq/fiq */ +#define DW_SPI_GINT_ENABLE (1<<0) /*!< designware interrupt enabled for control iic irq/fiq */ + +#define DW_SPI_MASTER_SUPPORTED (0x1) /*!< Support Designware SPI Master Mode */ +#define DW_SPI_SLAVE_SUPPORTED (0x2) /*!< Support Designware SPI Slave Mode */ +/*!< Support Designware SPI Both Master and Slave Mode */ +#define DW_SPI_BOTH_SUPPORTED (DW_SPI_MASTER_SUPPORTED|DW_SPI_SLAVE_SUPPORTED) + +/** + * \defgroup DEVICE_DW_SPI_REGSTRUCT DesignWare SPI Register Structure + * \ingroup DEVICE_DW_SPI + * \brief contains definitions of DesignWare SPI register structure. + * \details detailed description of DesignWare SPI register information + * @{ + */ +/** + * \brief DesignWare SPI register structure + * \details Detailed struct description of DesignWare SPI + * block register information, implementation of dev_spi_info::spi_regs + */ +typedef volatile struct dw_spi_reg +{ + /*!< Control Register */ + /*!< SPI Control Register 0 (0x0) */ + uint32_t CTRLR0; + /*!< SPI Control Register 1 (0x4) */ + uint32_t CTRLR1; + /*!< Enable Register */ + /*!< SPI Enable Register (0x8) */ + uint32_t SSIENR; + /*!< SPI Microwire Control Register (0xC) */ + uint32_t MWCR; + /*!< SPI Slave Enable Register (0x10) */ + uint32_t SER; + /*!< SPI Baud Rate Select Register (0x14) */ + uint32_t BAUDR; + /*!< TX and RX FIFO Control Register */ + /*!< SPI Transmit FIFO Threshold Level Register (0x18) */ + uint32_t TXFTLR; + /*!< SPI Receive FIFO Threshold Level Register (0x1C) */ + uint32_t RXFTLR; + /*!< SPI Transmit FIFO Level Register (0x20) */ + uint32_t TXFLR; + /*!< SPI Receive FIFO Level Register (0x24) */ + uint32_t RXFLR; + /*!< SPI Status Register (0x28) */ + uint32_t SR; + /*!< Interrupt Enable/Disable/Control Registers */ + /*!< SPI Interrupt Mask Register (0x2C) */ + uint32_t IMR; + /*!< SPI Interrupt Status Register (0x30) */ + uint32_t ISR; + /*!< SPI Raw Interrupt Status Register (0x34) */ + uint32_t RISR; + /*!< SPI Transmit FIFO Overflow Interrupt Clear Register (0x38) */ + uint32_t TXOICR; + /*!< SPI Receive FIFO Overflow Interrupt Clear Register (0x3C) */ + uint32_t RXOICR; + /*!< SPI Receive FIFO Underflow Interrupt Clear Register (0x40) */ + uint32_t RXUICR; + /*!< SPI Multi-Master Interrupt Clear Register (0x44) */ + uint32_t MSTICR; + /*!< SPI Interrupt Clear Register (0x48) */ + uint32_t ICR; + /*!< DMA Control Register (0x4C) */ + uint32_t DMACR; + /*!< DMA Transmit Data Level (0x50) */ + uint32_t DMATDLR; + /*!< DMA Receive Data Level (0x54) */ + uint32_t DMARDLR; + /*!< SPI Identification Register (0x58) */ + uint32_t IDR; + /*!< SPI CoreKit ID Register (Value after Reset : 0x3332322A) (0x5C) */ + uint32_t SSI_VER_ID; + /*!< Data Register */ + /*!< SPI DATA Register for both Read and Write (0x60) */ + uint32_t DATAREG; +} DW_SPI_REG, *DW_SPI_REG_PTR; +/** @} */ + +/** Designware SPI Message Transfer */ +typedef struct dw_spi_transfer +{ + uint32_t xfer_len; + uint32_t tx_idx; + uint32_t rx_idx; + uint32_t nbytes; + DEV_SPI_TRANSFER *tx_xfer; + DEV_SPI_TRANSFER *rx_xfer; +} DW_SPI_TRANSFER, *DW_SPI_TRANSFER_PTR; + +/** + * \brief DesignWare SPI control structure definition + * \details implement of dev_spi_info::dev_spi_info + */ +typedef struct dw_spi_ctrl +{ + DW_SPI_REG *dw_spi_regs; /*!< spi register */ + /* Variables which should be set during object implementation */ + uint32_t support_modes; /*!< supported spi modes */ + uint32_t intno; /*!< interrupt no */ + uint32_t dw_apb_bus_freq; /*!< spi ip apb bus frequency */ + uint32_t tx_fifo_len; /*!< transmit fifo length */ + uint32_t rx_fifo_len; /*!< receive fifo length */ + INT_HANDLER dw_spi_int_handler; /*!< spi interrupt handler */ + /* Variables which always change during iic operation */ + uint32_t int_status; /*!< iic interrupt status */ + DW_SPI_TRANSFER dw_xfer; /*!< designware spi transfer */ +} DW_SPI_CTRL, *DW_SPI_CTRL_PTR; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup DEVICE_DW_SPI_FUNCDLR DesignWare SPI Function Declaration + * \ingroup DEVICE_DW_SPI + * \brief contains declarations of designware spi functions. + * \details This are only used in \ref dw_spi_obj.c + * @{ + */ +extern int32_t dw_spi_open(DEV_SPI *spi_obj, uint32_t mode, uint32_t param); +extern int32_t dw_spi_close(DEV_SPI *spi_obj); +extern int32_t dw_spi_control(DEV_SPI *spi_obj, uint32_t ctrl_cmd, void *param); +extern int32_t dw_spi_write(DEV_SPI *spi_obj, const void *data, uint32_t len); +extern int32_t dw_spi_read(DEV_SPI *spi_obj, void *data, uint32_t len); +extern void dw_spi_isr(DEV_SPI *spi_obj, void *ptr); +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* _DEVICE_DW_SPI_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal.h new file mode 100644 index 000000000..5029f570e --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal.h @@ -0,0 +1,141 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-06-25 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup DEVICE_DW_SPI + * \brief DesignWare SPI driver hardware description related header file + * \details detailed hardware related definitions of DesignWare SPI driver + */ + +#ifndef _DEVICE_DW_SPI_HAL_H_ +#define _DEVICE_DW_SPI_HAL_H_ + +#include "device/designware/spi/dw_spi_hal_cfg.h" + +/* DW APB SPI bit definitions */ + +/** + * \name DesignWare SPI HAL CTRL0 Macros + * \brief DesignWare SPI hal ctrl0 macros, + * include dfs, scph, scppl, tmod, etc + * @{ + */ +#define DW_SPI_CTRLR0_DFS_MASK (0xf) + +#define DW_SPI_CTRLR0_SC_OFS (6) +#define DW_SPI_CTRLR0_SC_MASK (0xC0) +#define DW_SPI_CTRLR0_SCPH_HIGH (0x40) +#define DW_SPI_CTRLR0_SCPH_LOW (0) +#define DW_SPI_CTRLR0_SCPOL_HIGH (0x80) +#define DW_SPI_CTRLR0_SCPOL_LOW (0) + +#define DW_SPI_CTRLR0_TMOD_MASK (0x300) +#define DW_SPI_TMOD_TRANSMIT_RECEIVE (0) +#define DW_SPI_TMOD_TRANSMIT_ONLY (0x100) +#define DW_SPI_TMOD_RECEIVE_ONLY (0x200) +#define DW_SPI_TMOD_EEPROM_READ_ONLY (0x300) + +#define DW_SPI_CTRLR0_FRF_MOTOROLA (0x0) +#define DW_SPI_CTRLR0_FRF_TI (0x10) +#define DW_SPI_CTRLR0_FRF_MICROWIRE (0x20) + +#define DW_SPI_CTRLR0_SLV_OE_DISABLE (1<<10) +#define DW_SPI_CTRLR0_SLV_OE_ENABLE (0) + + +/** @} */ + +/** + * \name DesignWare SPI HAL ISR Flags + * \brief DesignWare SPI hal Interrupt Status Flags + * @{ + */ +#define DW_SPI_TX_OVERFLOW_ERROR (0x2) +#define DW_SPI_RX_UNDERFLOW_ERROR (0x4) +#define DW_SPI_RX_OVERFLOW_ERROR (0x8) + +#define DW_SPI_ISR_RX_FIFO_INT_MASK (0x10) +#define DW_SPI_ISR_TX_FIFO_INT_MASK (0x1) +#define DW_SPI_ISR_TX_OVERFLOW_INT_MASK (0x2) +#define DW_SPI_ISR_RX_UNDERFLOW_INT_MASK (0x4) +#define DW_SPI_ISR_RX_OVERFLOW_INT_MASK (0x8) +/** @} */ + +/** + * \name DesignWare SPI HAL SR Flags + * \brief DesignWare SPI hal Status Flags + * @{ + */ +#define DW_SPI_SR_DCOL (0x40) +#define DW_SPI_SR_TXE (0x20) +#define DW_SPI_SR_RFF (0x10) +#define DW_SPI_SR_RFNE (0x8) +#define DW_SPI_SR_TFE (0x4) +#define DW_SPI_SR_TFNF (0x2) +#define DW_SPI_SR_BUSY (0x1) +/** @} */ + +/** + * \name DesignWare SPI HAL SSI Enable Macros + * \brief DesignWare SPI hal ssi enable macros + * @{ + */ +/* Macros */ +#define DW_SPI_SSI_ENABLE (1) /*!< SSI Enable */ +#define DW_SPI_SSI_DISABLE (0) /*!< SSI Disable */ +/** @} */ + +/** + * \name DesignWare SPI HAL IMR Macros + * \brief DesignWare SPI hal interrupt mask macros + * @{ + */ +#define DW_SPI_IMR_MSTIM (0x20) /*!< Multi-Master Contention Interrupt Mask */ +#define DW_SPI_IMR_RXFIM (0x10) /*!< Receive FIFO Full Interrupt Mask */ +#define DW_SPI_IMR_RXOIM (0x08) /*!< Receive FIFO Overflow Interrupt Mask */ +#define DW_SPI_IMR_RXUIM (0x04) /*!< Receive FIFO Underflow Interrupt Mask */ +#define DW_SPI_IMR_TXOIM (0x02) /*!< Transmit FIFO Overflow Interrupt Mask */ +#define DW_SPI_IMR_TXEIM (0x01) /*!< Transmit FIFO Empty Interrupt Mask */ + +#define DW_SPI_IMR_XFER (DW_SPI_IMR_TXEIM|DW_SPI_IMR_RXFIM|DW_SPI_IMR_TXOIM|DW_SPI_IMR_RXOIM|DW_SPI_IMR_RXUIM) +/** @} */ + +#define DW_SPI_SSI_IDLE (1) +#define DW_SPI_SPI_TRANSMIT (1) +#define DW_SPI_SPI_RECEIVE (2) +#define DW_SPI_SSI_MASTER (1) +#define DW_SPI_SSI_SLAVE (0) + + +#endif /* _DEVICE_DW_SPI_HAL_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal_cfg.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal_cfg.h new file mode 100644 index 000000000..ef2c10b31 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/spi/dw_spi_hal_cfg.h @@ -0,0 +1,58 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2015-09-09 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup DEVICE_DW_SPI + * \brief DesignWare SPI driver hardware description + * related header file configuration file + * \details configuration file to enable or disable some function of spi + */ + +#ifndef _DEVICE_DW_SPI_HAL_CFG_H_ +#define _DEVICE_DW_SPI_HAL_CFG_H_ + +#ifndef DW_SPI_CALC_FIFO_LEN_ENABLE +#define DW_SPI_CALC_FIFO_LEN_ENABLE (1) /*!< Defaultly enable calculate fifo length */ +#endif + +#ifndef DW_SPI_MAX_FIFO_LENGTH +#define DW_SPI_MAX_FIFO_LENGTH (256) /*!< Max FIFO depth for designware SPI device */ +#endif + +#ifndef DW_SPI_MIN_FIFO_LENGTH +#define DW_SPI_MIN_FIFO_LENGTH (2) /*!< Min FIFO depth for designware SPI device */ +#endif + +#endif /* _DEVICE_DW_SPI_HAL_CFG_H_ */ + diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.c b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.c new file mode 100644 index 000000000..7183ff88d --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.c @@ -0,0 +1,1119 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-20 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_DW_UART Designware UART Driver + * \ingroup DEVICE_DW + * \brief Designware UART Driver Implementation + */ + +/** + * \file + * \ingroup DEVICE_DW_UART + * \brief DesignWare UART driver implementation based on device hal layer definition (\ref dev_uart.h) + */ +#include + +#include "inc/embARC_toolchain.h" +#include "inc/embARC_error.h" + +#include "inc/arc/arc_exception.h" + +#include "device/designware/uart/dw_uart_hal.h" +#include "device/designware/uart/dw_uart.h" + + +/** + * \name DesignWare UART Driver Macros + * \brief DesignWare UART driver macros used in uart driver + * @{ + */ +/** check expressions used in DesignWare UART driver implementation */ +#define DW_UART_CHECK_EXP(EXPR, ERROR_CODE) CHECK_EXP(EXPR, ercd, ERROR_CODE, error_exit) + +#ifndef DISABLE_DEVICE_OBJECT_VALID_CHECK +/** valid check of uart info object */ +#define VALID_CHK_UART_INFO_OBJECT(uartinfo_obj_ptr) { \ + DW_UART_CHECK_EXP((uartinfo_obj_ptr)!=NULL, E_OBJ); \ + DW_UART_CHECK_EXP(((uartinfo_obj_ptr)->uart_ctrl)!=NULL, E_OBJ); \ + } +#endif + +/** convert DesignWare baudrate to divisor */ +#define DW_UART_BAUD2DIV(perifreq, baud) ((perifreq) / ((baud)*16)) + +/** + * \name DesignWare UART Interrupt Callback Routine Select Marcos + * \brief DesignWare UART interrupt callback routines select macros definitions + * @{ + */ +#define DW_UART_RDY_SND (1U) /*!< ready to send callback */ +#define DW_UART_RDY_RCV (2U) /*!< ready to receive callback */ +/** @} */ + +/** @} */ + +/** + * \defgroup DEVICE_DW_UART_STATIC DesignWare UART Driver Static Functions + * \ingroup DEVICE_DW_UART + * \brief Static or inline functions, variables for DesignWare UART handle uart operations, + * only used in this file + * @{ + */ +const uint8_t dw_uart_databits[] = { \ + DW_UART_LCR_WORD_LEN5, DW_UART_LCR_WORD_LEN6, \ + DW_UART_LCR_WORD_LEN7, DW_UART_LCR_WORD_LEN8 + }; +const uint8_t dw_uart_parity[] = +{ + DW_UART_LCR_PARITY_NONE, DW_UART_LCR_PARITY_ODD, + DW_UART_LCR_PARITY_EVEN, DW_UART_LCR_PARITY_MASK, + DW_UART_LCR_PARITY_SPACE +}; +const uint8_t dw_uart_stopbits[] = +{ + DW_UART_LCR_1_STOP_BIT, DW_UART_LCR_1D5_STOP_BIT, + DW_UART_LCR_2_STOP_BIT +}; + +/** test whether uart is ready to send, 1 ready, 0 not ready */ +Inline int32_t dw_uart_putready(DW_UART_REG *uart_reg_ptr) +{ + return ((uart_reg_ptr->USR & DW_UART_USR_TFNF) != 0); +} +/** test whether uart is ready to receive, 1 ready, 0 not ready */ +Inline int32_t dw_uart_getready(DW_UART_REG *uart_reg_ptr) +{ + return ((uart_reg_ptr->USR & DW_UART_USR_RFNE) != 0); +} +/** write char to uart send fifo */ +Inline void dw_uart_putchar(DW_UART_REG *uart_reg_ptr, char chr) +{ + uart_reg_ptr->DATA = chr; +} +/** read data from uart receive fifo, return data received */ +Inline int32_t dw_uart_getchar(DW_UART_REG *uart_reg_ptr) +{ + return (int32_t)uart_reg_ptr->DATA; +} +/** + * \brief send char by uart when available, + * mostly used in interrupt method, non-blocked function + * \param[in] uart_reg_ptr uart register structure pointer + * \param[in] chr char to be sent + * \retval 0 send successfully + * \retval -1 not ready to send data + */ +Inline int32_t dw_uart_snd_chr(DW_UART_REG *uart_reg_ptr, char chr) +{ + if (dw_uart_putready(uart_reg_ptr)) + { + dw_uart_putchar(uart_reg_ptr, chr); + return 0; + } + + return -1; +} +/** + * \brief receive one char from uart, + * mostly used in interrupt routine, non-blocked function + * \param[in] uart_reg_ptr uart register structure pointer + * \return data received by the uart + */ +Inline int32_t dw_uart_rcv_chr(DW_UART_REG *uart_reg_ptr) +{ + return dw_uart_getchar(uart_reg_ptr); +} +/** + * \brief send char by uart in poll method, blocked function + * \param[in] uart_reg_ptr uart register structure pointer + * \param[in] chr char to be sent + */ +Inline void dw_uart_psnd_chr(DW_UART_REG *uart_reg_ptr, char chr) +{ + /** wait until uart is ready to send */ + while (!dw_uart_putready(uart_reg_ptr)); /* blocked */ + + /** send char */ + dw_uart_putchar(uart_reg_ptr, chr); +} +/** + * \brief receive one char from uart in poll method, blocked function + * \param[in] uart_reg_ptr uart register structure pointer + * \return data received by the uart + */ +Inline int32_t dw_uart_prcv_chr(DW_UART_REG *uart_reg_ptr) +{ + /** wait until uart is ready to receive */ + while (!dw_uart_getready(uart_reg_ptr)); /* blocked */ + + /** receive data */ + return dw_uart_getchar(uart_reg_ptr); +} + +/** Get TX FIFO Length */ +Inline uint32_t dw_uart_get_txfifo_len(DW_UART_REG *uart_reg_ptr) +{ + uint32_t txfifolen; + uint32_t uart_cpr; + + uart_cpr = uart_reg_ptr->CPR; + + if (uart_cpr & DW_UART_CPR_FIFO_STAT) + { + txfifolen = ((uart_cpr & DW_UART_CPR_FIFO_MODE) >> DW_UART_CPR_FIFO_MODE_OFS) << 4; + } + else + { + txfifolen = 0; + } + + return txfifolen; +} + +/** Get RX FIFO Length */ +Inline uint32_t dw_uart_get_rxfifo_len(DW_UART_REG *uart_reg_ptr) +{ + uint32_t rxfifolen; + uint32_t uart_cpr; + + uart_cpr = uart_reg_ptr->CPR; + + if (uart_cpr & DW_UART_CPR_FIFO_STAT) + { + rxfifolen = ((uart_cpr & DW_UART_CPR_FIFO_MODE) >> DW_UART_CPR_FIFO_MODE_OFS) << 4; + } + else + { + rxfifolen = 0; + } + + return rxfifolen; +} + +/** + * \brief set designware uart DPS value + * \param uart_reg_ptr uart register structure + * \param dps data bits/parity bit/stop bits parameter + * \retval 0 Set ok + * \retval !0 Set failed + */ +static int32_t dw_uart_set_dps(DW_UART_REG *uart_reg_ptr, UART_DPS_FORMAT *dps) +{ + uint32_t dps_value = 0; + + if (dps == NULL) { return -1; } + + /* data bits check */ + if ((dps->databits < 5) || (dps->databits > 8)) { return -1; } + + /* stop bits check */ + if (dps->stopbits > UART_STPBITS_TWO) { return -1; } + + /* parity bit type check */ + if (dps->parity > UART_PARITY_SPACE) { return -1; } + + dps_value |= (uint32_t)dw_uart_databits[dps->databits - 5]; + dps_value |= (uint32_t)dw_uart_stopbits[dps->stopbits]; + dps_value |= (uint32_t)dw_uart_parity[dps->parity]; + + /* clear dps bits */ + uart_reg_ptr->LCR &= (~DW_UART_LCR_DPS_MASK); + /* set dps bits */ + uart_reg_ptr->LCR |= dps_value; + + return 0; +} + +/** + * \brief set designware uart baudrate + * \param uart_reg_ptr uart register structure + * \param baud_divisor uart baudrate divisor + */ +static void dw_uart_set_baud(DW_UART_REG *uart_reg_ptr, uint32_t baud_divisor) +{ + /* enable uart baudrate update */ + uart_reg_ptr->LCR |= DW_UART_LCR_DLAB; + /** + * setting uart baudrate registers + */ + uart_reg_ptr->DATA = baud_divisor & 0xff; /*!< DLL */ + uart_reg_ptr->IER = (baud_divisor >> 8) & 0xff; /*!< DLH */ + /** disable DLAB */ + uart_reg_ptr->LCR &= ~(DW_UART_LCR_DLAB); +} + +/** + * \brief Do uart software reset + * \param uart_reg_ptr uart register structure + */ +Inline void dw_uart_software_reset(DW_UART_REG *uart_reg_ptr) +{ + uart_reg_ptr->SRR = DW_UART_SRR_UR | DW_UART_SRR_RFR | DW_UART_SRR_XFR; + + while (uart_reg_ptr->USR & DW_UART_USR_BUSY); /* wait until software reset completed */ +} + +/** + * \brief set designware uart baudrate + * \param uart_reg_ptr uart register structure + * \param hwfc uart hardware flow control type + * \note Need to set corresponding pin functions + */ +static void dw_uart_set_hwfc(DW_UART_REG *uart_reg_ptr, UART_HW_FLOW_CONTROL hwfc) +{ + if (hwfc == UART_FC_NONE) + { + uart_reg_ptr->MCR &= ~(DW_UART_MCR_AFCE | DW_UART_MCR_RTS); + } + + if ((hwfc == UART_FC_RTS) || (hwfc == UART_FC_BOTH)) + { + uart_reg_ptr->MCR |= (DW_UART_MCR_AFCE | DW_UART_MCR_RTS); + } + + if ((hwfc == UART_FC_CTS) || (hwfc == UART_FC_BOTH)) + { + uart_reg_ptr->MCR |= (DW_UART_MCR_AFCE); + } +} + +Inline void dw_uart_set_break(DW_UART_REG *uart_reg_ptr) +{ + uart_reg_ptr->LCR |= DW_UART_LCR_BREAK; +} + +Inline void dw_uart_clr_break(DW_UART_REG *uart_reg_ptr) +{ + uart_reg_ptr->LCR &= ~DW_UART_LCR_BREAK; +} + +/** + * \brief init designware uart with selected baud + * \param[in] uart_reg_ptr uart register structure pointer + * \param[in] baud_divisor baudrate divisor + */ +static void dw_uart_init(DW_UART_REG *uart_reg_ptr, uint32_t baud_divisor, UART_DPS_FORMAT *dps, + UART_HW_FLOW_CONTROL hwfc) +{ + dw_uart_software_reset(uart_reg_ptr); + + dw_uart_set_hwfc(uart_reg_ptr, hwfc); + dw_uart_set_dps(uart_reg_ptr, dps); + dw_uart_set_baud(uart_reg_ptr, baud_divisor); + + uart_reg_ptr->IIR = 0x1; /** enable uart fifo (FCR IIR is the same) */ + uart_reg_ptr->IER = 0x0; /** disable all uart interrupt */ +} + +/** + * \brief set designware uart baudrate + * \param uart_info_ptr uart information structure pointer + */ +static void dw_uart_flush_output(DEV_UART_INFO *uart_info_ptr) +{ + uint32_t i; + char *p_charbuf; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + if (uart_info_ptr->tx_buf.buf != NULL) + { + p_charbuf = (char *)(uart_info_ptr->tx_buf.buf); + + for (i = uart_info_ptr->tx_buf.ofs; i < uart_info_ptr->tx_buf.len; i ++) + { + dw_uart_psnd_chr(uart_reg_ptr, p_charbuf[i]); + } + + /* clear transmit buffer */ + uart_info_ptr->tx_buf.buf = NULL; + uart_info_ptr->tx_buf.len = 0; + uart_info_ptr->tx_buf.ofs = 0; + } + + /* wait until transmit fifo is empty */ + while ((uart_reg_ptr->USR & DW_UART_USR_TFE) == 0); + + while (uart_reg_ptr->USR & DW_UART_USR_BUSY); +} + +/** + * \brief disable designware uart send or receive interrupt + * \param[in] DEV_UART_INFO *uart_info_ptr + * \param[in] cbrtn control code of callback routine of send or receive + */ +static void dw_uart_dis_cbr(DEV_UART_INFO *uart_info_ptr, uint32_t cbrtn) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + switch (cbrtn) + { + case DW_UART_RDY_SND: + uart_reg_ptr->IER &= ~DW_UART_IER_XMIT_EMPTY; + uart_ctrl_ptr->int_status &= ~DW_UART_TXINT_ENABLE; + break; + + case DW_UART_RDY_RCV: + uart_reg_ptr->IER &= ~DW_UART_IER_DATA_AVAIL; + uart_ctrl_ptr->int_status &= ~DW_UART_RXINT_ENABLE; + break; + + default: + break; + } + + if (uart_ctrl_ptr->int_status & DW_UART_GINT_ENABLE) + { + if ((uart_ctrl_ptr->int_status & (DW_UART_RXINT_ENABLE | DW_UART_TXINT_ENABLE)) == 0) + { + int_disable(uart_ctrl_ptr->intno); + uart_ctrl_ptr->int_status &= ~DW_UART_GINT_ENABLE; + } + } +} + +/** + * \brief enable DesignWare UART send or receive interrupt + * \param[in] DEV_UART_INFO *uart_info_ptr + * \param[in] cbrtn control code of callback routine of send or receive + */ +static void dw_uart_ena_cbr(DEV_UART_INFO *uart_info_ptr, uint32_t cbrtn) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + switch (cbrtn) + { + case DW_UART_RDY_SND: + uart_ctrl_ptr->int_status |= DW_UART_TXINT_ENABLE; + uart_reg_ptr->IER |= DW_UART_IER_XMIT_EMPTY; + break; + + case DW_UART_RDY_RCV: + uart_ctrl_ptr->int_status |= DW_UART_RXINT_ENABLE; + uart_reg_ptr->IER |= DW_UART_IER_DATA_AVAIL; + break; + + default: + break; + } + + if ((uart_ctrl_ptr->int_status & DW_UART_GINT_ENABLE) == 0) + { + if (uart_ctrl_ptr->int_status & (DW_UART_RXINT_ENABLE | DW_UART_TXINT_ENABLE)) + { + uart_ctrl_ptr->int_status |= DW_UART_GINT_ENABLE; + int_enable(uart_ctrl_ptr->intno); + } + } +} + +/** + * \brief enable designware uart interrupt + * \param uart_info_ptr uart information structure pointer + */ +static void dw_uart_enable_interrupt(DEV_UART_INFO *uart_info_ptr) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + + int_handler_install(uart_ctrl_ptr->intno, uart_ctrl_ptr->dw_uart_int_handler); + uart_ctrl_ptr->int_status |= DW_UART_GINT_ENABLE; + int_enable(uart_ctrl_ptr->intno); /** enable uart interrupt */ +} +/** + * \brief disable designware uart interrupt + * \param uart_info_ptr uart information structure pointer + */ +static void dw_uart_disable_interrupt(DEV_UART_INFO *uart_info_ptr) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + + /** disable uart send&receive interrupt after disable uart interrupt */ + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_SND); + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_RCV); + /* disable uart interrupt */ + int_disable(uart_ctrl_ptr->intno); + uart_ctrl_ptr->int_status &= ~(DW_UART_GINT_ENABLE | DW_UART_TXINT_ENABLE | DW_UART_RXINT_ENABLE); +} + +/** enable designware uart */ +static void dw_uart_enable_device(DEV_UART_INFO *uart_info_ptr) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + if ((uart_info_ptr->status & DEV_ENABLED) == 0) + { + dw_uart_set_baud(uart_reg_ptr, uart_info_ptr->baudrate); + uart_info_ptr->status |= DEV_ENABLED; + } +} + +/** disable designware uart */ +static void dw_uart_disable_device(DEV_UART_INFO *uart_info_ptr) +{ + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + if ((uart_info_ptr->status & DEV_ENABLED) == DEV_ENABLED) + { + dw_uart_set_baud(uart_reg_ptr, 0); + uart_info_ptr->status &= ~DEV_ENABLED; + } +} + +/** abort current interrupt transmit transfer */ +static void dw_uart_abort_tx(DEV_UART *uart_obj) +{ + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + + if (uart_ctrl_ptr->int_status & DW_UART_TXINT_ENABLE) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_SND); + uart_info_ptr->status |= DEV_IN_TX_ABRT; + + if (uart_info_ptr->uart_cbs.tx_cb != NULL) + { + uart_info_ptr->uart_cbs.tx_cb(uart_obj); + } + + uart_info_ptr->status &= ~(DEV_IN_TX_ABRT); + } +} + +/** abort current interrupt receive transfer */ +static void dw_uart_abort_rx(DEV_UART *uart_obj) +{ + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + + if (uart_ctrl_ptr->int_status & DW_UART_RXINT_ENABLE) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_RCV); + uart_info_ptr->status |= DEV_IN_RX_ABRT; + + if (uart_info_ptr->uart_cbs.rx_cb != NULL) + { + uart_info_ptr->uart_cbs.rx_cb(uart_obj); + } + + uart_info_ptr->status &= ~(DEV_IN_RX_ABRT); + } +} + +/** Get available transmit fifo count */ +static int32_t dw_uart_get_txavail(DW_UART_CTRL *uart_ctrl_ptr) +{ + int32_t tx_avail = 0; + DW_UART_REG *uart_reg_ptr = (DW_UART_REG *)(uart_ctrl_ptr->dw_uart_regbase); + + if (uart_ctrl_ptr->tx_fifo_len <= 1) + { + if (dw_uart_putready(uart_reg_ptr) == 1) + { + tx_avail = 1; + } + else + { + tx_avail = 0; + } + } + else + { + tx_avail = uart_ctrl_ptr->tx_fifo_len - uart_reg_ptr->TFL; + } + + return tx_avail; +} + +/** Get available receive fifo count */ +static int32_t dw_uart_get_rxavail(DW_UART_CTRL *uart_ctrl_ptr) +{ + int32_t rx_avail = 0; + DW_UART_REG *uart_reg_ptr = (DW_UART_REG *)(uart_ctrl_ptr->dw_uart_regbase); + + if (uart_ctrl_ptr->rx_fifo_len <= 1) + { + if (dw_uart_getready(uart_reg_ptr) == 1) + { + rx_avail = 1; + } + else + { + rx_avail = 0; + } + } + else + { + rx_avail = uart_reg_ptr->RFL; + } + + return rx_avail; +} + + +/** @} end of group DEVICE_DW_UART_STATIC */ + +/** + * \brief open a designware uart device + * \param[in] uart_obj uart object structure pointer + * \param[in] baud baudrate to initialized + * \retval E_OK Open successfully without any issues + * \retval E_OPNED If device was opened before with different baudrate, then return E_OPNED + * \retval E_OBJ Device object is not valid + * \retval E_PAR Parameter is not valid + * \retval E_NOSPT Open settings are not supported + */ +int32_t dw_uart_open(DEV_UART *uart_obj, uint32_t baud) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + DW_UART_CHECK_EXP(baud > 0, E_PAR); + /* END OF ERROR CHECK */ + + uart_info_ptr->opn_cnt ++; + + if (uart_info_ptr->opn_cnt > 1) /* opened before */ + { + if (baud == uart_info_ptr->baudrate) /* baudrate is the same */ + { + return E_OK; + } + else /* open with different baudrate */ + { + return E_OPNED; + } + } + + int32_t baud_divisor = 0; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + /* Get FIFO Length */ + uart_ctrl_ptr->tx_fifo_len = dw_uart_get_txfifo_len(uart_reg_ptr); + uart_ctrl_ptr->rx_fifo_len = dw_uart_get_rxfifo_len(uart_reg_ptr); + + /** init uart */ + uart_info_ptr->baudrate = baud; + baud_divisor = DW_UART_BAUD2DIV(uart_ctrl_ptr->dw_apb_bus_freq, baud); + uart_info_ptr->dps_format = dps_format_default; + uart_info_ptr->hwfc = hwfc_default; + dw_uart_init(uart_reg_ptr, baud_divisor, &(uart_info_ptr->dps_format), uart_info_ptr->hwfc); + + uart_info_ptr->status = DEV_ENABLED; + uart_info_ptr->extra = NULL; + + /** + * uart interrupt related init + */ + dw_uart_disable_interrupt(uart_info_ptr); + /** install uart interrupt into system */ + int_handler_install(uart_ctrl_ptr->intno, uart_ctrl_ptr->dw_uart_int_handler); + + memset(&(uart_info_ptr->tx_buf), 0, sizeof(DEV_BUFFER)); + memset(&(uart_info_ptr->rx_buf), 0, sizeof(DEV_BUFFER)); + memset(&(uart_info_ptr->uart_cbs), 0, sizeof(DEV_UART_CBS)); + +error_exit: + return ercd; +} + +/** + * \brief close a DesignWare UART device + * \param[in] uart_obj uart object structure pointer + * \retval E_OK Open successfully without any issues + * \retval E_OPNED Device is still opened, the device opn_cnt decreased by 1 + * \retval E_OBJ Device object is not valid + */ +int32_t dw_uart_close(DEV_UART *uart_obj) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + DW_UART_CHECK_EXP(uart_info_ptr->opn_cnt > 0, E_OK); + /* END OF ERROR CHECK */ + + uart_info_ptr->opn_cnt --; + + if (uart_info_ptr->opn_cnt == 0) + { + dw_uart_disable_interrupt(uart_info_ptr); + dw_uart_abort_tx(uart_obj); + dw_uart_abort_rx(uart_obj); + dw_uart_flush_output(uart_info_ptr); + memset(&(uart_info_ptr->tx_buf), 0, sizeof(DEV_BUFFER)); + memset(&(uart_info_ptr->rx_buf), 0, sizeof(DEV_BUFFER)); + memset(&(uart_info_ptr->uart_cbs), 0, sizeof(DEV_UART_CBS)); + dw_uart_disable_device(uart_info_ptr); + uart_info_ptr->status = 0; + uart_info_ptr->extra = NULL; + } + else + { + ercd = E_OPNED; + } + +error_exit: + return ercd; +} + +/** + * \brief control uart by ctrl command + * \param[in] uart_obj uart object structure pointer + * \param[in] ctrl_cmd control command code to do specific uart work + * \param[in,out] param parameters used to control uart or return something + * \retval E_OK Control device successfully + * \retval E_CLSED Device is not opened + * \retval E_DIS Device is disabled + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Control device failed, due to hardware issues + * \retval E_CTX Control device failed, due to different reasons like in transfer state + * \retval E_NOSPT Control command is not supported or not valid + */ +int32_t dw_uart_control(DEV_UART *uart_obj, uint32_t ctrl_cmd, void *param) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + DW_UART_CHECK_EXP(uart_info_ptr->opn_cnt > 0, E_CLSED); + /* END OF ERROR CHECK */ + + uint32_t val32; /** to receive unsigned int value */ + int32_t baud_divisor = 0; + DEV_BUFFER *devbuf; + UART_DPS_FORMAT *dps_ptr; + UART_HW_FLOW_CONTROL hwfc_local; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + /* check whether current device is disabled */ + if ((uart_info_ptr->status & DEV_ENABLED) == 0) + { + /** When device is disabled, + * only UART_CMD_ENA_DEV, UART_CMD_DIS_DEV, UART_CMD_GET_STATUS + * are available, other commands will return E_SYS + */ + if ((ctrl_cmd != UART_CMD_ENA_DEV) && \ + (ctrl_cmd != UART_CMD_DIS_DEV) && \ + (ctrl_cmd != UART_CMD_GET_STATUS)) + { + return E_SYS; + } + } + + switch (ctrl_cmd) + { + case UART_CMD_SET_BAUD: + val32 = (uint32_t)param; + DW_UART_CHECK_EXP(val32 > 0, E_PAR); + + if (val32 != uart_info_ptr->baudrate) + { + baud_divisor = DW_UART_BAUD2DIV(uart_ctrl_ptr->dw_apb_bus_freq, val32); + dw_uart_set_baud(uart_reg_ptr, baud_divisor); + uart_info_ptr->baudrate = val32; + } + + break; + + case UART_CMD_GET_STATUS: + DW_UART_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = uart_info_ptr->status; + break; + + case UART_CMD_ENA_DEV: + dw_uart_enable_device(uart_info_ptr); + break; + + case UART_CMD_DIS_DEV: + dw_uart_disable_device(uart_info_ptr); + break; + + case UART_CMD_FLUSH_OUTPUT: + dw_uart_flush_output(uart_info_ptr); + break; + + case UART_CMD_GET_RXAVAIL: + DW_UART_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = dw_uart_get_rxavail(uart_ctrl_ptr); + break; + + case UART_CMD_GET_TXAVAIL: + DW_UART_CHECK_EXP((param != NULL) && CHECK_ALIGN_4BYTES(param), E_PAR); + *((int32_t *)param) = dw_uart_get_txavail(uart_ctrl_ptr); + break; + + case UART_CMD_BREAK_SET: + dw_uart_set_break(uart_reg_ptr); + break; + + case UART_CMD_BREAK_CLR: + dw_uart_clr_break(uart_reg_ptr); + break; + + case UART_CMD_SET_DPS_FORMAT: + DW_UART_CHECK_EXP(param != NULL, E_PAR); + dps_ptr = (UART_DPS_FORMAT *)param; + + if (dw_uart_set_dps(uart_reg_ptr, dps_ptr) == 0) + { + uart_info_ptr->dps_format = *dps_ptr; + } + else + { + ercd = E_PAR; + } + + break; + + case UART_CMD_SET_HWFC: + hwfc_local = (UART_HW_FLOW_CONTROL)param; + DW_UART_CHECK_EXP(((hwfc_local >= UART_FC_NONE) && (hwfc_local <= UART_FC_BOTH)), E_PAR); + dw_uart_set_hwfc(uart_reg_ptr, hwfc_local); + uart_info_ptr->hwfc = hwfc_local; + break; + + case UART_CMD_SET_TXCB: + DW_UART_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + uart_info_ptr->uart_cbs.tx_cb = param; + break; + + case UART_CMD_SET_RXCB: + DW_UART_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + uart_info_ptr->uart_cbs.rx_cb = param; + break; + + case UART_CMD_SET_ERRCB: + DW_UART_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + uart_info_ptr->uart_cbs.err_cb = param; + break; + + case UART_CMD_ABORT_TX: + dw_uart_abort_tx(uart_obj); + break; + + case UART_CMD_ABORT_RX: + dw_uart_abort_rx(uart_obj); + break; + + case UART_CMD_SET_TXINT: + val32 = (uint32_t)param; + + if (val32 == 0) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_SND); + } + else + { + dw_uart_ena_cbr(uart_info_ptr, DW_UART_RDY_SND); + } + + break; + + case UART_CMD_SET_RXINT: + val32 = (uint32_t)param; + + if (val32 == 0) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_RCV); + } + else + { + dw_uart_ena_cbr(uart_info_ptr, DW_UART_RDY_RCV); + } + + break; + + case UART_CMD_SET_TXINT_BUF: + DW_UART_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + + if (param != NULL) + { + devbuf = (DEV_BUFFER *)param; + uart_info_ptr->tx_buf = *devbuf; + uart_info_ptr->tx_buf.ofs = 0; + } + else + { + uart_info_ptr->tx_buf.buf = NULL; + uart_info_ptr->tx_buf.len = 0; + uart_info_ptr->tx_buf.ofs = 0; + } + + break; + + case UART_CMD_SET_RXINT_BUF: + DW_UART_CHECK_EXP(CHECK_ALIGN_4BYTES(param), E_PAR); + + if (param != NULL) + { + devbuf = (DEV_BUFFER *)param; + uart_info_ptr->rx_buf = *devbuf; + uart_info_ptr->rx_buf.ofs = 0; + } + else + { + uart_info_ptr->rx_buf.buf = NULL; + uart_info_ptr->rx_buf.len = 0; + uart_info_ptr->rx_buf.ofs = 0; + } + + break; + + default: + ercd = E_NOSPT; + break; + } + +error_exit: + return ercd; +} + +/** + * \brief send data through DesignWare UART + * \param[in] uart_obj uart object structure pointer + * \param[in] data data that need to send (data must be char type) + * \param[in] len data length need to send + * \retval >0 Byte count that was successfully sent for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Can't write data to hardware due to hardware issues + */ +int32_t dw_uart_write(DEV_UART *uart_obj, const void *data, uint32_t len) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + DW_UART_CHECK_EXP(uart_info_ptr->opn_cnt > 0, E_CLSED); + DW_UART_CHECK_EXP(uart_info_ptr->status & DEV_ENABLED, E_SYS); + DW_UART_CHECK_EXP(data != NULL, E_PAR); + DW_UART_CHECK_EXP(len > 0, E_PAR); + /* END OF ERROR CHECK */ + + int32_t i = 0; + const char *p_charbuf = (const char *)data; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + while (i < len) + { + dw_uart_psnd_chr(uart_reg_ptr, p_charbuf[i++]); + } + + ercd = i; + +error_exit: + return ercd; +} + +/** + * \brief read data through DesignWare UART + * \param[in] uart_obj uart object structure pointer + * \param[out] data data that need to read (data must be char type) + * \param[in] len data count need to read + * \retval >0 Byte count that was successfully sent for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Can't receive data from hardware due to hardware issues, such as device is disabled + */ +int32_t dw_uart_read(DEV_UART *uart_obj, void *data, uint32_t len) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + DW_UART_CHECK_EXP(uart_info_ptr->opn_cnt > 0, E_CLSED); + DW_UART_CHECK_EXP(uart_info_ptr->status & DEV_ENABLED, E_SYS); + DW_UART_CHECK_EXP(data != NULL, E_PAR); + DW_UART_CHECK_EXP(len > 0, E_PAR); + /* END OF ERROR CHECK */ + + int32_t i = 0; + char *p_charbuf = (char *)data; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + while (i < len) + { + p_charbuf[i++] = dw_uart_prcv_chr(uart_reg_ptr); + } + + ercd = i; + +error_exit: + return ercd; +} + +/** + * \brief DesignWare UART interrupt processing routine + * \param[in] uart_obj uart object structure pointer + * \param[in] ptr extra information + */ +void dw_uart_isr(DEV_UART *uart_obj, void *ptr) +{ + int32_t ercd = E_OK; + DEV_UART_INFO *uart_info_ptr = &(uart_obj->uart_info); + + /* START ERROR CHECK */ + VALID_CHK_UART_INFO_OBJECT(uart_info_ptr); + /* END OF ERROR CHECK */ + + uint32_t uart_int_status; /** uart interrupt status */ + volatile uint32_t temp; /** read error status to clear interrupt */ + DEV_BUFFER *buf_ptr; + char *p_charbuf; + + DW_UART_CTRL *uart_ctrl_ptr = (DW_UART_CTRL_PTR)(uart_info_ptr->uart_ctrl); + DW_UART_REG *uart_reg_ptr = (DW_UART_REG_PTR)(uart_ctrl_ptr->dw_uart_regbase); + + /** get uart interrupt status */ + uart_int_status = (uart_reg_ptr->IIR) & DW_UART_IIR_INT_ID_MASK; + + switch (uart_int_status) + { + case DW_UART_IIR_MDM_STATUS: + temp = (volatile uint32_t)(uart_reg_ptr->MSR); + break; + + case DW_UART_IIR_LINE_STATUS: + if (uart_info_ptr->uart_cbs.err_cb) + { + uart_info_ptr->uart_cbs.err_cb(uart_info_ptr); + } + + temp = (volatile uint32_t)(uart_reg_ptr->LSR); + break; + + case DW_UART_IIR_XMIT_EMPTY: + buf_ptr = &(uart_info_ptr->tx_buf); + p_charbuf = (char *)buf_ptr->buf; + + if (p_charbuf != NULL) + { + while (dw_uart_putready(uart_reg_ptr)) + { + dw_uart_putchar(uart_reg_ptr, p_charbuf[buf_ptr->ofs]); + buf_ptr->ofs ++; + + if (buf_ptr->ofs >= buf_ptr->len) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_SND); + + if (uart_info_ptr->uart_cbs.tx_cb) + { + uart_info_ptr->uart_cbs.tx_cb(uart_obj); + } + + /* clear the send buffer pointer */ + memset(buf_ptr, 0, sizeof(DEV_BUFFER)); + break; + } + } + } + else + { + if (uart_info_ptr->uart_cbs.tx_cb) + { + uart_info_ptr->uart_cbs.tx_cb(uart_obj); + } + } + + break; + + case DW_UART_IIR_RX_TIMEOUT: + temp = dw_uart_getchar(uart_reg_ptr); + break; + + case DW_UART_IIR_DATA_AVAIL: + buf_ptr = &(uart_info_ptr->rx_buf); + p_charbuf = (char *)buf_ptr->buf; + + if (p_charbuf != NULL) + { + while (dw_uart_getready(uart_reg_ptr)) + { + p_charbuf[buf_ptr->ofs] = (char)dw_uart_getchar(uart_reg_ptr); + buf_ptr->ofs ++; + + if (buf_ptr->ofs >= buf_ptr->len) + { + dw_uart_dis_cbr(uart_info_ptr, DW_UART_RDY_RCV); + + if (uart_info_ptr->uart_cbs.rx_cb) + { + uart_info_ptr->uart_cbs.rx_cb(uart_obj); + } + + /* clear the send buffer pointer */ + memset(buf_ptr, 0, sizeof(DEV_BUFFER)); + break; + } + } + } + else + { + if (uart_info_ptr->uart_cbs.rx_cb) + { + uart_info_ptr->uart_cbs.rx_cb(uart_obj); + } + } + + break; + + default: + temp = (volatile uint32_t)(uart_reg_ptr->USR); + break; + } + +error_exit: + return; +} diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.h new file mode 100644 index 000000000..8ce47f92b --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart.h @@ -0,0 +1,143 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-20 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup DEVICE_DW_UART + * \brief DesignWare UART driver header file + * \details detailed definitions of designware uart driver + */ + +#ifndef _DW_UART_H_ +#define _DW_UART_H_ + +#include "device/device_hal/inc/dev_uart.h" + +#include "inc/arc/arc_exception.h" + +/** + * if this header file is included, + * will indicate that this designware uart device + * is used + */ +#define DEVICE_USE_DESIGNWARE_UART + +/** + * \name DesignWare UART Register Structure + * \brief contains definitions of DesignWare UART register structure. + * @{ + */ +/** + * \brief DesignWare UART register structure + * \details Detailed struct description of DesignWare UART + * block register information, implementation of dev_uart_info::uart_regs + */ +typedef volatile struct dw_uart_reg +{ + uint32_t DATA; /*!< data in/out and DLL */ + uint32_t IER; /*!< Interrupt enable register and DLH */ + uint32_t IIR; /*!< Interrupt Id register and FCR */ + uint32_t LCR; /*!< Line control Register */ + uint32_t MCR; /*!< Modem control register */ + uint32_t LSR; /*!< Line Status Register */ + uint32_t MSR; /*!< Modem status Register */ + uint32_t SCRATCHPAD; /*!< Uart scratch pad register */ + uint32_t LPDLL; /*!< Low Power Divisor Latch (Low) Reg */ + uint32_t LPDLH; /*!< Low Power Divisor Latch (High) Reg */ + uint32_t RES1[2]; /*!< Reserved */ + uint32_t SHR[16]; /*!< Shadow data register(SRBR and STHR) */ + uint32_t FAR; /*!< FIFO Access register */ + uint32_t TFR; /*!< Transmit FIFO Read */ + uint32_t RFW; /*!< Receive FIFO write */ + uint32_t USR; /*!< UART status register */ + uint32_t TFL; /*!< Transmit FIFO level */ + uint32_t RFL; /*!< Receive FIFO level */ + uint32_t SRR; /*!< Software reset register */ + uint32_t SRTS; /*!< Shadow request to send */ + uint32_t SBCR; /*!< Shadow break control */ + uint32_t SDMAM; /*!< Shadow DMA mode */ + uint32_t SFE; /*!< Shadow FIFO enable */ + uint32_t SRT; /*!< Shadow RCVR Trigger */ + uint32_t STET; /*!< Shadow TX empty register */ + uint32_t HTX; /*!< Halt TX */ + uint32_t DMASA; /*!< DMA Software ACK */ + uint32_t RES2[18]; /*!< Reserved */ + uint32_t CPR; /*!< Camponent parameter register */ + uint32_t UCV; /*!< UART Component Version */ + uint32_t CTR; /*!< Component typw register */ +} DW_UART_REG, *DW_UART_REG_PTR; +/** @} */ + +#define DW_UART_GINT_DISABLED (0) /*!< designware interrupt disabled for control uart irq/fiq */ +#define DW_UART_GINT_ENABLE (1<<0) /*!< designware interrupt enabled for control uart irq/fiq */ +#define DW_UART_TXINT_ENABLE (1<<1) /*!< designware interrupt enabled for control transmit process */ +#define DW_UART_RXINT_ENABLE (1<<2) /*!< designware interrupt enabled for control transmit process */ + +/** + * \brief DesignWare UART control structure definition + * \details implement of dev_uart_info::uart_ctrl + */ +typedef struct dw_uart_ctrl +{ + uint32_t dw_uart_regbase; /*!< uart ip register base */ + uint32_t dw_apb_bus_freq; /*!< uart ip apb bus frequency */ + uint32_t intno; /*!< uart interrupt vector number */ + INT_HANDLER dw_uart_int_handler; /*!< uart interrupt handler */ + uint32_t tx_fifo_len; /*!< transmit fifo length, set by user in object implementation */ + uint32_t rx_fifo_len; /*!< receive fifo length, set by user in object implementation */ + uint32_t int_status; /*!< interrupt status for designware uart */ +} DW_UART_CTRL, *DW_UART_CTRL_PTR; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name DesignWare UART Function Declaration + * \brief contains declarations of designware uart functions. + * \details This are only used in uart object implementation source file + * @{ + */ +extern int32_t dw_uart_open(DEV_UART *uart_obj, uint32_t baud); +extern int32_t dw_uart_close(DEV_UART *uart_obj); +extern int32_t dw_uart_control(DEV_UART *uart_obj, uint32_t ctrl_cmd, void *param); +extern int32_t dw_uart_write(DEV_UART *uart_obj, const void *data, uint32_t len); +extern int32_t dw_uart_read(DEV_UART *uart_obj, void *data, uint32_t len); +extern void dw_uart_isr(DEV_UART *uart_obj, void *ptr); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DW_UART_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart_hal.h b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart_hal.h new file mode 100644 index 000000000..8e45c7739 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/designware/uart/dw_uart_hal.h @@ -0,0 +1,253 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-20 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup DEVICE_DW_IIC + * \brief DesignWare UART driver hardware description related header file + * \details detailed hardware related definitions of DesignWare UART driver + */ + +#ifndef _DEVICE_DW_UART_HAL_H_ +#define _DEVICE_DW_UART_HAL_H_ + +/* DW APB UART bit definitions */ + +/** + * \name DesignWare UART HAL IER Marcos + * \brief DesignWare UART hal IER related macros + * @{ + */ +/* IER */ +#define DW_UART_IER_DATA_AVAIL (0x01) +#define DW_UART_IER_XMIT_EMPTY (0x02) +#define DW_UART_IER_LINE_STATUS (0x04) +#define DW_UART_IER_MDM_STATUS (0x08) +#define DW_UART_IER_PTIME (0x80) +/** @} */ + +/** + * \name DesignWare UART HAL IIR Marcos + * \brief DesignWare UART hal IIR related macros + * @{ + */ +/* IIR */ +/* IIR READ */ +#define DW_UART_IIR_IP (0x01) +#define DW_UART_IIR_MASK (0x0E) +#define DW_UART_IIR_READ_FIFO_ENABLE (0xC0) + +/* Possible interrupt IIR_MASK values */ +#define DW_UART_IIR_MDM_STATUS (0x00) +#define DW_UART_IIR_XMIT_EMPTY (0x02) +#define DW_UART_IIR_DATA_AVAIL (0x04) +#define DW_UART_IIR_LINE_STATUS (0x06) +#define DW_UART_IIR_RX_TIMEOUT (0x0C) +#define DW_UART_IIR_INT_ID_MASK (0x0f) + +/* IIR WRITE */ +#define DW_UART_IIR_FIFO_ENABLE (0x01) +#define DW_UART_IIR_RCVR_FIFO_RESET (0x02) +#define DW_UART_IIR_XMIT_FIFO_RESET (0x04) +#define DW_UART_IIR_DMA_MODE_SELECT (0x08) +#define DW_UART_IIR_RCV_TRIGGER_MASK (0xC0) + +/* Values for IIR receive trigger */ +#define DW_UART_IIR_TRIGGER_LEVEL_1_CHAR (0x00) +#define DW_UART_IIR_TRIGGER_LEVEL_1_4_FULL (0x40) +#define DW_UART_IIR_TRIGGER_LEVEL_1_2_FULL (0x80) +#define DW_UART_IIR_TRIGGER_LEVEL_2_LESS_FULL (0xC0) +/** @} */ + +/** + * \name DesignWare UART HAL LCR Marcos + * \brief DesignWare UART hal LCR related macros + * @{ + */ +/* LCR */ +#define DW_UART_LCR_WORD_LEN_MASK (0x03) +#define DW_UART_LCR_STOP_BIT_MASK (0x04) +#define DW_UART_LCR_PARITY_MASK (0x38) +#define DW_UART_LCR_DPS_MASK (0x3F) +#define DW_UART_LCR_STICK_PARITY (0x20) +#define DW_UART_LCR_BREAK (0x40) +#define DW_UART_LCR_DLAB (0x80) + +/* Word length values */ +#define DW_UART_LCR_WORD_LEN5 (0x00) +#define DW_UART_LCR_WORD_LEN6 (0x01) +#define DW_UART_LCR_WORD_LEN7 (0x02) +#define DW_UART_LCR_WORD_LEN8 (0x03) + +/* stop bit values */ +#define DW_UART_LCR_1_STOP_BIT (0x00) +#define DW_UART_LCR_1D5_STOP_BIT (0x04) +#define DW_UART_LCR_2_STOP_BIT (0x04) + +/* Parity bit values */ +#define DW_UART_LCR_PARITY_NONE (0x00) +#define DW_UART_LCR_PARITY_ODD (0x08) +#define DW_UART_LCR_PARITY_EVEN (0x18) +#define DW_UART_LCR_PARITY_MARK (0x28) +#define DW_UART_LCR_PARITY_SPACE (0x38) + +/** @} */ + +/** + * \name DesignWare UART HAL MCR Marcos + * \brief DesignWare UART hal MCR related macros + * @{ + */ +/* MCR */ +#define DW_UART_MCR_DTR (0x01) +#define DW_UART_MCR_RTS (0x02) +#define DW_UART_MCR_LOOPBACK (0x10) +#define DW_UART_MCR_AFCE (0x20) +#define DW_UART_MCR_SIRE (0x40) +/** @} */ + +/** + * \name DesignWare UART HAL LSR Marcos + * \brief DesignWare UART hal LSR related macros + * @{ + */ +/* LSR */ +#define DW_UART_LSR_DR (0x01) +#define DW_UART_LSR_OVERRUN (0x02) +#define DW_UART_LSR_PARITYERR (0x04) +#define DW_UART_LSR_FRAMEERR (0x08) +#define DW_UART_LSR_BREAKRCVD (0x10) +#define DW_UART_LSR_TXD_EMPTY (0x20) +#define DW_UART_LSR_TX_STATUS (0x40) +#define DW_UART_LSR_RX_FIFOERR (0x80) +/** @} */ + +/** + * \name DesignWare UART HAL MSR Marcos + * \brief DesignWare UART hal MSR related macros + * @{ + */ +/* MSR */ +#define DW_UART_MSR_DCTS (0x01) +#define DW_UART_MSR_DDSR (0x02) +#define DW_UART_MSR_TERI (0x04) +#define DW_UART_MSR_DDCD (0x08) +#define DW_UART_MSR_CTS (0x10) +#define DW_UART_MSR_DSR (0x20) +#define DW_UART_MSR_RIC (0x40) +#define DW_UART_MSR_DCD (0x80) +/** @} */ + +/** + * \name DesignWare UART HAL FCR Marcos + * \brief DesignWare UART hal FCR related macros + * @{ + */ +/* FCR */ +#define DW_UART_FCR_FEN (0x01) +#define DW_UART_FCR_RFR (0x02) +#define DW_UART_FCR_TFR (0x04) +#define DW_UART_FCR_DMS (0x08) +#define DW_UART_FCR_RTL (0xC0) +/** @} */ + +/** + * \name DesignWare UART HAL USR Marcos + * \brief DesignWare UART hal USR related macros + * @{ + */ +/* USR */ +#define DW_UART_USR_BUSY (0x01) +#define DW_UART_USR_TFNF (0x02) +#define DW_UART_USR_TFE (0x04) +#define DW_UART_USR_RFNE (0x08) +#define DW_UART_USR_RFF (0x10) +/** @} */ + +/** + * \name DesignWare UART HAL SFE Marcos + * \brief DesignWare UART hal SFE related macros + * @{ + */ +/* SFE */ +#define DW_UART_SFE_SHADOW_FIFO_ENABLE (0x01) +/** @} */ + +/** + * \name DesignWare UART HAL SRR Marcos + * \brief DesignWare UART hal SRR related macros + * @{ + */ +/* SRR */ +#define DW_UART_SRR_UR (0x01) +#define DW_UART_SRR_RFR (0x02) +#define DW_UART_SRR_XFR (0x04) +/** @} */ + +/** + * \name DesignWare UART HAL SRT Marcos + * \brief DesignWare UART hal SRT related macros + * @{ + */ +/* SRT */ +#define DW_UART_SRT_TRIGGER_LEVEL_1_CHAR (0x00) +#define DW_UART_SRT_TRIGGER_LEVEL_1_4_FULL (0x01) +#define DW_UART_SRT_TRIGGER_LEVEL_1_2_FULL (0x02) +#define DW_UART_SRT_TRIGGER_LEVEL_2_LESS_FULL (0x03) +/** @} */ + +/** + * \name DesignWare UART HAL STET Marcos + * \brief DesignWare UART hal STET related macros + * @{ + */ +/* STET*/ +#define DW_UART_STET_FIFO_EMPTY (0x00) +#define DW_UART_STET_2_CHARS_IN_FIFO (0x01) +#define DW_UART_STET_1_4_FULL (0x02) +#define DW_UART_STET_1_2_FULL (0x03) +/** @} */ + +/** + * \name DesignWare UART HAL CPR Marcos + * \brief DesignWare UART hal CPR related macros + * @{ + */ +/* CPR*/ +#define DW_UART_CPR_FIFO_STAT (1<<10) +#define DW_UART_CPR_FIFO_MODE_OFS (16) +#define DW_UART_CPR_FIFO_MODE_MASK (0xFF) +#define DW_UART_CPR_FIFO_MODE (0xFF0000) +/** @} */ + +#endif /* _DEVICE_DW_UART_HAL_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_common.h b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_common.h new file mode 100644 index 000000000..daa54e5a8 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_common.h @@ -0,0 +1,174 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-16 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_HAL_COMMON Common Device Layer Definitions + * \ingroup DEVICE_HAL_DEF + * \brief common definitions for device layer (\ref dev_common.h) + * + * @{ + * + * \file + * \brief header file to define common definitions for device layer + * \details Here in this file provide definitions that need by other + * devices in device layer + */ + +#ifndef _DEVICE_HAL_COMMON_H_ +#define _DEVICE_HAL_COMMON_H_ + +#include + +/** + * \defgroup DEVICE_HAL_COMMON_DEVSTATE Common Device State + * \ingroup DEVICE_HAL_COMMON + * \brief definitions for device state + * \details here defines macros for device open/close, + * device working good/error, used in + * \ref DEVICE_HAL_UART, \ref DEVICE_HAL_SPI, + * \ref DEVICE_HAL_IIC, \ref DEVICE_HAL_GPIO + * @{ + */ +/* + * macros for device open and close state + */ +#define DEV_CLOSED (0) /*!< Indicate that device was closed */ +#define DEV_OPENED (1) /*!< Indicate that the device was opened */ + +/* + * macros for device good and error state + */ +#define DEV_GOOD (0) /*!< Indicate device is good */ +#define DEV_ERROR (1) /*!< Indicate device error */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_COMMON_DEVMTHD Common Device Working Method + * \ingroup DEVICE_HAL_COMMON + * \brief definitions for device working method(interrupt or poll) + * \details here defines macros for working method, + * interrupt or poll method,used in + * \ref DEVICE_HAL_UART, \ref DEVICE_HAL_SPI, + * \ref DEVICE_HAL_IIC, \ref DEVICE_HAL_GPIO + * @{ + */ +/* + * macros for device working method + */ +#define DEV_POLL_METHOD (0) /*!< Indicate that the device running in poll method */ +#define DEV_INTERRUPT_METHOD (1) /*!< Indicate that the device running in interrupt method */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_COMMON_DEVMODE Common Device Working Mode + * \ingroup DEVICE_HAL_COMMON + * \brief definitions for device working mode(master or slave) + * \details here defines macros for working mode, + * Master or Slave mode,used in + * \ref DEV_HAL_IIC, \ref DEV_HAL_SPI. + * @{ + */ +/* + * macros for device working mode + */ +#define DEV_MASTER_MODE (0) /*!< Indicate that the device working as master */ +#define DEV_SLAVE_MODE (1) /*!< Indicate that the device working as slave */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_COMMON_DEVSTATUS Common Device Status + * \ingroup DEVICE_HAL_COMMON + * \brief definitions for device status, 1 bit for 1 function + * @{ + */ +#define DEV_DISABLED (0) /*!< Bit 0 for device enabled state, disabled */ +#define DEV_ENABLED (1<<0) /*!< Bit 0 for device enabled state, enabled */ +#define DEV_IN_TX (1<<1) /*!< Bit 1 for device in transmit state */ +#define DEV_IN_RX (1<<2) /*!< Bit 2 for device in receive state */ +#define DEV_IN_XFER (1<<3) /*!< Bit 3 for device in transfer state */ +#define DEV_IN_TX_ABRT (1<<4) /*!< Bit 4 for device in transmit abort state */ +#define DEV_IN_RX_ABRT (1<<5) /*!< Bit 5 for device in receive abort state */ +#define DEV_IN_XFER_ABRT (1<<6) /*!< Bit 6 for device in transfer abort state */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_COMMON_DEFCMD Common Device Defining Command + * \ingroup DEVICE_HAL_COMMON + * \brief definitions for defining command code + * \details here defines macros to define command code, + * in system code, use \ref DEV_SET_SYSCMD to define command code. + * in user code, use \ref DEV_SET_USRCMD to define command code. + * So that there will be no conflicts in system and user defined command code. + * this used used in + * \ref DEVICE_HAL_UART, \ref DEVICE_HAL_SPI, + * \ref DEVICE_HAL_IIC, \ref DEVICE_HAL_GPIO, + * and in user code + * @{ + */ +/* + * macros for control command base + */ +#define DEV_SYS_CMDBSE (0x00000000) /*!< default system device control command base(defined by embARC) */ +#define DEV_USR_CMDBSE (0x80000000) /*!< default user device control command base(defined by user) in user implementing */ +#define DEV_SET_SYSCMD(cmd) (DEV_SYS_CMDBSE|(cmd)) /*!< set device system control command */ +#define DEV_SET_USRCMD(cmd) (DEV_USR_CMDBSE|(cmd)) /*!< set device user control command */ + +#define CONV2VOID(param) ((void *)(param)) /*!< convert param into void * type */ +/** @} */ + +/** + * Common Device Buffer Structure + */ +typedef struct dev_buffer +{ + void *buf; /*!< buffer pointer */ + uint32_t len; /*!< buffer length in bytes */ + uint32_t ofs; /*!< current offset in buffer */ +} DEV_BUFFER; + +/** Init device buffer */ +#define DEV_BUFFER_INIT(devbuf, buffer, size) { \ + (devbuf)->buf = (void *)(buffer); \ + (devbuf)->len = (uint32_t)(size); \ + (devbuf)->ofs = (uint32_t)(0); \ + } + +/** + * Device callback function typedef. + * This is usually used in device callback settings, + * and \ptr should be the device object pointer, + * such as DEV_IIC * */ +typedef void (*DEV_CALLBACK)(void *ptr); + +/** @} */ +#endif /* _DEVICE_HAL_COMMON_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_gpio.h b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_gpio.h new file mode 100644 index 000000000..d64d15352 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_gpio.h @@ -0,0 +1,431 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-17 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_HAL_GPIO GPIO Device HAL Interface + * \ingroup DEVICE_HAL_DEF + * \brief definitions for gpio device hardware layer (\ref dev_gpio.h) + * \details provide interfaces for gpio driver to implement + * Here is a diagram for the gpio interface. + * + * \htmlonly + *
+ *
+ * GPIO Device HAL Interface Diagram + *

GPIO Device HAL Interface Diagram

+ *
+ *
+ * \endhtmlonly + * + * @{ + * + * \file + * \brief gpio device hardware layer definitions + * \details Provide common definitions for gpio device, + * then the software developer can develop gpio driver + * following these definitions, and the applications + * can directly call this definition to realize functions + * + */ + +#ifndef _DEVICE_HAL_GPIO_H_ +#define _DEVICE_HAL_GPIO_H_ + +#include "device/device_hal/inc/dev_common.h" + +/** + * \defgroup DEVICE_HAL_GPIO_DEFDIR GPIO Port Direction Definition + * \ingroup DEVICE_HAL_GPIO + * \brief Define macros to indicate gpio directions + * @{ + */ +/* + * defines for gpio directions + */ +#define GPIO_DIR_INPUT (0) /*!< gpio works as input */ +#define GPIO_DIR_OUTPUT (1) /*!< gpio works as output */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_GPIO_CTRLCMD GPIO Device Control Commands + * \ingroup DEVICE_HAL_GPIO + * \brief Definitions for gpio control command, used in \ref dev_gpio::gpio_control "GPIO IO Control" + * \details These commands defined here can be used in user code directly. + * - Parameters Usage + * - For passing parameters like integer, just use uint32_t/int32_t to directly pass values + * - For passing parameters for a structure, please use pointer to pass values + * - For getting some data, please use pointer to store the return data + * - Common Return Values + * - \ref E_OK, Control device successfully + * - \ref E_CLSED, Device is not opened + * - \ref E_OBJ, Device object is not valid or not exists + * - \ref E_PAR, Parameter is not valid for current control command + * - \ref E_SYS, Control device failed, due to hardware issues such as device is disabled + * - \ref E_NOSPT, Control command is not supported or not valid + * @{ + */ +/** + * Set the \ref dev_gpio_info::direction "direction" of masked bits of gpio port into \ref GPIO_DIR_INPUT "input" + * - Param type : uint32_t + * - Param usage : 1 in each bit will be masked. + * - Return value explanation : + */ +#define GPIO_CMD_SET_BIT_DIR_INPUT DEV_SET_SYSCMD(0) +/** + * Set the \ref dev_gpio_info::direction "direction" of masked bits of gpio port into \ref GPIO_DIR_OUTPUT "output" + * - Param type : uint32_t + * - Param usage : 1 in each bit will be masked. + * - Return value explanation : + */ +#define GPIO_CMD_SET_BIT_DIR_OUTPUT DEV_SET_SYSCMD(1) +/** + * Get \ref dev_gpio_info::direction "gpio port direction". + * - Param type : uint32_t + * - Param usage : 1 bit for 1 bit of gpio port, 0 for input, 1 for output + * - Return value explanation : + */ +#define GPIO_CMD_GET_BIT_DIR DEV_SET_SYSCMD(2) +/** + * Set gpio interrupt configuration for each bit. + * - Param type : \ref DEV_GPIO_INT_CFG * + * - Param usage : store gpio interrupt configuration for each bit. + * - Return value explanation : + */ +#define GPIO_CMD_SET_BIT_INT_CFG DEV_SET_SYSCMD(3) +/** + * Get gpio interrupt configuration for each bit. + * - Param type : \ref DEV_GPIO_INT_CFG * + * - Param usage : First set int_bit_mask in DEV_GPIO_INT_CFG structure to + * the mask of which bit of GPIO you want to get. And the interrupt configuration + * will be stored in the structure DEV_GPIO_INT_CFG, each bit stand for each bit of port. + * - Return value explanation : + */ +#define GPIO_CMD_GET_BIT_INT_CFG DEV_SET_SYSCMD(4) +/** + * Set gpio service routine for each bit. + * - Param type : \ref DEV_GPIO_BIT_ISR * + * - Param usage : store gpio handler information for each bit, int handler's param will be DEV_GPIO *. + * - Return value explanation : + */ +#define GPIO_CMD_SET_BIT_ISR DEV_SET_SYSCMD(5) +/** + * Get gpio service routine for each bit. + * - Param type : \ref DEV_GPIO_BIT_ISR * + * - Param usage : By passing int_bit_ofs in DEV_GPIO_BIT_ISR, + * it will return interrupt handler for this bit and store it in int_bit_handler. + * - Return value explanation : + */ +#define GPIO_CMD_GET_BIT_ISR DEV_SET_SYSCMD(6) +/** + * Enable gpio interrupt of the masked bits. + * - Param type : uint32_t + * - Param usage : 1 in each bit will be masked. + * - Return value explanation : + */ +#define GPIO_CMD_ENA_BIT_INT DEV_SET_SYSCMD(7) +/** + * Disable gpio interrupt of the masked bits. + * - Param type : uint32_t + * - Param usage : 1 in each bit will be masked. + * - Return value explanation : + */ +#define GPIO_CMD_DIS_BIT_INT DEV_SET_SYSCMD(8) +/** + * Get \ref dev_gpio_info::method "gpio interrupt enable status". + * - Param type : uint32_t * + * - Param usage : 1 bit for 1 bit of gpio port, 0 for poll, 1 for interrupt + * - Return value explanation : + */ +#define GPIO_CMD_GET_BIT_MTHD DEV_SET_SYSCMD(9) +/* @} */ + +/** + * \defgroup DEVICE_HAL_GPIO_INT_CFG_SET GPIO Device Int Configuration Settings + * \ingroup DEVICE_HAL_GPIO + * \brief definition of gpio interrupt type + * @{ + */ + +/* GPIO Mask Defintions */ +/** Mask none bits of the max 32bits */ +#define GPIO_BITS_MASK_NONE (0) +/** Mask all bits of the max 32bits */ +#define GPIO_BITS_MASK_ALL (0XFFFFFFFF) + +/* GPIO Interrupt Type Related Definitions */ + +/** Level sensitive interrupt type for 1 bit */ +#define GPIO_INT_LEVEL_TRIG (0) +/** Edge sensitive interrupt type for 1 bit */ +#define GPIO_INT_EDGE_TRIG (1) +/** Level sensitive interrupt type for all 32 bits */ +#define GPIO_INT_LEVEL_TRIG_ALL (0) +/** Edge sensitive interrupt type for all 32 bits */ +#define GPIO_INT_EDGE_TRIG_ALL (0XFFFFFFFF) + +/* For bit settings */ +/** Set bit interrupt type of gpio into level sensitive */ +#define GPIO_INT_BIT_LEVEL_TRIG(bit_ofs) (GPIO_INT_LEVEL_TRIG<<(bit_ofs)) +/** Set bit interrupt type of gpio into edge sensitive */ +#define GPIO_INT_BIT_EDGE_TRIG(bit_ofs) (GPIO_INT_EDGE_TRIG<<(bit_ofs)) +/* For bits settings */ +/** Set interrupt type of masked bits of gpio into level sensitive */ +#define GPIO_INT_BITS_LEVEL_TRIG(bit_mask) (GPIO_INT_LEVEL_TRIG_ALL&(bit_mask)) +/** Set bit interrupt type of gpio into edge sensitive */ +#define GPIO_INT_BITS_EDGE_TRIG(bit_mask) (GPIO_INT_EDGE_TRIG_ALL&(bit_mask)) + +/* GPIO Interrupt Polarity Related Definitions */ + +/** GPIO Interrupt polarity type enum */ +typedef enum gpio_int_polarity +{ + /* Polarity for 1 bit */ + GPIO_INT_ACTIVE_LOW = 0, /*!< Active low for level-sensitive interrupt for 1 bit */ + GPIO_INT_FALLING_EDGE = 0, /*!< Falling-edge for edge-sensitive interrupt for 1 bit */ + GPIO_INT_ACTIVE_HIGH = 1, /*!< Active high for level-sensitive interrupt for 1 bit */ + GPIO_INI_RISING_EDGE = 1, /*!< Rising-edge for edge-sensitive interrupt for 1 bit */ + /* Polartiy for all 32 bits */ + GPIO_INT_ACTIVE_LOW_ALL = 0, /*!< Active low for level-sensitive interrupt for all bits */ + GPIO_INT_FALLING_EDGE_ALL = 0, /*!< Falling-edge for edge-sensitive interrupt for all bits */ + GPIO_INT_ACTIVE_HIGH_ALL = 0XFFFFFFFF, /*!< Active high for level-sensitive interrupt for all bits */ + GPIO_INI_RISING_EDGE_ALL = 0XFFFFFFFF /*!< Rising-edge for edge-sensitive interrupt for all bits */ +} GPIO_INT_POLARITY; + +/* For bit settings */ +/** Set bit polarity of gpio into active low */ +#define GPIO_INT_BIT_POL_ACT_LOW(bit_ofs) (GPIO_INT_ACTIVE_LOW<<(bit_ofs)) +/** Set bit polarity of gpio into active high */ +#define GPIO_INT_BIT_POL_ACT_HIGH(bit_ofs) (GPIO_INT_ACTIVE_HIGH<<(bit_ofs)) +/** Set bit polarity of gpio into falling edge */ +#define GPIO_INT_BIT_POL_FALL_EDGE(bit_ofs) (GPIO_INT_FALLING_EDGE<<(bit_ofs)) +/** Set bit polarity of gpio into rising edge */ +#define GPIO_INT_BIT_POL_RISE_EDGE(bit_ofs) (GPIO_INI_RISING_EDGE<<(bit_ofs)) + +/* For bits settings */ +/** Set polarity of masked bits of gpio into active low */ +#define GPIO_INT_BITS_POL_ACT_LOW(bit_mask) (GPIO_INT_ACTIVE_LOW_ALL&(bit_mask)) +/** Set polarity of masked bits of gpio into active high */ +#define GPIO_INT_BITS_POL_ACT_HIGH(bit_mask) (GPIO_INT_ACTIVE_HIGH_ALL&(bit_mask)) +/** Set polarity of masked bits of gpio into falling edge */ +#define GPIO_INT_BITS_POL_FALL_EDGE(bit_mask) (GPIO_INT_FALLING_EDGE_ALL&(bit_mask)) +/** Set polarity of masked bits of gpio into rising edge */ +#define GPIO_INT_BITS_POL_RISE_EDGE(bit_mask) (GPIO_INI_RISING_EDGE_ALL&(bit_mask)) + +/* GPIO Interrupt Debounce Related Definitions */ + +/* For bit settings */ +/** Disable debounce circuitry for 1 bit */ +#define GPIO_INT_NO_DEBOUNCE (0) +/** Enable debounce circuitry for 1 bit */ +#define GPIO_INT_DEBOUNCE (1) + +/* For bits settings */ +/** Disable debounce circuitry for all bits */ +#define GPIO_INT_NO_DEBOUNCE_ALL (0) +/** Enable debounce circuitry for all bits */ +#define GPIO_INT_DEBOUNCE_ALL (0XFFFFFFFF) + +/* For bit settings */ +/** Set bit interrupt debounce of gpio into enabled */ +#define GPIO_INT_BIT_ENA_DEBOUNCE(bit_ofs) (GPIO_INT_DEBOUNCE<<(bit_ofs)) +/** Set bit interrupt debounce of gpio into disabled */ +#define GPIO_INT_BIT_DIS_DEBOUNCE(bit_ofs) (GPIO_INT_NO_DEBOUNCE<<(bit_ofs)) +/* For bits settings */ +/** Set bit interrupt debounce of gpio into enabled */ +#define GPIO_INT_BITS_ENA_DEBOUNCE(bit_mask) (GPIO_INT_DEBOUNCE_ALL&(bit_mask)) +/** Set bit interrupt debounce of gpio into disabled */ +#define GPIO_INT_BITS_DIS_DEBOUNCE(bit_mask) (GPIO_INT_NO_DEBOUNCE_ALL&(bit_mask)) + +/** GPIO interrupt configuration */ +typedef struct dev_gpio_int_cfg +{ + uint32_t int_bit_mask; /*!< interrupt bit mask for gpio */ + uint32_t int_bit_type; /*!< \ref GPIO_INT_LEVEL_TRIG "level sensitive" or \ref GPIO_INT_EDGE_TRIG "edge sensitive" for each gpio bit */ + uint32_t int_bit_polarity; /*!< active high or low, refer to \ref GPIO_INT_POLARITY for each gpio bit */ + uint32_t int_bit_debounce; /*!< \ref GPIO_INT_DEBOUNCE "enable" or \ref GPIO_INT_NO_DEBOUNCE "disable" debounce logic for each gpio bit */ +} DEV_GPIO_INT_CFG, * DEV_GPIO_INT_CFG_PTR; + +/** Default interrupt configuration for all gpio bits */ +static const DEV_GPIO_INT_CFG gpio_int_cfg_default = \ +{ + GPIO_BITS_MASK_ALL, GPIO_INT_LEVEL_TRIG_ALL, \ + GPIO_INT_ACTIVE_LOW_ALL, GPIO_INT_NO_DEBOUNCE_ALL +}; + +/** GPIO interrupt handler or Interrupt Service Routine(ISR) */ +typedef void (*DEV_GPIO_HANDLER)(void *ptr); + +/** interrupt handler for each port bit */ +typedef struct dev_gpio_bit_isr +{ + uint32_t int_bit_ofs; /*!< int bit offset */ + DEV_GPIO_HANDLER int_bit_handler; /*!< interrupt handler */ +} DEV_GPIO_BIT_ISR, * DEV_GPIO_BIT_ISR_PTR; +/* @} */ + +/** + * \defgroup DEVICE_HAL_GPIO_DEVSTRUCT GPIO Device Interface Definition + * \ingroup DEVICE_HAL_GPIO + * \brief contains definitions of gpio device structure. + * \details This structure will be used in user implemented code, which was called + * \ref DEVICE_IMPL "Device Driver Implement Layer" for gpio to use in implementation code. + * Application developer should use the GPIO API provided here to access to GPIO devices. + * BSP developer should follow the API definition to implement GPIO device drivers. + * @{ + */ +/** + * \brief gpio information struct definition + * \details informations about gpio open count, working status + * gpio registers and control block, gpio io direction and interrupt/poll for each bit of gpio + * \note Only available for gpio with max 32bits + */ +typedef struct dev_gpio_info +{ + void *gpio_ctrl; /*!< gpio control related pointer, implemented by bsp developer, and this should be set during gpio object implementation */ + uint32_t opn_cnt; /*!< gpio open count, open it will increase 1, close it will decrease 1, 0 for close, >0 for open */ + uint32_t direction; /*!< each bit direction of this GPIO, default all \ref GPIO_DIR_INPUT "input" for first open */ + uint32_t method; /*!< int/poll method for each bit of GPIO, 0 for poll, 1 for interrupt, default all \ref DEV_POLL_METHOD "poll" for first open */ + void *extra; /*!< a extra pointer to get hook to applications which should not used by bsp developer, + this should be NULL for first open and you can \ref DEV_GPIO_INFO_SET_EXTRA_OBJECT "set" + or \ref DEV_GPIO_INFO_GET_EXTRA_OBJECT "get" the extra information pointer */ +} DEV_GPIO_INFO, * DEV_GPIO_INFO_PTR; +/** Set extra information pointer of gpio info */ +#define DEV_GPIO_INFO_SET_EXTRA_OBJECT(gpio_info_ptr, extra_info) (gpio_info_ptr)->extra = (void *)(extra_info) +/** Get extra information pointer of gpio info */ +#define DEV_GPIO_INFO_GET_EXTRA_OBJECT(gpio_info_ptr) ((gpio_info_ptr)->extra) + +/** Method of all gpio bits set to poll */ +#define DEV_GPIO_BITS_MTHD_POLL (0) +/** Method of all gpio bits set to interrupt */ +#define DEV_GPIO_BITS_MTHD_INTERRUPT (0xFFFFFFFF) +/** Default method of all gpio bits should be poll for first open */ +#define DEV_GPIO_BITS_MTHD_DEFAULT (DEV_GPIO_BITS_MTHD_POLL) + +/** + * \brief gpio device interface definition + * \details define gpio device interface, like gpio information structure, + * fuctions to open/close/control gpio, write or read data via gpio + * \note all this details are implemented by user in user porting code + */ +typedef struct dev_gpio +{ + DEV_GPIO_INFO gpio_info; /*!< gpio device information */ + int32_t (*gpio_open)(uint32_t dir); /*!< open gpio device with pre-defined gpio direction */ + int32_t (*gpio_close)(void); /*!< close gpio device */ + int32_t (*gpio_control)(uint32_t ctrl_cmd, void *param); /*!< control gpio device */ + int32_t (*gpio_write)(uint32_t val, uint32_t mask); /*!< write gpio device with val, only write the masked bits */ + int32_t (*gpio_read)(uint32_t *val, uint32_t mask); /*!< read gpio device val, only read the masked bits */ +} DEV_GPIO, * DEV_GPIO_PTR; + +/** + * \fn int32_t (* dev_gpio::gpio_open) (uint32_t dir) + * \details Open a gpio device with pre-defined io direction. + * \param[in] dir gpio direction for each bit + * \retval E_OK Open successfully without any issues + * \retval E_OPNED If device was opened before with different parameters, + * then just increase the \ref dev_gpio_info::opn_cnt "opn_cnt" and return \ref E_OPNED + * \retval E_OBJ Device object is not valid + * \retval E_PAR Parameter is not valid + * \retval E_NOSPT Open settings are not supported + */ + +/** + * \fn int32_t (* dev_gpio::gpio_close) (void) + * \details Close an gpio device, just decrease the \ref dev_gpio_info::opn_cnt "opn_cnt", + * if \ref dev_gpio_info::opn_cnt "opn_cnt" equals 0, then close the device + * \retval E_OK Close successfully without any issues(including scenario that device is already closed) + * \retval E_OPNED Device is still opened, the device \ref dev_gpio_info::opn_cnt "opn_cnt" decreased by 1 + * \retval E_OBJ Device object is not valid + */ + +/** + * \fn int32_t (* dev_gpio::gpio_control) (uint32_t ctrl_cmd, void *param) + * \details Control an gpio device by \ref ctrl_cmd, with passed \ref param. + * you can control gpio device using predefined gpio control commands defined using \ref DEV_SET_SYSCMD + * (which must be implemented by bsp developer), such as \ref GPIO_CMD_SET_BIT_DIR_INPUT + * "change masked gpio direction to input", and \ref DEVICE_HAL_GPIO_CTRLCMD "more". + * And you can also control gpio device using your own specified commands defined using \ref DEV_SET_USRCMD, + * but these specified commands should be defined in your own gpio device driver implementation. + * \param[in] ctrl_cmd \ref DEVICE_HAL_GPIO_CTRLCMD "control command", to change or get some thing related to gpio + * \param[in,out] param parameters that maybe argument of the command, or return values of the command + * \retval E_OK Control device successfully + * \retval E_CLSED Device is not opened + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Control device failed, due to hardware issues + * \retval E_CTX Control device failed, due to different reasons like in transfer state + * \retval E_NOSPT Control command is not supported or not valid, such as interrupt is not supported + */ + +/** + * \fn int32_t (* dev_gpio::gpio_write) (uint32_t val, uint32_t mask) + * \details Write gpio with \ref val, and only change the masked bits of gpio. + * \param[in] val the data that need to write to gpio + * \param[in] mask gpio bit mask + * \retval E_OK Write gpio with specified value successfully + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + */ + +/** + * \fn int32_t (* dev_gpio::gpio_read) (uint32_t *val, uint32_t mask) + * \details Read the masked gpio value + * \param[out] val pointer to data need to read from gpio + * \param[in] mask gpio bit mask + * \retval E_OK Read gpio data successfully + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + */ + +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief get an \ref dev_gpio "gpio device" by gpio device id. + * For how to use gpio device hal refer to \ref dev_gpio "Functions in gpio device structure" + * \param[in] gpio_id id of gpio, defined by user + * \retval !NULL pointer to an \ref dev_gpio "gpio device structure" + * \retval NULL failed to find the gpio device by \ref gpio_id + * \note need to implemented by user in user code + */ +extern DEV_GPIO_PTR gpio_get_dev(int32_t gpio_id); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* _DEVICE_HAL_GPIO_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_spi.h b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_spi.h new file mode 100644 index 000000000..522ded53a --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_spi.h @@ -0,0 +1,582 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2014-06-16 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_HAL_SPI SPI Device HAL Interface + * \ingroup DEVICE_HAL_DEF + * \brief definitions for spi device hardware layer (\ref dev_spi.h) + * \details provide interfaces for spi driver to implement + * Here is a diagram for the spi interface. + * + * \htmlonly + *
+ *
+ * SPI Device HAL Interface Diagram + *

SPI Device HAL Interface Diagram

+ *
+ *
+ * \endhtmlonly + * + * @{ + * + * \file + * \brief spi device hardware layer definitions + * \details provide common definitions for spi device, + * then software developer can develop spi driver + * following this definitions, and the applications + * can directly call this definition to realize functions + */ + +#ifndef _DEVICE_HAL_SPI_H_ +#define _DEVICE_HAL_SPI_H_ + +#include "device/device_hal/inc/dev_common.h" + + +/** + * \defgroup DEVICE_HAL_SPI_CTRLCMD SPI Device Control Commands + * \ingroup DEVICE_HAL_SPI + * \brief Definitions for spi control command, used in \ref dev_spi::spi_control "SPI IO Control" + * \details These commands defined here can be used in user code directly. + * - Parameters Usage + * - For passing parameters like integer, just use uint32_t/int32_t to directly pass values + * - For passing parameters for a structure, please use pointer to pass values + * - For getting some data, please use pointer to store the return data + * - Common Return Values + * - \ref E_OK, Control device successfully + * - \ref E_CLSED, Device is not opened + * - \ref E_OBJ, Device object is not valid or not exists + * - \ref E_PAR, Parameter is not valid for current control command + * - \ref E_SYS, Control device failed, due to hardware issues such as device is disabled + * - \ref E_CTX, Control device failed, due to different reasons like in transfer state + * - \ref E_NOSPT, Control command is not supported or not valid + * - Usage Comment + * - For SPI poll or interrupt read/write/transfer operations, only 1 operation can be triggered. + * If there is a operation is running, any other operation will return \ref E_CTX + * - If SPI is in transfer, then the following operations may return \ref E_CTX. Like + * \ref SPI_CMD_SET_CLK_MODE, \ref SPI_CMD_SET_TXINT_BUF, \ref SPI_CMD_SET_RXINT_BUF, + * \ref SPI_CMD_SET_TXINT, \ref SPI_CMD_SET_RXINT, \ref SPI_CMD_ABORT_TX, \ref SPI_CMD_ABORT_RX, + * \ref SPI_CMD_FLUSH_TX, \ref SPI_CMD_FLUSH_RX, \ref SPI_CMD_SET_DFS, \ref SPI_CMD_TRANSFER_POLLING, + * \ref SPI_CMD_TRANSFER_INT, \ref SPI_CMD_ABORT_XFER, \ref SPI_CMD_MST_SEL_DEV, \ref SPI_CMD_MST_DSEL_DEV, + * \ref SPI_CMD_MST_SET_FREQ and \ref dev_spi::spi_write "SPI Poll Write" or \ref dev_spi::spi_read "SPI Poll Read". + * @{ + */ + +/** Define SPI control commands for common usage */ +#define DEV_SET_SPI_SYSCMD(cmd) DEV_SET_SYSCMD((cmd)) +/** Define SPI control commands for master usage */ +#define DEV_SET_SPI_MST_SYSCMD(cmd) DEV_SET_SYSCMD(0x00001000|(cmd)) +/** Define SPI control commands for slave usage */ +#define DEV_SET_SPI_SLV_SYSCMD(cmd) DEV_SET_SYSCMD(0x00002000|(cmd)) + + +/* ++++ Common commands for SPI Device ++++ */ +/** + * Get \ref dev_spi_info::status "current device status" + * - Param type : uint32_t * + * - Param usage : store result of current status + * - Return value explanation : + */ +#define SPI_CMD_GET_STATUS DEV_SET_SPI_SYSCMD(0) +/** + * set the \ref dev_spi_info::clk_mode "clock mode" of spi transfer + * - Param type : uint32_t + * - Param usage : spi clock mode to choose clock phase and clock polarity + * - Return value explanation : + */ +#define SPI_CMD_SET_CLK_MODE DEV_SET_SPI_SYSCMD(1) +/** + * set spi \ref dev_spi_info::dfs "data frame size" + * - Param type : uint32_t + * - Param usage : should > 0 + * - Return value explanation : If dfs is not supported, then return \ref E_SYS + */ +#define SPI_CMD_SET_DFS DEV_SET_SPI_SYSCMD(2) +/** + * set the \ref dev_spi_info::dummy "dummy data" during spi transfer + * - Param type : uint32_t + * - Param usage : dummy data to transfer + * - Return value explanation : + */ +#define SPI_CMD_SET_DUMMY_DATA DEV_SET_SPI_SYSCMD(3) +/** + * Set \ref dev_spi_cbs::tx_cb "spi transmit success callback" function + * when all required bytes are transmitted for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : transmit success callback function for spi + * - Return value explanation : + */ +#define SPI_CMD_SET_TXCB DEV_SET_SPI_SYSCMD(4) +/** + * Set \ref dev_spi_cbs::rx_cb "spi receive success callback" function + * when all required bytes are received for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : receive success callback function for spi + * - Return value explanation : + */ +#define SPI_CMD_SET_RXCB DEV_SET_SPI_SYSCMD(5) +/** + * Set \ref dev_spi_cbs::xfer_cb "spi transfer success callback" function + * when all required transfer are done for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : transfer success callback function for spi + * - Return value explanation : + */ +#define SPI_CMD_SET_XFERCB DEV_SET_SPI_SYSCMD(6) +/** + * Set \ref dev_spi_cbs::err_cb "spi transfer error callback" function + * when something error happened for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : transfer error callback function for spi + * - Return value explanation : + */ +#define SPI_CMD_SET_ERRCB DEV_SET_SPI_SYSCMD(7) +/** + * Set buffer in interrupt transmit, and it will set \ref dev_spi_info::xfer "spi tranfer". + * - SPI master and slave mode use case \n + * For both master and slave mode, if you set tx buffer to NULL, when tx interrupt is enabled and entered into tx interrupt, + * it will automatically disable the tx interrupt, so when you want to transfer something, you need to set the + * tx buffer to Non-NULL and enable tx interrupt, when the tx buffer is sent, it will disable the tx interrupt + * and call tx callback function if available. + * - Param type : DEV_BUFFER * or NULL + * - Param usage : buffer structure pointer, if param is NULL, then it will set xfer to empty + * - Return value explanation : + */ +#define SPI_CMD_SET_TXINT_BUF DEV_SET_SPI_SYSCMD(8) +/** + * Set buffer in interrupt receive, and it will set \ref dev_spi_info::xfer "spi tranfer". + * - SPI master mode use case \n + * Similar to \ref SPI_CMD_SET_TXINT_BUF + * - SPI slave mode use case \n + * Similiar to \ref SPI_CMD_SET_TXINT_BUF + * - Param type : DEV_BUFFER * or NULL + * - Param usage : buffer structure pointer, if param is NULL, then it will set xfer to empty + * - Return value explanation : + */ +#define SPI_CMD_SET_RXINT_BUF DEV_SET_SPI_SYSCMD(9) +/** + * Enable or disable transmit interrupt, + * for master mode, only one of tx and rx interrupt can be enabled, + * if tx interrupt is enabled, then rx interrupt can't be enabled. + * - Param type : uint32_t + * - Param usage : enable(none-zero) or disable(zero) flag + * - Return value explanation : + */ +#define SPI_CMD_SET_TXINT DEV_SET_SPI_SYSCMD(10) +/** + * Enable or disable receive interrupt, + * for master mode, only one of tx and rx interrupt can be enabled, + * if rx interrupt is enabled, then tx interrupt can't be enabled. + * - Param type : uint32_t + * - Param usage : enable(none-zero) or disable(zero) flag + * - Return value explanation : + */ +#define SPI_CMD_SET_RXINT DEV_SET_SPI_SYSCMD(11) +/** + * start the transfer by polling + * - Param type : \ref DEV_SPI_TRANSFER * + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_TRANSFER_POLLING DEV_SET_SPI_SYSCMD(12) +/** + * start the transfer by interrupt + * - Param type : \ref DEV_SPI_TRANSFER * or NULL + * - Param usage : If NULL, it will disable transfer interrupt, if not NULL, it will enable transfer interrupt + * - Return value explanation : + */ +#define SPI_CMD_TRANSFER_INT DEV_SET_SPI_SYSCMD(13) +/** + * Abort current interrupt transmit operation if tx interrupt enabled, + * it will disable transmit interrupt, and set \ref DEV_IN_TX_ABRT + * in \ref dev_spi_info::status "status" variable, + * and call the transmit callback function, when tx callback is finished, + * it will clear \ref DEV_IN_TX_ABRT and return + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_ABORT_TX DEV_SET_SPI_SYSCMD(14) +/** + * Abort current interrupt receive operation if rx interrupt enabled, + * it will disable receive interrupt, and set \ref DEV_IN_TX_ABRT + * in \ref dev_spi_info::status "status" variable, + * and call the receive callback function, when rx callback is finished, + * it will clear \ref DEV_IN_TX_ABRT and return + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_ABORT_RX DEV_SET_SPI_SYSCMD(15) +/** + * Abort current interrupt transfer operation if transfer is issued, + * it will disable transfer interrupt, and set \ref DEV_IN_XFER_ABRT + * in \ref dev_spi_info::status "status" variable, + * and call the transfer callback function, when xfer callback is finished, + * it will clear \ref DEV_IN_XFER_ABRT and return + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_ABORT_XFER DEV_SET_SPI_SYSCMD(16) +/** + * Do a software reset for SPI device, it will stop current transfer, + * and clear error state and bring device to normal state, set next condition to STOP + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_RESET DEV_SET_SPI_SYSCMD(17) +/** + * Flush spi tx fifo, this will clear the data in tx fifo + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_FLUSH_TX DEV_SET_SPI_SYSCMD(18) +/** + * Flush spi rx fifo, this will clear the data in rx fifo + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define SPI_CMD_FLUSH_RX DEV_SET_SPI_SYSCMD(19) +/** + * Enable spi device + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define SPI_CMD_ENA_DEV DEV_SET_SPI_SYSCMD(20) +/** + * Disable spi device, when device is disabled, + * only \ref SPI_CMD_ENA_DEV, \ref SPI_CMD_DIS_DEV, + * \ref SPI_CMD_GET_STATUS and \ref SPI_CMD_RESET + * commands can be executed, other commands will return \ref E_SYS + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define SPI_CMD_DIS_DEV DEV_SET_SPI_SYSCMD(21) +/** + * Get how many bytes space in spi are available to transmit, + * this can be used in interrupt callback functions, + * cooperate with \ref dev_spi::spi_write "spi_write" API to realize non-blocked write + * - Param type : int32_t * + * - Param usage : store the write available bytes, > 0 for available bytes, 0 for not available + * - Return value explanation : + */ +#define SPI_CMD_GET_TXAVAIL DEV_SET_SPI_SYSCMD(22) +/** + * Get how many bytes in spi are available to receive, + * this can be used in interrupt callback functions, + * cooperate with \ref dev_spi::spi_read "spi_read" API to realize non-blocked read + * - Param type : int32_t * + * - Param usage : store the read available bytes, > 0 for available bytes, 0 for not available + * - Return value explanation : + */ +#define SPI_CMD_GET_RXAVAIL DEV_SET_SPI_SYSCMD(23) + + +/* ++++ Master only commands for SPI Device ++++ */ +/** + * select spi slave device + * - Param type : uint32_t + * - Param usage : the number of spi slave device to select + * - Return value explanation : return \ref E_SYS when selection can't be done, return \ref E_CTX during transfer + */ +#define SPI_CMD_MST_SEL_DEV DEV_SET_SPI_MST_SYSCMD(0) +/** + * de-select spi slave device + * - Param type : uint32_t + * - Param usage : the number of spi slave device to de-select + * - Return value explanation : return \ref E_SYS when selection can't be done, return \ref E_CTX during transfer + */ +#define SPI_CMD_MST_DSEL_DEV DEV_SET_SPI_MST_SYSCMD(1) +/** +* Set \ref dev_spi_info::freq "spi frequency". +* - Param type : uint32_t +* - Param usage : spi freq +* - Return value explanation : no return +*/ +#define SPI_CMD_MST_SET_FREQ DEV_SET_SPI_MST_SYSCMD(2) + + +/* ++++ Slave only commands for SPI Device ++++ */ + +/* \todo add spi slave related CMDs */ + +/** @} */ + +/** + * \defgroup DEVICE_HAL_SPI_CALLBACK SPI Interrupt callback functions + * \ingroup DEVICE_HAL_SPI + * \brief callback function structure for SPI device + * @{ + */ +typedef struct dev_spi_cbs +{ + DEV_CALLBACK tx_cb; /*!< spi data transmit success required bytes callback */ + DEV_CALLBACK rx_cb; /*!< spi data receive success required bytes callback */ + DEV_CALLBACK err_cb; /*!< spi error callback */ + DEV_CALLBACK xfer_cb; /*!< transfer callback */ +} DEV_SPI_CBS, *DEV_SPI_CBS_PTR; +/** @} */ + +/** SPI Clock Mode */ +typedef enum spi_clk_mode +{ + SPI_CPOL_0_CPHA_0 = 0, /*!< Inactive state of serial clock is low, serial clock toggles in middle of first data bit */ + SPI_CPOL_0_CPHA_1 = 1, /*!< Inactive state of serial clock is low, serial clock toggles at start of first data bit */ + SPI_CPOL_1_CPHA_0 = 2, /*!< Inactive state of serial clock is high, serial clock toggles in middle of first data bit */ + SPI_CPOL_1_CPHA_1 = 3, /*!< Inactive state of serial clock is high, serial clock toggles at start of first data bit */ + + SPI_CLK_MODE_0 = SPI_CPOL_0_CPHA_0, /*!< Equal to \ref SPI_CPOL_0_CPHA_0 */ + SPI_CLK_MODE_1 = SPI_CPOL_0_CPHA_1, /*!< Equal to \ref SPI_CPOL_0_CPHA_1 */ + SPI_CLK_MODE_2 = SPI_CPOL_1_CPHA_0, /*!< Equal to \ref SPI_CPOL_1_CPHA_0 */ + SPI_CLK_MODE_3 = SPI_CPOL_1_CPHA_1 /*!< Equal to \ref SPI_CPOL_1_CPHA_1 */ +} SPI_CLK_MODE; + +#define SPI_CLK_MODE_DEFAULT SPI_CPOL_0_CPHA_0 /*!< Default SPI device clock mode */ + +/** + * \defgroup DEVICE_HAL_SPI_DEVSTRUCT SPI Device Structure + * \ingroup DEVICE_HAL_SPI + * \brief contains definitions of spi device structure. + * \details this structure will be used in user implemented code, which was called + * Device Driver Implement Layer for spi to realize in user code. + * @{ + */ +typedef struct dev_spi_transfer DEV_SPI_TRANSFER, *DEV_SPI_TRANSFER_PTR; +/** + * \brief spi read and write data structure used by \ref SPI_CMD_TRANSFER + * spi write then read data + * + */ +struct dev_spi_transfer +{ + DEV_SPI_TRANSFER *next; + /* Calc by software */ + /** tot_len = (tx_totlen>rx_totlen)?tx_totlen:rx_totlen */ + uint32_t tot_len; + /* Set by user */ + uint8_t *tx_buf; + uint32_t tx_ofs; + uint32_t tx_len; + uint8_t *rx_buf; + uint32_t rx_ofs; + uint32_t rx_len; + /* Should auto set to proper value during set buffer value */ + uint32_t tx_idx; + uint32_t tx_totlen; /** tx_totlen = tx_len + tx_ofs */ + uint32_t rx_idx; + uint32_t rx_totlen; /** rx_totlen = rx_len + rx_ofs */ +}; + +/** Set tx buffer of device spi transfer */ +#define DEV_SPI_XFER_SET_TXBUF(xfer, buf, ofs, len) { \ + (xfer)->tx_buf = (uint8_t *)(buf); \ + (xfer)->tx_len = (uint32_t)(len); \ + (xfer)->tx_ofs = (uint32_t)(ofs); \ + (xfer)->tx_idx = 0; \ + (xfer)->tx_totlen = ( (uint32_t)(len) \ + + (uint32_t)(ofs) ) ; \ + } + +/** Set rx buffer of device spi transfer */ +#define DEV_SPI_XFER_SET_RXBUF(xfer, buf, ofs, len) { \ + (xfer)->rx_buf = (uint8_t *)(buf); \ + (xfer)->rx_len = (uint32_t)(len); \ + (xfer)->rx_ofs = (uint32_t)(ofs); \ + (xfer)->rx_idx = 0; \ + (xfer)->rx_totlen = ( (uint32_t)(len) \ + + (uint32_t)(ofs) ) ; \ + } + +/** Calculate total length of current transfer without next transfer */ +#define DEV_SPI_XFER_CALC_TOTLEN(xfer) (xfer)->tot_len = \ + ((xfer)->tx_totlen > (xfer)->rx_totlen) ? (xfer)->tx_totlen : (xfer)->rx_totlen ; + +/** Set next SPI transfer */ +#define DEV_SPI_XFER_SET_NEXT(xfer, next_xfer) (xfer)->next = (next_xfer); + +/** Init spi transfer */ +#define DEV_SPI_XFER_INIT(xfer) { \ + (xfer)->tx_idx = 0; \ + (xfer)->rx_idx = 0; \ + (xfer)->tx_totlen = ((xfer)->tx_len \ + + (xfer)->tx_ofs) ; \ + (xfer)->rx_totlen = ((xfer)->rx_len \ + + (xfer)->rx_ofs) ; \ + DEV_SPI_XFER_CALC_TOTLEN(xfer); \ + } +/** + * \brief spi information struct definition + * \details informations about spi open state, working state, + * frequency, spi registers, working method, interrupt number + */ +typedef struct dev_spi_info +{ + void *spi_ctrl; /*!< spi control related */ + uint32_t status; /*!< current working status, refer to \ref DEVICE_HAL_COMMON_DEVSTATUS, this should be \ref DEV_ENABLED for first open */ + uint32_t freq; /*!< spi working baudrate */ + uint8_t mode; /*!< spi working mode (master/slave) */ + uint8_t clk_mode; /*!< spi clock phase and polarity, this should be \ref SPI_CLK_MODE_DEFAULT for first open */ + uint8_t opn_cnt; /*!< spi open count, open it will increase 1, close it will decrease 1, 0 for close, >0 for open */ + uint8_t slave; /*!< current selected slave device no, start from 0, this should be \ref SPI_SLAVE_NOT_SELECTED for first open */ + uint8_t dfs; /*!< data frame size, this should be \ref SPI_DFS_DEFAULT for first open */ + + DEV_SPI_TRANSFER xfer; /*!< spi transfer, this should be set to all zero for first open */ + DEV_SPI_CBS spi_cbs; /*!< spi callbacks, for both master and slave mode, this should be all NULL for first open */ + void *extra; /*!< a extra pointer to get hook to applications which should not used by bsp developer, + this should be NULL for first open and you can \ref DEV_SPI_INFO_SET_EXTRA_OBJECT "set" + or \ref DEV_SPI_INFO_GET_EXTRA_OBJECT "get" the extra information pointer */ + uint32_t dummy; /*!< dummy write data when send and receive, this should be \ref SPI_DUMMY_DEFAULT for first open */ +} DEV_SPI_INFO, * DEV_SPI_INFO_PTR; + +/** Set extra information pointer of spi info */ +#define DEV_SPI_INFO_SET_EXTRA_OBJECT(spi_info_ptr, extra_info) (spi_info_ptr)->extra = (void *)(extra_info) +/** Get extra information pointer of spi info */ +#define DEV_SPI_INFO_GET_EXTRA_OBJECT(spi_info_ptr) ((spi_info_ptr)->extra) + +#define SPI_DFS_DEFAULT 8 /*!< Default spi data frame size */ +#define SPI_SLAVE_NOT_SELECTED (0xFF) /*!< Slave is not selected */ +#define SPI_DUMMY_DEFAULT (0xFF) /*!< default dummy value for first open */ + +/** + * \brief spi device interface definition + * \details define spi device interface, like spi information structure, + * fuctions to get spi info, open/close/control spi, send/receive data by spi + * \note all this details are implemented by user in user porting code + */ +typedef struct dev_spi +{ + DEV_SPI_INFO spi_info; /*!< spi device information */ + int32_t (*spi_open)(uint32_t mode, uint32_t param); /*!< open spi device in master/slave mode, \ + when in master mode, param stands for frequency, \ + when in slave mode, param stands for clock mode */ + int32_t (*spi_close)(void); /*!< close spi device */ + int32_t (*spi_control)(uint32_t ctrl_cmd, void *param); /*!< control spi device */ + int32_t (*spi_write)(const void *data, uint32_t len); /*!< send data to spi device (blocking method) */ + int32_t (*spi_read)(void *data, uint32_t len); /*!< read data from spi device (blocking method) */ +} DEV_SPI, * DEV_SPI_PTR; + +/** + * \fn int32_t (* dev_spi::spi_open) (uint32_t mode, uint32_t param) + * \details open an spi device with selected mode (master or slave) with defined \ref param + * \param[in] mode working mode (\ref DEV_MASTER_MODE "master" or \ref DEV_SLAVE_MODE "slave") + * \param[in] param When mode is \ref DEV_MASTER_MODE, param stands for \ref dev_spi_info::freq "frequency", + * when mode is \ref DEV_SLAVE_MODE, param stands for \ref dev_spi_info::clk_mode "slave clock mode" + * \retval E_OK Open successfully without any issues + * \retval E_OPNED If device was opened before with different parameters, + * then just increase the \ref dev_spi_info::opn_cnt "opn_cnt" and return \ref E_OPNED + * \retval E_OBJ Device object is not valid + * \retval E_SYS Device is opened for different mode before, if you want to open it with different mode, you need to fully close it first. + * \retval E_PAR Parameter is not valid + * \retval E_NOSPT Open settings are not supported + */ + +/** + * \fn int32_t (* dev_spi::spi_close) (void) + * \details close an spi device, just decrease the \ref dev_spi_info::opn_cnt "opn_cnt", + * if \ref dev_spi_info::opn_cnt "opn_cnt" equals 0, then close the device + * \retval E_OK Close successfully without any issues(including scenario that device is already closed) + * \retval E_OPNED Device is still opened, the device \ref dev_spi_info::opn_cnt "opn_cnt" decreased by 1 + * \retval E_OBJ Device object is not valid + */ + +/** + * \fn int32_t (* dev_spi::spi_control) (uint32_t ctrl_cmd, void *param) + * \details control an spi device by \ref ctrl_cmd, with passed \ref param. + * you can control spi device using predefined spi control commands defined using \ref DEV_SET_SYSCMD + * (which must be implemented by bsp developer), such as \ref SPI_CMD_MST_SET_FREQ "set spi master frequency", + * \ref SPI_CMD_FLUSH_TX "flush tx" and \ref DEVICE_HAL_SPI_CTRLCMD "more". + * And you can also control spi device using your own specified commands defined using \ref DEV_SET_USRCMD, + * but these specified commands should be defined in your own spi device driver implementation. + * \param[in] ctrl_cmd \ref DEVICE_HAL_SPI_CTRLCMD "control command", to change or get some thing related to spi + * \param[in,out] param parameters that maybe argument of the command, + * or return values of the command, must not be NULL + * \retval E_OK Control device successfully + * \retval E_CLSED Device is not opened + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Control device failed, due to hardware issues, such as device is disabled + * \retval E_CTX Control device failed, due to different reasons like in transfer state + * \retval E_NOSPT Control command is not supported or not valid + */ + +/** + * \fn int32_t (* dev_spi::spi_write) (const void *data, uint32_t len) + * \details send \ref data through spi with defined \ref len to slave device . + * \param[in] data pointer to data need to send by spi + * \param[in] len length of data to be sent + * \retval >0 Byte count that was successfully sent for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + * \retval E_CTX Device is still in transfer state + * \retval E_SYS Can't write data to hardware due to hardware issues, such as device is disabled + */ + +/** + * \fn int32_t (* dev_spi::spi_read) (void *data, uint32_t len) + * \details receive \ref data of defined \ref len through spi from slave device . + * \param[out] data pointer to data need to received by spi + * \param[in] len length of data to be received + * \retval >0 Byte count that was successfully received for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_CTX Device is still in transfer state + * \retval E_PAR Parameter is not valid + * \retval E_SYS Can't receive data from hardware due to hardware issues, such as device is disabled + */ +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief get an \ref dev_spi "spi device" by spi device id. + * For how to use spi device hal refer to \ref dev_spi "Functions in spi device structure" + * \param[in] spi_id id of spi, defined by user + * \retval !NULL pointer to an \ref dev_spi "spi device structure" + * \retval NULL failed to find the spi device by \ref spi_id + * \note need to implemented by user in user code + */ +extern DEV_SPI_PTR spi_get_dev(int32_t spi_id); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* _DEVICE_HAL_SPI_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_uart.h b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_uart.h new file mode 100644 index 000000000..eb04619bf --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/device/device_hal/inc/dev_uart.h @@ -0,0 +1,485 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-16 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \defgroup DEVICE_HAL_UART UART Device HAL Interface + * \ingroup DEVICE_HAL_DEF + * \brief Definitions for uart device hardware layer (\ref dev_uart.h) + * \details Provide unified APIs for uart driver to implement. + * Here is a diagram for the uart interface. + * + * \htmlonly + *
+ *
+ * UART Device HAL Interface Diagram + *

UART Device HAL Interface Diagram

+ *
+ *
+ * \endhtmlonly + * + * ### Reference Links + * * [Serial Port](https://en.wikipedia.org/wiki/Serial_port) + * + * @{6 + * + * \file + * \brief uart device hardware layer definitions + * \details Provide common definitions for uart device, + * then software developer can develop uart driver + * following this definitions, and the applications + * can directly call this definition to realize functions + * + */ + +#ifndef _DEVICE_HAL_UART_H_ +#define _DEVICE_HAL_UART_H_ + +#include "device/device_hal/inc/dev_common.h" + +/** + * \defgroup DEVICE_HAL_UART_BAUD UART Device Baudrate Definitions + * \ingroup DEVICE_HAL_UART + * \brief Macros for uart baudrate. + * \details Definitions for baudrate from 4800 to 115200bps. + * @{ + */ +/* + * defines for uart baudrates + */ +#define UART_BAUDRATE_110 (110) /*!< uart baudrate 110bps */ +#define UART_BAUDRATE_300 (300) /*!< uart baudrate 300bps */ +#define UART_BAUDRATE_600 (600) /*!< uart baudrate 600bps */ +#define UART_BAUDRATE_1200 (1200) /*!< uart baudrate 1200bps */ +#define UART_BAUDRATE_2400 (2400) /*!< uart baudrate 2400bps */ +#define UART_BAUDRATE_4800 (4800) /*!< uart baudrate 4800bps */ +#define UART_BAUDRATE_9600 (9600) /*!< uart baudrate 9600bps */ +#define UART_BAUDRATE_14400 (14400) /*!< uart baudrate 14400bps */ +#define UART_BAUDRATE_19200 (19200) /*!< uart baudrate 19200bps */ +#define UART_BAUDRATE_38400 (38400) /*!< uart baudrate 38400bps */ +#define UART_BAUDRATE_57600 (57600) /*!< uart baudrate 57600bps */ +#define UART_BAUDRATE_115200 (115200) /*!< uart baudrate 115200bps */ +#define UART_BAUDRATE_230400 (230400) /*!< uart baudrate 230400bps */ +#define UART_BAUDRATE_460800 (460800) /*!< uart baudrate 460800bps */ +#define UART_BAUDRATE_921600 (921600) /*!< uart baudrate 921600bps */ +/** @} */ + +/** + * \defgroup DEVICE_HAL_UART_FORMAT UART Device Format Definitions + * \ingroup DEVICE_HAL_UART + * \brief Macros for uart format. + * \details Definitions for uart format like databits, parity, stopbits. + * @{ + */ +/** + * UART Device Parity Types Enum + */ +typedef enum +{ + UART_PARITY_NONE = 0, /*!< no parity bit */ + UART_PARITY_ODD = 1, /*!< odd parity bit */ + UART_PARITY_EVEN = 2, /*!< even parity bit */ + UART_PARITY_MARK = 3, /*!< mark parity bit, always logical 1 */ + UART_PARITY_SPACE = 4 /*!< space parity bit, always logical 0 */ +} UART_PARITY; + +/** + * UART Device Stop Bits Enum + */ +typedef enum +{ + UART_STPBITS_ONE = 0, /*!< 1 stop bit */ + UART_STPBITS_ONEHALF = 1, /*!< 1.5 stop bits */ + UART_STPBITS_TWO = 2 /*!< 2 stop bits */ +} UART_STOPBITS; + +/** + * UART DPS Format: databits/parity/stopbits + */ +typedef struct uart_dps_format +{ + uint32_t databits; /*!< data bits */ + UART_PARITY parity; /*!< parity bit type */ + UART_STOPBITS stopbits; /*!< stop bits */ +} UART_DPS_FORMAT; + +#define UART_DATABITS_DEFAULT 8 /*!< default data bits */ + +/** Default UART DPS format */ +static const UART_DPS_FORMAT dps_format_default = {UART_DATABITS_DEFAULT, UART_PARITY_NONE, UART_STPBITS_ONE}; +/** @} */ + +/** + * UART Device Hardware Flow Control Types Enum + */ +typedef enum +{ + UART_FC_NONE = 0, /*!< Non hardware flow control */ + UART_FC_RTS = 1, /*!< Request To Send */ + UART_FC_CTS = 2, /*!< Clear To Send */ + UART_FC_BOTH = 3 /*!< Both hardware flow control methods */ +} UART_HW_FLOW_CONTROL; +/** Default hardware flow control method */ +static const UART_HW_FLOW_CONTROL hwfc_default = UART_FC_NONE; + +/** + * \defgroup DEVICE_HAL_UART_CTRLCMD UART Device Control Commands + * \ingroup DEVICE_HAL_UART + * \brief Definitions for uart control command, used in \ref dev_uart::uart_control "UART IO Control" + * \details These commands defined here can be used in user code directly. + * - Parameters Usage + * - For passing parameters like integer, just use uint32_t/int32_t to directly pass values + * - For passing parameters for a structure, please use pointer to pass values + * - For getting some data, please use pointer to store the return data + * - Common Return Values + * - \ref E_OK, Control device successfully + * - \ref E_CLSED, Device is not opened + * - \ref E_OBJ, Device object is not valid or not exists + * - \ref E_PAR, Parameter is not valid for current control command + * - \ref E_SYS, Control device failed, due to hardware issues such as device is disabled + * - \ref E_CTX, Control device failed, due to different reasons like in transfer state + * - \ref E_NOSPT, Control command is not supported or not valid + * @{ + */ +/** + * Set \ref dev_uart_info::baudrate "uart baudrate". + * - Param type : uint32_t + * - Param usage : uart baudrate, must above zero. Here is a list of \ref DEVICE_HAL_UART_BAUD "possible baudrates" + * - Return value explanation : + */ +#define UART_CMD_SET_BAUD DEV_SET_SYSCMD(0) +/** + * Get \ref dev_uart_info::status "current device status" + * - Param type : uint32_t * + * - Param usage : store result of current status + * - Return value explanation : + */ +#define UART_CMD_GET_STATUS DEV_SET_SYSCMD(1) +/** + * Enable uart device + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define UART_CMD_ENA_DEV DEV_SET_SYSCMD(2) +/** + * Disable uart device, when device is disabled, + * only \ref UART_CMD_ENA_DEV, \ref UART_CMD_DIS_DEV and + * \ref UART_CMD_GET_STATUS commands can be executed, + * other commands will return \ref E_SYS + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define UART_CMD_DIS_DEV DEV_SET_SYSCMD(3) +/** + * Flush uart device output + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define UART_CMD_FLUSH_OUTPUT DEV_SET_SYSCMD(4) +/** + * Get how many bytes space in uart are available to transmit, + * this can be used in interrupt callback functions, + * cooperate with \ref dev_uart::uart_write "uart_write" API to realize non-blocked write + * - Param type : int32_t * + * - Param usage : store the write available bytes, > 0 for available bytes, 0 for not available + * - Return value explanation : + */ +#define UART_CMD_GET_TXAVAIL DEV_SET_SYSCMD(5) +/** + * Get how many bytes in uart are available to receive, + * this can be used in interrupt callback functions, + * cooperate with \ref dev_uart::uart_read "uart_read" API to realize non-blocked read + * - Param type : int32_t * + * - Param usage : store the read available bytes, > 0 for available bytes, 0 for not available + * - Return value explanation : + */ +#define UART_CMD_GET_RXAVAIL DEV_SET_SYSCMD(6) +/** + * Cause a break condition to be transmitted to the receiving device + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define UART_CMD_BREAK_SET DEV_SET_SYSCMD(7) +/** + * Clear break condition and return to normal + * - Param type : NULL + * - Param usage : param is not required + * - Return value explanation : + */ +#define UART_CMD_BREAK_CLR DEV_SET_SYSCMD(8) +/** + * Change uart \ref dev_uart_info::dps_format "D/P/S(Data/Parity/Stop) format" + * - Param type : \ref UART_DPS_FORMAT * + * - Param usage : uart dps format including databits, parity and stopbits + * - Return value explanation : + */ +#define UART_CMD_SET_DPS_FORMAT DEV_SET_SYSCMD(9) +/** + * Set uart device \ref dev_uart_info::hwfc "hardware flow control" + * - Param type : \ref UART_HW_FLOW_CONTROL + * - Param usage : uart dps format including databits, parity and stopbits + * - Return value explanation : + */ +#define UART_CMD_SET_HWFC DEV_SET_SYSCMD(10) +/** + * Set \ref dev_uart_cbs::tx_cb "uart transmit success callback" function + * when all required bytes are transmitted for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : transmit success callback function for uart + * - Return value explanation : + */ +#define UART_CMD_SET_TXCB DEV_SET_SYSCMD(11) +/** + * Set \ref dev_uart_cbs::rx_cb "uart receive success callback" function + * when all required bytes are received for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : receive success callback function for uart + * - Return value explanation : + */ +#define UART_CMD_SET_RXCB DEV_SET_SYSCMD(12) +/** + * Set \ref dev_uart_cbs::err_cb "uart transfer error callback" function + * when something error happened for interrupt method + * - Param type : \ref DEV_CALLBACK * or NULL + * - Param usage : transfer error callback function for uart + * - Return value explanation : + */ +#define UART_CMD_SET_ERRCB DEV_SET_SYSCMD(13) +/** + * Set transmit buffer via interrupt, and it will set \ref dev_uart_info::tx_buf "tx_buf" + * - Param type : DEV_BUFFER * or NULL + * - Param usage : buffer structure pointer, if param is NULL, then it will set tx_buf to NULL + * - Return value explanation : + */ +#define UART_CMD_SET_TXINT_BUF DEV_SET_SYSCMD(14) +/** + * Set receive buffer via interrupt, and it will set \ref dev_uart_info::rx_buf "rx_buf" + * - Param type : DEV_BUFFER * or NULL + * - Param usage : buffer structure pointer, if param is NULL, then it will set rx_buf to NULL + * - Return value explanation : + */ +#define UART_CMD_SET_RXINT_BUF DEV_SET_SYSCMD(15) +/** + * Enable or disable transmit interrupt + * - Param type : uint32_t + * - Param usage : enable(none-zero) or disable(zero) flag + * - Return value explanation : + */ +#define UART_CMD_SET_TXINT DEV_SET_SYSCMD(16) +/** + * Enable or disable receive interrupt + * - Param type : uint32_t + * - Param usage : enable(none-zero) or disable(zero) flag + * - Return value explanation : + */ +#define UART_CMD_SET_RXINT DEV_SET_SYSCMD(17) +/** + * Abort current interrupt transmit operation if tx interrupt enabled, + * it will disable transmit interrupt, and set \ref DEV_IN_TX_ABRT + * in \ref dev_uart_info::status "status" variable, + * and call the transmit callback function, when tx callback is finished, + * it will clear \ref DEV_IN_TX_ABRT and return + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define UART_CMD_ABORT_TX DEV_SET_SYSCMD(18) +/** + * Abort current interrupt receive operation if rx interrupt enabled, + * it will disable receive interrupt, and set \ref DEV_IN_TX_ABRT + * in \ref dev_uart_info::status "status" variable, + * and call the receive callback function, when rx callback is finished, + * it will clear \ref DEV_IN_TX_ABRT and return + * - Param type : NULL + * - Param usage : + * - Return value explanation : + */ +#define UART_CMD_ABORT_RX DEV_SET_SYSCMD(19) + +/** @} */ + +/** + * \defgroup DEVICE_HAL_UART_CALLBACK UART Interrupt callback functions + * \ingroup DEVICE_HAL_UART + * \brief callback function structure for UART device + * @{ + */ +typedef struct dev_uart_cbs +{ + DEV_CALLBACK tx_cb; /*!< uart data transmit success required bytes callback */ + DEV_CALLBACK rx_cb; /*!< uart data receive success required bytes callback */ + DEV_CALLBACK err_cb; /*!< uart error callback */ +} DEV_UART_CBS, *DEV_UART_CBS_PTR; +/** @} */ + +/** + * \defgroup DEVICE_HAL_UART_DEVSTRUCT UART Device Interface Definition + * \ingroup DEVICE_HAL_UART + * \brief Contains definitions of uart device interface structure. + * \details This structure will be used in user implemented code, which was called + * \ref DEVICE_IMPL "Device Driver Implement Layer" for uart to use in implementation code. + * Application developer should use the UART API provided here to access to UART devices. + * BSP developer should follow the API definition to implement UART device drivers. + * @{ + */ +/** + * \brief UART information struct definition + * \details informations about uart open count, working status, + * baudrate, uart registers and ctrl structure, uart dps format + */ +typedef struct dev_uart_info +{ + void *uart_ctrl; /*!< uart control related pointer, implemented by bsp developer, and this should be set during uart object implementation */ + uint32_t opn_cnt; /*!< uart open count, open it will increase 1, close it will decrease 1, 0 for close, >0 for open */ + uint32_t status; /*!< current working status, refer to \ref DEVICE_HAL_COMMON_DEVSTATUS, this should be \ref DEV_ENABLED for first open */ + uint32_t baudrate; /*!< uart baud rate, this should be the value of baud passing by uart_open if first successfully opened */ + UART_DPS_FORMAT + dps_format; /*!< D/P/S format settings for uart device, here is \ref dps_format_default "default settings for first open" */ + UART_HW_FLOW_CONTROL + hwfc; /*!< UART hardware flow control, here is \ref hwfc_default "default hardware flow control settings for first open" */ + DEV_BUFFER tx_buf; /*!< transmit buffer via interrupt, this should be all zero for first open */ + DEV_BUFFER rx_buf; /*!< receive buffer via interrupt, this should be all zero for first open */ + DEV_UART_CBS + uart_cbs; /*!< uart callbacks, callback arguments should be \ref DEV_UART * or NULL, this should be all NULL for first open */ + void *extra; /*!< a extra pointer to get hook to applications which should not used by bsp developer, + this should be NULL for first open and you can \ref DEV_UART_INFO_SET_EXTRA_OBJECT "set" + or \ref DEV_UART_INFO_GET_EXTRA_OBJECT "get" the extra information pointer */ +} DEV_UART_INFO, * DEV_UART_INFO_PTR; + +/** Set extra information pointer of uart info */ +#define DEV_UART_INFO_SET_EXTRA_OBJECT(uart_info_ptr, extra_info) (uart_info_ptr)->extra = (void *)(extra_info) +/** Get extra information pointer of uart info */ +#define DEV_UART_INFO_GET_EXTRA_OBJECT(uart_info_ptr) ((uart_info_ptr)->extra) + +/** + * \brief UART device interface definition + * \details Define uart device interface, like uart information structure, + * provide functions to open/close/control uart, send/receive data by uart + * \note All this details are implemented by user in user porting code + */ +typedef struct dev_uart +{ + DEV_UART_INFO uart_info; /*!< UART device information */ + int32_t (*uart_open)(uint32_t baud); /*!< Open uart device */ + int32_t (*uart_close)(void); /*!< Close uart device */ + int32_t (*uart_control)(uint32_t ctrl_cmd, void *param); /*!< Control uart device */ + int32_t (*uart_write)(const void *data, uint32_t len); /*!< Send data by uart device(blocked) */ + int32_t (*uart_read)(void *data, uint32_t len); /*!< Read data from uart device(blocked) */ +} DEV_UART, * DEV_UART_PTR; + +/** + * \fn int32_t (* dev_uart::uart_open) (uint32_t baud) + * \details open an uart device with defined baudrate + * \param[in] baud \ref DEVICE_HAL_UART_BAUD "initial baudrate of uart", must > 0 + * \retval E_OK Open successfully without any issues + * \retval E_OPNED If device was opened before with different parameters, + * then just increase the \ref dev_uart_info::opn_cnt "opn_cnt" and return \ref E_OPNED + * \retval E_OBJ Device object is not valid + * \retval E_PAR Parameter is not valid + * \retval E_NOSPT Open settings are not supported + */ + +/** + * \fn int32_t (* dev_uart::uart_close) (void) + * \details close an uart device, just decrease the \ref dev_uart_info::opn_cnt "opn_cnt", + * if \ref dev_uart_info::opn_cnt "opn_cnt" equals 0, then close the device + * \retval E_OK Close successfully without any issues(including scenario that device is already closed) + * \retval E_OPNED Device is still opened, the device \ref dev_uart_info::opn_cnt "opn_cnt" decreased by 1 + * \retval E_OBJ Device object is not valid + */ + +/** + * \fn int32_t (* dev_uart::uart_control) (uint32_t ctrl_cmd, void *param) + * \details control an uart device by \ref ctrl_cmd, with passed \ref param. + * you can control uart device using predefined uart control commands defined using \ref DEV_SET_SYSCMD + * (which must be implemented by bsp developer), such as \ref UART_CMD_SET_BAUD "change baudrate", + * \ref UART_CMD_FLUSH_OUTPUT "flush output" and \ref DEVICE_HAL_UART_CTRLCMD "more". + * And you can also control uart device using your own specified commands defined using \ref DEV_SET_USRCMD, + * but these specified commands should be defined in your own uart device driver implementation. + * \param[in] ctrl_cmd \ref DEVICE_HAL_UART_CTRLCMD "control command", to change or get some thing related to uart + * \param[in,out] param parameters that maybe argument of the command, or return values of the command + * \retval E_OK Control device successfully + * \retval E_CLSED Device is not opened + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid for current control command + * \retval E_SYS Control device failed, due to hardware issues, such as device is disabled + * \retval E_CTX Control device failed, due to different reasons like in transfer state + * \retval E_NOSPT Control command is not supported or not valid + */ + +/** + * \fn int32_t (* dev_uart::uart_write) (const void *data, uint32_t len) + * \details send \ref data through uart with defined \ref len(blocked). + * \param[in] data pointer to data need to send by uart, must not be NULL + * \param[in] len length of data to be sent, must > 0 + * \retval >0 Byte count that was successfully sent for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + * \retval E_SYS Can't write data to hardware due to hardware issues, such as device is disabled + */ + +/** + * \fn int32_t (* dev_uart::uart_read) (void *data, uint32_t len) + * \details receive \ref data of defined \ref len through uart(blocked). + * \param[out] data pointer to data need to received by uart, must not be NULL + * \param[in] len length of data to be received, must > 0 + * \retval >0 Byte count that was successfully received for poll method + * \retval E_OBJ Device object is not valid or not exists + * \retval E_PAR Parameter is not valid + * \retval E_SYS Can't receive data from hardware due to hardware issues, such as device is disabled + */ +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief get an \ref dev_uart "uart device" by uart device id. + * For how to use uart device hal refer to \ref DEVICE_HAL_UART_DEVSTRUCT "Functions in uart device structure" + * \param[in] uart_id id of uart, defined by user + * \retval !NULL pointer to an \ref dev_uart "uart device structure" + * \retval NULL failed to find the uart device by \ref uart_id + * \note need to implemented by user in user code + */ +extern DEV_UART_PTR uart_get_dev(int32_t uart_id); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* _DEVICE_HAL_UART_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/embARC_BSP_config.h b/third_party/synopsys/embarc_emsk_bsp/embARC_BSP_config.h new file mode 100755 index 000000000..372cf0fe2 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/embARC_BSP_config.h @@ -0,0 +1,83 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-12-25 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup COMMON_CONFIG + * \brief header file to define common definitions error management + */ + +/** + * \addtogroup COMMON_CONFIG + * @{ + */ + +#ifndef _COMMON_CONFIG_H_ +#define _COMMON_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOARD_EMSK +/**************************************************************************** + * BSP Definition + ****************************************************************************/ +/** + * Toolchain Definition for MetaWare or GNU + */ +// #define __MW__ +#define __GNU__ +#define _HAVE_LIBGLOSS_ + +/** + * Use task_main in embARC Startup process. See board/board.c for details. + */ +#define EMBARC_USE_BOARD_MAIN + +/** + * Must be set. + * If changed, modify .lcf file for + * .stack ALIGN(4) SIZE(524288): {} + * .heap? ALIGN(4) SIZE(524288): {} + */ +#define _STACKSIZE 524288 +#define _HEAPSZ 524288 + + +#ifdef __cplusplus +} +#endif + +#endif /* _COMMON_CONFIG_H_ */ +/** @} end of group COMMON_CONFIG */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc.h new file mode 100644 index 000000000..c1c7ae953 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc.h @@ -0,0 +1,436 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-20 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_CORE_COMM + * \brief header file including common core definitions + */ + +/** + * \addtogroup ARC_HAL_CORE_COMM + * @{ + */ + + +#ifndef _ARC_HAL_CORE_H_ +#define _ARC_HAL_CORE_H_ + +#include "inc/arc/arc_feature_config.h" + +/** + * \name exception number definitions + * @{ + */ + +/* ARC exception number */ +#define EXC_NO_RESET (0) /*!< reset vector, the entry of power up and reset */ +#define EXC_NO_MEM_ERR (1) /*!< external memory bus error */ +#define EXC_NO_INS_ERR (2) /*!< illegal instruction or illegal instruction sequence */ +#define EXC_NO_MAC_CHK (3) /*!< machine check error */ +#define EXC_NO_TLB_MISS_I (4) /*!< instruction TLB missing exception, useless without MMU */ +#define EXC_NO_TLB_MISS_D (5) /*!< data TLB missing exception, useless without MMU */ +#define EXC_NO_PRO_VIO (6) /*!< protection violation */ +#define EXC_NO_PRI_VIO (7) /*!< privilege violation */ +#define EXC_NO_SWI (8) /*!< software interrupt */ +#define EXC_NO_TRAP (9) /*!< trap */ +#define EXC_NO_EXT (10) /*!< extension exception */ +#define EXC_NO_DIV_ZER0 (11) /*!< divide by zero */ +#define EXC_NO_DC_ERR (12) /*!< data cache consistency error */ +#define EXC_NO_MAL_ALIGN (13) /*!< misaligned data access */ +#define EXC_NO_RESERVE0 (14) /*!< reserved */ +#define EXC_NO_RESERVE1 (15) /*!< reserved */ + +/* extension interrupts */ +#define EXC_NO_16 (16) /*!< interrupt vector 16 */ +#define EXC_NO_17 (17) /*!< interrupt vector 17 */ +#define EXC_NO_18 (18) /*!< interrupt vector 18 */ +#define EXC_NO_19 (19) /*!< interrupt vector 19 */ +#define EXC_NO_20 (20) /*!< interrupt vector 20 */ +#define EXC_NO_21 (21) /*!< interrupt vector 21 */ +#define EXC_NO_22 (22) /*!< interrupt vector 22 */ +#define EXC_NO_23 (23) /*!< interrupt vector 23 */ +#define EXC_NO_24 (24) /*!< interrupt vector 24 */ +#define EXC_NO_25 (25) /*!< interrupt vector 25 */ +#define EXC_NO_26 (26) /*!< interrupt vector 26 */ +#define EXC_NO_27 (27) /*!< interrupt vector 27 */ +#define EXC_NO_28 (28) /*!< interrupt vector 28 */ +#define EXC_NO_29 (29) /*!< interrupt vector 29 */ +#define EXC_NO_30 (30) /*!< interrupt vector 30 */ +#define EXC_NO_31 (31) /*!< interrupt vector 31 */ +/* ... ARC supports 255 interrupt vectors at most */ +#define EXC_NO_255 (255) /*!< interrupt vector 255 */ + +/** @} */ + +/** + * \name exception vector offset + * @{ + */ +#define EXC_NO_TO_OFFSET(no) (no << 2) + +/* ARC exception vector offset */ +#define EXC_VECTOR_RESET (0x00) /*!< EXC_NO_RESET offset */ +#define EXC_VECTOR_MEM_ERR (0x04) /*!< EXC_NO_MEM_ERR offset */ +#define EXC_VECTOR_INS_ERR (0x08) /*!< EXC_NO_INS_ERR offset */ +#define EXC_VECTOR_MAC_CHK (0x0c) /*!< EXC_NO_MAC_CHK offset */ +#define EXC_VECTOR_TLB_MISS_I (0x10) /*!< EXC_NO_TLB_MISS_I offset */ +#define EXC_VECTOR_TLB_MISS_D (0x14) /*!< EXC_NO_TLB_MISS_D offset */ +#define EXC_VECTOR_PRO_VIO (0x18) /*!< EXC_NO_PRO_VIO offset */ +#define EXC_VECTOR_PRI_VIO (0x1c) /*!< EXC_NO_PRI_VIO offset */ +#define EXC_VECTOR_SWI (0x20) /*!< EXC_NO_SWI offset */ +#define EXC_VECTOR_TRAP (0x24) /*!< EXC_NO_TRAP offset */ +#define EXC_VECTOR_EXT (0x28) /*!< EXC_NO_EXT offset */ +#define EXC_VECTOR_DIV_ZER0 (0x2c) /*!< EXC_NO_DIV_ZER0 offset */ +#define EXC_VECTOR_DC_ERR (0x30) /*!< EXC_NO_DC_ERR offset */ +#define EXC_VECTOR_MAL_ALIGN (0x34) /*!< EXC_NO_MAL_ALIGN offset */ +#define EXC_VECTOR_RESERVE0 (0x38) /*!< EXC_NO_RESERVE0 offset */ +#define EXC_VECTOR_RESERVE1 (0x3c) /*!< EXC_NO_RESERVE1 offset */ +/** @} */ + +/** + * \name build configuration register + * @{ + */ +#define AUX_BCR_VER (0x60) /*!< build configuration register version */ +#define AUX_BCR_BTA (0x63) /*!< build configuration for BTA LINK */ +#define AUX_BCR_VECBASE (0x68) /*!< build configuration for interrupt vector base */ +#define AUX_BCR_MPU (0x6d) /*!< build configuration for memory protection unit */ +#define AUX_BCR_RF (0x6e) /*!< build configuration for core registers */ +#define AUX_BCR_D_CACHE (0x72) /*!< build configuration for data cache */ +#define AUX_BCR_DCCM (0x74) /*!< build configuration for DCCM */ +#define AUX_BCR_TIMERS (0x75) /*!< build configuration for processor timers */ +#define AUX_BCR_AP (0x76) /*!< build configuration for actionpoints */ +#define AUX_BCR_I_CACHE (0x77) /*!< build configuration for instruction cache */ +#define AUX_BCR_ICCM (0x78) /*!< build configuration for ICCM */ +#define AUX_BCR_DSP (0x7a) /*!< build configuration for DSP */ +#define AUX_BCR_MUL (0x7b) /*!< build configuration for multiply */ +#define AUX_BCR_SWAP (0x7c) /*!< build configuration for swap */ +#define AUX_BCR_NORM (0x7d) /*!< build configuration for normalize */ +#define AUX_BCR_MIXMAX (0x7e) /*!< build configuration for MIN/MAX */ +#define AUX_BCR_BARREL (0x7f) /*!< build configuration for barrel shift */ +#define AUX_BCR_ISA (0xc1) /*!< build configuration for ISA configuration */ +#define AUX_BCR_STACK (0xc5) /*!< build configuration for stack region */ +#define AUX_BCR_ERP (0xc7) /*!< build configuration for error protection */ +#define AUX_BCR_FPU (0xc8) /*!< build configuration for floating-point unit */ +#define AUX_BCR_CPORT (0xc9) /*!< build configuration for code protection */ +#define AUX_BCR_BS (0xcb) /*!< build configuration for bitstream */ +#define AUX_BCR_AGU (0xcc) /*!< build configuration for address generate unit */ +#define AUX_BCR_DMAC (0xcd) /*!< build configuration for DMA */ +#define AUX_BCR_CONNECT_SYSTEM (0xd0) /*!< build configuration for arc connect */ +#define AUX_BCR_CONNECT_SEMA (0xd1) /*!< build configuration for inter-core semaphore */ +#define AUX_BCR_CONNECT_MESSAGE (0xd2) /*!< build configuration for inter-code message */ +#define AUX_BCR_CONNECT_PMU (0xd3) /*!< build configuration for power management unit */ +#define AUX_BCR_CONNECT_GFRC (0xd6) /*!< build configuration for global free running counter */ +#define AUX_BCR_CAL_STORE (0xd9) /*!< build configuration for calibration parameter storage */ +#define AUX_BCR_CONNECT_ICI (0xe0) /*!< build configuration for inter-core interrupt unit */ +#define AUX_BCR_CONNECT_ICD (0xe1) /*!< build configuration for inter-core debug unit */ +#define AUX_BCR_CONNECT_PDM (0xe3) /*!< build configuration for power domain management unit*/ +#define AUX_BCR_RTT (0xf2) /*!< build configuration for real-time trace */ +#define AUX_BCR_IRQ (0xf3) /*!< build configuration for interrupt */ +#define AUX_BCR_PCT (0xf5) /*!< build configuration for performance counters */ +#define AUX_BCR_CC (0xf6) /*!< build configuration for performance counters */ +#define AUX_BCR_PDM_DVFS (0xf7) /*!< build configuration for PDM and DVFS */ + +#define AUX_BCR_SEC_BUILD (0xdb) + +/* from 0xF5 and 0xF6 */ + +#define AUX_BCR_IFQUEUE (0xfe) /*!< build configuration for instruction fetch queue */ +#define AUX_BCR_SMART (0xff) /*!< build configuration for SmaRT debug feature */ +/** @} */ + + +#define AUX_SEC_STAT (0x9) +#define AUX_SEC_STAT_BIT_SSC (0) +#define AUX_SEC_STAT_BIT_NSRT (1) +#define AUX_SEC_STAT_BIT_NSRU (2) +#define AUX_SEC_STAT_BIT_IRM (3) +#define AUX_SEC_STAT_BIT_SUE (4) +#define AUX_SEC_STAT_BIT_NIC (5) + +/** + * \name status register STATUS32 + * @{ + */ +#define AUX_STATUS32 (0xa) +#define AUX_STATUS32_P0 (0xb) + +/* STATUS32 bit-field definition */ +#define AUX_STATUS_BIT_AE (5) /*!< processor is in an exception */ +#define AUX_STATUS_BIT_DE (6) /*!< delayed branch is pending */ +#define AUX_STATUS_BIT_U (7) /*!< user mode */ +#define AUX_STATUS_BIT_L (12) /*!< zero-overhead loop enable */ +#define AUX_STATUS_BIT_IE (31) /*!< interrupt enable */ + +/* masks correspond to STATUS32 bit-field */ +#define AUX_STATUS_MASK_AE (1< Pre Incr + * Eff Addr for load = [reg2 + x] + * + * LD.ab reg1, [reg2, x] => Post Incr + * Eff Addr for load = [reg2] + */ +#if defined(__GNU__) +.macro PUSH reg +st.a \reg, [sp, -4] +.endm + +.macro PUSHAX aux +lr r10, [\aux] +PUSH r10 +.endm + +.macro POP reg +ld.ab \reg, [sp, 4] +.endm + +.macro POPAX aux +POP r10 +sr r10, [\aux] +.endm +#else +.macro PUSH, reg +st.a reg, [sp, -4] +.endm + +.macro PUSHAX, aux +lr r10, [aux] +PUSH r10 +.endm + +.macro POP, reg +ld.ab reg, [sp, 4] +.endm + +.macro POPAX, aux +POP r10 +sr r10, [aux] +.endm +#endif + +/*-------------------------------------------------------------- + * Helpers to save/restore callee-saved regs: + * used by several macros below + *-------------------------------------------------------------*/ +.macro SAVE_CALLEE_REGS +PUSH r13 +PUSH r14 +PUSH r15 +#ifndef ARC_FEATURE_RF16 +PUSH r16 +PUSH r17 +PUSH r18 +PUSH r19 +PUSH r20 +PUSH r21 +PUSH r22 +PUSH r23 +PUSH r24 +PUSH r25 +#endif +.endm + +.macro RESTORE_CALLEE_REGS +#ifndef ARC_FEATURE_RF16 +POP r25 +POP r24 +POP r23 +POP r22 +POP r21 +POP r20 +POP r19 +POP r18 +POP r17 +POP r16 +#endif +POP r15 +POP r14 +POP r13 +.endm + +.macro CLEAR_CALLEE_REGS +#ifndef ARC_FEATURE_RF16 +mov r25, 0 +mov r24, 0 +mov r23, 0 +mov r22, 0 +mov r21, 0 +mov r20, 0 +mov r19, 0 +mov r18, 0 +mov r17, 0 +mov r16, 0 +#endif +mov r15, 0 +mov r14, 0 +mov r13, 0 +.endm + +.macro CLEAR_SCRATCH_REGS +mov r1, 0 +mov r2, 0 +mov r3, 0 +mov r4, 0 +mov r5, 0 +mov r6, 0 +mov r7, 0 +mov r8, 0 +mov r9, 0 +mov r10, 0 +mov r11, 0 +mov r12, 0 + +mov fp, 0 +mov r29, 0 +mov r30, 0 +.endm + + +.macro SAVE_LP_REGS +PUSH r60 +PUSHAX AUX_LP_START +PUSHAX AUX_LP_END +.endm + +.macro RESTORE_LP_REGS +POPAX AUX_LP_END +POPAX AUX_LP_START +POP r10 +/* must not use the LP_COUNT register(r60) as the destination of multi-cycle instruction */ +mov r60, r10 + +.endm + +.macro SAVE_R0_TO_R12 +PUSH r0 +PUSH r1 +PUSH r2 +PUSH r3 +#ifndef ARC_FEATURE_RF16 +PUSH r4 +PUSH r5 +PUSH r6 +PUSH r7 +PUSH r8 +PUSH r9 +#endif +PUSH r10 +PUSH r11 +PUSH r12 +.endm + +.macro RESTORE_R0_TO_R12 +POP r12 +POP r11 +POP r10 +#ifndef ARC_FEATURE_RF16 +POP r9 +POP r8 +POP r7 +POP r6 +POP r5 +POP r4 +#endif +POP r3 +POP r2 +POP r1 +POP r0 +.endm + +.macro SAVE_CODE_DENSITY +PUSHAX AUX_JLI_BASE +PUSHAX AUX_LDI_BASE +PUSHAX AUX_EI_BASE +.endm + +.macro RESTORE_CODE_DENSITY +POPAX AUX_EI_BASE +POPAX AUX_LDI_BASE +POPAX AUX_JLI_BASE +.endm + +/* todo: check the contents of NON_SCRATCH_REGS in debug */ +.macro SAVE_NONSCRATCH_REGS +/* r0-r12 are saved by caller function */ +PUSH gp +PUSH fp +PUSH blink +SAVE_CALLEE_REGS +.endm + +.macro RESTORE_NONSCRATCH_REGS +RESTORE_CALLEE_REGS +POP blink +POP fp +POP gp +.endm + + +.macro SAVE_FIQ_EXC_REGS +#ifndef ARC_FEATURE_RGF_BANKED_REGS +SAVE_R0_TO_R12 + +PUSH gp +PUSH fp +PUSH r30 /* general purpose */ +PUSH blink + +#else +#if ARC_FEATURE_RGF_BANKED_REGS != 4 && ARC_FEATURE_RGF_BANKED_REGS != 8 && \ + ARC_FEATURE_RGF_BANKED_REGS != 16 && ARC_FEATURE_RGF_BANKED_REGS != 32 +#error "unsupported ARC_FEATURE_RGF_BANKED_REGS" +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 || \ + ARC_FEATURE_RGF_BANKED_REGS == 16 +PUSH r4 +PUSH r5 +PUSH r6 +PUSH r7 +PUSH r8 +PUSH r9 +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 +PUSH r10 +PUSH r11 +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 +PUSH r12 +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 +PUSH gp +PUSH fp +PUSH r30 /* general purpose */ +PUSH blink +#endif + +#endif /* #ifndef ARC_FEATURE_RGF_BANKED_REGS */ + +#ifdef ARC_FEATURE_CODE_DENSITY +SAVE_CODE_DENSITY +#endif +SAVE_LP_REGS +.endm + +.macro RESTORE_FIQ_EXC_REGS +RESTORE_LP_REGS +#ifdef ARC_FEATURE_CODE_DENSITY +RESTORE_CODE_DENSITY +#endif + +#ifndef ARC_FEATURE_RGF_BANKED_REGS +POP blink +POP r30 +POP fp +POP gp + +RESTORE_R0_TO_R12 +#else + +#if ARC_FEATURE_RGF_BANKED_REGS != 4 && ARC_FEATURE_RGF_BANKED_REGS != 8 && \ + ARC_FEATURE_RGF_BANKED_REGS != 16 && ARC_FEATURE_RGF_BANKED_REGS != 32 +#error "unsupported ARC_FEATURE_RGF_BANKED_REGS" +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 +POP blink +POP r30 +POP fp +POP gp +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 +POP r12 +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 +POP r11 +POP r10 +#endif + +#if ARC_FEATURE_RGF_BANKED_REGS == 4 || ARC_FEATURE_BANKED_REGS == 8 || \ + ARC_FEATURE_RGF_BANKED_REGS == 16 +POP r9 +POP r8 +POP r7 +POP r6 +POP r5 +POP r4 +#endif + +#endif /* #ifndef ARC_FEATURE_RGF_BANKED_REGS */ +.endm + +/* normal interrupt prologue, pc, status and r0-r11 are saved by hardware */ +.macro INTERRUPT_PROLOGUE +PUSH r12 +PUSH gp +PUSH fp +PUSH ilink +PUSH r30 + +sub sp, sp, 4 /* skip bta */ +.endm + + +/* normal interrupt epilogue, pc, status and r0-r11 are restored by hardware */ +.macro INTERRUPT_EPILOGUE +add sp, sp, 4 /* skip bta */ + +POP r30 +POP ilink +POP fp +POP gp +POP r12 +.endm + +#if SECURESHIELD_VERSION == 2 +/* exception prologue, create the same frame of interrupt manually */ +.macro EXCEPTION_PROLOGUE +st.as r10, [sp, -6] /* save r10 first, free up a register*/ + +PUSHAX AUX_ERSTATUS +sub sp, sp, 4 /* slot for SEC_STAT */ +PUSHAX AUX_ERRET + +PUSH blink + +PUSH r11 +sub sp, sp, 4 /* r10 is pushed before */ +#ifndef ARC_FEATURE_RF16 +PUSH r9 +PUSH r8 +PUSH r7 +PUSH r6 +PUSH r5 +PUSH r4 +#endif +PUSH r3 +PUSH r2 +PUSH r1 +PUSH r0 + +#ifdef ARC_FEATURE_CODE_DENSITY +SAVE_CODE_DENSITY +#endif +SAVE_LP_REGS + +PUSH r12 +PUSH gp +PUSH fp +PUSH ilink +PUSH r30 + +PUSHAX AUX_ERBTA +.endm + +/* exception epilogue, restore the same frame of interrupt manually */ +.macro EXCEPTION_EPILOGUE +POPAX AUX_ERBTA + +POP r30 +POP ilink +POP fp +POP gp +POP r12 + +RESTORE_LP_REGS + +#ifdef ARC_FEATURE_CODE_DENSITY +RESTORE_CODE_DENSITY +#endif +POP r0 +POP r1 +POP r2 +POP r3 +#ifndef ARC_FEATURE_RF16 +POP r4 +POP r5 +POP r6 +POP r7 +POP r8 +POP r9 +#endif +add sp, sp, 4 /* r10 will be popped finally */ +POP r11 + +POP blink + + +POPAX AUX_ERRET +add sp, sp, 4 /* slot for SEC_STAT */ +POPAX AUX_ERSTATUS + +ld.as r10, [sp, -6] /* restore r10 */ +.endm +#else /* normal version */ +/* exception prologue, create the same frame of interrupt manually */ +.macro EXCEPTION_PROLOGUE +#ifdef ARC_FEATURE_CODE_DENSITY +st.as r10, [sp, -11] /* save r10 first, free up a register*/ +#else +st.as r10, [sp, -8] +#endif +PUSHAX AUX_ERSTATUS +PUSHAX AUX_ERRET + +#ifdef ARC_FEATURE_CODE_DENSITY +SAVE_CODE_DENSITY +#endif +SAVE_LP_REGS + +PUSH blink + +PUSH r11 +sub sp, sp, 4 /* r10 is pushed before */ +#ifndef ARC_FEATURE_RF16 +PUSH r9 +PUSH r8 +PUSH r7 +PUSH r6 +PUSH r5 +PUSH r4 +#endif +PUSH r3 +PUSH r2 +PUSH r1 +PUSH r0 + +PUSH r12 +PUSH gp +PUSH fp +PUSH ilink +PUSH r30 + +PUSHAX AUX_ERBTA +.endm + +/* exception epilogue, restore the same frame of interrupt manually */ +.macro EXCEPTION_EPILOGUE +POPAX AUX_ERBTA + +POP r30 +POP ilink +POP fp +POP gp +POP r12 + +POP r0 +POP r1 +POP r2 +POP r3 +#ifndef ARC_FEATURE_RF16 +POP r4 +POP r5 +POP r6 +POP r7 +POP r8 +POP r9 +#endif +add sp, sp, 4 /* r10 will be popped finally */ +POP r11 + +POP blink + +RESTORE_LP_REGS + +#ifdef ARC_FEATURE_CODE_DENSITY +RESTORE_CODE_DENSITY +#endif + +POPAX AUX_ERRET +POPAX AUX_ERSTATUS + +#ifdef ARC_FEATURE_CODE_DENSITY +ld.as r10, [sp, -11] /* restore r10 */ +#else +ld.as r10, [sp, -8] +#endif +.endm + +#endif /* SECURESHIELD_VERSION == 2 */ + +#endif /* _ARC_HAL_ASM_COMMON_H */ +/** @endcond */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_builtin.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_builtin.h new file mode 100644 index 000000000..bbf257aad --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_builtin.h @@ -0,0 +1,308 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-12 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_BUILTIN + * \brief header file of builtin and helper functions + * + * The Metaware toolchain and the GNU toolchain are supported. The details please go to see the file. + */ + +/** + * \addtogroup ARC_HAL_BUILTIN + * @{ + */ + +#ifndef _ARC_HAL_BUILTIN_H_ +#define _ARC_HAL_BUILTIN_H_ + +#include "inc/embARC_toolchain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__MW__) /* Metaware toolchain */ + +#define _arc_nop _nop /*!< no operation, generate a nop instruction produces a single NOP instruction in the compiled code */ + +#define _arc_brk _brk /*!< generate a brk instruction */ + +#define _arc_clri _clri /*!< generate a clri instruction */ + +#define _arc_seti(c) _seti(c) /*!< generate a seti instruction */ + +#define _arc_core_write(regno, val) _core_write(val, regno) /*!< write core register */ + +#define _arc_core_read(regno) _core_read(regno) /*!< read core register */ + +#define _arc_lr_reg(aux) _lr(aux) /*!< read auxiliary register */ + +#define _arc_sr_reg(aux, val) _sr(val, aux) /*!< write auxiliary register */ + +#define _arc_sleep(a) _sleep(a) /*!< generate a sleep instruction */ + +#define _arc_flag(a) _flag(a) /*!< generate a flag instruction */ + +#define _arc_kflag(a) + +#define _arc_sync _sync /*!< generate a sync instruction */ + +/* + * !< _arc_usually (expr) evaluates expression expr and + * informs the compiler that the value is usually true. + */ +#define _arc_usually(a) _Usually((a)) + +/* + * !< _arc_rarely (expr) evaluates expression expr and + * informs the compiler that the value is rarely true. + */ +#define _arc_rarely(a) _Rarely((a)) + +#if 0 +/** + * \brief Reverses the byte order of the 16-bit operand, + * reversing the endianness of the value. + * Not for ARC HS family + */ +#define _arc_swap16(a) _swap16(a) +/** + * \brief Reverses the byte order of the 32-bit operand, + * reversing the endianness of the value. + * Not for ARC HS family + */ +#define _arc_swap32(a) _swap32(a) +#else +Inline uint32_t _arc_swap32(uint32_t val) +{ + register uint32_t v; + __asm__ volatile("swape %0, %1" :"=r"(v): "r"(val)); + return v; +} + +Inline uint16_t _arc_swap16(uint32_t val) +{ + register uint32_t temp; + register uint32_t v; + __asm__ volatile("swape %0, %1" :"=r"(temp): "r"(val)); + __asm__ volatile("lsr16 %0, %1" :"=r"(v): "r"(temp)); + return (unsigned short)v; +} +#endif + +/** + * \brief Each call to _swi() generates one + * software interrupt instruction (SWI) for processors + * to support the SWI instruction. + */ +#define _arc_swi _swi + +/* \todo add more builtin functions of metaware tool */ + +#elif defined (__GNU__) /* GNU toolchain */ + +#define _arc_nop __builtin_arc_nop +#define _arc_brk __builtin_arc_brk +#define _arc_seti(c) __builtin_arc_seti(c) +#define _arc_core_write(regno, val) __builtin_arc_core_write(regno,val) +#define _arc_core_read(regno) __builtin_arc_core_read(regno) +#define _arc_flag(a) __builtin_arc_flag(a) +#define _arc_kflag(a) __builtin_arc_kflag(a) +#define _arc_lr_reg(aux) __builtin_arc_lr(aux) +/* don't uncomment this now */ +//#define _arc_sr_reg(aux, val) __builtin_arc_sr(aux, val) +#define _arc_sleep(a) __builtin_arc_sleep(a) +//#define _arc_sync __builtin_arc_sync + +/** + * \brief _arc_usually (expr) evaluates expression expr and + * informs the compiler that the value is usually true. + */ +#define _arc_usually(a) __builtin_expect((int)(a), 1) + +/** + * \brief _arc_rarely (expr) evaluates expression expr and + * informs the compiler that the value is rarely true. + */ +#define _arc_rarely(a) __builtin_expect((int)(a), 0) + +/** + * \brief Each call to _swi() generates one + * software interrupt instruction (SWI) for processors + * to support the SWI instruction. + */ +#define _arc_swi __builtin_arc_swi + +Inline uint32_t _arc_clri(void) +{ + register uint32_t v; + __asm__ volatile("clri %0" :"=r"(v)); + return v; + +} +/* \todo add more builtin functions of gnu tool */ + +Inline uint32_t _arc_swap32(uint32_t val) +{ + register uint32_t v; + __asm__ volatile("swape %0, %1" :"=r"(v): "r"(val)); + return v; +} + +Inline uint16_t _arc_swap16(uint32_t val) +{ + register uint32_t temp; + register uint32_t v; + __asm__ volatile("swape %0, %1" :"=r"(temp): "r"(val)); + __asm__ volatile("lsr16 %0, %1" :"=r"(v): "r"(temp)); + return (unsigned short)v; +} + +Inline void _arc_sync(void) +{ + __asm__ volatile("sync"); +} + +/** + * \note Following is a workaround for arc gcc + * built-in function __builtin_arc_sr. + * But it is wrong in GCC arc-4.8-R3-rc3 and shouldn't be used. + */ + +/* + * The auxiliary register address is specified as a long immediate operand by caller. + * e.g. + * write_aux_reg(0x69, some_val); + * This generates the tightest code. + */ +#define write_aux_reg(reg_imm, val) \ +({ \ + Asm( \ + " sr %0, [%1] \n" \ + : \ + : "ir"(val), "r"(reg_imm)); \ +}) + +#define _arc_sr_reg(aux, val) write_aux_reg(aux, val) + +#endif + +/* \todo add more helper functions here, such as memory operation */ + +#define _arc_aux_read(aux) _arc_lr_reg(aux) +#define _arc_aux_write(aux, val) _arc_sr_reg(aux, val) + +/** + * \name cache related helper function + * @{ + */ + +/** + * \brief read memory and bypass the cache + * \param[in] ptr memory address + * \return value in the memory + */ +Inline uint32_t _arc_read_uncached_32(void *ptr) +{ + uint32_t __ret; + Asm("ld.di %0, [%1]": "=r"(__ret): "r"(ptr)); + return __ret; +} + +/** + * \brief write memory and bypass the cache + * \param[in] ptr memory address + * \param[in] data vaule to be written + */ +Inline void _arc_write_uncached_32(void *ptr, uint32_t data) +{ + Asm("st.di %0, [%1]":: "r"(data), "r"(ptr)); +} + +/** + * \brief read memory with cache + * \param[in] ptr memory address + * \returns value in the memory + */ +Inline uint32_t _arc_read_cached_32(void *ptr) +{ + uint32_t __ret; + Asm("ld %0, [%1]": "=r"(__ret): "r"(ptr)); + return __ret; +} + +/** + * \brief read memory with cache + * \param[in] ptr memory address + * \param[in] data vaule to be written + * \return description + */ +Inline void _arc_write_cached_32(void *ptr, uint32_t data) +{ + Asm("st %0, [%1]":: "r"(data), "r"(ptr)); +} + +/** + * \brief go to main function with proper arguments + * \param argc argument count + * \param argv argument content array + * \retval return value of main function + */ +Inline int32_t _arc_goto_main(int argc, char **argv) +{ + int __ret; + __asm__ volatile( + "mov %%r0, %1\n" + "mov %%r1, %2\n" + "push_s %%blink\n" + "jl main\n" + "pop_s %%blink\n" + "mov %0, %%r0" + :"=r"(__ret): "r"(argc), "r"(argv)); + return (int)__ret; +} + +#ifdef __cplusplus +} +#endif + +#if defined(LIB_SECURESHIELD) && defined(LIB_SECURESHIELD_OVERRIDES) && (SECURESHIELD_VERSION == 1) +#define OVERRIDE_ARC_HAL_BUILTIN_H +#include "secureshield_overrides.h" +#endif + +/** @} */ +#endif /* _ARC_HAL_BUILTIN_H_ */ +/** @} */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_cache.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_cache.h new file mode 100644 index 000000000..e53f9ee04 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_cache.h @@ -0,0 +1,354 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_MISC_CACHE + * \brief header file of cache module + */ + +#ifndef _ARC_HAL_CACHE_H_ +#define _ARC_HAL_CACHE_H_ + +#include "inc/embARC_toolchain.h" +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" +#include "inc/arc/arc_exception.h" + +/** + * \name instruction cache control register related definition + * \todo this definitions will be reviewed. + * @{ + */ +#define IC_CTRL_IC_ENABLE 0x0 /*!< enable instruction cache */ +#define IC_CTRL_IC_DISABLE 0x1 /*!< disable instruction cache */ +#define IC_CTRL_DIRECT_ACCESS 0x0 /*!< direct access mode */ +#define IC_CTRL_INDIRECT_ACCESS 0x20 /*!< indirect access mode */ +#define IC_CTRL_OP_SUCCEEDED 0x8 /*!< instruction cache operation succeeded */ +/** @} */ + +/** + * \name data cache control register related definition + * \todo this definition will be reviewed. + * @{ + */ +#define IC_CTRL_I +#define DC_CTRL_DC_ENABLE 0x0 /*!< enable data cache */ +#define DC_CTRL_DC_DISABLE 0x1 /*!< disable data cache */ +#define DC_CTRL_INVALID_ONLY 0x0 /*!< invalid data cache only */ +#define DC_CTRL_INVALID_FLUSH 0x40 /*!< invalid and flush data cache */ +#define DC_CTRL_ENABLE_FLUSH_LOCKED 0x80 /*!< the locked data cache can be flushed */ +#define DC_CTRL_DISABLE_FLUSH_LOCKED 0x0 /*!< the locked data cache cannot be flushed */ +#define DC_CTRL_FLUSH_STATUS 0x100 /*!< flush status */ +#define DC_CTRL_DIRECT_ACCESS 0x0 /*!< direct access mode */ +#define DC_CTRL_INDIRECT_ACCESS 0x20 /*!< indirect access mode */ +#define DC_CTRL_OP_SUCCEEDED 0x4 /*!< data cache operation succeeded */ +/** @} */ + +/** + * \name instruction cache related inline function + * @{ + */ + +/** + * \brief check whether instruction cache is available, + * 0 for not available, >0 for available + */ +Inline uint8_t icache_available(void) +{ + return (_arc_aux_read(AUX_BCR_I_CACHE) & 0xF); +} + +/** + * \brief enable instruction cache + * \param[in] icache_en_mask operation mask + */ +Inline void icache_enable(uint32_t icache_en_mask) +{ + if (!icache_available()) { return; } + + _arc_aux_write(AUX_IC_CTRL, icache_en_mask); +} + +/** + * \brief disable instruction cache + */ +Inline void icache_disable(void) +{ + if (!icache_available()) { return; } + + _arc_aux_write(AUX_IC_CTRL, IC_CTRL_IC_DISABLE); +} + +/** + * \brief invalidate the entire instruction cache + */ +Inline void icache_invalidate(void) +{ + if (!icache_available()) { return; } + + /* invalidate the entire icache */ + _arc_aux_write(AUX_IC_IVIC, 0); + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); +} + +/** + * \brief invalidate specific cache line + * \param[in] address memory address + */ +Inline void icache_invalidate_line(uint32_t address) +{ + if (!icache_available()) { return; } + + _arc_aux_write(AUX_IC_IVIL, address); + /* the 3 nops are required by ARCv2 ISA */ + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); +} + +/** + * \brief lock specific cache line + * \param[in] address memory address + * \return 0, succeeded, -1, failed + */ +Inline int32_t icache_lock_line(uint32_t address) +{ + if (!icache_available()) { return -1; } + + _arc_aux_write(AUX_IC_LIL, address); + + if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) + { + return 0; + } + else + { + return -1; + } +} + +/** + * \brief set icache access mode + * \param[in] mode, access mode, 1: indirect access 0:direct access + */ +Inline void icache_access_mode(uint32_t mode) +{ + if (!icache_available()) { return; } + + if (mode) + { + _arc_aux_write(AUX_IC_CTRL, _arc_aux_read(AUX_IC_CTRL) | IC_CTRL_INDIRECT_ACCESS); + } + else + { + _arc_aux_write(AUX_IC_CTRL, _arc_aux_read(AUX_IC_CTRL) & (~IC_CTRL_INDIRECT_ACCESS)); + } +} + + +/** @} */ + +/** + * \name data cache related inline functions + * @{ + */ + +/** + * \brief check whether data cache is available, + * 0 for not available, >0 for available + */ +Inline uint8_t dcache_available(void) +{ + return (_arc_aux_read(AUX_BCR_D_CACHE) & 0xF); +} + +/** + * \brief invalidate the entire data cache + */ +Inline void dcache_invalidate(void) +{ + if (!dcache_available()) { return; } + + uint32_t status; + + status = cpu_lock_save(); + _arc_aux_write(AUX_DC_IVDC, 1); + + /* wait for flush completion */ + while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); + + cpu_unlock_restore(status); +} + +/** + * \brief invalidate the specific cache line + * \param[in] address memory address + */ +Inline void dcache_invalidate_line(uint32_t address) +{ + if (!dcache_available()) { return; } + + _arc_aux_write(AUX_DC_IVDL, address); + Asm("nop_s"); + Asm("nop_s"); + Asm("nop_s"); +} + +/** + * \brief enable data cache + * \param[in] dcache_en_mask operation mask + */ +Inline void dcache_enable(uint32_t dcache_en_mask) +{ + if (!dcache_available()) { return; } + + _arc_aux_write(AUX_DC_CTRL, dcache_en_mask); +} + +/** + * \brief disable data cache + */ +Inline void dcache_disable(void) +{ + if (!dcache_available()) { return; } + + _arc_aux_write(AUX_DC_CTRL, DC_CTRL_DC_DISABLE); +} + +/** + * \brief flush data cache + */ +Inline void dcache_flush(void) +{ + if (!dcache_available()) { return; } + + uint32_t status; + + status = cpu_lock_save(); + _arc_aux_write(AUX_DC_FLSH, 1); + + /* wait for flush completion */ + while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); + + cpu_unlock_restore(status); +} + +/** + * \brief flush the specific data cache line + * \param[in] address memory address + */ +Inline void dcache_flush_line(uint32_t address) +{ + if (!dcache_available()) { return; } + + uint32_t status; + + status = cpu_lock_save(); + _arc_aux_write(AUX_DC_FLDL, address); + + while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); + + cpu_unlock_restore(status); +} + +/** + * \brief lock the specific data cache line + * \param[in] address memory address + * \return 0, succeeded, -1, failed + */ +Inline int dcache_lock_line(uint32_t address) +{ + if (!dcache_available()) { return -1; } + + _arc_aux_write(AUX_DC_LDL, address); + + if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) + { + return 0; + } + else + { + return -1; + } +} + +/** + * \brief set dcache access mode + * \param[in] mode, access mode, 1: indirect access 0:direct access + */ +Inline void dcache_access_mode(uint32_t mode) +{ + if (!dcache_available()) { return; } + + if (mode) + { + _arc_aux_write(AUX_DC_CTRL, _arc_aux_read(AUX_DC_CTRL) | DC_CTRL_INDIRECT_ACCESS); + } + else + { + _arc_aux_write(AUX_DC_CTRL, _arc_aux_read(AUX_DC_CTRL) & (~DC_CTRL_INDIRECT_ACCESS)); + } +} + +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name declarations of cache related functions + * @{ + */ +extern int32_t icache_invalidate_mlines(uint32_t start_addr, uint32_t size); +extern int32_t icache_lock_mlines(uint32_t start_addr, uint32_t size); +extern int32_t icache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data); +extern int32_t icache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data); +extern int32_t icache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data); +extern int32_t dcache_invalidate_mlines(uint32_t start_addr, uint32_t size); +extern int32_t dcache_flush_mlines(uint32_t start_addr, uint32_t size); +extern int32_t dcache_lock_mlines(uint32_t start_addr, uint32_t size); +extern int32_t dcache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data); +extern int32_t dcache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data); +extern int32_t dcache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data); +extern void arc_cache_init(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* _ARC_HAL_CACHE_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_em.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_em.h new file mode 100644 index 000000000..284cc31e3 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_em.h @@ -0,0 +1,133 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-06-12 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_CORE_EM + * \brief header file of EM series + */ + +/** + * \addtogroup ARC_HAL_CORE_EM + * @{ + */ + +#ifndef _ARC_HAL_EM_H_ +#define _ARC_HAL_EM_H_ + +#include "inc/arc/arc.h" + +#define AUX_ACC0_LO (0x580) +#define AUX_ACC0_GLO (0x581) +#define AUX_ACC0_HI (0x582) +#define AUX_ACC0_GHI (0x583) +#define AUX_DSP_BFLY0 (0x598) +#define AUX_DSP_FFT_CTRL (0x59e) +#define AUX_DSP_CTRL (0x59f) + +#define AUX_AGU_AUX_AP0 (0x5c0) +#define AUX_AGU_AUX_AP1 (0x5c1) +#define AUX_AGU_AUX_AP2 (0x5c2) +#define AUX_AGU_AUX_AP3 (0x5c3) +#define AUX_AGU_AUX_AP4 (0x5c4) +#define AUX_AGU_AUX_AP5 (0x5c5) +#define AUX_AGU_AUX_AP6 (0x5c6) +#define AUX_AGU_AUX_AP7 (0x5c7) +#define AUX_AGU_AUX_AP8 (0x5c8) +#define AUX_AGU_AUX_AP9 (0x5c9) +#define AUX_AGU_AUX_AP10 (0x5ca) +#define AUX_AGU_AUX_AP11 (0x5cb) +#define AUX_AGU_AUX_AP12 (0x5cc) +#define AUX_AGU_AUX_AP13 (0x5cd) +#define AUX_AGU_AUX_AP14 (0x5ce) +#define AUX_AGU_AUX_AP15 (0x5cf) + +#define AUX_AGU_AXU_OS0 (0x5d0) +#define AUX_AGU_AXU_OS1 (0x5d1) +#define AUX_AGU_AXU_OS2 (0x5d2) +#define AUX_AGU_AXU_OS3 (0x5d3) +#define AUX_AGU_AXU_OS4 (0x5d4) +#define AUX_AGU_AXU_OS5 (0x5d5) +#define AUX_AGU_AXU_OS6 (0x5d6) +#define AUX_AGU_AXU_OS7 (0x5d7) +#define AUX_AGU_AXU_OS8 (0x5d8) +#define AUX_AGU_AXU_OS9 (0x5d9) +#define AUX_AGU_AXU_OS10 (0x5da) +#define AUX_AGU_AXU_OS11 (0x5db) +#define AUX_AGU_AXU_OS12 (0x5dc) +#define AUX_AGU_AXU_OS13 (0x5dd) +#define AUX_AGU_AXU_OS14 (0x5de) +#define AUX_AGU_AXU_OS15 (0x5df) + +#define AUX_AGU_AUX_MOD0 (0x5e0) +#define AUX_AGU_AUX_MOD1 (0x5e1) +#define AUX_AGU_AUX_MOD2 (0x5e2) +#define AUX_AGU_AUX_MOD3 (0x5e3) +#define AUX_AGU_AUX_MOD4 (0x5e4) +#define AUX_AGU_AUX_MOD5 (0x5e5) +#define AUX_AGU_AUX_MOD6 (0x5e6) +#define AUX_AGU_AUX_MOD7 (0x5e7) +#define AUX_AGU_AUX_MOD8 (0x5e8) +#define AUX_AGU_AUX_MOD9 (0x5e9) +#define AUX_AGU_AUX_MOD10 (0x5ea) +#define AUX_AGU_AUX_MOD11 (0x5eb) +#define AUX_AGU_AUX_MOD12 (0x5ec) +#define AUX_AGU_AUX_MOD13 (0x5ed) +#define AUX_AGU_AUX_MOD14 (0x5ee) +#define AUX_AGU_AUX_MOD15 (0x5ef) +#define AUX_AGU_AUX_MOD16 (0x5f0) +#define AUX_AGU_AUX_MOD17 (0x5f1) +#define AUX_AGU_AUX_MOD18 (0x5f2) +#define AUX_AGU_AUX_MOD19 (0x5f3) +#define AUX_AGU_AUX_MOD20 (0x5f4) +#define AUX_AGU_AUX_MOD21 (0x5f5) +#define AUX_AGU_AUX_MOD22 (0x5f6) +#define AUX_AGU_AUX_MOD23 (0x5f7) + +#define AUX_XCCM_BASE (0x5f8) +#define AUX_YCCM_BASE (0x5f9) + + +/** \todo add em series specific definitions here */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ARC_HAL_EM_H_ */ + +/** @} */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_exception.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_exception.h new file mode 100644 index 000000000..19c87a9fb --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_exception.h @@ -0,0 +1,473 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_EXCEPTION_CPU ARC_HAL_EXCEPTION_INTERRUPT + * \brief header file of exception and interrupt management module + */ + +#ifndef _ARC_HAL_EXCEPTION_H_ +#define _ARC_HAL_EXCEPTION_H_ + +#include "inc/embARC_toolchain.h" +#include "inc/arc/arc.h" +#include "inc/arc/arc_builtin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup ARC_HAL_EXCEPTION_CPU + * @{ + * \todo need a conf.h from application or board to define the + * features of processor, such as number of exception, code + * density and FIQ. + */ +#ifndef NUM_EXC_CPU +#define NUM_EXC_CPU 16 /*!< number of CPU exceptions */ +#endif + +#ifndef NUM_EXC_INT +#define NUM_EXC_INT 9 /*!< number of interrupt exceptions, defined by users*/ +#endif + +#define NUM_EXC_ALL (NUM_EXC_CPU + NUM_EXC_INT) /*!< total number of exceptions */ + + + +#ifdef ARC_FEATURE_SEC_PRESENT +typedef struct int_exc_frame +{ + uint32_t erbta; + + uint32_t r30; /* r30 is useless, skipped? */ + uint32_t ilink; /* r29 is useless, skipped?*/ + /* r28 is sp, saved other place */ + uint32_t fp; /* r27 */ + uint32_t gp; /* r26 */ + + uint32_t r12; + + uint32_t lp_end, lp_start, lp_count; + +#ifdef ARC_FEATURE_CODE_DENSITY + uint32_t ei, ldi, jli; +#endif + + uint32_t r0, r1, r2, r3; +#ifndef ARC_FEATURE_RF16 + uint32_t r4, r5, r6, r7, r8, r9; +#endif + uint32_t r10, r11; + + uint32_t blink; /* r31 */ + uint32_t ret; + uint32_t sec_stat; + uint32_t status32; +} EMBARC_PACKED INT_EXC_FRAME; +#else +typedef struct int_exc_frame +{ + uint32_t erbta; + + uint32_t r30; /* r30 is useless, skipped? */ + uint32_t ilink; /* r29 is useless, skipped?*/ + /* r28 is sp, saved other place */ + uint32_t fp; /* r27 */ + uint32_t gp; /* r26 */ + + uint32_t r12; + + uint32_t r0, r1, r2, r3; +#ifndef ARC_FEATURE_RF16 + uint32_t r4, r5, r6, r7, r8, r9; +#endif + uint32_t r10, r11; + + uint32_t blink; /* r31 */ + + uint32_t lp_end, lp_start, lp_count; + +#ifdef ARC_FEATURE_CODE_DENSITY + uint32_t ei, ldi, jli; +#endif + + uint32_t ret; + uint32_t status32; +} EMBARC_PACKED INT_EXC_FRAME; +#endif + +typedef struct callee_frame +{ +#ifndef ARC_FEATURE_RF16 + uint32_t r25; + uint32_t r24; + uint32_t r23; + uint32_t r22; + uint32_t r21; + uint32_t r20; + uint32_t r19; + uint32_t r18; + uint32_t r17; + uint32_t r16; +#endif + uint32_t r15; + uint32_t r14; + uint32_t r13; +} EMBARC_PACKED CALLEE_FRAME; + +typedef struct processor_frame +{ + CALLEE_FRAME callee_regs; + INT_EXC_FRAME exc_frame; +} EMBARC_PACKED PROCESSOR_FRAME; + +#define ARC_PROCESSOR_FRAME_SIZE (sizeof(PROCESSOR_FRAME) / sizeof(uint32_t)) +#define ARC_EXC_FRAME_SIZE (sizeof(INT_EXC_FRAME) / sizeof(uint32_t)) +#define ARC_CALLEE_FRAME_SIZE (sizeof(CALLEE_FRAME) / sizeof(uint32_t)) + + +extern uint32_t exc_nest_count; + +/** + * \brief write the exception vector base + * + * \param[in] vec_base the target vector base + */ +Inline void arc_vector_base_write(const void *vec_base) +{ + _arc_aux_write(AUX_INT_VECT_BASE, (uint32_t)vec_base); +} + +/** + * \brief read current exception vector base + * + * \returns exception vector base (uint32_t) + */ +Inline uint32_t arc_vector_base_read(void) +{ + return _arc_aux_read(AUX_INT_VECT_BASE); +} + +/** + * \brief sense whether in exc/interrupt processing + * + * \retval 0 not in exc/interrupt processing + * \retval 1 in exc/interrupt processing + */ +Inline uint32_t exc_sense(void) +{ + return (exc_nest_count > 0U); +} + +/** @}*/ + +/** + * \addtogroup ARC_HAL_EXCEPTION_INTERRUPT + * @{ + */ +#ifndef INT_PRI_MIN +#define INT_PRI_MIN (-2) /*!< the minimum interrupt priority */ +#endif + +#define INT_PRI_MAX (-1) /*!< the maximum interrupt priority */ +/** + * \brief disable the specific interrupt + * + * \param[in] intno interrupt number + */ +Inline void arc_int_disable(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + _arc_aux_write(AUX_IRQ_ENABLE, 0); +} + +/** + * \brief enable the specific int + * + * \param[in] intno interrupt number + */ +Inline void arc_int_enable(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + _arc_aux_write(AUX_IRQ_ENABLE, 1); +} + +/** + * \brief check whether the specific int is enabled + * + * \param[in] intno interrupt number + * \return 0 disabled, 1 enabled + */ +Inline uint32_t arc_int_enabled(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + return _arc_aux_read(AUX_IRQ_ENABLE); +} + +/** + * \brief get the interrupt priority mask + * + * \returns interrupt priority mask, negative num + */ +Inline uint32_t arc_int_ipm_get(void) +{ + return ((_arc_aux_read(AUX_STATUS32) >> 1) & 0x0f); +} + +/** + * \brief set the interrupt priority mask + * + * \param[in] intpri interrupt priority + */ +Inline void arc_int_ipm_set(uint32_t intpri) +{ + volatile uint32_t status; + status = _arc_aux_read(AUX_STATUS32) & ~0x1e; + + status = status | ((intpri << 1) & 0x1e); + /* sr cannot write AUX_STATUS32 */ + Asm("kflag %0"::"ir"(status)); +} + +/** + * \brief get current interrupt priority mask + * + * \param[in] intno interrupt number + */ +Inline uint32_t arc_int_pri_get(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + return _arc_aux_read(AUX_IRQ_PRIORITY); +} + +/** + * \brief set interrupt priority + * + * \param[in] intno interrupt number + * \param[in] intpri interrupt priority + */ +Inline void arc_int_pri_set(const uint32_t intno, uint32_t intpri) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + _arc_aux_write(AUX_IRQ_PRIORITY, intpri | (_arc_aux_read(AUX_IRQ_PRIORITY) & 0xfffffff0)); +} + +/** + * \brief set interrupt secure or not secure + * + * \param[in] intno interrupt number + * \param[in] secure, 0 for normal, >0 for secure + */ +Inline void arc_int_secure_set(const uint32_t intno, uint32_t secure) +{ + + _arc_aux_write(AUX_IRQ_SELECT, intno); + + if (secure) + { + _arc_aux_write(AUX_IRQ_PRIORITY, _arc_aux_read(AUX_IRQ_PRIORITY) | + (1 << AUX_IRQ_PRIORITY_BIT_S)); + } + else + { + _arc_aux_write(AUX_IRQ_PRIORITY, _arc_aux_read(AUX_IRQ_PRIORITY) & 0xf); + } + +} + +/** + * \brief probe the pending status of interrupt + * + * \param[in] intno interrupt number + * + * \returns 1 pending, 0 no pending + */ +Inline uint32_t arc_int_probe(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + return _arc_aux_read(AUX_IRQ_PENDING); +} + +/** + * \brief trigger the interrupt in software + * + * \param[in] intno interrupt number + */ +Inline void arc_int_sw_trigger(const uint32_t intno) +{ + _arc_aux_write(AUX_IRQ_HINT, intno); +} + +/** + * \brief config the interrupt level triggered or pulse triggered + * + * \param[in] intno interrupt number + * \param[in] level, 0-level trigger, 1-pluse triggered + */ +Inline void arc_int_level_config(const uint32_t intno, const uint32_t level) +{ + _arc_aux_write(AUX_IRQ_SELECT, intno); + _arc_aux_write(AUX_IRQ_TRIGGER, level); +} + +/** + * \brief lock cpu, disable interrupts + */ +Inline void arc_lock(void) +{ + Asm("clri"); + Asm(""::: "memory"); +} + +/** + * \brief unlock cpu, enable interrupts to happen + */ +Inline void arc_unlock(void) +{ + Asm(""::: "memory"); + Asm("seti"); +} + +/** + * \brief lock cpu and staus + * + * \returns cpu status + */ +Inline uint32_t arc_lock_save(void) +{ + return _arc_clri(); +} + +/** + * \brief unlock cpu with the specific status + * + * \param[in] status cpu status saved by cpu_lock_save + */ +Inline void arc_unlock_restore(const uint32_t status) +{ + _arc_seti(status); +} +/** @}*/ + +/** + * \addtogroup ARC_HAL_EXCEPTION_CPU + * @{ + */ +/** + * \typedef EXC_ENTRY + * \brief the data type for exception entry + */ +typedef void (*EXC_ENTRY)(void); +/** + * \typedef EXC_HANDLER + * \brief the data type for exception handler + */ +typedef void (*EXC_HANDLER)(void *exc_frame); +/** @}*/ + + +/** + * \ingroup ARC_HAL_EXCEPTION_INTERRUPT + * \typedef INT_HANDLER + * \brief the data type for interrupt handler + */ +typedef void (*INT_HANDLER)(void *ptr); + +extern EXC_ENTRY exc_entry_table[NUM_EXC_ALL]; +extern EXC_HANDLER exc_int_handler_table[NUM_EXC_ALL]; + +/** \ingroup ARC_HAL_EXCEPTION_CPU + * @{ + */ +/** + * \fn _arc_reset + * \brief the reset entry + */ +extern void _arc_reset(void); +/** + * \fn exc_entry_cpu + * \brief the default CPU exception entry + */ +extern void exc_entry_cpu(void); + +/** + * \fn exc_entry_firq + * \brief the fast interrupt exception entry + */ +extern void exc_entry_firq(void); +/** + * \fn exc_entry_int + * \brief the interrupt exception entry + */ +extern void exc_entry_int(void); +/** @}*/ + +/* excetpion related apis */ +extern void exc_int_init(void); +extern int32_t exc_entry_install(const uint32_t excno, EXC_ENTRY entry); +extern EXC_ENTRY exc_entry_get(const uint32_t excno); +extern int32_t exc_handler_install(const uint32_t excno, EXC_HANDLER handler); +extern EXC_HANDLER exc_handler_get(const uint32_t excno); + +/* interrupt related apis */ +extern int32_t int_disable(const uint32_t intno); +extern int32_t int_enable(const uint32_t intno); +extern int32_t int_enabled(const uint32_t intno); +extern int32_t int_ipm_get(void); +extern int32_t int_ipm_set(int32_t intpri); +extern int32_t int_pri_get(const uint32_t intno); +extern int32_t int_pri_set(const uint32_t intno, int32_t intpri); +extern int32_t int_probe(const uint32_t intno); +extern int32_t int_sw_trigger(const uint32_t intno); +extern int32_t int_level_config(const uint32_t intno, const uint32_t level); +extern void cpu_lock(void); +extern void cpu_unlock(void); +extern uint32_t cpu_lock_save(void); +extern void cpu_unlock_restore(const uint32_t status); +extern int32_t int_handler_install(const uint32_t intno, INT_HANDLER handler); +extern INT_HANDLER int_handler_get(const uint32_t intno); +extern int32_t int_secure_set(const uint32_t intno, uint32_t secure); + +#ifdef __cplusplus +} +#endif + +#if defined(LIB_SECURESHIELD) && defined(LIB_SECURESHIELD_OVERRIDES) && (SECURESHIELD_VERSION == 1) +#define OVERRIDE_ARC_HAL_EXCEPTION_H +#include "secureshield_overrides.h" +#endif + +#endif /* _ARC_HAL_EXCEPTION_H_*/ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_feature_config.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_feature_config.h new file mode 100644 index 000000000..2f62e4301 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_feature_config.h @@ -0,0 +1,397 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2016-09-08 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_MISC + * \brief header file for arc feature configuration + */ + +/** + * \addtogroup ARC_HAL_MISC + * @{ + */ + +#ifndef _ARC_FEATURE_CONFIG_H_ +#define _ARC_FEATURE_CONFIG_H_ + +// Enable core_config.h in EMSK OSP +//#ifdef EMBARC_TCF_GENERATED +#include "arc_core_config.h" +//#endif + +/** ARC baseline instruction set version number */ +#if !defined(_ARCVER) +#if defined(core_config_cir_identity_arcver) +#define _ARCVER core_config_cir_identity_arcver +#else +#define _ARCVER 0x42 +#endif +#endif + +/** ARC CPU Clock Frequency in Hz unit */ +#if !defined(ARC_FEATURE_CPU_CLOCK_FREQ) +#if defined(core_config_clock_speed) +#define ARC_FEATURE_CPU_CLOCK_FREQ (core_config_clock_speed*1000000) +#endif +#endif + +/** ARC PC size */ +#if !defined(ARC_FEATURE_PC_SIZE) +#if defined(core_config_pc_size) +#define ARC_FEATURE_PC_SIZE core_config_pc_size +#else +#define ARC_FEATURE_PC_SIZE 32 +#endif +#endif + +/** ARC LPC size */ +#if !defined(ARC_FEATURE_LPC_SIZE) +#if defined(core_config_lpc_size) +#define ARC_FEATURE_LPC_SIZE core_config_lpc_size +#else +#define ARC_FEATURE_LPC_SIZE 32 +#endif +#endif + +/** ARC Addr size */ +#if !defined(ARC_FEATURE_ADDR_SIZE) +#if defined(core_config_addr_size) +#define ARC_FEATURE_ADDR_SIZE core_config_addr_size +#else +#define ARC_FEATURE_ADDR_SIZE 32 +#endif +#endif + +/** ARC Endian/Byte Order */ +#define ARC_FEATURE_LITTLE_ENDIAN 1234 +#define ARC_FEATURE_BIG_ENDIAN 4321 + +#if !defined(ARC_FEATURE_BYTE_ORDER) +#if defined(core_config_bcr_isa_config_b) +#if core_config_bcr_isa_config_b == 0 +#define ARC_FEATURE_BYTE_ORDER ARC_FEATURE_LITTLE_ENDIAN +#else +#define ARC_FEATURE_BYTE_ORDER ARC_FEATURE_BIG_ENDIAN +#endif +#else +#define ARC_FEATURE_BYTE_ORDER ARC_FEATURE_LITTLE_ENDIAN +#endif +#endif + +/** Reduced register option, if enabled, ARC_FEATURE_RF16 will be defined */ +#if !defined(ARC_FEATURE_RF16) +#if defined(core_config_bcr_rf_build_e) && core_config_bcr_rf_build_e == 1 +#define ARC_FEATURE_RF16 +#endif +#endif + +/** Unaligned access option, if enabled, ARC_FEATURE_UNALIGNED will be defined */ +#if !defined(ARC_FEATURE_UNALIGNED) +#if defined(core_config_unaligned) && core_config_unaligned == 1 +#define ARC_FEATURE_UNALIGNED +#endif +#endif + + +/** Code density option, if enabled, ARC_FEATURE_CODE_DENSITY will be defined */ +#if !defined(ARC_FEATURE_CODE_DENSITY) +#if defined(core_config_code_density) && core_config_code_density == 1 +#define ARC_FEATURE_CODE_DENSITY +#endif +#endif + +/** The number of register file banks */ +#if !defined(ARC_FEATURE_RGF_NUM_BANKS) +#if defined(core_config_rgf_num_banks) +#define ARC_FEATURE_RGF_NUM_BANKS core_config_rgf_num_banks +#else +#define ARC_FEATURE_RGF_NUM_BANKS 1 +#endif +#endif + +/** The number of registers replicated per register bank */ +#if !defined(ARC_FEATURE_RGF_BANKED_REGS) +#if defined(core_config_rgf_banked_regs) +#define ARC_FEATURE_RGF_BANKED_REGS core_config_rgf_banked_regs +#endif +#endif + +/** Interrupt unit presence */ +#if !defined(ARC_FEATURE_INTERRUPTS_PRESENT) +#if defined(core_config_interrupts_present) +#define ARC_FEATURE_INTERRUPTS_PRESENT core_config_interrupts_present +#endif +#endif + +/** FIRQ_OPTION configuration option, 1 for enabled, 0 for disabled */ +#if !defined(ARC_FEATURE_FIRQ) +#if defined(core_config_bcr_irq_build_f) +#define ARC_FEATURE_FIRQ core_config_bcr_irq_build_f +#else +#define ARC_FEATURE_FIRQ 0 +#endif +#endif + +/** The number of interrupts */ +#if !defined(NUM_EXC_INT) +#if defined(core_config_interrupts_number) +#define NUM_EXC_INT core_config_interrupts_number +#endif +#endif + +/** The number of external interrupts */ +#if !defined(NUM_EXC_EXT_INT) +#if defined(core_config_interrupts_externals) +#define NUM_EXC_EXT_INT core_config_interrupts_externals +#endif +#endif + +/** The interrupt priority levels */ +#if !defined(INT_PRI_MIN) +#if defined(core_config_interrupts_priorities) +#define INT_PRI_MIN (-core_config_interrupts_priorities) +#endif +#endif + +// ARC TIMER_BUILD +/** Timer0 present or not */ +#if !defined(ARC_FEATURE_TIMER0_PRESENT) +#if defined(core_config_timer0) +#define ARC_FEATURE_TIMER0_PRESENT core_config_timer0 +#define ARC_FEATURE_TIMER0_LEVEL (core_config_timer0_level-core_config_interrupts_priorities) +#define ARC_FEATURE_TIMER0_VECTOR core_config_timer0_vector +#endif +#endif + +/** Timer1 present or not */ +#if !defined(ARC_FEATURE_TIMER1_PRESENT) +#if defined(core_config_timer1) +#define ARC_FEATURE_TIMER1_PRESENT core_config_timer1 +#define ARC_FEATURE_TIMER1_LEVEL (core_config_timer1_level-core_config_interrupts_priorities) +#define ARC_FEATURE_TIMER1_VECTOR core_config_timer1_vector +#endif +#endif + +/** Secure Timer0 present or not */ +#if !defined(ARC_FEATURE_SEC_TIMER0_PRESENT) +#if defined(core_config_sec_timer0) +#define ARC_FEATURE_SEC_TIMER0_PRESENT core_config_sec_timer0 +#define ARC_FEATURE_SEC_TIMER0_LEVEL (core_config_sec_timer0_level-core_config_interrupts_priorities) +#define ARC_FEATURE_SEC_TIMER0_VECTOR 20 +#endif +#endif + +/** Secure Timer1 present or not */ +#if !defined(ARC_FEATURE_SEC_TIMER1_PRESENT) +#if defined(core_config_sec_timer1) +#define ARC_FEATURE_SEC_TIMER1_PRESENT core_config_sec_timer1 +#define ARC_FEATURE_SEC_TIMER1_LEVEL (core_config_sec_timer1_level-core_config_interrupts_priorities) +#define ARC_FEATURE_SEC_TIMER1_VECTOR 21 +#endif +#endif + + +/** 64bit RTC present or not */ +#if !defined(ARC_FEATURE_RTC_PRESENT) +#if defined(core_config_rtc) +#define ARC_FEATURE_RTC_PRESENT core_config_rtc +#endif +#endif + +// Memory related definitions +/** ICCM Presence, base address and size */ +#if !defined(ARC_FEATURE_ICCM_PRESENT) +#if defined(core_config_iccm_present) && core_config_iccm_present == 1 +#define ARC_FEATURE_ICCM_PRESENT 1 +#define ARC_FEATURE_ICCM_BASE core_config_iccm_base +#define ARC_FEATURE_ICCM_SIZE core_config_iccm_size +#endif +#endif + +/** ICCM0 Presence, base address and size */ +#if !defined(ARC_FEATURE_ICCM0_PRESENT) +#if defined(core_config_iccm0_present) && core_config_iccm0_present == 1 +#define ARC_FEATURE_ICCM0_PRESENT 1 +#define ARC_FEATURE_ICCM0_BASE core_config_iccm0_base +#define ARC_FEATURE_ICCM0_SIZE core_config_iccm0_size +#endif +#endif + +/** ICCM1 Presence, base address and size */ +#if !defined(ARC_FEATURE_ICCM1_PRESENT) +#if defined(core_config_iccm1_present) && core_config_iccm1_present == 1 +#define ARC_FEATURE_ICCM1_PRESENT 1 +#define ARC_FEATURE_ICCM1_BASE core_config_iccm1_base +#define ARC_FEATURE_ICCM1_SIZE core_config_iccm1_size +#endif +#endif + +/** DCCM Presence, base address and size */ +#if !defined(ARC_FEATURE_DCCM_PRESENT) +#if defined(core_config_dccm_present) && core_config_dccm_present == 1 +#define ARC_FEATURE_DCCM_PRESENT 1 +#define ARC_FEATURE_DCCM_BASE core_config_dccm_base +#define ARC_FEATURE_DCCM_SIZE core_config_dccm_size +#ifdef core_config_dccm_interleave +#define ARC_FEATURE_DCCM_INTERLEAVE core_config_dccm_interleave +#endif +#endif +#endif + +/** Peripheral memory region(DMP) base address, if dmp configured, this macro will be defined as base address */ +#if !defined(ARC_FEATURE_DMP_PERIPHERAL) +#if defined(core_config_cir_dmp_peripheral) +#define ARC_FEATURE_DMP_PERIPHERAL core_config_cir_dmp_peripheral +#endif +#endif + +/** MPU options */ +#if !defined(ARC_FEATURE_MPU_PRESENT) +#if defined(core_config_mpu_present) && core_config_mpu_present == 1 +#define ARC_FEATURE_MPU_PRESENT 1 +#define ARC_FEATURE_MPU_VERSION core_config_bcr_mpu_build_version +#define ARC_FEATURE_MPU_REGIONS core_config_mpu_regions +#ifdef core_config_bcr_mpu_build_i +#define ARC_FEATURE_MPU_BUILD_I core_config_bcr_mpu_build_i +#endif +#ifdef core_config_bcr_mpu_build_s +#define ARC_FEATURE_MPU_BUILD_S core_config_bcr_mpu_build_s +#endif +#endif +#endif + +/** Secure BCR SEC_BUILD BCR */ +#if !defined(ARC_FEATURE_SEC_PRESENT) +#if defined(core_config_bcr_sec_build) +#define ARC_FEATURE_SEC_PRESENT 1 +#define ARC_FEATURE_SEC_VERSION core_config_bcr_sec_build_version +#define ARC_FEATURE_SEC_BUILD_DSM core_config_bcr_sec_build_dsm +#define ARC_FEATURE_SEC_BUILD_NSM core_config_bcr_sec_build_nsm +#define ARC_FEATURE_SEC_BUILD_I1SM core_config_bcr_sec_build_i1sm +#define ARC_FEATURE_SEC_BUILD_I0SM core_config_bcr_sec_build_i0sm +#define ARC_FEATURE_SEC_BUILD_S core_config_bcr_sec_build_s +#define ARC_FEATURE_SEC_BUILD_EI core_config_bcr_sec_build_ei +#define ARC_FEATURE_SEC_BUILD_ED core_config_bcr_sec_build_ed +#endif +#endif + +#if !defined(ARC_FEATURE_SEC_MODES) +#if defined(core_config_sec_modes) +#define ARC_FEATURE_SEC_MODES core_config_sec_modes +#endif +#endif + +/** Data Cache options */ +#if !defined(ARC_FEATURE_DCACHE_PRESENT) +#if defined(core_config_dcache_present) && core_config_dcache_present == 1 +#define ARC_FEATURE_DCACHE_PRESENT 1 +#define ARC_FEATURE_DCACHE_BUILD core_config_bcr_d_cache_build +#define ARC_FEATURE_DCACHE_BUILD_VERSION core_config_bcr_d_cache_build_version +#define ARC_FEATURE_DCACHE_BUILD_ASSOC core_config_bcr_d_cache_build_assoc +#define ARC_FEATURE_DCACHE_BUILD_CAPACITY core_config_bcr_d_cache_build_capacity +#define ARC_FEATURE_DCACHE_BUILD_BSIZE core_config_bcr_d_cache_build_bsize +#define ARC_FEATURE_DCACHE_BUILD_FL core_config_bcr_d_cache_build_fl +#define ARC_FEATURE_DCACHE_BUILD_U core_config_bcr_d_cache_build_u +#define ARC_FEATURE_DCACHE_SIZE core_config_dcache_size +#define ARC_FEATURE_DCACHE_LINE_SIZE core_config_dcache_line_size +#define ARC_FEATURE_DCACHE_WAYS core_config_dcache_ways +#define ARC_FEATURE_DCACHE_FEATURE core_config_dcache_feature +#endif +#endif + +/** Instruction Cache options */ +#if !defined(ARC_FEATURE_ICACHE_PRESENT) +#if defined(core_config_icache_present) && core_config_icache_present == 1 +#define ARC_FEATURE_ICACHE_PRESENT 1 +#define ARC_FEATURE_ICACHE_BUILD core_config_bcr_i_cache_build +#define ARC_FEATURE_ICACHE_BUILD_VERSION core_config_bcr_i_cache_build_version +#define ARC_FEATURE_ICACHE_BUILD_ASSOC core_config_bcr_i_cache_build_assoc +#define ARC_FEATURE_ICACHE_BUILD_CAPACITY core_config_bcr_i_cache_build_capacity +#define ARC_FEATURE_ICACHE_BUILD_BSIZE core_config_bcr_i_cache_build_bsize +#define ARC_FEATURE_ICACHE_BUILD_FL core_config_bcr_i_cache_build_fl +#define ARC_FEATURE_ICACHE_BUILD_D core_config_bcr_i_cache_build_d +#define ARC_FEATURE_ICACHE_SIZE core_config_icache_size +#define ARC_FEATURE_ICACHE_LINE_SIZE core_config_icache_line_size +#define ARC_FEATURE_ICACHE_WAYS core_config_icache_ways +#define ARC_FEATURE_ICACHE_FEATURE core_config_icache_feature +#endif +#endif + +/** ARC uDMA options */ +#if !defined(ARC_FEATURE_DMAC) +#if defined(core_config_dmac) +#define ARC_FEATURE_DMAC core_config_dmac +#define CORE_DMAC_CHANNELS core_config_dmac_channels +#define CORE_DMAC_REGISTERS core_config_dmac_registers +#if core_config_bcr_dmac_build_int_cfg == 2 && core_config_bcr_dmac_build_int_cfg == 4 +#define DMA_MULTI_IRQ 1 +#else +#define DMA_MULTI_IRQ 0 +#endif +#define ARC_FEATURE_DMAC_PRESENT core_config_dmac +#define ARC_FEATURE_DMAC_VERSION core_config_bcr_dmac_build_version +#define ARC_FEATURE_DMAC_CHANNELS core_config_dmac_channels +#define ARC_FEATURE_DMAC_REGISTERS core_config_dmac_registers +#define ARC_FEATURE_DMAC_INT_CFG core_config_bcr_dmac_build_int_cfg +#define ARC_FEATURE_DMAC_FIFO_DEPTH core_config_dmac_fifo_depth + +#ifdef ARC_FEATURE_SEC_TIMER0_PRESENT +#define DMA_IRQ_NUM_START 22 +#define ARC_FEATURE_DMAC_VECTOR_START 22 +#else +#define DMA_IRQ_NUM_START 20 +#define ARC_FEATURE_DMAC_VECTOR_START 20 +#endif + +#endif +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ARC_FEATURE_UNALIGNED +#define STATUS32_RESET_VALUE (1<<19) +#else +#define STATUS32_RESET_VALUE (0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ARC_FEATURE_CONFIG_H_ */ + +/** @} */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_timer.h b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_timer.h new file mode 100644 index 000000000..a4a0016b4 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/arc/arc_timer.h @@ -0,0 +1,99 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-07-15 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup ARC_HAL_MISC_TIMER + * \brief header file of ARC internal timer + */ + +/** + * \addtogroup ARC_HAL_MISC_TIMER + * @{ + */ + +#ifndef _ARC_HAL_TIMER_H_ +#define _ARC_HAL_TIMER_H_ +#include "inc/arc/arc.h" +#include "inc/embARC_toolchain.h" + +/** + * \name arc internal timers names + * @{ + */ +#define TIMER_0 0 /*!< macro name for arc internal timer 0 */ +#define TIMER_1 1 /*!< macro name for arc internal timer 1 */ +#define TIMER_RTC 2 /*!< macro name for arc internal RTC */ + +/** @} */ + +/** + * \name bit definition of RTC CTRL reg + * @{ + */ + +#define TIMER_RTC_ENABLE 0x01 /*!< enable RTC */ +#define TIMER_RTC_CLEAR 0x02 /* clears the AUX_RTC_LOW and AUX_RTC_HIGH */ +#define TIMER_RTC_STATUS_A0 0x40000000 /*!< track bit of atomicity of reads of RTC */ +#define TIMER_RTC_STATUS_A1 0x80000000 /*!< track bit of atomicity of reads of RTC */ + +/** @} */ + +/** + * \name bit definition of timer CTRL reg + * @{ + */ +#define TIMER_CTRL_IE (1 << 0) /*!< Interrupt when count reaches limit */ +#define TIMER_CTRL_NH (1 << 1) /*!< Count only when CPU NOT halted */ +#define TIMER_CTRL_W (1 << 2) /*!< watchdog enable */ +#define TIMER_CTRL_IP (1 << 3) /*!< interrupt pending */ + +/** @} */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int32_t timer_present(const uint32_t no); +extern int32_t timer_start(const uint32_t no, const uint32_t mode, const uint32_t val); +extern int32_t timer_stop(const uint32_t no); +extern int32_t timer_current(const uint32_t no, void *val); +extern int32_t timer_int_clear(const uint32_t no); +extern void timer_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _ARC_HAL_TIMER_H_ */ +/** }@*/ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/embARC_error.h b/third_party/synopsys/embarc_emsk_bsp/inc/embARC_error.h new file mode 100644 index 000000000..5b5e18f6f --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/embARC_error.h @@ -0,0 +1,156 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-12-25 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup EMBARC_ERROR + * \brief header file to define common definitions error management + */ + +/** + * \addtogroup EMBARC_ERROR + * @{ + */ + +#ifndef _EMBARC_ERROR_H_ +#define _EMBARC_ERROR_H_ + +#include +#include "inc/arc/arc_builtin.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * \name Main Error Code Definitions + * @{ + */ +#define E_OK (0) /*!< ok */ +#define E_SYS (-5) /*!< system error */ +#define E_NOSPT (-9) /*!< unsupported features */ +#define E_RSFN (-10) /*!< reserved function code */ +#define E_RSATR (-11) /*!< reserved attribute */ +#define E_PAR (-17) /*!< parameter error */ +#define E_ID (-18) /*!< invalid ID number */ +#define E_CTX (-25) /*!< context error */ +#define E_MACV (-26) /*!< memory access violation */ +#define E_OACV (-27) /*!< object access violation */ +#define E_ILUSE (-28) /*!< illegal service call use */ +#define E_NOMEM (-33) /*!< insufficient memory */ +#define E_NOID (-34) /*!< no ID number available */ +#define E_NORES (-35) /*!< no resource available */ +#define E_OBJ (-41) /*!< object state error */ +#define E_NOEXS (-42) /*!< non-existent object */ +#define E_QOVR (-43) /*!< queue overflow */ +#define E_RLWAI (-49) /*!< forced release from waiting */ +#define E_TMOUT (-50) /*!< polling failure or timeout */ +#define E_DLT (-51) /*!< waiting object deleted */ +#define E_CLS (-52) /*!< waiting object state changed */ +#define E_WBLK (-57) /*!< non-blocking accepted */ +#define E_BOVR (-58) /*!< buffer overflow */ +#define E_OPNED (-6) /*!< device is opened */ +#define E_CLSED (-7) /*!< device is closed */ +/** @} end of name */ + +/** + * \name Generate And Decompose Error Code + * @{ + */ +#ifndef ERCD +/** generate error code using main error code and sub error code */ +#define ERCD(mercd, sercd) \ + ((uint32_t)((((uint32_t) sercd) << 8) | (((uint32_t) mercd) & 0xffU))) +#endif /* ERCD */ + +#ifndef MERCD +#ifdef INT8_MAX +/** get main error code from error code */ +#define MERCD(ercd) ((uint32_t)((int8_t)(ercd))) +#else /* INT8_MAX */ +/** get main error code from error code */ +#define MERCD(ercd) ((uint32_t)(((uint32_t) ercd) | ~0xffU)) +#endif /* INT8_MAX */ +#endif /* MERCD */ + +#ifndef SERCD +/** get sub error code from error code */ +#define SERCD(ercd) ((uint32_t)((ercd) >> 8)) +#endif /* SERCD */ +/** @} end of name */ + +/** + * \name Check Error + * @{ + */ +/** + * \brief check an expression to see if it is right, and when error + * set the ercd, and goto exit_label + * \param EXPR the expression that need to be checked (==0 failed) + * \param ERCD MUST pass a variable to here to get the error code + * \param ERROR_CODE error code that pass to ERCD + * \param EXIT_LABEL a label to go when error happens + */ +#define CHECK_EXP(EXPR, ERCD, ERROR_CODE, EXIT_LABEL) { \ + if (_arc_rarely(!(EXPR))) { \ + ERCD = (ERROR_CODE); \ + goto EXIT_LABEL; \ + } \ + } +/** + * \brief check an expression to see if it is right, and when error + * directly goto exit_label + * \param EXPR the expression that need to be checked (==0 failed) + * \param EXIT_LABEL a label to go when error happens + * \retval + */ +#define CHECK_EXP_NOERCD(EXPR, EXIT_LABEL) { \ + if (_arc_rarely(!(EXPR))) { \ + goto EXIT_LABEL; \ + } \ + } +/** check cnt bytes align, 1 for aligned, 0 for not-aligned */ +#define CHECK_ALIGN_BYTES(pointer, cnt) ((((uint32_t)(pointer)) & (cnt-1)) == 0) +/** check 2 bytes align, 1 for aligned, 0 for not-aligned */ +#define CHECK_ALIGN_2BYTES(pointer) ((((uint32_t)(pointer)) & 0x1) == 0) +/** check 4 bytes align, 1 for aligned, 0 for not-aligned */ +#define CHECK_ALIGN_4BYTES(pointer) ((((uint32_t)(pointer)) & 0x3) == 0) +/** check 8 bytes align, 1 for aligned, 0 for not-aligned */ +#define CHECK_ALIGN_8BYTES(pointer) ((((uint32_t)(pointer)) & 0x7) == 0) +/** @} end of name */ + +#ifdef __cplusplus +} +#endif + +#endif /* _EMBARC_ERROR_H_ */ +/** @} end of group EMBARC_ERROR */ diff --git a/third_party/synopsys/embarc_emsk_bsp/inc/embARC_toolchain.h b/third_party/synopsys/embarc_emsk_bsp/inc/embARC_toolchain.h new file mode 100644 index 000000000..d55363a0b --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/inc/embARC_toolchain.h @@ -0,0 +1,121 @@ +/* ------------------------------------------ + * Copyright (c) 2016, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2016.05 + * \date 2014-12-25 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup TOOLCHAIN + * \brief toolchain dependent definitions + */ + +#include /* C99 standard lib */ +#include /* C99 standard lib */ +#include /* C99 standard lib */ +#include /* C99 standard lib */ + +#include "embARC_BSP_config.h" + +/** + * \addtogroup TOOLCHAIN + * @{ + */ + +#ifndef _EMBARC_TOOLCHAIN_H_ +#define _EMBARC_TOOLCHAIN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * macro definitions of compiler extend function + */ +#ifndef __cplusplus /* C++ supports inline */ +#if __STDC_VERSION__ < 199901L /* C99 supports inline */ +#ifndef inline +#define inline __inline__ /* inline function */ +#endif +#endif /* __STDC_VERSION__ < 199901L */ +#endif /* __cplusplus */ + +#ifndef Inline +#define Inline static __inline__ /* inline function */ +#endif + +#ifndef __cplusplus /* C++ supports asm */ +#ifndef asm +#define asm __asm__ /* inline asm */ +#endif +#endif /* __cplusplus */ + +#ifndef Asm +#define Asm __asm__ volatile /* inline asm (no optimization) */ +#endif + +/* compiler attributes */ +#define EMBARC_FORCEINLINE __attribute__((always_inline)) +#define EMBARC_NOINLINE __attribute__((noinline)) +#define EMBARC_PACKED __attribute__((packed)) +#define EMBARC_WEAK __attribute__((weak)) +#define EMBARC_ALIAS(f) __attribute__((weak, alias (#f))) +#define EMBARC_LINKTO(f) __attribute__((alias (#f))) +#define EMBARC_NORETURN __attribute__((noreturn)) +#define EMBARC_NAKED __attribute__((naked)) /* function without return */ +#define EMBARC_ALIGNED(x) __attribute__((aligned(x))) + + +/* array count macro */ +#define EMBARC_ARRAY_COUNT(x) (sizeof(x)/sizeof(x[0])) + +/* convert macro argument to string */ +/* note: this needs one level of indirection, accomplished with the helper macro + * __EMBARC_TO_STRING */ +#define __EMBARC_TO_STRING(x) #x +#define EMBARC_TO_STRING(x) __EMBARC_TO_STRING(x) + +#if defined(__GNU__) +/* GNU tool specific definitions */ + +#elif defined(__MW__) +/* Metaware tool specific definitions */ +/* Metaware toolchain related definitions */ + +#else +#error "unsupported toolchain" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _EMBARC_TOOLCHAIN_H_ */ +/** }@ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/dirent.h b/third_party/synopsys/embarc_emsk_bsp/library/clib/dirent.h new file mode 100755 index 000000000..b322f1002 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/dirent.h @@ -0,0 +1,46 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-20 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +#ifndef _DIRENT_H_ +#define _DIRENT_H_ + +#include "fatfs_dirent.h" +//#undef S_ISREG + +#undef DIR +#define DIR FATFS_DIR + +// #define stat fatfs_stat +// #define S_ISREG FATFS_S_ISREG + +#endif /*_DIRENT_H_*/ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_misc.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_misc.c new file mode 100644 index 000000000..3dc215083 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_misc.c @@ -0,0 +1,49 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-03-02 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +#include "embARC_BSP_config.h" + +#include "inc/arc/arc_exception.h" +#include "embARC_syscalls.h" + +/** + * \brief Install the syscall swi handler into exception table. + * This need to be done after exception table has been initialized. + * When RTOS is implemented, you need to manually call this function after + * your RTOS exception table is setup. + */ +void gnu_printf_setup(void) +{ +#if defined(__GNU__) && !defined(_HAVE_LIBGLOSS_) && !defined(_HOSTLINK_) + exc_handler_install(EXC_NO_SWI, (EXC_HANDLER)syscall_swi); +#endif +} \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_sbrk.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_sbrk.c new file mode 100644 index 000000000..a98664174 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_sbrk.c @@ -0,0 +1,122 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-03-02 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +#include "embARC_BSP_config.h" + +#include +#include +#include +#include +#include +#include "embARC_syscalls.h" + +#ifndef _HOSTLINK_ /* Not using hostlink library */ + +/////////////////////// +// Memory Management // +/////////////////////// +/** Allocating Memory */ +#define EMBARC_WITH_MWSBRK +/* Whether heap has been initialized. */ +#if defined(__MW__) && defined(EMBARC_WITH_MWSBRK) + +static int __heap_init = 0; +static char *__heap_end, *__heap_cur; +extern char _f_heap[]; +extern char _e_heap[]; + +/** Allocating Memory */ +void *SYSCALL_PREFIX(_sbrk)(unsigned int size) +{ + char *new_cur; + + if (__heap_init == 0) + { + __heap_cur = _f_heap; + __heap_end = _e_heap; + __heap_init = 1; + } + + new_cur = __heap_cur + size; + + if (__heap_cur <= new_cur && new_cur <= __heap_end) + { + void *p = (void *)__heap_cur; + __heap_cur = new_cur; + return (void *)p; /** return old __heap_cur */ + } + + return NULL; +} + +/** Freeing Memory */ +void *SYSCALL_PREFIX(_brk)(void *p) +{ + __heap_cur = p; + return NULL; +} + +#pragma weak sbrk = _sbrk +#pragma weak brk = _brk + +#elif defined(__GNU__) + +extern char __start_heap; +extern char __end_heap; + +caddr_t *SYSCALL_PREFIX(_sbrk)(size_t nbytes) +{ + static char *heap_ptr = NULL; + char *prev_heap_ptr; + + if (heap_ptr == NULL) + { + heap_ptr = &__start_heap; + } + + /* Align the 'heap_ptr' so that memory will always be allocated at word + boundaries. */ + heap_ptr = (char *)((((unsigned long) heap_ptr) + 7) & ~7); + prev_heap_ptr = heap_ptr; + + if ((heap_ptr + nbytes) < &__end_heap) + { + heap_ptr += nbytes; + return (caddr_t *) prev_heap_ptr; + } + + errno = ENOMEM; + return (caddr_t *) - 1; +} +#endif + +#endif /* !defined(_HOSTLINK_) */ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.c new file mode 100644 index 000000000..3cc55e29e --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.c @@ -0,0 +1,894 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-18 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +#include "embARC_syscalls.h" +#include "device/device_hal/inc/dev_uart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __GNU__ +#include +#include +#include +#include +#endif + +/** + * \todo Consider hostlink and nsim support + */ + +#ifndef _HOSTLINK_ /* Not using hostlink library */ + +#ifndef _ENVIRON_LEN +#define _ENVIRON_LEN 32 +#endif + +#ifndef BOARD_CONSOLE_UART_ID +#define BOARD_CONSOLE_UART_ID 1 +#endif +#ifndef BOARD_CONSOLE_UART_BAUD +#define BOARD_CONSOLE_UART_BAUD UART_BAUDRATE_115200 +#endif + +#ifndef EMBARC_CFG_STDIO_CRLF +#define EMBARC_CFG_STDIO_CRLF 1 +#endif + +#ifndef EMBARC_CFG_USE_RTCTIME +#define EMBARC_CFG_USE_RTCTIME 0 +#endif + +#define STDIO_FID_OFS 3 + +int stdio_uart_inited = 0; +DEV_UART *stdio_uart_obj; +static void init_stdio_serial(void) +{ + if (stdio_uart_inited) { return; } + + stdio_uart_inited = 1; + stdio_uart_obj = uart_get_dev(BOARD_CONSOLE_UART_ID); + + if (stdio_uart_obj) + { + stdio_uart_obj->uart_open(BOARD_CONSOLE_UART_BAUD); + stdio_uart_obj->uart_control(UART_CMD_SET_BAUD, CONV2VOID(BOARD_CONSOLE_UART_BAUD)); + } + else + { + stdio_uart_inited = -1; + } +} + +static int stdio_read(char *buffer, unsigned int length) +{ + if (!stdio_uart_obj) { return -1; } + + unsigned int avail_len; + stdio_uart_obj->uart_control(UART_CMD_GET_RXAVAIL, (void *)(&avail_len)); + length = (length < avail_len) ? length : avail_len; + + if (length == 0) + { + length = 1; + } + + return (int)stdio_uart_obj->uart_read((void *)buffer, (uint32_t)length); +} + +static void stdio_write_char(char data) +{ + stdio_uart_obj->uart_write((const void *)(&data), 1); +} + + +static int stdio_write(const char *buffer, unsigned int length) +{ + if (!stdio_uart_obj) { return -1; } + +#if EMBARC_CFG_STDIO_CRLF + unsigned int i = 0; + + while (i < length) + { + if (_arc_rarely(buffer[i] == '\n')) + { + stdio_write_char('\r'); + } + + stdio_write_char(buffer[i]); + i++; + } + + return (int)i; +#else + return (int)stdio_uart_obj->uart_write((const void *)buffer, (uint32_t)length); +#endif +} +///////////////////// +// File Processing // +///////////////////// +#ifdef MID_FATFS +#include "ff.h" +#ifndef EMBARC_CFG_MAX_FILEHANDLES +#define EMBARC_CFG_MAX_FILEHANDLES 32 +#endif +static FIL *file_handles[EMBARC_CFG_MAX_FILEHANDLES] = { NULL }; +#endif + +#if defined(MID_FATFS) && !_FS_READONLY +/** Posix mode to FatFS mode */ +Inline BYTE conv_openmode(int flags) +{ + BYTE openmode = 0; + + if (flags == O_RDONLY) + { + openmode = FA_READ; + } + + if (flags & O_WRONLY) + { + openmode |= FA_WRITE; + } + + if (flags & O_RDWR) + { + openmode |= FA_READ | FA_WRITE; + } + + if (flags & O_CREAT) + { + if (flags & O_TRUNC) + { + openmode |= FA_CREATE_ALWAYS; + } + else + { + openmode |= FA_OPEN_ALWAYS; + } + } + + return openmode; +} +#endif + +/** Opening Files */ +#ifdef __MW__ +int SYSCALL_PREFIX(_open)(const char *path, int flags, /* int mode */ ...) +#else +int SYSCALL_PREFIX(_open)(const char *path, int flags, int mode) +#endif +{ +#ifdef MID_FATFS + int fid; /** file handle id */ + FIL *tmp_filep; /** temp file handle pointer */ + BYTE openmode; + + /* Find the first available file pointer in this handles */ + for (fid = 0; fid < EMBARC_CFG_MAX_FILEHANDLES; fid ++) + { + if (file_handles[fid] == NULL) + { + break; + } + } + + if (fid >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + /* Malloc memory for FIL object */ + tmp_filep = (FIL *)malloc(sizeof(FIL)); + + if (!tmp_filep) /* No more memory */ + { + return -1; + } + + file_handles[fid] = tmp_filep; +#if _FS_READONLY + + if (flags == O_RDONLY) + { + openmode = FA_READ; + } + else + { + return -1; + } + +#else + openmode = conv_openmode(flags); +#endif + FRESULT res = f_open(tmp_filep, path, openmode); + + if (res) /* open error */ + { + free(tmp_filep); + file_handles[fid] = NULL; + return -1; + } + + /** Append if O_APPEND flags is set */ + if (flags & O_APPEND) + { + f_lseek(tmp_filep, f_size(tmp_filep)); + } + + return fid + STDIO_FID_OFS; /* 0-2 are stdin/stdout/stderr, so plus 3 */ + +#else /* No File System */ + return -1; +#endif +} + +/** Closing Files */ +int SYSCALL_PREFIX(_close)(int handle) +{ + if (handle < STDIO_FID_OFS) /* for stdin/stdout/stderr */ + { + return 0; + } + +#ifdef MID_FATFS + + if ((handle - STDIO_FID_OFS) >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + FIL *tmp_filep; /** temp file handle pointer */ + tmp_filep = file_handles[handle - STDIO_FID_OFS]; + + if (tmp_filep) + { + file_handles[handle - STDIO_FID_OFS] = NULL; + FRESULT res = f_close(tmp_filep); + free(tmp_filep); + + if (res) + { + return -1; + } + + return 0; + } + +#endif + return -1; +} + +/** Reading Files */ +int SYSCALL_PREFIX(_read)(int handle, char *buffer, unsigned int length) +{ + if (handle < STDIO_FID_OFS) + { + init_stdio_serial(); + return stdio_read(buffer, length); + } + +#ifdef MID_FATFS + + if ((handle - STDIO_FID_OFS) >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + FIL *tmp_filep; /** temp file handle pointer */ + tmp_filep = file_handles[handle - STDIO_FID_OFS]; + + if (tmp_filep) + { + UINT br; + FRESULT res = f_read(tmp_filep, (void *)buffer, (UINT)length, &br); + + if (res) + { + return -1; + } + + return (int)br; + } + +#endif + return -1; +} + +/** Writing Files */ +int SYSCALL_PREFIX(_write)(int handle, const char *buffer, unsigned int length) +{ + if (handle < STDIO_FID_OFS) + { + init_stdio_serial(); + return stdio_write(buffer, length); + } + +#ifdef MID_FATFS + + if ((handle - STDIO_FID_OFS) >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + FIL *tmp_filep; /** temp file handle pointer */ + tmp_filep = file_handles[handle - STDIO_FID_OFS]; + + if (tmp_filep) + { + UINT bw; + FRESULT res = f_write(tmp_filep, (void *)buffer, (UINT)length, &bw); + + if (res) + { + return -1; + } + + return (int)bw; + } + +#endif + return -1; +} + +/** Seeking to a Location in a File */ +long SYSCALL_PREFIX(_lseek)(int handle, long offset, int method) +{ + if (handle < STDIO_FID_OFS) + { + return 0; + } + +#ifdef MID_FATFS + + if ((handle - STDIO_FID_OFS) >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + FIL *tmp_filep; /** temp file handle pointer */ + tmp_filep = file_handles[handle - STDIO_FID_OFS]; + + if (tmp_filep) + { + FRESULT res; + long ofs = offset; + + if (method == SEEK_CUR) + { + ofs = (long)f_tell(tmp_filep) + offset; + } + else if (method == SEEK_END) + { + ofs = (long)f_size(tmp_filep) + offset; + } + + if (ofs >= 0) + { + res = f_lseek(tmp_filep, (DWORD)ofs); + + if (res) { return -1; } + + return f_tell(tmp_filep); + } + + } + +#endif + return -1; +} + +/** Testing File Access */ +int SYSCALL_PREFIX(_access)(const char *name, int mode) +{ +#ifdef MID_FATFS + FRESULT res = f_stat((const TCHAR *)name, NULL); + + if (res) { return -1; } + + return 0; +#endif + return -1; +} + +/** Testing for an Interactive Display Device */ +int SYSCALL_PREFIX(_isatty)(int handle) +{ + if (handle < STDIO_FID_OFS) + { + return 1; + } + +#ifdef MID_FATFS + + if ((handle - STDIO_FID_OFS) >= EMBARC_CFG_MAX_FILEHANDLES) + { + return -1; /* No more available file handler */ + } + + FIL *tmp_filep; /** temp file handle pointer */ + tmp_filep = file_handles[handle - STDIO_FID_OFS]; + + if (tmp_filep) + { + return 0; + } + +#endif + return -1; +} + +/** Unlink Files */ +int SYSCALL_PREFIX(_unlink)(const char *path) +{ +#ifdef MID_FATFS + + if (f_unlink((const TCHAR *)path) == FR_OK) + { + return 0; + } + +#endif + return -1; +} + +/** Renaming Files */ +int SYSCALL_PREFIX(rename)(const char *old, const char *new) +{ +#ifdef MID_FATFS + + if (f_rename((const TCHAR *)old, (const TCHAR *)new) == FR_OK) + { + return 0; + } + +#endif + return -1; +} + +/** Remove Directory */ +int SYSCALL_PREFIX(_rmdir)(const char *pathname) +{ + return SYSCALL_PREFIX(_unlink)(pathname); +} + +/** Status of a file (by name). */ +int SYSCALL_PREFIX(_stat)(const char *path, struct stat *buf) +{ + if (!buf) { return -1; } + +#ifdef MID_FATFS + FILINFO fno; + +#if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; +#endif + + if (f_stat((const TCHAR *)path, &fno) == FR_OK) + { + if (fno.fattrib & AM_DIR) + { + buf->st_mode = S_IFDIR; + } + else + { + buf->st_mode = S_IFREG; + } + + buf->st_size = fno.fsize; + buf->st_mtime = fno.ftime; + return 0; + } + +#endif + return -1; +} + +/** Status of a file (by name). */ +int SYSCALL_PREFIX(_lstat)(const char *path, struct stat *buf) +{ + return SYSCALL_PREFIX(_stat)(path, buf); +} + +/** Status of an open file */ +/** \todo fstat need more work to provide correct file stat */ +int SYSCALL_PREFIX(_fstat)(int handle, struct stat *buf) +{ + if (!buf) { return -1; } + + if (handle < STDIO_FID_OFS) + { + buf->st_mode = S_IFCHR; + buf->st_blksize = 1; + return 0; + } + + /** Can't provide unix file stat using fatfs API */ + return -1; +} + +////////////////////////////// +// Directory Identification // +////////////////////////////// +/** Determining the Current Directory */ +char *SYSCALL_PREFIX(_getcwd)(char *buf, int len) +{ +#ifdef MID_FATFS + + if (f_getcwd((TCHAR *)buf, (UINT)len) == FR_OK) + { + return buf; + } + +#endif + return NULL; +} + +#ifdef __GNU__ +char *SYSCALL_PREFIX(getcwd)(char *buf, int len) +{ + return SYSCALL_PREFIX(_getcwd)(buf, len); +} +#endif + +#if __MW__ +#pragma weak open = _open +#pragma weak close = _close +#pragma weak read = _read +#pragma weak write = _write +#pragma weak lseek = _lseek +#pragma weak unlink = _unlink +#pragma weak getcwd = _getcwd +#pragma weak isatty = _isatty +#pragma weak getpid = _getpid +#pragma weak access = _access +#pragma weak remove = _unlink + +#pragma weak fstat = _fstat +#pragma weak stat = _stat +#pragma weak lstat = _lstat + +#endif + +//////////////////////////////////////// +// Process Management // +// \todo Integrate with FreeRTOS task // +//////////////////////////////////////// +/** Determining a Process ID */ +int SYSCALL_PREFIX(_getpid)(void) +{ + return 0; +} + +extern void __attribute__((noreturn)) _exit_loop(); + +/** Terminating a Process */ +void __attribute__((noreturn)) SYSCALL_PREFIX(_exit)(int status) +{ + _exit_loop(status); +} + +/** Kill a process */ +int SYSCALL_PREFIX(_kill)(int pid, int sig) +{ + SYSCALL_PREFIX(_exit)(sig); + return -1; +} + +//////////////////////////////// +// Environment Identification // +// No environment provided // +//////////////////////////////// +static char *settings[_ENVIRON_LEN] = +{ + /* + * Add your default environment here: + */ + "PLATFORM=EMBARC", + "POSIXLY_CORRECT", + 0 +}; + +char **_environ = settings; + +/** Getting Environment Variables */ +char *SYSCALL_PREFIX(_getenv)(const char *var) +{ + int len; + char **ep; + + if (!(ep = _environ)) { return NULL; } + + len = strlen(var); + + while (*ep) + { + if (memcmp(var, *ep, len) == 0 && (*ep)[len] == '=') + { + return *ep + len + 1; + } + + ep++; + } + + return NULL; +} + +/** Putting Environment Variable */ +int SYSCALL_PREFIX(_putenv)(char *string) +{ + int i, len; + + for (len = 0; string[len] && string[len] != '='; len++); + + for (i = 0; i < _ENVIRON_LEN; i++) + { + if (_environ[i] != 0 && strncmp(string, _environ[i], len) == 0) + { + _environ[i] = string; + return 0; + } + } + + for (i = 0; i < _ENVIRON_LEN; i++) + { + if (_environ[i] == NULL) + { + _environ[i] = string; + + if ((i + 1) < _ENVIRON_LEN) + { + _environ[i + 1] = NULL; + } + + return 0; + } + } + + return -1; +} + +#if __MW__ +char *_mwgetenv2(const char *var) +{ + return SYSCALL_PREFIX(_getenv)(var); +} +#pragma weak getenv = _getenv +#pragma weak putenv = _putenv +#endif + +////////////////////// +// Time Calculation // +////////////////////// + +/** Determining the Clock Value */ +clock_t SYSCALL_PREFIX(clock)(void) +{ + uint64_t total_ticks; + + total_ticks = (uint64_t)OSP_GET_CUR_HWTICKS(); + + return (clock_t)((uint64_t)(total_ticks * CLOCKS_PER_SEC) / BOARD_CPU_CLOCK); +} + +#if !EMBARC_CFG_USE_RTCTIME +static int buildtime_ready = 0; +static struct tm build_tm; +static time_t build_time; +#endif +/** Determining the Time Value */ +time_t SYSCALL_PREFIX(_time)(time_t *timer) +{ + if (!buildtime_ready) + { + build_time = get_build_timedate(&build_tm); + buildtime_ready = 1; + } + + time_t cur_time; + cur_time = build_time + (OSP_GET_CUR_MS() / 1000); + + if (timer) + { + *timer = cur_time; + } + + return cur_time; +} + +#ifdef __GNU__ +int SYSCALL_PREFIX(_times)(struct tms *buf) +{ + if (!buf) { return -1; } + + buf->tms_utime = OSP_GET_CUR_MS() / 1000; + buf->tms_stime = 0; + buf->tms_cutime = 0; + buf->tms_cstime = 0; + return 0; +} +#endif + +int SYSCALL_PREFIX(_gettimeofday)(struct timeval *tv, void *tz) +{ + if (tv == NULL) { return -1; } + + if (!buildtime_ready) + { + build_time = get_build_timedate(&build_tm); + buildtime_ready = 1; + } + + tv->tv_sec = build_time + (OSP_GET_CUR_US() / 1000000); + tv->tv_usec = OSP_GET_CUR_US() % 1000000; + return 0; +} + +#if __MW__ +#pragma weak time = _time +#pragma weak gettimeofday = _gettimeofday +#endif + +///////////////////////// +// Argument Processing // +///////////////////////// +/** Counting Arguments */ +int SYSCALL_PREFIX(__argc)(void) +{ + return 0; +} +/** Finding the Value of an Argument */ +char *SYSCALL_PREFIX(__argv)(int num) +{ + return NULL; +} + +#endif /* !defined(_HOSTLINK_) */ + +#if defined(__GNU__) && !defined(_HAVE_LIBGLOSS_) && !defined(_HOSTLINK_) +/* Support newlibc for newlibc(<= ARC GNU 2015.06) */ +typedef struct exc_frame +{ + uint32_t erbta; + uint32_t eret; + uint32_t erstatus; + uint32_t lpcount; + uint32_t lpend; + uint32_t lpstart; + uint32_t blink; + uint32_t r30; + uint32_t ilink; + uint32_t fp; + uint32_t gp; + uint32_t r12; + uint32_t r11; + uint32_t r10; + uint32_t r9; + uint32_t r8; + uint32_t r7; + uint32_t r6; + uint32_t r5; + uint32_t r4; + uint32_t r3; + uint32_t r2; + uint32_t r1; + uint32_t r0; +} EXC_FRAME; +/** + * \brief syscall functions + * partly implemented for gnu in swi exception handler + * \param ptr exception handle stack pointer + */ +void syscall_swi(void *ptr) +{ + EXC_FRAME *swi_frame = (EXC_FRAME *)ptr; + + switch (swi_frame->r8) + { + case SYS_read: + swi_frame->r0 = SYSCALL_PREFIX(_read)((int)(swi_frame->r0), (char *)(swi_frame->r1), (int)(swi_frame->r2)); + break; + + case SYS_write: + swi_frame->r0 = SYSCALL_PREFIX(_write)((int)(swi_frame->r0), (char *)(swi_frame->r1), (int)(swi_frame->r2)); + break; + + case SYS_exit: + SYSCALL_PREFIX(_exit)(1); + break; + + case SYS_open: + swi_frame->r0 = SYSCALL_PREFIX(_open)((const char *)(swi_frame->r0), (int)(swi_frame->r1), (int)(swi_frame->r2)); + break; + + case SYS_close: + swi_frame->r0 = SYSCALL_PREFIX(_close)((int)(swi_frame->r0)); + break; + + case SYS_lseek: + swi_frame->r0 = SYSCALL_PREFIX(_lseek)((int)(swi_frame->r0), (long)(swi_frame->r1), (int)(swi_frame->r2)); + break; + + case SYS_fstat: + swi_frame->r0 = SYSCALL_PREFIX(_fstat)((int)(swi_frame->r0), (struct stat *)(swi_frame->r1)); + break; + + case SYS_unlink: + swi_frame->r0 = SYSCALL_PREFIX(_unlink)((const char *)(swi_frame->r0)); + break; + + case SYS_time: + swi_frame->r0 = SYSCALL_PREFIX(_time)((time_t *)(swi_frame->r0)); + break; + + case SYS_gettimeofday: + swi_frame->r0 = SYSCALL_PREFIX(_gettimeofday)((struct timeval *)(swi_frame->r0), (void *)(swi_frame->r1)); + break; + + case SYS_access: + swi_frame->r0 = SYSCALL_PREFIX(_access)((const char *)(swi_frame->r0), (int)(swi_frame->r1)); + break; + + case SYS_kill: + swi_frame->r0 = SYSCALL_PREFIX(_kill)((int)(swi_frame->r0), (int)(swi_frame->r1)); + break; + + case SYS_rename: + swi_frame->r0 = SYSCALL_PREFIX(rename)((const char *)(swi_frame->r0), (const char *)(swi_frame->r1)); + break; + + case SYS_times: + swi_frame->r0 = SYSCALL_PREFIX(_times)((struct tms *)(swi_frame->r0)); + break; + + case SYS_getcwd: + swi_frame->r0 = (uint32_t)SYSCALL_PREFIX(_getcwd)((char *)(swi_frame->r0), (int)(swi_frame->r1)); + break; + + default: + swi_frame->r0 = -1; + break; + } + + swi_frame->eret = swi_frame->eret + 4; +} +#endif /* __GNU__ && !_HAVE_LIBGLOSS_ && _HOSTLINK_ */ \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.h b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.h new file mode 100644 index 000000000..3cabfa0f4 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_syscalls.h @@ -0,0 +1,70 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-18 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup EMBARC_SYSCALL + * \brief Syscall support header file + */ +#ifndef _EMBARC_SYSCALLS_ +#define _EMBARC_SYSCALLS_ + +#include "embARC_BSP_config.h" +#include "board/board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNU__) && !defined(_HAVE_LIBGLOSS_) +/* _HAVE_LIBGLOSS_ is defined in options/toolchain/toolchain_gnu.mk */ +#include +#define SYSCALL_PREFIX(x) syscall##x + +#endif /* __GNU__ && !_HAVE_LIBGLOSS_ */ + +#ifndef SYSCALL_PREFIX +#define SYSCALL_PREFIX(x) x +#endif + +#if defined(__GNU__) && !defined(_HAVE_LIBGLOSS_) && !defined(_HOSTLINK_) +extern void syscall_swi(void *ptr); +#endif + +#include "embARC_target.h" + +#ifdef __cplusplus +} +#endif + +#endif /* _EMBARC_SYSCALLS_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.c new file mode 100644 index 000000000..50df0b3a2 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.c @@ -0,0 +1,84 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-03-02 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ +#include +#include +#include +#include +#include +#include +#include "embARC_syscalls.h" + +////////////////////////////// +// OTHER REQUIRED FUNCTIONS // +////////////////////////////// + +static const char szEnglishMonth[12][4] = { \ + "Jan", "Feb", "Mar", "Apr", \ + "May", "Jun", "Jul", "Aug", \ + "Sep", "Oct", "Nov", "Dec" + }; + +time_t get_build_timedate(struct tm *build_tm) +{ + if (!build_tm) { return 0; } + + char szMonth[5]; + int tm_year, tm_mon = 0, tm_day; + int tm_hour, tm_min, tm_sec; + time_t build_time; + + /** Get Build Date */ + sscanf(__DATE__, "%s %d %d", szMonth, &tm_day, &tm_year) ; + + for (int i = 0; i < 12; i++) + { + if (strncmp(szMonth, szEnglishMonth[i], 3) == 0) + { + tm_mon = i; + break; + } + } + + /** Get Build Time */ + sscanf(__TIME__, "%d:%d:%d", &tm_hour, &tm_min, &tm_sec); + build_tm->tm_sec = tm_sec; + build_tm->tm_min = tm_min; + build_tm->tm_hour = tm_hour; + build_tm->tm_mday = tm_day; + build_tm->tm_mon = tm_mon; + build_tm->tm_year = tm_year - 1900; + build_tm->tm_isdst = 0; + + build_time = mktime(build_tm); + return build_time; +} \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.h b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.h new file mode 100644 index 000000000..e651b145f --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/embARC_target.h @@ -0,0 +1,64 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-03-02 + * \author Huaqi Fang(Huaqi.Fang@synopsys.com) +--------------------------------------------- */ + +/** + * \file + * \ingroup EMBARC_SYSCALL + * \brief Common functions provided for embARC target platform + */ +#ifndef _EMBARC_TARGET_H_ +#define _EMBARC_TARGET_H_ +#include "embARC_BSP_config.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#if defined(__MW__) +#include "ya_getopt.h" +#endif + +extern time_t get_build_timedate(struct tm *build_tm); +extern void gnu_printf_setup(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _EMBARC_TARGET_H_ */ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.c new file mode 100644 index 000000000..c905d671c --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.c @@ -0,0 +1,130 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY FATFS_DIRECT, INFATFS_DIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-20 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +#ifdef MID_FATFS + +#include +#include +#include "fatfs_dirent.h" + +FATFS_DIR *opendir(const char *path) +{ + FRESULT res; + FATFS_DIR *dp; + + /* Malloc memory for dir object */ + dp = (FATFS_DIR *)malloc(sizeof(FATFS_DIR)); + + if (!dp) /* No more memory */ + { + return NULL; + } + + res = f_opendir(&dp->dir, path); + + if (res != FR_OK) + { + free(dp); + return NULL; + } + + return dp; +} + +extern struct dirent *readdir(FATFS_DIR *dp) +{ + if (!dp) { return NULL; } + + FRESULT res; + FILINFO info; + +#if _USE_LFN + info.lfname = dp->d_dirent.d_name; + info.lfsize = sizeof(dp->d_dirent.d_name); +#endif + res = f_readdir(&dp->dir, &info); + + if (res != FR_OK || info.fname[0] == 0) + { + return NULL; + } + +#if _USE_LFN + + if (*(info.lfname) == 0) + { + dp->d_dirent.d_namlen = 13; /* 8.3 format */ + memcpy(dp->d_dirent.d_name, info.fname, 13); + } + +#else + dp->d_dirent.d_namlen = 13; /* 8.3 format */ + memcpy(dp->d_dirent.d_name, info.fname, 13); +#endif + + return &(dp->d_dirent); +} + +extern int closedir(FATFS_DIR *dp) +{ + FRESULT res; + + if (!dp) { return -1; } + + res = f_closedir(&dp->dir); + free(dp); + + if (res != FR_OK) + { + return -1; + } + + return 0; +} + + +extern int fatfs_stat(const char *path, struct fatfs_stat *buf) +{ + FRESULT res; + + res = f_stat(path, &(buf->fatfs_filinfo)); + + if (res != FR_OK) + { + return -1; + } + + buf->st_mode = buf->fatfs_filinfo.fattrib; + return 0; +} +#endif \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.h b/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.h new file mode 100644 index 000000000..8fac9f39b --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/fatfs_dirent.h @@ -0,0 +1,84 @@ +/* ------------------------------------------ + * Copyright (c) 2017, Synopsys, Inc. All rights reserved. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + + * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * \version 2017.03 + * \date 2016-01-20 + * \author Wayne Ren(Wei.Ren@synopsys.com) +--------------------------------------------- */ + +#ifndef _FATFS_DIRENT_H_ +#define _FATFS_DIRENT_H_ + +#include "board/board.h" +#include + +#ifndef MID_FATFS +#error "FatFs should be enabled" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if _USE_LFN +#define MAXNAMLEN _MAX_LFN +#else +#define MAXNAMLEN 64 +#endif + +struct fatfs_stat +{ + FILINFO fatfs_filinfo; + unsigned char st_mode; +}; + +struct dirent +{ + unsigned short d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1]; /* name (up to MAXNAMLEN + 1) */ +}; + + +typedef struct +{ + DIR dir; /* FatFS DIR struct */ + struct dirent d_dirent; +} FATFS_DIR; + +extern FATFS_DIR *opendir(const char *path); +extern struct dirent *readdir(FATFS_DIR *dp); +extern int closedir(FATFS_DIR *dp); +extern int fatfs_stat(const char *path, struct fatfs_stat *buf); + +#define FATFS_S_ISREG(m) (m == 0) + +#ifdef __cplusplus +} +#endif + +#endif /*_FATFS_DIRENT_H_*/ diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/malloc.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/malloc.c new file mode 100644 index 000000000..2c14eee83 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/malloc.c @@ -0,0 +1,7282 @@ +#include "embARC_BSP_config.h" +#ifndef __GNU__ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/publicdomain/zero/1.0/ Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (minimum) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + It is also possible to limit the maximum total allocatable + space, using malloc_set_footprint_limit. This is not + designed as a security feature in itself (calls to set limits + are not screened or privileged), but may be useful as one + aspect of a secure implementation. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with a lock. By default, this uses a plain + pthread mutex, win32 critical section, or a spin-lock if if + available for the platform and not disabled by setting + USE_SPIN_LOCKS=0. However, if USE_RECURSIVE_LOCKS is defined, + recursive versions are used instead (which are not required for + base functionality but may be needed in layered extensions). + Using a global lock is not especially fast, and can be a major + bottleneck. It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + consider instead using nedmalloc + (http://www.nedprod.com/programs/portable/nedmalloc/) or + ptmalloc (See http://www.malloc.de), which are derived from + versions of this malloc. + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. In real-time + applications, you can optionally suppress segment traversals using + NO_SEGMENT_TRAVERSAL, which assures bounded execution even when + system allocators return non-contiguous spaces, at the typical + expense of carrying around more memory and increased fragmentation. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. Normally, this requires use of locks. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. You can also +use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. Beware that there seem to be some + cases where this malloc might not be a pure drop-in replacement for + Win32 malloc: Random-looking failures from Win32 GDI API's (eg; + SetDIBits()) may be due to bugs in some video driver implementations + when pixel buffers are malloc()ed, and the region spans more than + one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) + default granularity, pixel buffers may straddle virtual allocation + regions more often than when using the Microsoft allocator. You can + avoid this by using VirtualAlloc() and VirtualFree() for all pixel + buffers rather than using malloc(). If this is not possible, + recompile this malloc with a larger DEFAULT_GRANULARITY. Note: + in cases where MSC and gcc (cygwin) are known to differ on WIN32, + conditions use _MSC_VER to distinguish them. + +DLMALLOC_EXPORT default: extern + Defines how public APIs are declared. If you want to export via a + Windows DLL, you might define this as + #define DLMALLOC_EXPORT extern __declspec(dllexport) + If you want a POSIX ELF shared object, you might use + #define DLMALLOC_EXPORT extern __attribute__((visibility("default"))) + +MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *)) + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) If set to a + non-zero value other than 1, locks are used, but their + implementation is left out, so lock functions must be supplied manually, + as described below. + +USE_SPIN_LOCKS default: 1 iff USE_LOCKS and spin locks available + If true, uses custom spin locks for locking. This is currently + supported only gcc >= 4.1, older gccs on x86 platforms, and recent + MS compilers. Otherwise, posix locks or win32 critical sections are + used. + +USE_RECURSIVE_LOCKS default: not defined + If defined nonzero, uses recursive (aka reentrant) locks, otherwise + uses plain mutexes. This is not required for malloc proper, but may + be needed for layered allocators such as nedmalloc. + +LOCK_AT_FORK default: not defined + If defined nonzero, performs pthread_atfork upon initialization + to initialize child lock while holding parent lock. The implementation + assumes that pthread locks (not custom locks) are being used. In other + cases, you may need to customize the implementation. + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +MALLOC_INSPECT_ALL default: NOT defined + If defined, compiles malloc_inspect_all and mspace_inspect_all, that + perform traversal of all heap space. Unless access to these + functions is otherwise restricted, you probably do not want to + include them in secure implementations. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. + +MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +NO_SEGMENT_TRAVERSAL default: 0 + If non-zero, suppresses traversals of memory segments + returned by either MORECORE or CALL_MMAP. This disables + merging of segments that are contiguous, and selectively + releasing them to the OS if unused, but bounds execution times. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 except on WINCE. + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero and on WIN32 except for WINCE. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. Similarly for Win32 under recent MS compilers. + (On most x86s, the asm version is only slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +NO_MALLOC_STATS default: 0 + If defined, don't compile "malloc_stats". This avoids calls to + fprintf and bringing in stdio dependencies you might not want. + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP + The number of consolidated frees between checks to release + unused segments when freeing. When using non-contiguous segments, + especially with multiple mspaces, checking only for topmost space + doesn't always suffice to trigger trimming. To compensate for this, + free() will, with a period of MAX_RELEASE_CHECK_RATE (or the + current number of segments, if greater) try to release unused + segments to the OS when freeing chunks that result in + consolidation. The best value for this parameter is a compromise + between slowing down frees with relatively costly checks that + rarely trigger versus holding on to unused memory. To effectively + disable, set to MAX_SIZE_T. This may lead to a very slight speed + improvement at the expense of carrying around more memory. +*/ +#include "inc/embARC_toolchain.h" +extern void *_sbrk(unsigned int size); + +#ifndef _WIN32 +#ifdef SMALL_MEMORY +#define malloc_getpagesize (128) +#else +#define malloc_getpagesize (4096) +#endif +#endif + +/* Version identifier to allow people to support multiple versions */ +#ifndef DLMALLOC_VERSION +#define DLMALLOC_VERSION 20806 +#endif /* DLMALLOC_VERSION */ + +#ifndef DLMALLOC_EXPORT +#define DLMALLOC_EXPORT extern +#endif + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define LACKS_SCHED_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef MMAP_CLEARS +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /*MMAP_CLEARS */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ +#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ + (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) +#endif /* USE_LOCKS */ + +#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ +#if ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) +#ifndef USE_SPIN_LOCKS +#define USE_SPIN_LOCKS 1 +#endif /* USE_SPIN_LOCKS */ +#elif USE_SPIN_LOCKS +#error "USE_SPIN_LOCKS defined without implementation" +#endif /* ... locks available... */ +#elif !defined(USE_SPIN_LOCKS) +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS */ + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ + +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef MALLOC_INSPECT_ALL +#define MALLOC_INSPECT_ALL 0 +#endif /* MALLOC_INSPECT_ALL */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#define _GNU_SOURCE /* Turns on mremap() definition */ +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT _sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef MAX_RELEASE_CHECK_RATE +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +#ifndef NO_MALLOC_STATS +#define NO_MALLOC_STATS 0 +#endif /* NO_MALLOC_STATS */ +#ifndef NO_SEGMENT_TRAVERSAL +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */ +#define _STRUCT_MALLINFO +#define STRUCT_MALLINFO_DECLARED 1 +struct mallinfo +{ + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +/* + Try to persuade compilers to inline. The most critical functions for + inlining are defined as macros, so these aren't used for them. +*/ + +#ifndef FORCEINLINE +#if defined(__GNUC__) +#define FORCEINLINE __inline __attribute__ ((always_inline)) +#elif defined(_MSC_VER) +#define FORCEINLINE __forceinline +#endif +#endif +#ifndef NOINLINE +#if defined(__GNUC__) +#define NOINLINE __attribute__ ((noinline)) +#elif defined(_MSC_VER) +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#ifndef FORCEINLINE +#define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE +#define FORCEINLINE +#endif + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlposix_memalign posix_memalign +#define dlrealloc realloc +#define dlrealloc_in_place realloc_in_place +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlmalloc_footprint_limit malloc_footprint_limit +#define dlmalloc_set_footprint_limit malloc_set_footprint_limit +#define dlmalloc_inspect_all malloc_inspect_all +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#define dlbulk_free bulk_free +#endif /* USE_DL_PREFIX */ + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +DLMALLOC_EXPORT void *dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +DLMALLOC_EXPORT void dlfree(void *); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +DLMALLOC_EXPORT void *dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ +DLMALLOC_EXPORT void *dlrealloc(void *, size_t); + +/* + realloc_in_place(void* p, size_t n) + Resizes the space allocated for p to size n, only if this can be + done without moving p (i.e., only if there is adjacent space + available if n is greater than p's current allocated size, or n is + less than or equal to p's size). This may be used instead of plain + realloc if an alternative allocation strategy is needed upon failure + to expand space; for example, reallocation of a buffer that must be + memory-aligned or cleared. You can use realloc_in_place to trigger + these alternatives only when needed. + + Returns p if successful; otherwise null. +*/ +DLMALLOC_EXPORT void *dlrealloc_in_place(void *, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +DLMALLOC_EXPORT void *dlmemalign(size_t, size_t); + +/* + int posix_memalign(void** pp, size_t alignment, size_t n); + Allocates a chunk of n bytes, aligned in accord with the alignment + argument. Differs from memalign only in that it (1) assigns the + allocated memory to *pp rather than returning it, (2) fails and + returns EINVAL if the alignment is not a power of two (3) fails and + returns ENOMEM if memory cannot be allocated. +*/ +DLMALLOC_EXPORT int dlposix_memalign(void **, size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +DLMALLOC_EXPORT void *dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. To workaround the fact that mallopt is specified to use int, + not size_t parameters, the value -1 is specially treated as the + maximum unsigned size_t value. + + SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +DLMALLOC_EXPORT int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void); + +/* + malloc_footprint_limit(); + Returns the number of bytes that the heap is allowed to obtain from + the system, returning the last value returned by + malloc_set_footprint_limit, or the maximum size_t value if + never set. The returned value reflects a permission. There is no + guarantee that this number of bytes can actually be obtained from + the system. +*/ +DLMALLOC_EXPORT size_t dlmalloc_footprint_limit(); + +/* + malloc_set_footprint_limit(); + Sets the maximum number of bytes to obtain from the system, causing + failure returns from malloc and related functions upon attempts to + exceed this value. The argument value may be subject to page + rounding to an enforceable limit; this actual value is returned. + Using an argument of the maximum possible size_t effectively + disables checks. If the argument is less than or equal to the + current malloc_footprint, then all future allocations that require + additional system memory will fail. However, invocation cannot + retroactively deallocate existing used memory. +*/ +DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); + +#if MALLOC_INSPECT_ALL +/* + malloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void* callback_arg), + void* arg); + Traverses the heap and calls the given handler for each managed + region, skipping all bytes that are (or may be) used for bookkeeping + purposes. Traversal does not include include chunks that have been + directly memory mapped. Each reported region begins at the start + address, and continues up to but not including the end address. The + first used_bytes of the region contain allocated data. If + used_bytes is zero, the region is unallocated. The handler is + invoked with the given callback argument. If locks are defined, they + are held during the entire traversal. It is a bad idea to invoke + other malloc functions from within the handler. + + For example, to count the number of in-use chunks with size greater + than 1000, you could write: + static int count = 0; + void count_chunks(void* start, void* end, size_t used, void* arg) { + if (used >= 1000) ++count; + } + then: + malloc_inspect_all(count_chunks, NULL); + + malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined. +*/ +DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void *, void *, size_t, void *), + void *arg); + +#endif /* MALLOC_INSPECT_ALL */ + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +DLMALLOC_EXPORT void **dlindependent_calloc(size_t, size_t, void **); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be freed when it is no longer needed. This can be + done all at once using bulk_free. + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +DLMALLOC_EXPORT void **dlindependent_comalloc(size_t, size_t *, void **); + +/* + bulk_free(void* array[], size_t n_elements) + Frees and clears (sets to null) each non-null pointer in the given + array. This is likely to be faster than freeing them one-by-one. + If footers are used, pointers that have been allocated in different + mspaces are not freed or cleared, and the count of all such pointers + is returned. For large arrays of pointers with poor locality, it + may be worthwhile to sort this array before calling bulk_free. +*/ +DLMALLOC_EXPORT size_t dlbulk_free(void **, size_t n_elements); + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +DLMALLOC_EXPORT void *dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +DLMALLOC_EXPORT int dlmalloc_trim(size_t); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +DLMALLOC_EXPORT void dlmalloc_stats(void); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void *); + +#endif /* ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void *mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +DLMALLOC_EXPORT size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +DLMALLOC_EXPORT mspace create_mspace_with_base(void *base, size_t capacity, int locked); + +/* + mspace_track_large_chunks controls whether requests for large chunks + are allocated in their own untracked mmapped regions, separate from + others in this mspace. By default large chunks are not tracked, + which reduces fragmentation. However, such chunks are not + necessarily released to the system upon destroy_mspace. Enabling + tracking by setting to true may increase fragmentation, but avoids + leakage when relying on destroy_mspace to release all memory + allocated using this space. The function returns the previous + setting. +*/ +DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable); + + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void *mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +DLMALLOC_EXPORT void mspace_free(mspace msp, void *mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +DLMALLOC_EXPORT void *mspace_realloc(mspace msp, void *mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +DLMALLOC_EXPORT void *mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +DLMALLOC_EXPORT void *mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void **mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void *chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +DLMALLOC_EXPORT void **mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void *chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + malloc_usable_size(void* p) behaves the same as malloc_usable_size; +*/ +DLMALLOC_EXPORT size_t mspace_usable_size(const void *mem); + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +DLMALLOC_EXPORT int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef _MSC_VER +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* _MSC_VER */ +#if !NO_MALLOC_STATS +#include /* for printing in malloc_stats */ +#endif /* NO_MALLOC_STATS */ +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#undef assert +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ +#if !defined(WIN32) && !defined(LACKS_TIME_H) +#include /* for magic initialization */ +#endif /* WIN32 */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ +#if (defined(linux) && !defined(__USE_GNU)) +#define __USE_GNU 1 +#include /* for mmap */ +#undef __USE_GNU +#else +#include /* for mmap */ +#endif /* linux */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#ifndef LACKS_UNISTD_H +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void *sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ + +/* Declarations for locking */ +#if USE_LOCKS +#ifndef WIN32 +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#elif !defined(LACKS_SCHED_H) +#include +#endif /* solaris or LACKS_SCHED_H */ +#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS +#include +#endif /* USE_RECURSIVE_LOCKS ... */ +#elif defined(_MSC_VER) +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#elif defined(WIN32) && defined(__GNUC__) +#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) +#define interlockedexchange __sync_lock_test_and_set +#endif /* Win32 */ +#else /* USE_LOCKS */ +#endif /* USE_LOCKS */ + +#ifndef LOCK_AT_FORK +#define LOCK_AT_FORK 0 +#endif + +/* Declarations for bit scanning on win32 */ +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) +extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some platforms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if HAVE_MMAP + +#ifndef WIN32 +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static FORCEINLINE void *win32mmap(size_t size) +{ + void *ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0) ? ptr : MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static FORCEINLINE void *win32direct_mmap(size_t size) +{ + void *ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0) ? ptr : MFAIL; +} + +/* This function supports releasing coalesed segments */ +static FORCEINLINE int win32munmap(void *ptr, size_t size) +{ + MEMORY_BASIC_INFORMATION minfo; + char *cptr = (char *)ptr; + + while (size) + { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + { + return -1; + } + + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + { + return -1; + } + + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + { + return -1; + } + + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + + return 0; +} + +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MREMAP +#ifndef WIN32 +#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ + +/** + * Define CALL_MORECORE + */ +#if HAVE_MORECORE +#ifdef MORECORE +#define CALL_MORECORE(S) MORECORE(S) +#else /* MORECORE */ +#define CALL_MORECORE(S) MORECORE_DEFAULT(S) +#endif /* MORECORE */ +#else /* HAVE_MORECORE */ +#define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/** + * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP + */ +#if HAVE_MMAP +#define USE_MMAP_BIT (SIZE_T_ONE) + +#ifdef MMAP +#define CALL_MMAP(s) MMAP(s) +#else /* MMAP */ +#define CALL_MMAP(s) MMAP_DEFAULT(s) +#endif /* MMAP */ +#ifdef MUNMAP +#define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#else /* MUNMAP */ +#define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) +#endif /* MUNMAP */ +#ifdef DIRECT_MMAP +#define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) +#else /* DIRECT_MMAP */ +#define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) +#endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ +#define USE_MMAP_BIT (SIZE_T_ZERO) + +#define MMAP(s) MFAIL +#define MUNMAP(a, s) (-1) +#define DIRECT_MMAP(s) MFAIL +#define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) +#define CALL_MMAP(s) MMAP(s) +#define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ + +/** + * Define CALL_MREMAP + */ +#if HAVE_MMAP && HAVE_MREMAP +#ifdef MREMAP +#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) +#else /* MREMAP */ +#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) +#endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ +#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +/* + When locks are defined, there is one global lock, plus + one per-mspace lock. + + The global lock_ensures that mparams.magic and other unique + mparams values are initialized only once. It also protects + sequences of calls to MORECORE. In many cases sys_alloc requires + two calls, that should not be interleaved with calls by other + threads. This does not protect against direct calls to MORECORE + by other threads not using this lock, so there is still code to + cope the best we can on interference. + + Per-mspace locks surround calls to malloc, free, etc. + By default, locks are simple non-reentrant mutexes. + + Because lock-protected regions generally have bounded times, it is + OK to use the supplied simple spinlocks. Spinlocks are likely to + improve performance for lightly contended applications, but worsen + performance under heavy contention. + + If USE_LOCKS is > 1, the definitions of lock routines here are + bypassed, in which case you will need to define the type MLOCK_T, + and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK + and TRY_LOCK. You must also declare a + static MLOCK_T malloc_global_mutex = { initialization values };. + +*/ + +#if !USE_LOCKS +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) (0) +#define DESTROY_LOCK(l) (0) +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() + +#else +#if USE_LOCKS > 1 +/* ----------------------- User-defined locks ------------------------ */ +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(lk) ... */ +/* #define DESTROY_LOCK(lk) ... */ +/* #define ACQUIRE_LOCK(lk) ... */ +/* #define RELEASE_LOCK(lk) ... */ +/* #define TRY_LOCK(lk) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ + +#elif USE_SPIN_LOCKS + +/* First, define CAS_LOCK and CLEAR_LOCK on ints */ +/* Note CAS_LOCK defined to return 0 on success */ + +#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) +#define CLEAR_LOCK(sl) __sync_lock_release(sl) + +#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) +/* Custom spin locks for older gcc on x86 */ +static FORCEINLINE int x86_cas_lock(int *sl) +{ + int ret; + int val = 1; + int cmp = 0; + __asm__ __volatile__("lock; cmpxchgl %1, %2" + : "=a"(ret) + : "r"(val), "m"(*(sl)), "0"(cmp) + : "memory", "cc"); + return ret; +} + +static FORCEINLINE void x86_clear_lock(int *sl) +{ + assert(*sl != 0); + int prev = 0; + int ret; + __asm__ __volatile__("lock; xchgl %0, %1" + : "=r"(ret) + : "m"(*(sl)), "0"(prev) + : "memory"); +} + +#define CAS_LOCK(sl) x86_cas_lock(sl) +#define CLEAR_LOCK(sl) x86_clear_lock(sl) + +#else /* Win32 MSC */ +#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1) +#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0) + +#endif /* ... gcc spins locks ... */ + +/* How to yield for a spin lock */ +#define SPINS_PER_YIELD 63 +#if defined(_MSC_VER) +#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ +#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) +#elif defined (__SVR4) && defined (__sun) /* solaris */ +#define SPIN_LOCK_YIELD thr_yield(); +#elif !defined(LACKS_SCHED_H) +#define SPIN_LOCK_YIELD sched_yield(); +#else +#define SPIN_LOCK_YIELD +#endif /* ... yield ... */ + +#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 +/* Plain spin locks use single word (embedded in malloc_states) */ +static int spin_acquire_lock(int *sl) +{ + int spins = 0; + + while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) + { + if ((++spins & SPINS_PER_YIELD) == 0) + { + SPIN_LOCK_YIELD; + } + } + + return 0; +} + +#define MLOCK_T int +#define TRY_LOCK(sl) !CAS_LOCK(sl) +#define RELEASE_LOCK(sl) CLEAR_LOCK(sl) +#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0) +#define INITIAL_LOCK(sl) (*sl = 0) +#define DESTROY_LOCK(sl) (0) +static MLOCK_T malloc_global_mutex = 0; + +#else /* USE_RECURSIVE_LOCKS */ +/* types for lock owners */ +#ifdef WIN32 +#define THREAD_ID_T DWORD +#define CURRENT_THREAD GetCurrentThreadId() +#define EQ_OWNER(X,Y) ((X) == (Y)) +#else +/* + Note: the following assume that pthread_t is a type that can be + initialized to (casted) zero. If this is not the case, you will need to + somehow redefine these or not use spin locks. +*/ +#define THREAD_ID_T pthread_t +#define CURRENT_THREAD pthread_self() +#define EQ_OWNER(X,Y) pthread_equal(X, Y) +#endif + +struct malloc_recursive_lock +{ + int sl; + unsigned int c; + THREAD_ID_T threadid; +}; + +#define MLOCK_T struct malloc_recursive_lock +static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0}; + +static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) +{ + assert(lk->sl != 0); + + if (--lk->c == 0) + { + CLEAR_LOCK(&lk->sl); + } +} + +static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) +{ + THREAD_ID_T mythreadid = CURRENT_THREAD; + int spins = 0; + + for (;;) + { + if (*((volatile int *)(&lk->sl)) == 0) + { + if (!CAS_LOCK(&lk->sl)) + { + lk->threadid = mythreadid; + lk->c = 1; + return 0; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) + { + ++lk->c; + return 0; + } + + if ((++spins & SPINS_PER_YIELD) == 0) + { + SPIN_LOCK_YIELD; + } + } +} + +static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) +{ + THREAD_ID_T mythreadid = CURRENT_THREAD; + + if (*((volatile int *)(&lk->sl)) == 0) + { + if (!CAS_LOCK(&lk->sl)) + { + lk->threadid = mythreadid; + lk->c = 1; + return 1; + } + } + else if (EQ_OWNER(lk->threadid, mythreadid)) + { + ++lk->c; + return 1; + } + + return 0; +} + +#define RELEASE_LOCK(lk) recursive_release_lock(lk) +#define TRY_LOCK(lk) recursive_try_lock(lk) +#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) +#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) +#define DESTROY_LOCK(lk) (0) +#endif /* USE_RECURSIVE_LOCKS */ + +#elif defined(WIN32) /* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) +#define RELEASE_LOCK(lk) LeaveCriticalSection(lk) +#define TRY_LOCK(lk) TryEnterCriticalSection(lk) +#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000)) +#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; +static volatile LONG malloc_global_mutex_status; + +/* Use spin loop to initialize global lock */ +static void init_malloc_global_mutex() +{ + for (;;) + { + long stat = malloc_global_mutex_status; + + if (stat > 0) + { + return; + } + + /* transition to < 0 while initializing, then to > 0) */ + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, (LONG) - 1, (LONG)0) == 0) + { + InitializeCriticalSection(&malloc_global_mutex); + interlockedexchange(&malloc_global_mutex_status, (LONG)1); + return; + } + + SleepEx(0, FALSE); + } +} + +#else /* pthreads-based locks */ +#define MLOCK_T pthread_mutex_t +#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) +#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) +#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) +#define INITIAL_LOCK(lk) pthread_init_lock(lk) +#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) + +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) +/* Cope with old-style linux recursive lock initialization by adding */ +/* skipped internal declaration from pthread.h */ +extern int pthread_mutexattr_setkind_np __P((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif /* USE_RECURSIVE_LOCKS ... */ + +static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int pthread_init_lock(MLOCK_T *lk) +{ + pthread_mutexattr_t attr; + + if (pthread_mutexattr_init(&attr)) { return 1; } + +#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) { return 1; } + +#endif + + if (pthread_mutex_init(lk, &attr)) { return 1; } + + if (pthread_mutexattr_destroy(&attr)) { return 1; } + + return 0; +} + +#endif /* ... lock types ... */ + +/* Common code for all lock types */ +#define USE_LOCK_BIT (2U) + +#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#endif + +#ifndef RELEASE_MALLOC_GLOBAL_LOCK +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#endif + +#endif /* USE_LOCKS */ + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 0) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse (unless the chunk is mmapped). This redundancy enables usage + checks within free and realloc, and reduces indirection when freeing + and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, have both cinuse and pinuse bits + cleared in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk +{ + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk *fd; /* double links -- used only if free. */ + struct malloc_chunk *bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk *mchunkptr; +typedef struct malloc_chunk *sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use, unless mmapped, in which case both bits are cleared. + + FLAG4_BIT is not used by this malloc, but might be useful in extensions. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define flag4inuse(p) ((p)->head & FLAG4_BIT) +#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) +#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) + +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define set_flag4(p) ((p)->head |= FLAG4_BIT) +#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk +{ + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk *fd; + struct malloc_tree_chunk *bk; + + struct malloc_tree_chunk *child[2]; + struct malloc_tree_chunk *parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk *tchunkptr; +typedef struct malloc_tree_chunk *tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If USE_MMAP_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment +{ + char *base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment *next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment *msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Max allowed footprint + The maximum allowed bytes to allocate from system (zero means no limit) + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Trim support + Fields holding the amount of unused topmost memory that should trigger + trimming, and a counter to force periodic scanning to release unused + non-topmost segments. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. + + Extension support + A void* pointer and a size_t field that can be used to help implement + extensions to this malloc. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state +{ + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char *least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS + 1) * 2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + size_t footprint_limit; /* zero means no limit */ + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void *extp; /* Unused but available for extensions */ + size_t exts; +}; + +typedef struct malloc_state *mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. Note that the non-zeroness of "magic" + also serves as an initialization flag. +*/ + +struct malloc_params +{ + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* Ensure mparams initialized */ +#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams()) + +#if !ONLY_MSPACES + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) + +#endif /* !ONLY_MSPACES */ + +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#if USE_LOCKS +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) +#else +#define disable_lock(M) +#endif + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#if HAVE_MMAP +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) +#else +#define disable_mmap(M) +#endif + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + + +/* For mmap, use granularity alignment on windows, else page-align */ +#ifdef WIN32 +#define mmap_align(S) granularity_align(S) +#else +#define mmap_align(S) page_align(S) +#endif + +/* For sys_alloc, enough padding to ensure can malloc request on success */ +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char *addr) +{ + msegmentptr sp = &m->seg; + + for (;;) + { + if (addr >= sp->base && addr < sp->base + sp->size) + { + return sp; + } + + if ((sp = sp->next) == 0) + { + return 0; + } + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) +{ + msegmentptr sp = &m->seg; + + for (;;) + { + if ((char *)sp >= ss->base && (char *)sp < ss->base + ss->size) + { + return 1; + } + + if ((sp = sp->next) == 0) + { + return 0; + } + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void *mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I. Use x86 asm if possible */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, (DWORD) X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + +/* index corresponding to given bit. Use x86 asm if possible */ + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = __builtin_ctz(X); \ + I = (bindex_t)J;\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} + +#elif USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probabalistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has inuse status */ +#define ok_inuse(p) is_inuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_inuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Macros for setting head/foot of non-mmapped chunks */ + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +#if LOCK_AT_FORK +static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); } +static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); } +static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } +#endif /* LOCK_AT_FORK */ + +/* Initialize mparams */ +static int init_mparams(void) +{ +#ifdef NEED_GLOBAL_LOCK_INIT + + if (malloc_global_mutex_status <= 0) + { + init_malloc_global_mutex(); + } + +#endif + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (mparams.magic == 0) + { + size_t magic; + size_t psize; + size_t gsize; + +#ifndef WIN32 + psize = malloc_getpagesize; + gsize = ((DEFAULT_GRANULARITY != 0) ? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + psize = system_info.dwPageSize; + gsize = ((DEFAULT_GRANULARITY != 0) ? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char *)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT - SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE - SIZE_T_ONE)) != 0) || + ((gsize & (gsize - SIZE_T_ONE)) != 0) || + ((psize & (psize - SIZE_T_ONE)) != 0)) + { + ABORT; + } + + mparams.granularity = gsize; + mparams.page_size = psize; + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT | USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if !ONLY_MSPACES + /* Set up lock for main malloc area */ + gm->mflags = mparams.default_mflags; + (void)INITIAL_LOCK(&gm->mutex); +#endif +#if LOCK_AT_FORK + pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); +#endif + + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) + { + magic = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ +#ifdef WIN32 + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); + +#elif defined(LACKS_TIME_H) + magic = (size_t)&magic ^ (size_t)0x55555555U; +#else + magic = (size_t)(time(0) ^ (size_t)0x55555555U); +#endif + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + /* Until memory modes commonly available, use volatile-write */ + (*(volatile size_t *)(&(mparams.magic))) = magic; + } + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) +{ + size_t val; + ensure_initialization(); + val = (value == -1) ? MAX_SIZE_T : (size_t)value; + + switch (param_number) + { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val - 1)) == 0)) + { + mparams.granularity = val; + return 1; + } + else + { + return 0; + } + + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) +{ + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) +{ + msegmentptr sp = segment_holding(m, (char *)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char *)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!pinuse(chunk_plus_offset(p, sz))); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) +{ + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size - SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz + SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) +{ + do_check_any_chunk(m, p); + assert(is_inuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + + if (is_mmapped(p)) + { + do_check_mmapped_chunk(m, p); + } +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) +{ + size_t sz = chunksize(p); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!is_inuse(p)); + assert(!next_pinuse(p)); + assert(!is_mmapped(p)); + + if (p != m->dv && p != m->top) + { + if (sz >= MIN_CHUNK_SIZE) + { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert(next == m->top || is_inuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + { + assert(sz == SIZE_T_SIZE); + } + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void *mem, size_t s) +{ + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~INUSE_BITS; + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) +{ + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS - 1) || (tsize < minsize_for_tree_index((idx + 1)))); + + do /* traverse through chain of same-sized nodes */ + { + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!is_inuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + + if (u->parent == 0) + { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else + { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert(u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr *)(u->parent)) == u); + + if (u->child[0] != 0) + { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + + if (u->child[1] != 0) + { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + + if (u->child[0] != 0 && u->child[1] != 0) + { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + + u = u->fd; + } + while (u != t); + + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) +{ + tbinptr *tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + + if (t == 0) + { + assert(empty); + } + + if (!empty) + { + do_check_tree(m, t); + } +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) +{ + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + + if (p == b) + { + assert(empty); + } + + if (!empty) + { + for (; p != b; p = p->bk) + { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + + if (q->head != FENCEPOST_HEAD) + { + do_check_inuse_chunk(m, q); + } + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) +{ + size_t size = chunksize(x); + + if (is_small(size)) + { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + + if (smallmap_is_marked(m, sidx)) + { + mchunkptr p = b; + + do + { + if (p == x) + { + return 1; + } + } + while ((p = p->fd) != b); + } + } + else + { + bindex_t tidx; + compute_tree_index(size, tidx); + + if (treemap_is_marked(m, tidx)) + { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + + while (t != 0 && chunksize(t) != size) + { + t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + + if (t != 0) + { + tchunkptr u = t; + + do + { + if (u == (tchunkptr)x) + { + return 1; + } + } + while ((u = u->fd) != t); + } + } + } + + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) +{ + size_t sum = 0; + + if (is_initialized(m)) + { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + + while (s != 0) + { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) + { + sum += chunksize(q); + + if (is_inuse(q)) + { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else + { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + + lastq = q; + q = next_chunk(q); + } + + s = s->next; + } + } + + return sum; +} + + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) +{ + bindex_t i; + size_t total; + + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + { + do_check_smallbin(m, i); + } + + for (i = 0; i < NTREEBINS; ++i) + { + do_check_treebin(m, i); + } + + if (m->dvsize != 0) /* check dv chunk */ + { + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) /* check top chunk */ + { + do_check_top_chunk(m, m->top); + /*assert(m->topsize == chunksize(m->top)); redundant */ + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) +{ + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + ensure_initialization(); + + if (!PREACTION(m)) + { + check_malloc_state(m); + + if (is_initialized(m)) + { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + + while (s != 0) + { + mchunkptr q = align_as_chunk(s->base); + + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) + { + size_t sz = chunksize(q); + sum += sz; + + if (!is_inuse(q)) + { + mfree += sz; + ++nfree; + } + + q = next_chunk(q); + } + + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + + return nm; +} +#endif /* !NO_MALLINFO */ + +#if !NO_MALLOC_STATS +static void internal_malloc_stats(mstate m) +{ + ensure_initialization(); + + if (!PREACTION(m)) + { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + + if (is_initialized(m)) + { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) + { + mchunkptr q = align_as_chunk(s->base); + + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) + { + if (!is_inuse(q)) + { + used -= chunksize(q); + } + + q = next_chunk(q); + } + + s = s->next; + } + } + + POSTACTION(m); /* drop lock */ + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + } +} +#endif /* NO_MALLOC_STATS */ + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(B == smallbin_at(M,I) ||\ + (ok_address(M, B) && B->fd == P))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F) {\ + clear_smallmap(M, I);\ + }\ + else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + assert(is_small(DVS));\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + ((m == gm)? dlmalloc(b) : mspace_malloc(m, b)) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). +*/ + +/* Malloc using mmap */ +static void *mmap_alloc(mstate m, size_t nb) +{ + size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + + if (m->footprint_limit != 0) + { + size_t fp = m->footprint + mmsize; + + if (fp <= m->footprint || fp > m->footprint_limit) + { + return 0; + } + } + + if (mmsize > nb) /* Check for wrap around 0 */ + { + char *mm = (char *)(CALL_DIRECT_MMAP(mmsize)); + + if (mm != CMFAIL) + { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset; + p->head = psize; + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize + SIZE_T_SIZE)->head = 0; + + if (m->least_addr == 0 || mm < m->least_addr) + { + m->least_addr = mm; + } + + if ((m->footprint += mmsize) > m->max_footprint) + { + m->max_footprint = m->footprint; + } + + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) +{ + size_t oldsize = chunksize(oldp); + (void)flags; /* placate people compiling -Wunused */ + + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + { + return 0; + } + + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + { + return oldp; + } + else + { + size_t offset = oldp->prev_foot; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char *cp = (char *)CALL_MREMAP((char *)oldp - offset, + oldmmsize, newmmsize, flags); + + if (cp != CMFAIL) + { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = psize; + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + { + m->least_addr = cp; + } + + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + { + m->max_footprint = m->footprint; + } + + check_mmapped_chunk(m, newp); + return newp; + } + } + + return 0; +} + + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) +{ + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char *)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) +{ + /* Establish circular links for smallbins */ + bindex_t i; + + for (i = 0; i < NSMALLBINS; ++i) + { + sbinptr bin = smallbin_at(m, i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) +{ + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallmap = m->treemap = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + + for (i = 0; i < NTREEBINS; ++i) + { + *treebin_at(m, i) = 0; + } + + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void *prepend_alloc(mstate m, char *newbase, char *oldbase, + size_t nb) +{ + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char *)oldfirst - (char *)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char *)oldfirst > (char *)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) + { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) + { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else + { + if (!is_inuse(oldfirst)) + { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char *tbase, size_t tsize, flag_t mmapped) +{ + /* Determine locations and sizes of segment, fenceposts, old top */ + char *old_top = (char *)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char *old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char *rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char *asp = rawsp + offset; + char *csp = (asp < (old_top + MIN_CHUNK_SIZE)) ? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) + { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + + if ((char *)(&(nextp->head)) < old_end) + { + p = nextp; + } + else + { + break; + } + } + + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) + { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void *sys_alloc(mstate m, size_t nb) +{ + char *tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + size_t asize; /* allocation size */ + + ensure_initialization(); + + /* Directly map large chunks, but only if already initialized */ + if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) + { + void *mem = mmap_alloc(m, nb); + + if (mem != 0) + { + return mem; + } + } + + asize = granularity_align(nb + SYS_ALLOC_PADDING); + + if (asize <= nb) + { + return 0; /* wraparound */ + } + + if (m->footprint_limit != 0) + { + size_t fp = m->footprint + asize; + + if (fp <= m->footprint || fp > m->footprint_limit) + { + return 0; + } + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + + In all cases, we need to request enough bytes from system to ensure + we can malloc nb bytes upon success, so pad with enough space for + top_foot, plus alignment-pad to make sure we don't lose bytes if + not on boundary, and round this up to a granularity unit. + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) + { + char *br = CMFAIL; + size_t ssize = asize; /* sbrk call size */ + msegmentptr ss = (m->top == 0) ? 0 : segment_holding(m, (char *)m->top); + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (ss == 0) /* First time through or recovery */ + { + char *base = (char *)CALL_MORECORE(0); + + if (base != CMFAIL) + { + size_t fp; + + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + { + ssize += (page_align((size_t)base) - (size_t)base); + } + + fp = m->footprint + ssize; /* recheck limits */ + + if (ssize > nb && ssize < HALF_MAX_SIZE_T && + (m->footprint_limit == 0 || + (fp > m->footprint && fp <= m->footprint_limit)) && + (br = (char *)(CALL_MORECORE(ssize))) == base) + { + tbase = base; + tsize = ssize; + } + } + } + else + { + /* Subtract out existing available top space from MORECORE request. */ + ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); + + /* Use mem here only if it did continuously extend old space */ + if (ssize < HALF_MAX_SIZE_T && + (br = (char *)(CALL_MORECORE(ssize))) == ss->base + ss->size) + { + tbase = br; + tsize = ssize; + } + } + + if (tbase == CMFAIL) /* Cope with partial failure */ + { + if (br != CMFAIL) /* Try to use/extend the space we did get */ + { + if (ssize < HALF_MAX_SIZE_T && + ssize < nb + SYS_ALLOC_PADDING) + { + size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize); + + if (esize < HALF_MAX_SIZE_T) + { + char *end = (char *)CALL_MORECORE(esize); + + if (end != CMFAIL) + { + ssize += esize; + } + else /* Can't use; try to release */ + { + (void) CALL_MORECORE(-ssize); + br = CMFAIL; + } + } + } + } + + if (br != CMFAIL) /* Use the space we did get */ + { + tbase = br; + tsize = ssize; + } + else + { + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) /* Try MMAP */ + { + char *mp = (char *)(CALL_MMAP(asize)); + + if (mp != CMFAIL) + { + tbase = mp; + tsize = asize; + mmap_flag = USE_MMAP_BIT; + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) /* Try noncontiguous MORECORE */ + { + if (asize < HALF_MAX_SIZE_T) + { + char *br = CMFAIL; + char *end = CMFAIL; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + br = (char *)(CALL_MORECORE(asize)); + end = (char *)(CALL_MORECORE(0)); + RELEASE_MALLOC_GLOBAL_LOCK(); + + if (br != CMFAIL && end != CMFAIL && br < end) + { + size_t ssize = end - br; + + if (ssize > nb + TOP_FOOT_SIZE) + { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) + { + + if ((m->footprint += tsize) > m->max_footprint) + { + m->max_footprint = m->footprint; + } + + if (!is_initialized(m)) /* first-time initialization */ + { + if (m->least_addr == 0 || tbase < m->least_addr) + { + m->least_addr = tbase; + } + + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + init_bins(m); +#if !ONLY_MSPACES + + if (is_global(m)) + { + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + } + else +#endif + { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); + } + } + + else + { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + + /* Only consider most recent segment if traversal suppressed */ + while (sp != 0 && tbase != sp->base + sp->size) + { + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + } + + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag && + segment_holds(sp, m->top)) /* append */ + { + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else + { + if (tbase < m->least_addr) + { + m->least_addr = tbase; + } + + sp = &m->seg; + + while (sp != 0 && sp->base != tbase + tsize) + { + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + } + + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & USE_MMAP_BIT) == mmap_flag) + { + char *oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + { + add_segment(m, tbase, tsize, mmap_flag); + } + } + } + + if (nb < m->topsize) /* Allocate from new or extended top space */ + { + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) +{ + size_t released = 0; + int nsegs = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + + while (sp != 0) + { + char *base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + ++nsegs; + + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) + { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!is_inuse(p) && (char *)p + psize >= base + size - TOP_FOOT_SIZE) + { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char *)sp)); + + if (p == m->dv) + { + m->dv = 0; + m->dvsize = 0; + } + else + { + unlink_large_chunk(m, tp); + } + + if (CALL_MUNMAP(base, size) == 0) + { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else /* back out if cannot unmap */ + { + insert_large_chunk(m, tp, psize); + } + } + } + + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + { + break; + } + + pred = sp; + sp = next; + } + + /* Reset check counter */ + m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE) ? + (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); + return released; +} + +static int sys_trim(mstate m, size_t pad) +{ + size_t released = 0; + ensure_initialization(); + + if (pad < MAX_REQUEST && is_initialized(m)) + { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) + { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char *)m->top); + + if (!is_extern_segment(sp)) + { + if (is_mmapped_segment(sp)) + { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) /* can't shrink if pinned */ + { + size_t newsize = sp->size - extra; + (void)newsize; /* placate people compiling -Wunused-variable */ + + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) + { + released = extra; + } + } + } + else if (HAVE_MORECORE) + { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + { + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + } + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char *old_br = (char *)(CALL_MORECORE(0)); + + if (old_br == sp->base + sp->size) + { + char *rel_br = (char *)(CALL_MORECORE(-extra)); + char *new_br = (char *)(CALL_MORECORE(0)); + + if (rel_br != CMFAIL && new_br < old_br) + { + released = old_br - new_br; + } + } + } + RELEASE_MALLOC_GLOBAL_LOCK(); + } + } + + if (released != 0) + { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + { + released += release_unused_segments(m); + } + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0 && m->topsize > m->trim_check) + { + m->trim_check = MAX_SIZE_T; + } + } + + return (released != 0) ? 1 : 0; +} + +/* Consolidate and bin a chunk. Differs from exported versions + of free mainly in that the chunk need not be marked as inuse. +*/ +static void dispose_chunk(mstate m, mchunkptr p, size_t psize) +{ + mchunkptr next = chunk_plus_offset(p, psize); + + if (!pinuse(p)) + { + mchunkptr prev; + size_t prevsize = p->prev_foot; + + if (is_mmapped(p)) + { + psize += prevsize + MMAP_FOOT_PAD; + + if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) + { + m->footprint -= psize; + } + + return; + } + + prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + + if (RTCHECK(ok_address(m, prev))) /* consolidate backward */ + { + if (p != m->dv) + { + unlink_chunk(m, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) + { + m->dvsize = psize; + set_free_with_pinuse(p, psize, next); + return; + } + } + else + { + CORRUPTION_ERROR_ACTION(m); + return; + } + } + + if (RTCHECK(ok_address(m, next))) + { + if (!cinuse(next)) /* consolidate forward */ + { + if (next == m->top) + { + size_t tsize = m->topsize += psize; + m->top = p; + p->head = tsize | PINUSE_BIT; + + if (p == m->dv) + { + m->dv = 0; + m->dvsize = 0; + } + + return; + } + else if (next == m->dv) + { + size_t dsize = m->dvsize += psize; + m->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + return; + } + else + { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(m, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + + if (p == m->dv) + { + m->dvsize = psize; + return; + } + } + } + else + { + set_free_with_pinuse(p, psize, next); + } + + insert_chunk(m, p, psize); + } + else + { + CORRUPTION_ERROR_ACTION(m); + } +} + +/* ---------------------------- malloc --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void *tmalloc_large(mstate m, size_t nb) +{ + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + + if ((t = *treebin_at(m, idx)) != 0) + { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + + for (;;) + { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + + if (trem < rsize) + { + v = t; + + if ((rsize = trem) == 0) + { + break; + } + } + + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; + + if (rt != 0 && rt != t) + { + rst = rt; + } + + if (t == 0) + { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + + sizebits <<= 1; + } + } + + if (t == 0 && v == 0) /* set t to root of next non-empty treebin */ + { + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + + if (leftbits != 0) + { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) /* find smallest of tree or subtree */ + { + size_t trem = chunksize(t) - nb; + + if (trem < rsize) + { + rsize = trem; + v = t; + } + + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) + { + if (RTCHECK(ok_address(m, v))) /* split */ + { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + + if (RTCHECK(ok_next(v, r))) + { + unlink_large_chunk(m, v); + + if (rsize < MIN_CHUNK_SIZE) + { + set_inuse_and_pinuse(m, v, (rsize + nb)); + } + else + { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + } + + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void *tmalloc_small(mstate m, size_t nb) +{ + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) + { + size_t trem = chunksize(t) - nb; + + if (trem < rsize) + { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) + { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + + if (RTCHECK(ok_next(v, r))) + { + unlink_large_chunk(m, v); + + if (rsize < MIN_CHUNK_SIZE) + { + set_inuse_and_pinuse(m, v, (rsize + nb)); + } + else + { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +#if !ONLY_MSPACES + +void *dlmalloc(size_t bytes) +{ + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif + + if (!PREACTION(gm)) + { + void *mem; + size_t nb; + + if (bytes <= MAX_SMALL_REQUEST) + { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) /* Remainderless fit to a smallbin. */ + { + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) + { + if (smallbits != 0) /* Use chunk in next nonempty smallbin */ + { + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + { + set_inuse_and_pinuse(gm, p, small_index2size(i)); + } + else + { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) + { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + { + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + } + else + { + nb = pad_request(bytes); + + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) + { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) + { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + + if (rsize >= MIN_CHUNK_SIZE) /* split dv */ + { + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else /* exhaust dv */ + { + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) /* Split top */ + { + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + +postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +/* ---------------------------- free --------------------------- */ + +void dlfree(void *mem) +{ + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + + if (!ok_magic(fm)) + { + USAGE_ERROR_ACTION(fm, p); + return; + } + +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + + if (!PREACTION(fm)) + { + check_inuse_chunk(fm, p); + + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) + { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + + if (!pinuse(p)) + { + size_t prevsize = p->prev_foot; + + if (is_mmapped(p)) + { + psize += prevsize + MMAP_FOOT_PAD; + + if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) + { + fm->footprint -= psize; + } + + goto postaction; + } + else + { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + + if (RTCHECK(ok_address(fm, prev))) /* consolidate backward */ + { + if (p != fm->dv) + { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) + { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + { + goto erroraction; + } + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) + { + if (!cinuse(next)) /* consolidate forward */ + { + if (next == fm->top) + { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + + if (p == fm->dv) + { + fm->dv = 0; + fm->dvsize = 0; + } + + if (should_trim(fm, tsize)) + { + sys_trim(fm, 0); + } + + goto postaction; + } + else if (next == fm->dv) + { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else + { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + + if (p == fm->dv) + { + fm->dvsize = psize; + goto postaction; + } + } + } + else + { + set_free_with_pinuse(p, psize, next); + } + + if (is_small(psize)) + { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else + { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + + if (--fm->release_checks == 0) + { + release_unused_segments(fm); + } + } + + goto postaction; + } + } + +erroraction: + USAGE_ERROR_ACTION(fm, p); +postaction: + POSTACTION(fm); + } + } + +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void *dlcalloc(size_t n_elements, size_t elem_size) +{ + void *mem; + size_t req = 0; + + if (n_elements != 0) + { + req = n_elements * elem_size; + + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + { + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + } + + mem = dlmalloc(req); + + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + { + memset(mem, 0, req); + } + + return mem; +} + +#endif /* !ONLY_MSPACES */ + +/* ------------ Internal support for realloc, memalign, etc -------------- */ + +/* Try to realloc; only in-place unless can_move true */ +static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, + int can_move) +{ + mchunkptr newp = 0; + size_t oldsize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, oldsize); + + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && + ok_next(p, next) && ok_pinuse(next))) + { + if (is_mmapped(p)) + { + newp = mmap_resize(m, p, nb, can_move); + } + else if (oldsize >= nb) /* already big enough */ + { + size_t rsize = oldsize - nb; + + if (rsize >= MIN_CHUNK_SIZE) /* split off remainder */ + { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + + newp = p; + } + else if (next == m->top) /* extend into top */ + { + if (oldsize + m->topsize > nb) + { + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + newtop->head = newtopsize | PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = p; + } + } + else if (next == m->dv) /* extend into dv */ + { + size_t dvs = m->dvsize; + + if (oldsize + dvs >= nb) + { + size_t dsize = oldsize + dvs - nb; + + if (dsize >= MIN_CHUNK_SIZE) + { + mchunkptr r = chunk_plus_offset(p, nb); + mchunkptr n = chunk_plus_offset(r, dsize); + set_inuse(m, p, nb); + set_size_and_pinuse_of_free_chunk(r, dsize); + clear_pinuse(n); + m->dvsize = dsize; + m->dv = r; + } + else /* exhaust dv */ + { + size_t newsize = oldsize + dvs; + set_inuse(m, p, newsize); + m->dvsize = 0; + m->dv = 0; + } + + newp = p; + } + } + else if (!cinuse(next)) /* extend into next free chunk */ + { + size_t nextsize = chunksize(next); + + if (oldsize + nextsize >= nb) + { + size_t rsize = oldsize + nextsize - nb; + unlink_chunk(m, next, nextsize); + + if (rsize < MIN_CHUNK_SIZE) + { + size_t newsize = oldsize + nextsize; + set_inuse(m, p, newsize); + } + else + { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dispose_chunk(m, r, rsize); + } + + newp = p; + } + } + } + else + { + USAGE_ERROR_ACTION(m, chunk2mem(p)); + } + + return newp; +} + +static void *internal_memalign(mstate m, size_t alignment, size_t bytes) +{ + void *mem = 0; + + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + { + alignment = MIN_CHUNK_SIZE; + } + + if ((alignment & (alignment - SIZE_T_ONE)) != 0) /* Ensure a power of 2 */ + { + size_t a = MALLOC_ALIGNMENT << 1; + + while (a < alignment) { a <<= 1; } + + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) + { + if (m != 0) /* Test isn't needed but avoids compiler warning */ + { + MALLOC_FAILURE_ACTION; + } + } + else + { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + mem = internal_malloc(m, req); + + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) + { + return 0; + } + + if ((((size_t)(mem)) & (alignment - 1)) != 0) /* misaligned */ + { + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char *br = (char *)mem2chunk((size_t)(((size_t)((char *)mem + alignment - + SIZE_T_ONE)) & + -alignment)); + char *pos = ((size_t)(br - (char *)(p)) >= MIN_CHUNK_SIZE) ? + br : br + alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char *)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) /* For mmapped chunks, just adjust offset */ + { + newp->prev_foot = p->prev_foot + leadsize; + newp->head = newsize; + } + else /* Otherwise, give back leader, use the rest */ + { + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + dispose_chunk(m, p, leadsize); + } + + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) + { + size_t size = chunksize(p); + + if (size > nb + MIN_CHUNK_SIZE) + { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + dispose_chunk(m, remainder, remainder_size); + } + } + + mem = chunk2mem(p); + assert(chunksize(p) >= nb); + assert(((size_t)mem & (alignment - 1)) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + } + } + + return mem; +} + +/* + Common support for independent_X routines, handling + all of the combinations that can result. + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed +*/ +static void **ialloc(mstate m, + size_t n_elements, + size_t *sizes, + int opts, + void *chunks[]) +{ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void *mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void **marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + ensure_initialization(); + + /* compute array length, if needed */ + if (chunks != 0) + { + if (n_elements == 0) + { + return chunks; /* nothing to do */ + } + + marray = chunks; + array_size = 0; + } + else + { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + { + return (void **)internal_malloc(m, 0); + } + + marray = 0; + array_size = request2size(n_elements * (sizeof(void *))); + } + + /* compute total element size */ + if (opts & 0x1) /* all-same-size */ + { + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else /* add up all the sizes */ + { + element_size = 0; + contents_size = 0; + + for (i = 0; i != n_elements; ++i) + { + contents_size += request2size(sizes[i]); + } + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + + if (was_enabled) + { + enable_mmap(m); + } + + if (mem == 0) + { + return 0; + } + + if (PREACTION(m)) { return 0; } + + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) /* optionally clear the elements */ + { + memset((size_t *)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) + { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void **)(chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) + { + marray[i] = chunk2mem(p); + + if (i != n_elements - 1) + { + if (element_size != 0) + { + size = element_size; + } + else + { + size = request2size(sizes[i]); + } + + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else /* the final element absorbs any overallocation slop */ + { + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + + if (marray != chunks) + { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) + { + assert(remainder_size == element_size); + } + else + { + assert(remainder_size == request2size(sizes[i])); + } + + check_inuse_chunk(m, mem2chunk(marray)); + } + + for (i = 0; i != n_elements; ++i) + { + check_inuse_chunk(m, mem2chunk(marray[i])); + } + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + +/* Try to free all pointers in the given array. + Note: this could be made faster, by delaying consolidation, + at the price of disabling some user integrity checks, We + still optimize some consolidations by combining adjacent + chunks before freeing, which will occur often if allocated + with ialloc or the array is sorted. +*/ +static size_t internal_bulk_free(mstate m, void *array[], size_t nelem) +{ + size_t unfreed = 0; + + if (!PREACTION(m)) + { + void **a; + void **fence = &(array[nelem]); + + for (a = array; a != fence; ++a) + { + void *mem = *a; + + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); + size_t psize = chunksize(p); +#if FOOTERS + + if (get_mstate_for(p) != m) + { + ++unfreed; + continue; + } + +#endif + check_inuse_chunk(m, p); + *a = 0; + + if (RTCHECK(ok_address(m, p) && ok_inuse(p))) + { + void **b = a + 1; /* try to merge with next chunk */ + mchunkptr next = next_chunk(p); + + if (b != fence && *b == chunk2mem(next)) + { + size_t newsize = chunksize(next) + psize; + set_inuse(m, p, newsize); + *b = chunk2mem(p); + } + else + { + dispose_chunk(m, p, psize); + } + } + else + { + CORRUPTION_ERROR_ACTION(m); + break; + } + } + } + + if (should_trim(m, m->topsize)) + { + sys_trim(m, 0); + } + + POSTACTION(m); + } + + return unfreed; +} + +/* Traversal */ +#if MALLOC_INSPECT_ALL +static void internal_inspect_all(mstate m, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void *callback_arg), + void *arg) +{ + if (is_initialized(m)) + { + mchunkptr top = m->top; + msegmentptr s; + + for (s = &m->seg; s != 0; s = s->next) + { + mchunkptr q = align_as_chunk(s->base); + + while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) + { + mchunkptr next = next_chunk(q); + size_t sz = chunksize(q); + size_t used; + void *start; + + if (is_inuse(q)) + { + used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ + start = chunk2mem(q); + } + else + { + used = 0; + + if (is_small(sz)) /* offset by possible bookkeeping */ + { + start = (void *)((char *)q + sizeof(struct malloc_chunk)); + } + else + { + start = (void *)((char *)q + sizeof(struct malloc_tree_chunk)); + } + } + + if (start < (void *)next) /* skip if all space is bookkeeping */ + { + handler(start, next, used, arg); + } + + if (q == top) + { + break; + } + + q = next; + } + } + } +} +#endif /* MALLOC_INSPECT_ALL */ + +/* ------------------ Exported realloc, memalign, etc -------------------- */ + +#if !ONLY_MSPACES + +void *dlrealloc(void *oldmem, size_t bytes) +{ + void *mem = 0; + + if (oldmem == 0) + { + mem = dlmalloc(bytes); + } + else if (bytes >= MAX_REQUEST) + { + MALLOC_FAILURE_ACTION; + } + +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) + { + dlfree(oldmem); + } + +#endif /* REALLOC_ZERO_BYTES_FREES */ + else + { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + + if (!ok_magic(m)) + { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } + +#endif /* FOOTERS */ + + if (!PREACTION(m)) + { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + + if (newp != 0) + { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else + { + mem = internal_malloc(m, bytes); + + if (mem != 0) + { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); + internal_free(m, oldmem); + } + } + } + } + + return mem; +} + +void *dlrealloc_in_place(void *oldmem, size_t bytes) +{ + void *mem = 0; + + if (oldmem != 0) + { + if (bytes >= MAX_REQUEST) + { + MALLOC_FAILURE_ACTION; + } + else + { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + + if (!ok_magic(m)) + { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } + +#endif /* FOOTERS */ + + if (!PREACTION(m)) + { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + + if (newp == oldp) + { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + + return mem; +} + +void *dlmemalign(size_t alignment, size_t bytes) +{ + if (alignment <= MALLOC_ALIGNMENT) + { + return dlmalloc(bytes); + } + + return internal_memalign(gm, alignment, bytes); +} + +int dlposix_memalign(void **pp, size_t alignment, size_t bytes) +{ + void *mem = 0; + + if (alignment == MALLOC_ALIGNMENT) + { + mem = dlmalloc(bytes); + } + else + { + size_t d = alignment / sizeof(void *); + size_t r = alignment % sizeof(void *); + + if (r != 0 || d == 0 || (d & (d - SIZE_T_ONE)) != 0) + { + return EINVAL; + } + else if (bytes <= MAX_REQUEST - alignment) + { + if (alignment < MIN_CHUNK_SIZE) + { + alignment = MIN_CHUNK_SIZE; + } + + mem = internal_memalign(gm, alignment, bytes); + } + } + + if (mem == 0) + { + return ENOMEM; + } + else + { + *pp = mem; + return 0; + } +} + +void *dlvalloc(size_t bytes) +{ + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void *dlpvalloc(size_t bytes) +{ + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +void **dlindependent_calloc(size_t n_elements, size_t elem_size, + void *chunks[]) +{ + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void **dlindependent_comalloc(size_t n_elements, size_t sizes[], + void *chunks[]) +{ + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +size_t dlbulk_free(void *array[], size_t nelem) +{ + return internal_bulk_free(gm, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void dlmalloc_inspect_all(void(*handler)(void *start, + void *end, + size_t used_bytes, + void *callback_arg), + void *arg) +{ + ensure_initialization(); + + if (!PREACTION(gm)) + { + internal_inspect_all(gm, handler, arg); + POSTACTION(gm); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int dlmalloc_trim(size_t pad) +{ + int result = 0; + ensure_initialization(); + + if (!PREACTION(gm)) + { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + + return result; +} + +size_t dlmalloc_footprint(void) +{ + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) +{ + return gm->max_footprint; +} + +size_t dlmalloc_footprint_limit(void) +{ + size_t maf = gm->footprint_limit; + return maf == 0 ? MAX_SIZE_T : maf; +} + +size_t dlmalloc_set_footprint_limit(size_t bytes) +{ + size_t result; /* invert sense of 0 */ + + if (bytes == 0) + { + result = granularity_align(1); /* Use minimal size */ + } + + if (bytes == MAX_SIZE_T) + { + result = 0; /* disable */ + } + else + { + result = granularity_align(bytes); + } + + return gm->footprint_limit = result; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) +{ + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +#if !NO_MALLOC_STATS +void dlmalloc_stats() +{ + internal_malloc_stats(gm); +} +#endif /* NO_MALLOC_STATS */ + +int dlmallopt(int param_number, int value) +{ + return change_mparam(param_number, value); +} + +size_t dlmalloc_usable_size(void *mem) +{ + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); + + if (is_inuse(p)) + { + return chunksize(p) - overhead_for(p); + } + } + + return 0; +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char *tbase, size_t tsize) +{ + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + (void)INITIAL_LOCK(&m->mutex); + msp->head = (msize | INUSE_BITS); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + m->mflags = mparams.default_mflags; + m->extp = 0; + m->exts = 0; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) +{ + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + + if (capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) + { + size_t rs = ((capacity == 0) ? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char *tbase = (char *)(CALL_MMAP(tsize)); + + if (tbase != CMFAIL) + { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = USE_MMAP_BIT; + set_lock(m, locked); + } + } + + return (mspace)m; +} + +mspace create_mspace_with_base(void *base, size_t capacity, int locked) +{ + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) + { + m = init_user_mstate((char *)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + + return (mspace)m; +} + +int mspace_track_large_chunks(mspace msp, int enable) +{ + int ret = 0; + mstate ms = (mstate)msp; + + if (!PREACTION(ms)) + { + if (!use_mmap(ms)) + { + ret = 1; + } + + if (!enable) + { + enable_mmap(ms); + } + else + { + disable_mmap(ms); + } + + POSTACTION(ms); + } + + return ret; +} + +size_t destroy_mspace(mspace msp) +{ + size_t freed = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + msegmentptr sp = &ms->seg; + (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ + + while (sp != 0) + { + char *base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + (void)base; /* placate people compiling -Wunused-variable */ + sp = sp->next; + + if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + { + freed += size; + } + } + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + +void *mspace_malloc(mspace msp, size_t bytes) +{ + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + return 0; + } + + if (!PREACTION(ms)) + { + void *mem; + size_t nb; + + if (bytes <= MAX_SMALL_REQUEST) + { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) /* Remainderless fit to a smallbin. */ + { + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) + { + if (smallbits != 0) /* Use chunk in next nonempty smallbin */ + { + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + { + set_inuse_and_pinuse(ms, p, small_index2size(i)); + } + else + { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) + { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + { + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + } + else + { + nb = pad_request(bytes); + + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) + { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) + { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + + if (rsize >= MIN_CHUNK_SIZE) /* split dv */ + { + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else /* exhaust dv */ + { + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) /* Split top */ + { + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + +postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void *mem) +{ + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + (void)msp; /* placate people compiling -Wunused */ +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + + if (!ok_magic(fm)) + { + USAGE_ERROR_ACTION(fm, p); + return; + } + + if (!PREACTION(fm)) + { + check_inuse_chunk(fm, p); + + if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) + { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + + if (!pinuse(p)) + { + size_t prevsize = p->prev_foot; + + if (is_mmapped(p)) + { + psize += prevsize + MMAP_FOOT_PAD; + + if (CALL_MUNMAP((char *)p - prevsize, psize) == 0) + { + fm->footprint -= psize; + } + + goto postaction; + } + else + { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + + if (RTCHECK(ok_address(fm, prev))) /* consolidate backward */ + { + if (p != fm->dv) + { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) + { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + { + goto erroraction; + } + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) + { + if (!cinuse(next)) /* consolidate forward */ + { + if (next == fm->top) + { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + + if (p == fm->dv) + { + fm->dv = 0; + fm->dvsize = 0; + } + + if (should_trim(fm, tsize)) + { + sys_trim(fm, 0); + } + + goto postaction; + } + else if (next == fm->dv) + { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else + { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + + if (p == fm->dv) + { + fm->dvsize = psize; + goto postaction; + } + } + } + else + { + set_free_with_pinuse(p, psize, next); + } + + if (is_small(psize)) + { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else + { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + + if (--fm->release_checks == 0) + { + release_unused_segments(fm); + } + } + + goto postaction; + } + } + +erroraction: + USAGE_ERROR_ACTION(fm, p); +postaction: + POSTACTION(fm); + } + } +} + +void *mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) +{ + void *mem; + size_t req = 0; + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + return 0; + } + + if (n_elements != 0) + { + req = n_elements * elem_size; + + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + { + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + } + + mem = internal_malloc(ms, req); + + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + { + memset(mem, 0, req); + } + + return mem; +} + +void *mspace_realloc(mspace msp, void *oldmem, size_t bytes) +{ + void *mem = 0; + + if (oldmem == 0) + { + mem = mspace_malloc(msp, bytes); + } + else if (bytes >= MAX_REQUEST) + { + MALLOC_FAILURE_ACTION; + } + +#ifdef REALLOC_ZERO_BYTES_FREES + else if (bytes == 0) + { + mspace_free(msp, oldmem); + } + +#endif /* REALLOC_ZERO_BYTES_FREES */ + else + { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + + if (!ok_magic(m)) + { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } + +#endif /* FOOTERS */ + + if (!PREACTION(m)) + { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + + if (newp != 0) + { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } + else + { + mem = mspace_malloc(m, bytes); + + if (mem != 0) + { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); + mspace_free(m, oldmem); + } + } + } + } + + return mem; +} + +void *mspace_realloc_in_place(mspace msp, void *oldmem, size_t bytes) +{ + void *mem = 0; + + if (oldmem != 0) + { + if (bytes >= MAX_REQUEST) + { + MALLOC_FAILURE_ACTION; + } + else + { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if ! FOOTERS + mstate m = (mstate)msp; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + (void)msp; /* placate people compiling -Wunused */ + + if (!ok_magic(m)) + { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } + +#endif /* FOOTERS */ + + if (!PREACTION(m)) + { + mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); + POSTACTION(m); + + if (newp == oldp) + { + check_inuse_chunk(m, newp); + mem = oldmem; + } + } + } + } + + return mem; +} + +void *mspace_memalign(mspace msp, size_t alignment, size_t bytes) +{ + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + return 0; + } + + if (alignment <= MALLOC_ALIGNMENT) + { + return mspace_malloc(msp, bytes); + } + + return internal_memalign(ms, alignment, bytes); +} + +void **mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void *chunks[]) +{ + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + return 0; + } + + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void **mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void *chunks[]) +{ + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + return 0; + } + + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +size_t mspace_bulk_free(mspace msp, void *array[], size_t nelem) +{ + return internal_bulk_free((mstate)msp, array, nelem); +} + +#if MALLOC_INSPECT_ALL +void mspace_inspect_all(mspace msp, + void(*handler)(void *start, + void *end, + size_t used_bytes, + void *callback_arg), + void *arg) +{ + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + if (!PREACTION(ms)) + { + internal_inspect_all(ms, handler, arg); + POSTACTION(ms); + } + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } +} +#endif /* MALLOC_INSPECT_ALL */ + +int mspace_trim(mspace msp, size_t pad) +{ + int result = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + if (!PREACTION(ms)) + { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return result; +} + +#if !NO_MALLOC_STATS +void mspace_malloc_stats(mspace msp) +{ + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + internal_malloc_stats(ms); + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } +} +#endif /* NO_MALLOC_STATS */ + +size_t mspace_footprint(mspace msp) +{ + size_t result = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + result = ms->footprint; + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return result; +} + +size_t mspace_max_footprint(mspace msp) +{ + size_t result = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + result = ms->max_footprint; + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return result; +} + +size_t mspace_footprint_limit(mspace msp) +{ + size_t result = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + size_t maf = ms->footprint_limit; + result = (maf == 0) ? MAX_SIZE_T : maf; + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return result; +} + +size_t mspace_set_footprint_limit(mspace msp, size_t bytes) +{ + size_t result = 0; + mstate ms = (mstate)msp; + + if (ok_magic(ms)) + { + if (bytes == 0) + { + result = granularity_align(1); /* Use minimal size */ + } + + if (bytes == MAX_SIZE_T) + { + result = 0; /* disable */ + } + else + { + result = granularity_align(bytes); + } + + ms->footprint_limit = result; + } + else + { + USAGE_ERROR_ACTION(ms, ms); + } + + return result; +} + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) +{ + mstate ms = (mstate)msp; + + if (!ok_magic(ms)) + { + USAGE_ERROR_ACTION(ms, ms); + } + + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +size_t mspace_usable_size(const void *mem) +{ + if (mem != 0) + { + mchunkptr p = mem2chunk(mem); + + if (is_inuse(p)) + { + return chunksize(p) - overhead_for(p); + } + } + + return 0; +} + +int mspace_mallopt(int param_number, int value) +{ + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea + * fix bad comparison in dlposix_memalign + * don't reuse adjusted asize in sys_alloc + * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion + * reduce compiler warnings -- thanks to all who reported/suggested these + + v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee) + * Always perform unlink checks unless INSECURE + * Add posix_memalign. + * Improve realloc to expand in more cases; expose realloc_in_place. + Thanks to Peter Buhr for the suggestion. + * Add footprint_limit, inspect_all, bulk_free. Thanks + to Barry Hayes and others for the suggestions. + * Internal refactorings to avoid calls while holding locks + * Use non-reentrant locks by default. Thanks to Roland McGrath + for the suggestion. + * Small fixes to mspace_destroy, reset_on_error. + * Various configuration extensions/changes. Thanks + to all who contributed these. + + V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu) + * Update Creative Commons URL + + V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) + * Use zeros instead of prev foot for is_mmapped + * Add mspace_track_large_chunks; thanks to Jean Brouwers + * Fix set_inuse in internal_realloc; thanks to Jean Brouwers + * Fix insufficient sys_alloc padding when using 16byte alignment + * Fix bad error check in mspace_footprint + * Adaptations for ptmalloc; thanks to Wolfram Gloger. + * Reentrant spin locks; thanks to Earl Chew and others + * Win32 improvements; thanks to Niall Douglas and Earl Chew + * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options + * Extension hook in malloc_state + * Various small adjustments to reduce warnings on some compilers + * Various configuration extensions/changes for more platforms. Thanks + to all who contributed these. + + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ +#endif /* !__GNU__ */ \ No newline at end of file diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.c b/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.c new file mode 100644 index 000000000..4cd052efd --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.c @@ -0,0 +1,430 @@ +/* -*- indent-tabs-mode: nil -*- + * + * ya_getopt - Yet another getopt + * https://github.com/kubo/ya_getopt + * + * Copyright 2015 Kubo Takehiro + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of the authors. + * + */ +#include +#include +#include +#include +#include "ya_getopt.h" + +char *ya_optarg = NULL; +int ya_optind = 1; +int ya_opterr = 1; +int ya_optopt = '?'; +static char *ya_optnext = NULL; +static int posixly_correct = -1; +static int handle_nonopt_argv = 0; + +static void ya_getopt_error(const char *optstring, const char *format, ...); +static void check_gnu_extension(const char *optstring); +static int ya_getopt_internal(int argc, char *const argv[], const char *optstring, const struct option *longopts, + int *longindex, int long_only); +static int ya_getopt_shortopts(int argc, char *const argv[], const char *optstring, int long_only); +static int ya_getopt_longopts(int argc, char *const argv[], char *arg, const char *optstring, + const struct option *longopts, int *longindex, int *long_only_flag); + +static void ya_getopt_error(const char *optstring, const char *format, ...) +{ +#if 0 + + if (ya_opterr && optstring[0] != ':') + { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } + +#endif +} + +static void check_gnu_extension(const char *optstring) +{ +#if 1 + + if (optstring[0] == '+' || getenv("POSIXLY_CORRECT") != NULL) + { +#else + + if (optstring[0] == '+') + { +#endif + posixly_correct = 0; + } + else + { + posixly_correct = 1; + } + + if (optstring[0] == '-') + { + handle_nonopt_argv = 1; + } + else + { + handle_nonopt_argv = 0; + } +} + +int ya_getopt(int argc, char *const argv[], const char *optstring) +{ + return ya_getopt_internal(argc, argv, optstring, NULL, NULL, 0); +} + +int ya_getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex) +{ + return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 0); +} + +int ya_getopt_long_only(int argc, char *const argv[], const char *optstring, const struct option *longopts, + int *longindex) +{ + return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 1); +} + +static int ya_getopt_internal(int argc, char *const argv[], const char *optstring, const struct option *longopts, + int *longindex, int long_only) +{ + static int start, end; + + if (ya_optopt == '?') + { + ya_optopt = 0; + } + + if (posixly_correct == -1) + { + check_gnu_extension(optstring); + } + + if (ya_optind == 0) + { + check_gnu_extension(optstring); + ya_optind = 1; + ya_optnext = NULL; + } + + switch (optstring[0]) + { + case '+': + case '-': + optstring++; + } + + if (ya_optnext == NULL && start != 0) + { + int last_pos = ya_optind - 1; + + ya_optind -= end - start; + + if (ya_optind <= 0) + { + ya_optind = 1; + } + + while (start < end--) + { + int i; + char *arg = argv[end]; + + for (i = end; i < last_pos; i++) + { + ((char **)argv)[i] = argv[i + 1]; + } + + ((char const **)argv)[i] = arg; + last_pos--; + } + + start = 0; + } + + if (ya_optind >= argc) + { + ya_optarg = NULL; + return -1; + } + + if (ya_optnext == NULL) + { + const char *arg = argv[ya_optind]; + + if (*arg != '-') + { + if (handle_nonopt_argv) + { + ya_optarg = argv[optind++]; + start = 0; + return 1; + } + else if (posixly_correct) + { + ya_optarg = NULL; + return -1; + } + else + { + int i; + + start = ya_optind; + + for (i = ya_optind + 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + end = i; + break; + } + } + + if (i == argc) + { + ya_optarg = NULL; + return -1; + } + + ya_optind = i; + arg = argv[ya_optind]; + } + } + + if (strcmp(arg, "--") == 0) + { + ya_optind++; + return -1; + } + + if (longopts != NULL && arg[1] == '-') + { + return ya_getopt_longopts(argc, argv, argv[ya_optind] + 2, optstring, longopts, longindex, NULL); + } + } + + if (ya_optnext == NULL) + { + ya_optnext = argv[ya_optind] + 1; + } + + if (long_only && longopts != NULL) + { + int long_only_flag = 0; + int rv = ya_getopt_longopts(argc, argv, ya_optnext, optstring, longopts, longindex, &long_only_flag); + + if (!long_only_flag) + { + ya_optnext = NULL; + return rv; + } + } + + return ya_getopt_shortopts(argc, argv, optstring, long_only); +} + +static int ya_getopt_shortopts(int argc, char *const argv[], const char *optstring, int long_only) +{ + int opt = *ya_optnext; + const char *os = strchr(optstring, opt); + + if (os == NULL) + { + ya_optarg = NULL; + + if (long_only) + { + ya_getopt_error(optstring, "%s: unrecognized option '-%s'\n", argv[0], ya_optnext); + ya_optind++; + ya_optnext = NULL; + } + else + { + ya_optopt = opt; + ya_getopt_error(optstring, "%s: invalid option -- '%c'\n", argv[0], opt); + + if (*(++ya_optnext) == 0) + { + ya_optind++; + ya_optnext = NULL; + } + } + + return '?'; + } + + if (os[1] == ':') + { + if (ya_optnext[1] == 0) + { + ya_optind++; + + if (os[2] == ':') + { + /* optional argument */ + ya_optarg = NULL; + } + else + { + if (ya_optind == argc) + { + ya_optarg = NULL; + ya_optopt = opt; + ya_getopt_error(optstring, "%s: option requires an argument -- '%c'\n", argv[0], opt); + + if (optstring[0] == ':') + { + return ':'; + } + else + { + return '?'; + } + } + + ya_optarg = argv[ya_optind]; + ya_optind++; + } + } + else + { + ya_optarg = ya_optnext + 1; + ya_optind++; + } + + ya_optnext = NULL; + } + else + { + ya_optarg = NULL; + + if (ya_optnext[1] == 0) + { + ya_optnext = NULL; + ya_optind++; + } + else + { + ya_optnext++; + } + } + + return opt; +} + +static int ya_getopt_longopts(int argc, char *const argv[], char *arg, const char *optstring, + const struct option *longopts, int *longindex, int *long_only_flag) +{ + char *val = NULL; + const struct option *opt; + size_t namelen; + int idx; + + for (idx = 0; longopts[idx].name != NULL; idx++) + { + opt = &longopts[idx]; + namelen = strlen(opt->name); + + if (strncmp(arg, opt->name, namelen) == 0) + { + switch (arg[namelen]) + { + case '\0': + switch (opt->has_arg) + { + case ya_required_argument: + ya_optind++; + + if (ya_optind == argc) + { + ya_optarg = NULL; + ya_optopt = opt->val; + ya_getopt_error(optstring, "%s: option '--%s' requires an argument\n", argv[0], opt->name); + + if (optstring[0] == ':') + { + return ':'; + } + else + { + return '?'; + } + } + + val = argv[ya_optind]; + break; + } + + goto found; + + case '=': + if (opt->has_arg == ya_no_argument) + { + const char *hyphens = (argv[ya_optind][1] == '-') ? "--" : "-"; + + ya_optind++; + ya_optarg = NULL; + ya_optopt = opt->val; + ya_getopt_error(optstring, "%s: option '%s%s' doesn't allow an argument\n", argv[0], hyphens, opt->name); + return '?'; + } + + val = arg + namelen + 1; + goto found; + } + } + } + + if (long_only_flag) + { + *long_only_flag = 1; + } + else + { + ya_getopt_error(optstring, "%s: unrecognized option '%s'\n", argv[0], argv[ya_optind]); + ya_optind++; + } + + return '?'; +found: + ya_optarg = val; + ya_optind++; + + if (opt->flag) + { + *opt->flag = opt->val; + } + + if (longindex) + { + *longindex = idx; + } + + return opt->flag ? 0 : opt->val; +} diff --git a/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.h b/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.h new file mode 100644 index 000000000..00c121077 --- /dev/null +++ b/third_party/synopsys/embarc_emsk_bsp/library/clib/ya_getopt.h @@ -0,0 +1,78 @@ +/* -*- indent-tabs-mode: nil -*- + * + * ya_getopt - Yet another getopt + * https://github.com/kubo/ya_getopt + * + * Copyright 2015 Kubo Takehiro + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of the authors. + * + */ +#ifndef YA_GETOPT_H +#define YA_GETOPT_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + +#define ya_no_argument 0 +#define ya_required_argument 1 +#define ya_optional_argument 2 + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +int ya_getopt(int argc, char *const argv[], const char *optstring); +int ya_getopt_long(int argc, char *const argv[], const char *optstring, + const struct option *longopts, int *longindex); +int ya_getopt_long_only(int argc, char *const argv[], const char *optstring, + const struct option *longopts, int *longindex); + +extern char *ya_optarg; +extern int ya_optind, ya_opterr, ya_optopt; + +#ifndef YA_GETOPT_NO_COMPAT_MACRO +#define getopt ya_getopt +#define getopt_long ya_getopt_long +#define getopt_long_only ya_getopt_long_only +#define optarg ya_optarg +#define optind ya_optind +#define opterr ya_opterr +#define optopt ya_optopt +#define no_argument ya_no_argument +#define required_argument ya_required_argument +#define optional_argument ya_optional_argument +#endif + +#if defined(__cplusplus) +} +#endif + +#endif