diff --git a/cpu/mips32r2_common/cpu.c b/cpu/mips32r2_common/cpu.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c12b988fb380436579208d7a80a24756bfae0ef
--- /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 <mips/m32c0.h>
+#include <mips/regdef.h>
+#include <mips/asm.h>
+#include <string.h>
+#include <assert.h>
+
+#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 0000000000000000000000000000000000000000..cb1d1c633c3af738031402ec7eb3ceafb9b91095
--- /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 <neil.jones@imgtec.com>
+ */
+
+#ifndef CPU_H_
+#define CPU_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#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 0000000000000000000000000000000000000000..46afd1759c7f9f4818a43de6c20ba5bab89f1fce
--- /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 <neil.jones@imgtec.com>
+ */
+
+#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 0000000000000000000000000000000000000000..5b42c50930a37bd05919102e662d7b94e79fbd9d
--- /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 0000000000000000000000000000000000000000..e9b0c70c659ba607043875f3602c313355f5615a
--- /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 <mips/m32c0.h>
+#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 0000000000000000000000000000000000000000..2b127808aba1cccd382df0bb401cb20e98d07f99
--- /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 <mips/asm.h>
+#include <mips/regdef.h>
+#include <mips/m32c0.h>
+#include <mips/hal.h>
+#include <mips/endian.h>
+
+#
+# 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 0000000000000000000000000000000000000000..0ce1d17b96cc7c07e580f64eb9af4dd48c5c3ae0
--- /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 <mips/asm.h>
+#include <mips/regdef.h>
+#include <mips/cpu.h>
+#include <mips/hal.h>
+
+# 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/pm.c b/cpu/mips32r2_common/periph/pm.c
new file mode 100644
index 0000000000000000000000000000000000000000..16d327e12a97f29b165e1340bd5664b0f317f443
--- /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 <neil.jones@imgtec.com>
+ *
+ * @}
+ */
+
+#include <mips/m32c0.h>
+#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 0000000000000000000000000000000000000000..91af124931283723f54cf87f2e2086e46a7db877
--- /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 <mips/cpu.h>
+#include <mips/m32c0.h>
+#include <mips/regdef.h>
+#include <mips/asm.h>
+#include <string.h>
+
+#include <periph/timer.h>
+#include "cpu_conf.h"
+#include <stdio.h>
+#include "sched.h"
+#include "thread.h"
+#include "board.h"
+#include "irq.h"
+#include "timex.h"
+#include "div.h"
+
+#include <sys/time.h>
+
+/*
+ * 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 0000000000000000000000000000000000000000..69b8fbb94bfbad566541e8a986860408822c5d26
--- /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 <mips/cpu.h>
+#include <mips/hal.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 <mips/uhi_syscalls.h>
+            /*
+             * 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(&currentfpctx->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);
+}