diff --git a/Makefile.buildtests b/Makefile.buildtests index 4d5d99badd..8679ed5f25 100644 --- a/Makefile.buildtests +++ b/Makefile.buildtests @@ -63,6 +63,7 @@ buildtest: WERROR=$${WERROR} \ LTO=$${LTO} \ TOOLCHAIN=$${TOOLCHAIN} \ + MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \ $(MAKE) -j$(NPROC) clean all 2>&1) ; \ if [ "$${?}" = "0" ]; then \ ${COLOR_ECHO} "${COLOR_GREEN}success${COLOR_RESET}"; \ @@ -97,6 +98,7 @@ buildtest: BINDIRBASE=$${BINDIRBASE} \ RIOTNOLINK=$${RIOTNOLINK} \ RIOT_VERSION=$${RIOT_VERSION} \ + MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \ $(MAKE) clean-intermediates 2>&1 >/dev/null || true; \ done; \ $${BUILDTESTOK} @@ -133,6 +135,7 @@ info-buildsizes: RIOTCPU=$${RIOTCPU} \ RIOTPKG=$${RIOTPKG} \ BINDIRBASE=$${BINDIRBASE} \ + MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \ $(MAKE) info-buildsize 2>/dev/null | tail -n-1 | cut -f-4)" "$${BOARD}"; \ done; @@ -150,6 +153,7 @@ info-buildsizes-diff: RIOTCPU=$${RIOTCPU} \ RIOTPKG=$${RIOTPKG} \ BINDIRBASE=$${BINDIRBASE} \ + MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \ $(MAKE) info-buildsize 2>/dev/null | tail -n-1 | cut -f-4; \ done | \ while read -a OLD && read -a NEW; do \ diff --git a/boards/mips-malta/Makefile b/boards/mips-malta/Makefile new file mode 100644 index 0000000000..f8fcbb53a0 --- /dev/null +++ b/boards/mips-malta/Makefile @@ -0,0 +1,3 @@ +MODULE = board + +include $(RIOTBASE)/Makefile.base diff --git a/boards/mips-malta/Makefile.features b/boards/mips-malta/Makefile.features new file mode 100644 index 0000000000..bf4ba1fe26 --- /dev/null +++ b/boards/mips-malta/Makefile.features @@ -0,0 +1,9 @@ +# Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_uart + +# Various other features (if any) +FEATURES_PROVIDED += cpp + +# The board MPU family (used for grouping by the CI system) +FEATURES_MCU_GROUP = mips32r2 diff --git a/boards/mips-malta/Makefile.include b/boards/mips-malta/Makefile.include new file mode 100644 index 0000000000..f162303b4d --- /dev/null +++ b/boards/mips-malta/Makefile.include @@ -0,0 +1,4 @@ +export CPU = mips32r2_common +export INCLUDES += -I$(RIOTBOARD)/$(BOARD)/include/ +export USE_HARD_FLOAT = 1 +export USE_DSP = 1 diff --git a/boards/mips-malta/include/board.h b/boards/mips-malta/include/board.h new file mode 100644 index 0000000000..9d69c1bbc6 --- /dev/null +++ b/boards/mips-malta/include/board.h @@ -0,0 +1,46 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @defgroup boards_mips-malta MIPS MALTA + * @ingroup boards + * @brief Board specific files for the MIPS Malta FPGA system + * @{ + * + * @file + * @brief Board specific definitions for the MIPS Malta FPGA System. + * + * @author Neil Jones + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set how many increments of the count register per uS + * needed by timer code + */ +#define TICKS_PER_US (15) + +/** + * @brief Board level initialisation + */ +void board_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _BOARD_H_ */ +/** @} */ diff --git a/boards/mips-malta/include/periph_conf.h b/boards/mips-malta/include/periph_conf.h new file mode 100644 index 0000000000..d8dad5660d --- /dev/null +++ b/boards/mips-malta/include/periph_conf.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @defgroup boards_mips-malta MIPS MALTA + * @ingroup boards + * @brief peripheral configuration for the MIPS Malta FPGA system + * @{ + * + * @file + * @brief peripheral configuration for the MIPS Malta FPGA system + * + * @author Neil Jones + */ + +#ifndef _PERIPH_CONF_H_ +#define _PERIPH_CONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Timer definitions + * @{ + */ +#define TIMER_NUMOF (1) +#define TIMER_0_CHANNELS (3) +/** @} */ + +/** + * @brief No UART driver for this board currently + * Note this value must be set though (to 0) + */ +#define UART_NUMOF (0) + +/** + * @brief Enable DSP context save + restore. + */ +#define MIPS_DSP (1) + +/** + * @brief Enable FPU context save + restore. + */ +#define MIPS_HARD_FLOAT (1) + +#ifdef __cplusplus +} +#endif + +#endif /*_PERIPH_CONF_H_*/ +/** @} */ diff --git a/boards/mips-malta/malta.c b/boards/mips-malta/malta.c new file mode 100644 index 0000000000..e2be4e3d02 --- /dev/null +++ b/boards/mips-malta/malta.c @@ -0,0 +1,28 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +#include +#include "periph/uart.h" + +#define MIPS_MALTA_ADDR (0xbf000500) +#define MIPS_MALTA_VAL_RST (0x42) + +static void malta_reset(void) +{ + *(volatile long *)MIPS_MALTA_ADDR = MIPS_MALTA_VAL_RST; + __asm__ volatile ("wait"); +} + +void board_init(void) +{ + /* Board initialisation is done by the bootloader (u-boot) on Malta */ +} + +void pm_reboot(void) +{ + malta_reset(); +} diff --git a/cpu/mips32r2_common/Makefile b/cpu/mips32r2_common/Makefile new file mode 100644 index 0000000000..7f386366f4 --- /dev/null +++ b/cpu/mips32r2_common/Makefile @@ -0,0 +1,4 @@ +MODULE = cpu +DIRS = periph + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/mips32r2_common/Makefile.include b/cpu/mips32r2_common/Makefile.include new file mode 100644 index 0000000000..d0c9b7a769 --- /dev/null +++ b/cpu/mips32r2_common/Makefile.include @@ -0,0 +1,48 @@ +ifndef MIPS_ELF_ROOT + $(error "Please set $$(MIPS_ELF_ROOT) and ensure $$(MIPS_ELF_ROOT)/bin is on your PATH") +endif + +# Target triple for the build. +export TARGET_ARCH ?= mips-mti-elf + +export ABI=32 +export MEMORY_BASE=0x80000000 +export MEMORY_SIZE=1M +export APP_START=0x80000000 + +include $(MIPS_ELF_ROOT)/share/mips/rules/mipshal.mk + +# define build specific options +export CFLAGS_CPU = -EL -march=mips32r2 -std=gnu99 +export CFLAGS_LINK = -ffunction-sections -fdata-sections -fno-builtin -fshort-enums +export CFLAGS_DBG = -O0 -g2 +export CFLAGS_OPT = -Os -g2 + +export CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_OPT) +#$(CFLAGS_DBG) + +ifeq ($(USE_HARD_FLOAT),1) + export CFLAGS += -mhard-float +else + export CFLAGS += -msoft-float #hard-float is the default so we must set soft-float + export LINKFLAGS += -msoft-float +endif + +ifeq ($(USE_DSP),1) + export CFLAGS += -mdsp +endif + +export ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_OPT) #$(CFLAGS_DBG) + +export LINKFLAGS += $(MIPS_HAL_LDFLAGS) -mabi=$(ABI) +export LINKFLAGS += -Tuhi32.ld +export LINKFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG) $(CFLAGS_OPT) +export LINKFLAGS += -Wl,--gc-sections + +# This CPU implementation is using the new core/CPU interface: +export CFLAGS += -DCOREIF_NG=1 + +# use newlib as libc, Actually use toolchains newlib. +#export USEMODULE += newlib + +export USEMODULE += periph diff --git a/cpu/mips32r2_common/cpu.c b/cpu/mips32r2_common/cpu.c new file mode 100644 index 0000000000..9c12b988fb --- /dev/null +++ b/cpu/mips32r2_common/cpu.c @@ -0,0 +1,77 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include +#include +#include +#include + +#include "periph/uart.h" +#include "periph/timer.h" +#include "arch/panic_arch.h" +#include "kernel_init.h" +#include "cpu.h" +#include "board.h" + +void mips_start(void); + +extern void _fini(void); +extern void atexit(void (*)(void)); +extern void _init(void); +extern void exit(int); + +#ifdef FLASH_XIP +extern char _rom_data_copy __attribute__((section("data"))); +extern char _fdata __attribute__((section("data"))); +extern char _edata __attribute__((section("data"))); +#endif + +/* + * Note the mips toolchain crt expects to jump to main but RIOT wants the user + * code to start at main for some perverse reason, but thankfully the crt + * does provide this hook function which gets called fairly close to the jump + * to main, thus if we finish off the job of the crt here and never returns + * we can support this madness. + */ +void software_init_hook(void) +{ +#ifdef FLASH_XIP + /* copy initialised data from its LMA to VMA */ + memcpy(&_fdata, &_rom_data_copy, (int)&_edata - (int)&_fdata); +#endif + + atexit(_fini); + _init(); + + mips_start(); + + exit(-1); +} + + +void mips_start(void) +{ + board_init(); + +#if MODULE_NEWLIB +#error "This Port is designed to work with the (newlib) C library provided with the mips sdk toolchain" +#endif + + /* kernel_init */ + kernel_init(); +} + +void panic_arch(void) +{ + printf("\nPANIC!\n"); + assert(0); + while (1) { + } +} diff --git a/cpu/mips32r2_common/include/cpu.h b/cpu/mips32r2_common/include/cpu.h new file mode 100644 index 0000000000..cb1d1c633c --- /dev/null +++ b/cpu/mips32r2_common/include/cpu.h @@ -0,0 +1,48 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cpu_mips32r2_commom MIPS32R2 Common + * @ingroup cpu + * @brief Common implementations and headers for mips32r2 compliant devices + * @{ + * + * @file + * @brief Common implementations and headers for mips32r2 compliant devices + * + * @author Neil Jones + */ + +#ifndef CPU_H_ +#define CPU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "irq.h" + +/** + * @brief Print the last instruction's address + * + * @todo: Not supported + */ +static inline void cpu_print_last_instruction(void) +{ + /* This function must exist else RIOT won't compile */ +} + +#ifdef __cplusplus +} +#endif + +#endif +/** @} */ diff --git a/cpu/mips32r2_common/include/cpu_conf.h b/cpu/mips32r2_common/include/cpu_conf.h new file mode 100644 index 0000000000..46afd1759c --- /dev/null +++ b/cpu/mips32r2_common/include/cpu_conf.h @@ -0,0 +1,70 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#ifndef _CPU_CONF_H_ +#define _CPU_CONF_H_ + +/** + * @defgroup cpu_mips32r2_commom MIPS32R2 Common + * @ingroup cpu + * @{ + * + * @file + * @brief Common CPU definitions for mip32r2 compatable devices. + * + * @author Neil Jones + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configuration of default stack sizes + * + * printf takes a pretty tortured route through the C lib + * then via UHI syscall exception to end up at the UART + * driver. + * + * When debugging timer code we get printfs on the idle threads + * stack which can easily blow its limits. + * + * Note code must be compiled at -Os with these values, using -O0 + * you'll overflow these stacks. + * + * NO ISR stack is in use yet, interrupt use the current running stack + * hence the big-ish default stack size. + * @{ + */ + +#ifndef THREAD_EXTRA_STACKSIZE_PRINTF +#define THREAD_EXTRA_STACKSIZE_PRINTF (1024) +#endif + +#ifndef THREAD_STACKSIZE_DEFAULT +#define THREAD_STACKSIZE_DEFAULT (2048) +#endif + +#ifndef THREAD_STACKSIZE_IDLE +#ifdef NDEBUG +#define THREAD_STACKSIZE_IDLE (512) +#else +#define THREAD_STACKSIZE_IDLE (512 + THREAD_EXTRA_STACKSIZE_PRINTF) +#endif +#endif + +#define ISR_STACKSIZE (0) +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif +/** @} */ diff --git a/cpu/mips32r2_common/include/periph_cpu.h b/cpu/mips32r2_common/include/periph_cpu.h new file mode 100644 index 0000000000..5b42c50930 --- /dev/null +++ b/cpu/mips32r2_common/include/periph_cpu.h @@ -0,0 +1,25 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/* This file must exist to get timer code to build */ + +/* No peripherals I/O via JTAG or Bootloader using UHI */ + +/* + * Note mips32r2_common can be selected in its own right as a CPU + * for testing on PFGA systems (like BOARD=mips-malta) with limited + * or no peripherals + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/cpu/mips32r2_common/irq_arch.c b/cpu/mips32r2_common/irq_arch.c new file mode 100644 index 0000000000..e9b0c70c65 --- /dev/null +++ b/cpu/mips32r2_common/irq_arch.c @@ -0,0 +1,42 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include "arch/irq_arch.h" + + +unsigned int irq_arch_enable(void) +{ + unsigned int status; + + __asm__ volatile ("ei %0" : "=r" (status)); + return status; +} + +unsigned int irq_arch_disable(void) +{ + unsigned int status; + + __asm__ volatile ("di %0" : "=r" (status)); + return status; +} + +void irq_arch_restore(unsigned int state) +{ + if (state & SR_IE) { + mips32_bs_c0(C0_STATUS, SR_IE); + } + else { + mips32_bc_c0(C0_STATUS, SR_IE); + } +} + +int irq_arch_in(void) +{ + return (mips32_get_c0(C0_STATUS) & SR_EXL) != 0; +} diff --git a/cpu/mips32r2_common/mips_dsp.S b/cpu/mips32r2_common/mips_dsp.S new file mode 100644 index 0000000000..2b127808ab --- /dev/null +++ b/cpu/mips32r2_common/mips_dsp.S @@ -0,0 +1,151 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * 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. +*/ + + +/* ************ PLEASE READ ME !!!! **************** + + This file is missing from $MIPS_ELF_ROOT/share/mips/hal + + Future toolchain versions will have this file included and this local copy will + be no longer needed. + + Note the above copyright/license is 3 Clause BSD and as such is compatible with LGPLv2.1 + as such we grant licensing this file under LGPLv2.1 (See the file LICENSE in the top level + directory for more details) as well. + + Thanks for reading. +*/ + +.set nomips16 +#include +#include +#include +#include +#include + +# +# FUNCTION: _dsp_save +# +# DESCRIPTION: save the DSP context. +# +# RETURNS: int +# +# 0: No context saved +# CTX_*: Type of conext stored +# +LEAF(_dsp_save) + PTR_S zero, LINKCTX_NEXT(a0) + move v0, zero + + # Test for DSP support + mfc0 t0, C0_CONFIG3 + ext t0, t0, CFG3_DSPP_SHIFT, 1 + beqz t0, 1f + + # Test for DSP enabled + mfc0 t0, C0_STATUS + ext t0, t0, SR_MX_SHIFT, 1 + beqz t0, 1f + + lui v0, %hi(LINKCTX_TYPE_DSP) + addiu v0, v0, %lo(LINKCTX_TYPE_DSP) + .set push + .set dsp + rddsp t1 + mfhi t2, $ac1 + mflo t3, $ac1 + mfhi t4, $ac2 + mflo t5, $ac2 + mfhi t6, $ac3 + mflo t7, $ac3 + .set pop + sw t1, DSPCTX_DSPC(a0) + sw t2, DSPCTX_HI1(a0) + sw t3, DSPCTX_LO1(a0) + sw t4, DSPCTX_HI2(a0) + sw t5, DSPCTX_LO2(a0) + sw t6, DSPCTX_HI3(a0) + sw t7, DSPCTX_LO3(a0) + REG_S v0, LINKCTX_ID(a0) +1: + jr ra +END(_dsp_save) + +# +# FUNCTION: _dsp_load +# +# DESCRIPTION: load the DSP context. +# +# RETURNS: int +# +# 0: Unrecognised context +# CTX_*: Type of context restored +# +LEAF(_dsp_load) + REG_L v0, LINKCTX_ID(a0) + lui v1, %hi(LINKCTX_TYPE_DSP) + addiu v1, v1, %lo(LINKCTX_TYPE_DSP) + bne v0,v1,1f + + # Test for DSP support + mfc0 t0, C0_CONFIG3 + ext t0, t0, CFG3_DSPP_SHIFT, 1 + beqz t0, 1f + + # Force on DSP + di t3 + ehb + or t3, t3, SR_MX + mtc0 t3, C0_STATUS + ehb + + lw t1, DSPCTX_DSPC(a0) + lw t2, DSPCTX_HI1(a0) + lw t3, DSPCTX_LO1(a0) + lw t4, DSPCTX_HI2(a0) + lw t5, DSPCTX_LO2(a0) + lw t6, DSPCTX_HI3(a0) + lw t7, DSPCTX_LO3(a0) + .set push + .set dsp + wrdsp t1 + mthi t2, $ac1 + mtlo t3, $ac1 + mthi t4, $ac2 + mtlo t5, $ac2 + mthi t6, $ac3 + mtlo t7, $ac3 + .set pop + jr ra +1: + # Don't recognise this context, fail + move v0, zero + jr ra +END(_dsp_load) diff --git a/cpu/mips32r2_common/mips_excpt_entry.S b/cpu/mips32r2_common/mips_excpt_entry.S new file mode 100644 index 0000000000..0ce1d17b96 --- /dev/null +++ b/cpu/mips32r2_common/mips_excpt_entry.S @@ -0,0 +1,288 @@ +/* + * Copyright 2014-2015, Imagination Technologies Limited and/or its + * affiliated group companies. + * 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. +*/ + + +/* ************ PLEASE READ ME !!!! **************** + + This file is a copy of the mips_excpt_entry.S from $MIPS_ELF_ROOT/share/mips/hal + (from the 2016.05-03 version) with a single modification, we add a global flag + '__exception_restore' so we can jump to the restore code sequence from C. + + Future toolchain versions will have this change included and this file will + be no longer needed. + + Note the above copyright/license is 3 Clause BSD and as such is compatible with LGPLv2.1 + as such we grant licensing this file under LGPLv2.1 (See the file LICENSE in the top level + directory for more details) as well. + + Thanks for reading. +*/ + + +# Keep each function in a separate named section +#define _FUNCTION_SECTIONS_ +.set nomips16 + +#include +#include +#include +#include + +# Context size, adjusted for ABI parameter area +#define ADJ (NARGSAVE * SZARG) +# Round up to 16-byte boundary (maximum stack alignment required for any +# supported ABI) +#define CTX_SIZEROUND ((CTX_SIZE + ALSZ) & ALMASK) +#define CTX_SIZEADJ (CTX_SIZEROUND + ADJ) + +#define e_ISR s1 +#define e_CR s3 +#define e_BADV s4 +#define e_SR s5 +#define e_EPC s6 +#define e_RA s7 + +# DESCRIPTION: Exception entry point. This is small because it must go at +# EBASE+0x180. It saves enough context to chain onwards to +# __exception_save. +# +LEAF(__exception_entry) + .set push + .set noat +.weak _mips_tlb_refill + _mips_tlb_refill = __exception_save +__tlb_refill_loop: + # Support an alternative entry point at the start of the exception + # vector. Since the exception vector is normally placed first + # in the link map this allows a user to start execution from the + # same address that an executable is loaded to. + LA k1, __first_boot + lw k1, 0(k1) + beqz k1, 1f + # The start code is responsible for clearing __first_boot prior + # to installing the exception handlers. + j _start +1: + LA k1, _mips_tlb_refill + beqz k1, __tlb_refill_loop + jr k1 + + .org 0x80 +.weak _mips_xtlb_refill + _mips_xtlb_refill = __exception_save +__xtlb_refill_loop: + LA k1, _mips_xtlb_refill + beqz k1, __xtlb_refill_loop + jr k1 + + .org 0x100 +.weak _mips_cache_error +__cache_error_loop: + LA k1, _mips_cache_error + beqz k1, __cache_error_loop + jr k1 + + .org 0x180 + # Free up k1, defering sp adjustment until later + REG_S k1, (-CTX_SIZEROUND + CTX_K1)(sp) + + # Use k1 to invoke __exception_save + LA k1, _mips_general_exception + jr k1 + .set pop +END(__exception_entry) + +# +# FUNCTION: __exception_save +# +# DESCRIPTION: Exception context save. Save the context, then fake up a call +# frame. +# +ANESTED(__exception_save, _mips_general_exception, CTX_SIZEADJ, zero) + .globl __exception_save; + .globl __exception_restore; + .set push + .set noat + + # k1 is already saved, so use it to save the users sp + move k1, sp + # Finally adjust sp + PTR_ADDU sp, sp, -CTX_SIZEADJ # This should be picked up by the backtracer + + # Save context + REG_S $1, CTX_REG(1) + ADJ(sp) + REG_S $2, CTX_REG(2) + ADJ(sp) + REG_S $3, CTX_REG(3) + ADJ(sp) + REG_S $4, CTX_REG(4) + ADJ(sp) + REG_S $5, CTX_REG(5) + ADJ(sp) + REG_S $6, CTX_REG(6) + ADJ(sp) + REG_S $7, CTX_REG(7) + ADJ(sp) + REG_S $8, CTX_REG(8) + ADJ(sp) + REG_S $9, CTX_REG(9) + ADJ(sp) + REG_S $10, CTX_REG(10) + ADJ(sp) + REG_S $11, CTX_REG(11) + ADJ(sp) + REG_S $12, CTX_REG(12) + ADJ(sp) + REG_S $13, CTX_REG(13) + ADJ(sp) + REG_S $14, CTX_REG(14) + ADJ(sp) + REG_S $15, CTX_REG(15) + ADJ(sp) + REG_S $16, CTX_REG(16) + ADJ(sp) + REG_S $17, CTX_REG(17) + ADJ(sp) + REG_S $18, CTX_REG(18) + ADJ(sp) + REG_S $19, CTX_REG(19) + ADJ(sp) + REG_S $20, CTX_REG(20) + ADJ(sp) + REG_S $21, CTX_REG(21) + ADJ(sp) + REG_S $22, CTX_REG(22) + ADJ(sp) + REG_S $23, CTX_REG(23) + ADJ(sp) + REG_S $24, CTX_REG(24) + ADJ(sp) + REG_S $25, CTX_REG(25) + ADJ(sp) + REG_S $26, CTX_REG(26) + ADJ(sp) + # k1/$27 has already been saved + REG_S $28, CTX_REG(28) + ADJ(sp) + REG_S k1, CTX_REG(29) + ADJ(sp) # Use saved sp from earlier + REG_S $30, CTX_REG(30) + ADJ(sp) + REG_S $31, CTX_REG(31) + ADJ(sp) + PTR_S $0, CTX_LINK + ADJ(sp) # Clear the link field + +#if (__mips_isa_rev < 6) + mfhi $9 + mflo $10 + REG_S $9, CTX_HI0 + ADJ(sp) + REG_S $10, CTX_LO0 + ADJ(sp) +#endif + + # Trick the backtracer into stepping back to the point where the exception + # occurred. + PTR_MFC0 ra, C0_EPC + mfc0 e_CR, C0_CR + REG_S ra, CTX_EPC + ADJ(sp) + + # Finish storing the rest of the CP0 registers + PTR_MFC0 $9, C0_BADVADDR + REG_S $9, CTX_BADVADDR + ADJ(sp) + sw e_CR, CTX_CAUSE + ADJ(sp) + + move $11, $0 + move $12, $0 + mfc0 $9, C0_CONFIG3 + ext $10, $9, CFG3_BP_SHIFT, 1 + beqz $10, 1f + mfc0 $11, C0_BADPINSTR +1: + ext $9, $9, CFG3_BI_SHIFT, 1 + beqz $9, 1f + mfc0 $12, C0_BADINSTR +1: + sw $11, CTX_BADPINSTR + ADJ(sp) + sw $12, CTX_BADINSTR + ADJ(sp) + + # Start computing the address of the context for a0 + move a0, sp + + # Clear EXL. Exceptions can now nest. + mfc0 e_SR, C0_SR + sw e_SR, CTX_STATUS + ADJ(sp) + lui $9, %hi(~SR_EXL) + addiu $9, $9, %lo(~SR_EXL) + and e_SR, e_SR, $9 + mtc0 e_SR, C0_SR + + # Manually set up the return address to restore the context below + LA ra, __exception_restore + # Extract the cause code + and a1, e_CR, CR_XMASK + + # Finish computing the address of the context for a0 + addiu a0, a0, ADJ + + # Shift exception number down into expected range + srl a1, a1, 2 + + # Call the handler, indirect through t9 albeit not for any specific + # reason + LA t9, _mips_handle_exception + jr t9 + +# Return point from handler +# Load context +# now a function on its own, note save code just falls through. + + +__exception_restore: + +#if (__mips_isa_rev < 6) + REG_L $9, CTX_HI0 + ADJ(sp) + REG_L $10, CTX_LO0 + ADJ(sp) + mthi $9 + mtlo $10 +#endif + + REG_L $1, CTX_REG(1) + ADJ(sp) + REG_L $2, CTX_REG(2) + ADJ(sp) + REG_L $3, CTX_REG(3) + ADJ(sp) + REG_L $4, CTX_REG(4) + ADJ(sp) + REG_L $5, CTX_REG(5) + ADJ(sp) + REG_L $6, CTX_REG(6) + ADJ(sp) + REG_L $7, CTX_REG(7) + ADJ(sp) + REG_L $8, CTX_REG(8) + ADJ(sp) + REG_L $9, CTX_REG(9) + ADJ(sp) + REG_L $10, CTX_REG(10) + ADJ(sp) + REG_L $11, CTX_REG(11) + ADJ(sp) + REG_L $12, CTX_REG(12) + ADJ(sp) + REG_L $13, CTX_REG(13) + ADJ(sp) + REG_L $14, CTX_REG(14) + ADJ(sp) + REG_L $15, CTX_REG(15) + ADJ(sp) + REG_L $16, CTX_REG(16) + ADJ(sp) + REG_L $17, CTX_REG(17) + ADJ(sp) + REG_L $18, CTX_REG(18) + ADJ(sp) + REG_L $19, CTX_REG(19) + ADJ(sp) + REG_L $20, CTX_REG(20) + ADJ(sp) + REG_L $21, CTX_REG(21) + ADJ(sp) + REG_L $22, CTX_REG(22) + ADJ(sp) + REG_L $23, CTX_REG(23) + ADJ(sp) + REG_L $24, CTX_REG(24) + ADJ(sp) + REG_L $25, CTX_REG(25) + ADJ(sp) + # $26/K0 and $27/K1 are restored with interrupts disabled + REG_L $28, CTX_REG(28) + ADJ(sp) + # $29/SP is restored last + REG_L $30, CTX_REG(30) + ADJ(sp) + REG_L $31, CTX_REG(31) + ADJ(sp) + di + lw k0, CTX_STATUS + ADJ(sp) + REG_L k1, CTX_EPC + ADJ(sp) + mtc0 k0, C0_SR + PTR_MTC0 k1, C0_EPC + ehb + REG_L k0, CTX_K0 + ADJ(sp) + REG_L k1, CTX_K1 + ADJ(sp) + REG_L sp, CTX_SP + ADJ(sp) + # Return from exception + eret + .set pop +END(__exception_save) diff --git a/cpu/mips32r2_common/periph/Makefile b/cpu/mips32r2_common/periph/Makefile new file mode 100644 index 0000000000..6d1887b640 --- /dev/null +++ b/cpu/mips32r2_common/periph/Makefile @@ -0,0 +1,3 @@ +MODULE = periph + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/mips32r2_common/periph/pm.c b/cpu/mips32r2_common/periph/pm.c new file mode 100644 index 0000000000..16d327e12a --- /dev/null +++ b/cpu/mips32r2_common/periph/pm.c @@ -0,0 +1,37 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_mips32r2_common + * @{ + * + * @file + * @brief common periph/pm functions + * + * @author Neil Jones + * + * @} + */ + +#include +#include "periph/pm.h" + +#ifndef FEATURES_PERIPH_PM +void pm_set_lowest(void) +{ + /* Dont wait if interrupts are not enabled - we would never return!*/ + if (mips32_get_c0(C0_STATUS) & SR_IE) { + __asm volatile ("wait"); + } +} +#endif + +void pm_off(void) +{ + /* No Generic Power off Mechanism */ +} diff --git a/cpu/mips32r2_common/periph/timer.c b/cpu/mips32r2_common/periph/timer.c new file mode 100644 index 0000000000..91af124931 --- /dev/null +++ b/cpu/mips32r2_common/periph/timer.c @@ -0,0 +1,217 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include "cpu_conf.h" +#include +#include "sched.h" +#include "thread.h" +#include "board.h" +#include "irq.h" +#include "timex.h" +#include "div.h" + +#include + +/* + * setting TIMER_ACCURACY_SHIFT lower will improve accuracy + * at the cost of more regular interrupts (hence less power efficient). + * */ +#define TIMER_ACCURACY_SHIFT (10) +#define TIMER_ACCURACY (1 << TIMER_ACCURACY_SHIFT) +#define CHANNELS (3) + +/* TICKS_PER_US must be set in the board file */ +#ifndef TICKS_PER_US +#error "Please set TICK_PER_US in your board file" +#endif + +/* + * The base MIPS count / compare timer is fixed frequency at core clock / 2 + * and is pretty basic This timer is currently only supported in Vectored + * Interrupt Mode (VI), EIC mode is not supported yet. + * + * RIOT's xtimer expects the timer to operate at 1MHZ or any 2^n multiple or + * factor of this, thus we maintain a software timer which counts at 1MHz. + * This is not particularly power efficient and may add latency too. + * + * If other SoC specific timers are available which are more flexible then + * it is advised to use them, this timer is a fallback version + * that should work on all MIPS implementations. + * + */ + +static timer_isr_ctx_t timer_isr_ctx; +volatile unsigned int counter; +volatile unsigned int compares[CHANNELS]; +static volatile int spurious_int; + +/* + * The mips toolchain C library does not implement gettimeofday() + * + * implement it here using the timer. + * + */ +int gettimeofday(struct timeval *__restrict __p, void *__restrict __tz) +{ + uint64_t now = counter * US_PER_MS; + __p->tv_sec = div_u64_by_1000000(now); + __p->tv_usec = now - (__p->tv_sec * US_PER_SEC); + + return 0; +} + +int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg) +{ + assert(dev == 0); + + (void)freq; /*Cannot adjust Frequency */ + + timer_isr_ctx.cb = cb; + timer_isr_ctx.arg = arg; + + /* Clear down soft counters */ + memset((void *)compares, 0, sizeof(compares)); + + counter = (1 << TIMER_ACCURACY_SHIFT); + + /* Set compare up */ + mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY); + + /* Start the timer if stopped */ + mips32_bc_c0(C0_CAUSE, CR_DC); + + /* Enable Timer Interrupts */ + mips32_bs_c0(C0_STATUS, SR_HINT5); + + + return 0; +} + +int timer_set(tim_t dev, int channel, unsigned int timeout) +{ + assert(dev == 0); + assert(channel < CHANNELS); + + timeout >>= TIMER_ACCURACY_SHIFT; + timeout <<= TIMER_ACCURACY_SHIFT; + + uint32_t status = irq_arch_disable(); + compares[channel] = counter + timeout; + irq_arch_restore(status); + + return channel; +} + +int timer_set_absolute(tim_t dev, int channel, unsigned int value) +{ + assert(dev == 0); + assert(channel < CHANNELS); + + value >>= TIMER_ACCURACY_SHIFT; + value <<= TIMER_ACCURACY_SHIFT; + + uint32_t status = irq_arch_disable(); + compares[channel] = value; + irq_arch_restore(status); + + return channel; +} + +int timer_clear(tim_t dev, int channel) +{ + assert(dev == 0); + assert(channel < CHANNELS); + + uint32_t status = irq_arch_disable(); + compares[channel] = 0; + irq_arch_restore(status); + + return channel; +} + +unsigned int timer_read(tim_t dev) +{ + assert(dev == 0); + + return counter; +} + +void timer_start(tim_t dev) +{ + mips32_bc_c0(C0_CAUSE, CR_DC); +} + +void timer_stop(tim_t dev) +{ + mips32_bs_c0(C0_CAUSE, CR_DC); +} + +void timer_irq_enable(tim_t dev) +{ + mips32_bs_c0(C0_STATUS, SR_HINT5); +} + +void timer_irq_disable(tim_t dev) +{ + mips32_bc_c0(C0_STATUS, SR_HINT5); +} + + +void __attribute__ ((interrupt("vector=hw5"))) _mips_isr_hw5(void) +{ + register int cr = mips_getcr(); + + if (cr & CR_TI) { + uint32_t status = irq_arch_disable(); + counter += TIMER_ACCURACY; + irq_arch_restore(status); + + if (counter == compares[0]) { + /* + * The Xtimer code expects the ISR to take some time + * but our counter is a fake software one, so bump it a + * bit to give the impression some time elapsed in the ISR. + * Without this the callback ( _shoot(timer) on xtimer_core.c ) + * never fires. + */ + counter += TIMER_ACCURACY; + timer_isr_ctx.cb(timer_isr_ctx.arg, 0); + + if (sched_context_switch_request) { + thread_yield(); + } + } + if (counter == compares[1]) { + timer_isr_ctx.cb(timer_isr_ctx.arg, 1); + + if (sched_context_switch_request) { + thread_yield(); + } + } + if (counter == compares[2]) { + timer_isr_ctx.cb(timer_isr_ctx.arg, 2); + + if (sched_context_switch_request) { + thread_yield(); + } + } + + mips_setcompare(mips_getcount() + TICKS_PER_US * TIMER_ACCURACY); + + } + else { + spurious_int++; + } +} diff --git a/cpu/mips32r2_common/thread_arch.c b/cpu/mips32r2_common/thread_arch.c new file mode 100644 index 0000000000..69b8fbb94b --- /dev/null +++ b/cpu/mips32r2_common/thread_arch.c @@ -0,0 +1,400 @@ +/* + * Copyright 2016, Imagination Technologies Limited and/or its + * affiliated group companies. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "cpu.h" +#include "irq.h" +#include "cpu_conf.h" +#include "periph_conf.h" /* for debug uart number */ +#include "periph/uart.h" +#include "malloc.h" + +#define STACK_END_PAINT (0xdeadc0de) +#define C0_STATUS_EXL (2) +#define PADDING (16) +#define MICROMIPS_ISA_MODE (1) +#define M32_SYSCALL (0xC) +#define M32_SYSCALL_MASK (0xfc00003f) + +/* + * note the major 16bits of a 32bit MicroMIPS opcode appear first in the + * instruction stream + */ +#define MM_SYSCALL (0x8B7C0000) +#define MM_SYSCALL_MASK (0xfffffc00) + + +#ifdef MIPS_HARD_FLOAT +/* pointer to the current and old fpu context for lazy context switching */ +static struct fp64ctx *currentfpctx; /* fpu context of current running task */ +static struct fp64ctx *oldfpctx; /* fpu context of last task that executed fpu */ +#endif + +/* + * Stack Layout, note struct gpctx is defined in + * $MIPS_ELF_ROOT/mips-mti-elf/include/mips/hal.h + * + * Top Of Stack + * --------------- + * | | + * | User stack | + * | | + * --------------- <--- gpctx->sp + * | | + * | gpctx | + * | | + * --------------- + * | 16 byte pad | + * --------------- <--- sched_active_thread->sp + */ + +char *thread_arch_stack_init(thread_task_func_t task_func, void *arg, + void *stack_start, int stack_size) +{ + /* make sure it is aligned to 8 bytes this is a requirement of the O32 ABI */ + uintptr_t *p = (uintptr_t *)(((long)(stack_start) + stack_size) & ~7); + uintptr_t *fp; + + /* paint */ + p--; + *p-- = STACK_END_PAINT; + + /* prepare stack for __exception_restore() */ + fp = p; + p -= sizeof(struct gpctx) / sizeof(unsigned int); + + struct gpctx *initial_ctx = (struct gpctx *)p; + initial_ctx->a[0] = (reg_t)arg; + initial_ctx->status = mips32_get_c0(C0_STATUS) | SR_IE; /* Enable interrupts */ + __asm volatile ("sw $gp, 0(%0)" : : "r" (&initial_ctx->gp)); + initial_ctx->epc = (reg_t)task_func; + initial_ctx->ra = (reg_t)sched_task_exit; + initial_ctx->sp = (reg_t)fp; + initial_ctx->link = (struct linkctx *)NULL; + +#ifdef MIPS_MICROMIPS + initial_ctx->epc |= MICROMIPS_ISA_MODE; + initial_ctx->ra |= MICROMIPS_ISA_MODE; +#endif + +#ifdef MIPS_HARD_FLOAT + /* + * Disable FPU so we get an exception on first use to allow + * Lazy FPU context save and restore + */ + initial_ctx->status &= ~SR_CU1; + initial_ctx->status |= SR_FR; /*use double width FPU */ +#endif + /* + * note the -4 (-16 bytes) as the toolchain exception handling code + * adjusts the sp for alignment + */ + p -= PADDING/sizeof(unsigned int); + + return (void *)p; +} + +void thread_arch_stack_print(void) +{ + uintptr_t *sp = (void *)sched_active_thread->sp; + + printf("Stack trace:\n"); + while (*sp != STACK_END_PAINT) { + printf(" 0x%p: 0x%08lx\n", sp, *sp); + sp++; + } +} + + +/* This function calculates the ISR_usage */ +int thread_arch_isr_stack_usage(void) +{ + /* TODO */ + return -1; +} + +void *thread_arch_isr_stack_pointer(void) +{ + /* TODO */ + return (void *)-1; +} + +void *thread_arch_isr_stack_start(void) +{ + /* TODO */ + return (void *)-1; +} + +extern void __exception_restore(void); +void thread_arch_start_threading(void) +{ + unsigned int status = mips32_get_c0(C0_STATUS); + + /* + * Set Exception level if we are not already running at it + * the EXL mode depends on the bootloader. + */ + + if ((status & C0_STATUS_EXL) == 0) { + mips32_set_c0(C0_STATUS, status | C0_STATUS_EXL); + } + + sched_run(); + + __asm volatile ("lw $sp, 0(%0)" : : "r" (&sched_active_thread->sp)); + + __exception_restore(); + + UNREACHABLE(); +} + +void thread_arch_yield(void) +{ + /* + * throw a syscall exception to get into exception level + * we context switch at exception level. + * + * Note syscall 1 is reserved for UHI see: + * http://wiki.prplfoundation.org/w/images/4/42/UHI_Reference_Manual.pdf + */ + __asm volatile ("syscall 2"); +} + +struct linkctx* exctx_find(reg_t id, struct gpctx *gp) +{ + struct linkctx **ctx = (struct linkctx **)&gp->link; + while (*ctx) { + if ((*ctx)->id == id) { + return *ctx; + } + ctx = &(*ctx)->next; + } + return NULL; +} + +/* unaligned access helper */ +static inline uint32_t __attribute__((optimize("-O3"))) +mem_rw(const void *vaddr) +{ + uint32_t v; + memcpy(&v, vaddr, sizeof(v)); + return v; +} + + +#ifdef MIPS_DSP +extern int _dsp_save(struct dspctx *ctx); +extern int _dsp_load(struct dspctx *ctx); +#endif +/* + * The nomips16 attribute should not really be needed, it works around a toolchain + * issue in 2016.05-03. + */ +void __attribute__((nomips16)) +_mips_handle_exception(struct gpctx *ctx, int exception) +{ + unsigned int syscall_num = 0; +#ifdef MIPS_DSP + struct dspctx dsp_ctx; /* intentionally allocated on current stack */ +#endif + + switch (exception) { + + case EXC_SYS: +#ifdef MIPS_MICROMIPS + /* note major 16bits of opcode is first in instruction stream */ + syscall_num = + mem_rw((const void *)(ctx->epc & ~MICROMIPS_ISA_MODE)) + & 0x3FF; +#else + syscall_num = (mem_rw((const void *)ctx->epc) >> 6) & 0xFFFF; +#endif + +#ifdef DEBUG_VIA_UART +#include + /* + * intercept UHI write syscalls (printf) which would normally + * get routed to debug probe or bootloader handler and output + * via a UART + */ + + if (syscall_num == __MIPS_UHI_SYSCALL_NUM) { + if (ctx->t2[1] == __MIPS_UHI_WRITE && + (ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDERR_FILENO)) { + uint32_t status = irq_arch_disable(); + uart_write(DEBUG_VIA_UART, (uint8_t *)ctx->a[1], ctx->a[2]); + ctx->v[0] = ctx->a[2]; + ctx->epc += 4; /* move PC past the syscall */ + irq_arch_restore(status); + return; + } + else if (ctx->t2[1] == __MIPS_UHI_FSTAT && + (ctx->a[0] == STDOUT_FILENO || ctx->a[0] == STDERR_FILENO)) { + /* + * Printf fstat's the stdout/stderr file so + * fill out a minimal struct stat. + */ + struct stat *sbuf = (struct stat *)ctx->a[1]; + memset(sbuf, 0, sizeof(struct stat)); + sbuf->st_mode = S_IRUSR | S_IWUSR | S_IWGRP; + sbuf->st_blksize = BUFSIZ; + /* return 0 */ + ctx->v[0] = 0; + ctx->epc += 4; /* move PC past the syscall */ + return; + } + } + else +#endif + if (syscall_num == 2) { + unsigned int return_instruction = 0; + struct gpctx *new_ctx; +#ifdef MIPS_DSP + struct dspctx *new_dspctx; +#endif + /* + * Syscall 1 is reserved for UHI. + */ + + /* + * save the stack pointer in the thread info + * note we want the saved value to include the + * saved off context and the 16 bytes padding. + * Note we cannot use the current sp value as + * the prologue of this function has adjusted it + */ + sched_active_thread->sp = (char *)(ctx->sp + - sizeof(struct gpctx) - PADDING); + +#ifdef MIPS_DSP + _dsp_save(&dsp_ctx); + _linkctx_append(ctx,&(dsp_ctx.link)); +#endif + +#ifdef MIPS_HARD_FLOAT + if(currentfpctx) { + _linkctx_append(ctx,&(currentfpctx->fp.link)); + } +#endif + + sched_run(); + + new_ctx = (struct gpctx *)((unsigned int)sched_active_thread->sp + PADDING); + +#ifdef MIPS_HARD_FLOAT + currentfpctx = (struct fp64ctx *)exctx_find(LINKCTX_TYPE_FP64, new_ctx); + if(!currentfpctx) { + /* check for half-width FPU ctx in-case hardware doesn't support double. */ + currentfpctx = (struct fp64ctx *)exctx_find(LINKCTX_TYPE_FP32, new_ctx); + } +#endif + +#ifdef MIPS_DSP + new_dspctx = (struct dspctx *)exctx_find(LINKCTX_TYPE_DSP, new_ctx); + if (new_dspctx) + _dsp_load(new_dspctx); +#endif + +#ifdef MIPS_MICROMIPS + return_instruction = + mem_rw((const void *)(new_ctx->epc & ~MICROMIPS_ISA_MODE)); + if ((return_instruction & MM_SYSCALL_MASK) == MM_SYSCALL) { /* syscall */ + new_ctx->epc += 4; /* move PC past the syscall */ + } +#else + return_instruction = mem_rw((const void *)new_ctx->epc); + if ((return_instruction & M32_SYSCALL_MASK) == M32_SYSCALL) { /* syscall */ + new_ctx->epc += 4; /* move PC past the syscall */ + } +#endif + + /* + * The toolchain Exception restore code just wholesale copies the + * status register from the context back to the register loosing + * any changes that may have occured, 'status' is really global state + * You dont enable interrupts on one thread and not another... + * So we just copy the current status value into the saved value + * so nothing changes on the restore + */ + + new_ctx->status = mips32_get_c0(C0_STATUS); + +#ifdef MIPS_HARD_FLOAT + /* + * Disable FPU so we get an exception on first use to allow + * Lazy FPU context save and restore + */ + new_ctx->status &= ~SR_CU1; +#endif + + __asm volatile ("lw $sp, 0(%0)" : : "r" (&sched_active_thread->sp)); + + /* + * Jump straight to the exception restore code + * if we return this functions prologue messes up + * the stack pointer + */ + __exception_restore(); + + UNREACHABLE(); + } + break; +#ifdef MIPS_HARD_FLOAT + case EXC_CPU: + { + int newly_allocd = false; + + mips_bissr(SR_CU1); + ctx->status |= SR_CU1; + + if (!currentfpctx) { + currentfpctx = malloc(sizeof(struct fp64ctx)); + assert(currentfpctx); + memset(currentfpctx,0,sizeof(struct fp64ctx)); + currentfpctx->fp.link.id = LINKCTX_TYPE_FP64; + newly_allocd = true; + } + + /* this means no one exec'd fpu since we last run */ + if (oldfpctx == currentfpctx) { + return; + } + + if (oldfpctx) { + _fpctx_save(&oldfpctx->fp); + } + + if (!newly_allocd) { + _fpctx_load(¤tfpctx->fp); + } + + /* + * next fpu exception must save our context as it's not necessarily + * the next context switch will cause fpu exception and it's very + * hard for any future task to determine which was the last one + * that performed fpu operations. so by saving this pointer now we + * give this knowledge to that future task + */ + oldfpctx = currentfpctx; + + return; + } +#endif + + /* default: */ + } + /* Pass all other exceptions through to the toolchain handler */ + __exception_handle(ctx, exception); +} diff --git a/examples/gnrc_border_router/Makefile b/examples/gnrc_border_router/Makefile index a2451aed3c..1c86908016 100644 --- a/examples/gnrc_border_router/Makefile +++ b/examples/gnrc_border_router/Makefile @@ -14,6 +14,8 @@ BOARD_INSUFFICIENT_MEMORY := airfy-beacon cc2650stk maple-mini msb-430 msb-430h nucleo-f030 nucleo-f070 microbit calliope-mini \ nucleo32-f042 nucleo32-f303 opencm9-04 +BOARD_BLACKLIST += mips-malta # No UART available. + # use ethos (ethernet over serial) for network communication and stdio over # UART, but not on native, as native has a tap interface towards the host. ifeq (,$(filter native,$(BOARD))) diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c index bfc61836d4..b30d951eb6 100644 --- a/sys/fmt/fmt.c +++ b/sys/fmt/fmt.c @@ -24,7 +24,7 @@ #include #include -#ifdef __WITH_AVRLIBC__ +#if defined(__WITH_AVRLIBC__) || defined(__mips__) #include /* for fwrite() */ #else /* work around broken sys/posix/unistd.h */ diff --git a/sys/od/od.c b/sys/od/od.c index c5cb933be0..36c851a1fd 100644 --- a/sys/od/od.c +++ b/sys/od/od.c @@ -93,7 +93,7 @@ static inline void _bytes_format(char *format, uint16_t flags) strncpy(format, " %024" PRIo64, sizeof(" %024" PRIo64)); break; -#if !defined(__MACH__) +#if !defined(__MACH__) && !defined(__mips__) case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%0%do", sizeof(short) * _OCTAL_BYTE_LENGTH); break; @@ -101,7 +101,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%0%dlo", sizeof(long) * _OCTAL_BYTE_LENGTH); break; -#else /* !defined(__MACH__) */ +#else /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %lu", sizeof(short) * _OCTAL_BYTE_LENGTH); break; @@ -109,7 +109,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_LONG: sprintf(format, " %lu", sizeof(long) * _OCTAL_BYTE_LENGTH); break; -#endif /* !defined(__MACH__) */ +#endif /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_1: strncpy(format, " %4d", sizeof(" %4d")); @@ -127,7 +127,7 @@ static inline void _bytes_format(char *format, uint16_t flags) strncpy(format, " %24" PRId64, sizeof(" %24" PRId64)); break; -#if !defined(__MACH__) +#if !defined(__MACH__) && !defined(__mips__) case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%%dd", sizeof(short) * _INT_BYTE_LENGTH); break; @@ -135,7 +135,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%%dld", sizeof(long) * _INT_BYTE_LENGTH); break; -#else /* !defined(__MACH__) */ +#else /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%%ld", sizeof(short) * _INT_BYTE_LENGTH); break; @@ -143,7 +143,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%%ld", sizeof(long) * _INT_BYTE_LENGTH); break; -#endif /* !defined(__MACH__) */ +#endif /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_1: strncpy(format, " %3u", sizeof(" %3u")); @@ -161,7 +161,7 @@ static inline void _bytes_format(char *format, uint16_t flags) strncpy(format, " %24" PRIu64, sizeof(" %24" PRIu64)); break; -#if !defined(__MACH__) +#if !defined(__MACH__) && !defined(__mips__) case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%%uu", (unsigned)sizeof(short) * _INT_BYTE_LENGTH); break; @@ -169,7 +169,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%%ulu", sizeof(long) * _INT_BYTE_LENGTH); break; -#else /* !defined(__MACH__) */ +#else /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%%lu", sizeof(short) * _INT_BYTE_LENGTH); break; @@ -177,7 +177,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%%lu", sizeof(long) * _INT_BYTE_LENGTH); break; -#endif /* !defined(__MACH__) */ +#endif /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_1: strncpy(format, " %02x", sizeof(" %02x")); @@ -195,7 +195,7 @@ static inline void _bytes_format(char *format, uint16_t flags) strncpy(format, " %016" PRIx64, sizeof(" %016" PRIx64)); break; -#if !defined(__MACH__) +#if !defined(__MACH__) && !defined(__mips__) case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%0%ux", (unsigned)sizeof(short) * _HEX_BYTE_LENGTH); break; @@ -203,7 +203,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%0%ulx", (unsigned)sizeof(long) * _HEX_BYTE_LENGTH); break; -#else /* !defined(__MACH__) */ +#else /* !defined(__MACH__) && !defined(__mips__) */ case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_SHORT: sprintf(format, " %%0%lx", sizeof(short) * _HEX_BYTE_LENGTH); break; @@ -211,7 +211,7 @@ static inline void _bytes_format(char *format, uint16_t flags) case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_LONG: sprintf(format, " %%0%lx", sizeof(long) * _HEX_BYTE_LENGTH); break; -#endif /* !defined(__MACH__) */ +#endif /* !defined(__MACH__) && !defined(__mips__) */ default: break; diff --git a/tests/leds/main.c b/tests/leds/main.c index 8882e02ca0..1405e12b10 100644 --- a/tests/leds/main.c +++ b/tests/leds/main.c @@ -19,6 +19,7 @@ */ #include +#include #include "board.h" #include "periph_conf.h" diff --git a/tests/slip/Makefile b/tests/slip/Makefile index 3b02cb7c70..7020f9481d 100644 --- a/tests/slip/Makefile +++ b/tests/slip/Makefile @@ -4,6 +4,8 @@ include ../Makefile.tests_common BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h nucleo-f334 stm32f0discovery weio \ nucleo-f030 nucleo32-f042 +BOARD_BLACKLIST += mips-malta + USEMODULE += auto_init_gnrc_netif USEMODULE += gnrc USEMODULE += gnrc_pktdump diff --git a/tests/xtimer_msg_receive_timeout/main.c b/tests/xtimer_msg_receive_timeout/main.c index 07725f0e69..c7794c3fe7 100644 --- a/tests/xtimer_msg_receive_timeout/main.c +++ b/tests/xtimer_msg_receive_timeout/main.c @@ -23,6 +23,7 @@ * * @} */ +#include #include "thread.h" #include "msg.h"