diff --git a/boards/common/esp8266/Makefile b/boards/common/esp8266/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..32556e8194f86acb624d47fd84313dfc700163ac
--- /dev/null
+++ b/boards/common/esp8266/Makefile
@@ -0,0 +1,3 @@
+MODULE = boards_common_esp8266
+
+include $(RIOTBASE)/Makefile.base
diff --git a/boards/common/esp8266/Makefile.dep b/boards/common/esp8266/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..63fcc8a2a67ce2bf819e12ec4d39dfdb6f0c1212
--- /dev/null
+++ b/boards/common/esp8266/Makefile.dep
@@ -0,0 +1,5 @@
+include $(RIOTCPU)/esp8266/Makefile.dep
+
+ifneq (,$(filter saul_default,$(USEMODULE)))
+  USEMODULE += saul_gpio
+endif
diff --git a/boards/common/esp8266/Makefile.features b/boards/common/esp8266/Makefile.features
new file mode 100644
index 0000000000000000000000000000000000000000..3bad7fb3441c2fd3cb6cdf2726de0555b60feaf3
--- /dev/null
+++ b/boards/common/esp8266/Makefile.features
@@ -0,0 +1,13 @@
+# MCU defined features that are provided independent on board definitions
+
+include $(RIOTCPU)/esp8266/Makefile.features
+
+# MCU defined peripheral features provided by all boards in alphabetical order
+
+FEATURES_PROVIDED += periph_adc
+FEATURES_PROVIDED += periph_gpio
+FEATURES_PROVIDED += periph_gpio_irq
+FEATURES_PROVIDED += periph_i2c
+FEATURES_PROVIDED += periph_pwm
+FEATURES_PROVIDED += periph_spi
+FEATURES_PROVIDED += periph_uart
diff --git a/boards/common/esp8266/Makefile.include b/boards/common/esp8266/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..5460a7fd323561fa48599b00c1e5d59570acb767
--- /dev/null
+++ b/boards/common/esp8266/Makefile.include
@@ -0,0 +1,11 @@
+# the cpu to build for
+export CPU ?= esp8266
+export CPU_MODEL ?= esp8266
+
+# configure the serial interface
+PORT_LINUX ?= /dev/ttyUSB0
+PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*)))
+include $(RIOTMAKE)/tools/serial.inc.mk
+
+# reset tool configuration
+export RESET = esptool.py --before default_reset run
diff --git a/boards/common/esp8266/board_common.c b/boards/common/esp8266/board_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7b25d16e23d2984a4442cb0bac4bc88d2c3f140
--- /dev/null
+++ b/boards/common/esp8266/board_common.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_common_esp8266 ESP8266 Common
+ * @ingroup     boards_common
+ * @brief       Common files for the esp8266 board.
+ * @{
+ *
+ * @file
+ * @brief       Definitions for all esp8266 board.
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#include "board_common.h"
+#include "log.h"
+#include "periph/gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void board_init(void)
+{
+    #ifdef LED0_PIN
+    gpio_init (LED0_PIN, GPIO_OUT);
+    LED0_OFF;
+    #endif
+    #ifdef LED1_PIN
+    gpio_init (LED1_PIN, GPIO_OUT);
+    LED1_OFF;
+    #endif
+    #ifdef LED2_PIN
+    gpio_init (LED2_PIN, GPIO_OUT);
+    LED2_OFF;
+    #endif
+}
+
+extern void pwm_print_config(void);
+extern void i2c_print_config(void);
+extern void spi_print_config(void);
+extern void uart_print_config(void);
+extern void timer_print_config(void);
+
+void board_print_config (void)
+{
+    LOG_INFO("\nBoard configuration:\n");
+
+    pwm_print_config();
+    i2c_print_config();
+    spi_print_config();
+    uart_print_config();
+    timer_print_config();
+
+    LOG_INFO("\tLED: pins=[ ");
+    #ifdef LED0_PIN
+    LOG_INFO("%d ", LED0_PIN);
+    #endif
+    #ifdef LED1_PIN
+    LOG_INFO("%d ", LED1_PIN);
+    #endif
+    #ifdef LED2_PIN
+    LOG_INFO("%d ", LED2_PIN);
+    #endif
+    LOG_INFO("]\n");
+
+    LOG_INFO("\n\n");
+}
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/** @} */
diff --git a/boards/common/esp8266/doc.txt b/boards/common/esp8266/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c93f01ee47437553e385120128479f23f11b89bc
--- /dev/null
+++ b/boards/common/esp8266/doc.txt
@@ -0,0 +1,21 @@
+/**
+ * @defgroup    boards_common_esp8266  ESP8266 Common
+ * @ingroup     boards_common
+ * @ingroup     boards_esp8266
+ * @brief       Definitions and configurations that are common for
+ *              all ESP8266 boards.
+ *
+ * For detailed information about the ESP8266, configuring and compiling RIOT
+ * for ESP8266 boards, please refer \ref esp8266_riot.
+ */
+
+/**
+ * @defgroup    boards_esp8266  ESP8266 Boards
+ * @ingroup     boards
+ * @brief       This group of boards contains the documentation
+ *              defined ESP8266 boards.
+ *
+ * @note        For detailed information about the ESP8266 SoC, the tool chain
+ *              as well as configuring and compiling RIOT for ESP8266 boards,
+ *              see \ref esp8266_riot.
+ */
diff --git a/boards/common/esp8266/include/board_common.h b/boards/common/esp8266/include/board_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f5c815c0b3d26b003234327e203f857f628d11c
--- /dev/null
+++ b/boards/common/esp8266/include/board_common.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 BOARD_COMMON_H
+#define BOARD_COMMON_H
+
+/**
+ * @ingroup     boards_common_esp8266
+ * @brief       Board definitions that are common for all ESP8266 boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#include <stdint.h>
+
+#include "cpu.h"
+#include "periph_conf.h"
+#include "periph_conf_common.h"
+#include "periph/gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    Common on-board LED control definitions
+ * @{
+ */
+#ifdef  LED0_PIN
+#define LED0_MASK   (BIT(LED0_PIN))
+#define LED0_TOGGLE (gpio_toggle(LED0_PIN))
+#define LED0_ON     (gpio_write(LED0_PIN, LED0_ACTIVE))
+#define LED0_OFF    (gpio_write(LED0_PIN, !LED0_ACTIVE))
+#endif
+
+#ifdef  LED1_PIN
+#define LED1_MASK   (BIT(LED1_PIN))
+#define LED1_TOGGLE (gpio_toggle(LED1_PIN))
+#define LED1_ON     (gpio_write(LED1_PIN, LED1_ACTIVE))
+#define LED1_OFF    (gpio_write(LED1_PIN, !LED1_ACTIVE))
+#endif
+
+#ifdef  LED2_PIN
+#define LED2_MASK   (BIT(LED2_PIN))
+#define LED2_TOGGLE (gpio_toggle(LED2_PIN))
+#define LED2_ON     (gpio_write(LED2_PIN, LED2_ACTIVE))
+#define LED2_OFF    (gpio_write(LED2_PIN, !LED2_ACTIVE))
+#endif
+/** @} */
+
+
+/**
+ * @name    STDIO configuration
+ * @{
+ */
+#ifndef STDIO_UART_BAUDRATE
+#define STDIO_UART_BAUDRATE (115200)    /**< Default baudrate of UART for stdio */
+#endif
+/** @} */
+
+
+#ifndef DOXYGEN
+/**
+ * @name    XTimer configuration
+ * @{
+ */
+#define XTIMER_OVERHEAD             (0U)
+
+#if defined(MODULE_ESP_SW_TIMER)
+#define XTIMER_BACKOFF              (100U)
+#define XTIMER_ISR_BACKOFF          (100U)
+#endif /* MODULE_ESP_SW_TIMER */
+
+/** @} */
+#endif /* DOXYGEN */
+
+
+#if defined(MODULE_MTD) || defined(DOXYGEN)
+/**
+ * @name    MTD device configuration
+ *
+ * Internal flash memory can be used as MTD device. For that purpose
+ * a system MTD device has to be defined.
+ * @{
+ */
+#include "mtd.h"
+
+/** Default MTD device definition */
+#define MTD_0 mtd0
+
+/** Pointer to the default MTD device structure */
+extern mtd_dev_t *mtd0;
+
+/** @} */
+#endif /* defined(MODULE_MTD) || defined(DOXYGEN) */
+
+
+#if defined(MODULE_SPIFFS) || defined(DOXYGEN)
+/**
+ * @name    SPIFFS configuration
+ *
+ * Configuration of the SPIFFS that can be used on the system MTD device.
+ * @{
+ */
+#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
+#define SPIFFS_READ_ONLY 0
+#define SPIFFS_SINGLETON 0
+#define SPIFFS_HAL_CALLBACK_EXTRA 1
+#define SPIFFS_CACHE 1
+/** @} */
+#endif /* defined(MODULE_SPIFFS) || defined(DOXYGEN) */
+
+
+/**
+ * @brief Initialize board specific hardware
+ *
+ * Since all features of ESP8266 boards are provided by the MCU, almost all
+ * initializations are done during the CPU initialization that is called from
+ * boot loader.
+ */
+extern void board_init(void);
+
+/**
+  * @brief Print the board configuration in a human readable format
+  */
+void board_print_config (void);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include definitions for optional off-board hardware modules */
+#include "board_modules.h"
+
+/** @} */
+
+#endif /* BOARD_COMMON_H */
diff --git a/boards/common/esp8266/include/board_modules.h b/boards/common/esp8266/include/board_modules.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fde8b1e8cccf2ae49dfcac0a54ff9f5a8a6e648
--- /dev/null
+++ b/boards/common/esp8266/include/board_modules.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 BOARD_MODULES_H
+#define BOARD_MODULES_H
+
+/**
+ * @ingroup     boards_common_esp8266
+ * @brief       Definitions for optional off-board hardware modules that can
+ *              be used with all ESP8266 boards.
+ *
+ * All ESP8266 boards can be used with different off-board hardware modules.
+ * This file contains the default configurations for those external hardware
+ * modules that have been tested with the ESP8266 and are preconfigured here.
+ * Most of these configurations can be overridden by application-specific
+ * configurations. The configuration for a hardware module is only used if the
+ * corresponding driver modules are used.
+ *
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#include <stdint.h>
+
+#include "cpu.h"
+#include "periph_conf.h"
+#include "periph_conf_common.h"
+#include "periph/gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(MODULE_ENC28J60) || defined(DOXYGEN)
+/**
+ * @name    ENC28J60 configuration
+ *
+ * Configuration for the ENC28J60 interface when module ```enc28j60``` is used.
+ *
+ * SPI_DEV(0) is always used for the the module. The only configurations that
+ * can be overridden by
+ * \ref esp8266_app_spec_conf "Application Specific Board Configuration"
+ * are the CS, INT and RESET signals.
+ *
+ * @note    The RESET signal can also be connected to the ESP8266 RST pin to
+ *          keep an additional GPIO free.
+ *
+ * @{
+ */
+#define ENC28J60_PARAM_SPI      SPI_DEV(0)  /**< SPI_DEV(0) is used (fixed) */
+
+#ifndef ENC28J60_PARAM_CS
+#define ENC28J60_PARAM_CS       GPIO4       /**< ENC28J60 CS signal (can be overriden) */
+#endif
+#ifndef ENC28J60_PARAM_INT
+#define ENC28J60_PARAM_INT      GPIO9       /**< ENC28J60 CS signal (can be overriden) */
+#endif
+#ifndef ENC28J60_PARAM_RESET
+#define ENC28J60_PARAM_RESET    GPIO10      /**< ENC28J60 RESET signal (can be overriden) */
+#endif
+/** @} */
+#endif /* defined(MODULE_ENC28J60) || defined(DOXYGEN) */
+
+#if defined(MODULE_MRF24J40) || defined(DOXYGEN)
+/**
+ * @name    MRF24J40 configuration
+ *
+ * Configuration for the MRF24J40 interface when module ```mrf24j40``` is used.
+ *
+ * SPI_DEV(0) is always used for the the module. The only configurations that
+ * can be overridden by
+ * \ref esp8266_app_spec_conf "Application Specific Board Configuration"
+ * are the CS, INT and RESET signals.
+ *
+ * @note    The RESET signal can also be connected to the ESP8266 RST pin to
+ *          keep an additional GPIO free.
+ * @{
+ */
+#define MRF24J40_PARAM_SPI      SPI_DEV(0)      /**< SPI_DEV(0) is used (fixed) */
+
+#ifndef MRF24J40_PARAM_SPI_CLK
+#define MRF24J40_PARAM_SPI_CLK  SPI_CLK_1MHZ    /**< SPI bus speed used (can be overriden) */
+#endif
+#ifndef MRF24J40_PARAM_CS
+#define MRF24J40_PARAM_CS       GPIO16          /**< MRF24J40 CS signal (can be overriden) */
+#endif
+#ifndef MRF24J40_PARAM_INT
+#define MRF24J40_PARAM_INT      GPIO0           /**< MRF24J40 CS signal (can be overriden) */
+#endif
+#ifndef MRF24J40_PARAM_RESET
+#define MRF24J40_PARAM_RESET    GPIO2           /**< MRF24J40 RESET signal (can be overriden) */
+#endif
+/** @} */
+#endif /* defined(MODULE_MRF24J40) || defined(DOXYGEN) */
+
+#if defined(MODULE_SDCARD_SPI) || defined(DOXYGEN)
+/**
+ * @name    SD-Card configuration
+ *
+ * Configuration of the SD-Card interface when module ```sdcard_spi``` is used.
+ *
+ * The SPI interface with the corresponding pins used for the SD-Card
+ * interface is fixed. SPI_DEV(0) is always used for the SD-Card. The only
+ * configuration that can be overridden by \ref esp8266_app_spec_conf
+ * "Application Specific Board Configuration" is the CS signal.
+ * If not defined, the default CS signal of SPI_DEV(0) is used.
+ * @{
+ */
+#define SDCARD_SPI_PARAM_SPI    SPI_DEV(0)      /**< SPI_DEV(0) is used (fixed) */
+#define SDCARD_SPI_PARAM_CLK    SPI0_SCK_GPIO   /**< SPI_DEV(0) SCK  is used (fixed) */
+#define SDCARD_SPI_PARAM_MOSI   SPI0_MOSI_GPIO  /**< SPI_DEV(0) MOSI is used (fixed) */
+#define SDCARD_SPI_PARAM_MISO   SPI0_MISO_GPIO  /**< SPI_DEV(0) MISO is used (fixed) */
+#define SDCARD_SPI_PARAM_POWER  GPIO_UNDEF      /**< power control is not used (fixed) */
+
+#ifndef SDCARD_SPI_PARAM_CS
+#define SDCARD_SPI_PARAM_CS     SPI0_CS0_GPIO   /**< SD-Card CS signal (can be overridden) */
+#endif
+/** @} */
+#endif /* defined(MODULE_SDCARD_SPI) || defined(DOXYGEN) */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/** @} */
+
+#endif /* BOARD_MODULES_H */
diff --git a/boards/common/esp8266/include/periph_conf_common.h b/boards/common/esp8266/include/periph_conf_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..96444e5753b412ace817f5f3a36e5714a0ec1318
--- /dev/null
+++ b/boards/common/esp8266/include/periph_conf_common.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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     boards_common_esp8266
+ * @brief       Configurations of the MCU periphery that are common for all
+ *              ESP8266 boards
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef PERIPH_CONF_COMMON_H
+#define PERIPH_CONF_COMMON_H
+
+/* include board.h and periph_cpu.h to make them visible in any case */
+#include "board.h"
+#include "periph_cpu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BIT
+#define BIT(X) (1<<(X))
+#endif
+
+/**
+ * @name    ADC configuration
+ *
+ * ESP8266 provides one ADC pin that is broken out on all boards.
+ * @{
+ */
+#define ADC_NUMOF   1   /**< number of ADC channels */
+/** @} */
+
+
+/**
+ * @name    PWM configuration
+ *
+ * The hardware implementation of ESP8266 PWM supports only frequencies as power of
+ * two. Therefore a software implementation of one PWM device PWM_DEV(0) with up to
+ * 8 PWM channels (PWM_CHANNEL_NUM_MAX) is used.
+ *
+ * @note   The minumum PWM period that can be realized is 10 us or 100.000 PWM
+ * clock cycles per second. Therefore, the product of frequency and resolution
+ * should not be greater than 100.000. Otherwise the frequency is scaled down
+ * automatically.
+ *
+ * @{
+ */
+
+#define PWM_NUMOF           (1)     /**< Number of PWM devices */
+
+/**
+ * @brief   Maximum number of channels per PWM device.
+ */
+#define PWM_CHANNEL_NUM_MAX (8)
+
+/**
+ * @brief   Definition of GPIOs that can be used as PWM channels
+ *          of device PWM_DEV(0).
+ *
+ * The following definition is just an example configuration. Declare up to
+ * \ref PWM_CHANNEL_NUM_MAX GPIOs as PWM channels. GPIOs with a duty cycle
+ * value of 0 can be used as normal GPIOs for other purposes. GPIOs in the
+ * list that are used for other purposes, e.g., I2C or SPI, are then not
+ * available as PWM channels.
+ */
+#ifndef PWM0_CHANNEL_GPIOS
+#define PWM0_CHANNEL_GPIOS { GPIO2, GPIO4, GPIO5 }
+#endif
+
+/** Alternative device definition */
+#define PWM0_DEV    PWM_DEV(0)
+/** @} */
+
+
+/**
+ * @name    SPI configuration
+ *
+ * ESP8266 provides two hardware SPI interfaces:
+ *
+ * _FSPI_ for flash memory and usually simply referred to as _SPI_<br>
+ * _HSPI_ for peripherals
+ *
+ * Even though _FSPI_ (or simply _SPI_) is a normal SPI interface, it is not
+ * possible to use it for peripherals. _HSPI_ is therefore the only usable
+ * SPI interface available for peripherals as RIOT's SPI_DEV(0).
+ *
+ * The pin configuration of the _HSPI_ interface SPI_DEV(0) is fixed. The
+ * only pin definition that can be overridden by an application-specific
+ * board configuration is the CS signal defined by SPI0_CS0_GPIO.
+ *
+ * Signal          | Pin
+ * ----------------|-------
+ * SPI_DEV(0).MISO | GPIO12
+ * SPI_DEV(0).MOSI | GPIO13
+ * SPI_DEV(0).SCK  | GPIO14
+ * SPI_DEV(0).CS   | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode)
+ * @{
+ */
+#if defined(MODULE_PERIPH_SPI) || defined(DOXYGEN)
+
+#define SPI_NUMOF   1                       /**< Number of SPI interfaces */
+#define SPI_DEV(x)  ((unsigned int)(x+1))   /**< SPI_DEV to SPI hardware mapping */
+
+#define SPI0_DEV         SPI_DEV(0) /**< HSPI / SPI_DEV(0) device */
+#define SPI0_MISO_GPIO   GPIO12     /**< HSPI / SPI_DEV(0) MISO pin */
+#define SPI0_MOSI_GPIO   GPIO13     /**< HSPI / SPI_DEV(0) MOSI pin */
+#define SPI0_SCK_GPIO    GPIO14     /**< HSPI / SPI_DEV(0) SCK pin */
+
+#ifndef SPI0_CS0_GPIO
+#define SPI0_CS0_GPIO    GPIO15  /**< HSPI / SPI_DEV(0) CS default pin, only used when cs
+                                      parameter in spi_acquire is GPIO_UNDEF */
+#endif
+#endif /* defined(MODULE_PERIPH_SPI) || defined(DOXYGEN) */
+/** @} */
+
+/**
+ * @name    Timer configuration
+ * @{
+ */
+#if defined(MODULE_ESP_SW_TIMER)
+
+/* software timer */
+#define TIMER_NUMOF         (1U)    /**< number of timer devices */
+#define TIMER_CHANNELS      (10U)   /**< number of channels per timer device */
+
+#else /* MODULE_ESP_SW_TIMER */
+
+/* hardware timer */
+#define TIMER_NUMOF         (1U)    /**< number of timer devices */
+#define TIMER_CHANNELS      (1U)    /**< number of channels per timer device */
+
+#endif /* MODULE_ESP_SW_TIMER */
+/** @} */
+
+
+/**
+ * @name   UART configuration
+ *
+ * All ESP8266 boards have exactly one UART device with fixed pin mapping.
+ * This UART device is used for flashing and as a console interface.
+ * Therefore, the number of UART devices is fixed and can not be overridden.
+ * Used pins are determined by the MCU implementation and are defined here
+ * only for documentation reasons.
+ *
+ * @{
+ */
+#define UART_NUMOF  1                   /**< Number of UART devices */
+#define UART0_TXD   GPIO1               /**< TxD pin of UART_DEV(0) */
+#define UART0_RXD   GPIO3               /**< RxD pin of UART_DEV(0) */
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* PERIPH_CONF_COMMON_H */
+/** @} */
diff --git a/boards/esp8266-esp-12x/Makefile b/boards/esp8266-esp-12x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..249af5843076285993696d5aaa52a008c957534a
--- /dev/null
+++ b/boards/esp8266-esp-12x/Makefile
@@ -0,0 +1,5 @@
+MODULE = board
+
+DIRS = $(RIOTBOARD)/common/esp8266
+
+include $(RIOTBASE)/Makefile.base
diff --git a/boards/esp8266-esp-12x/Makefile.dep b/boards/esp8266-esp-12x/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..c60e4b8da17c8f9826d7b8a34f7cfe56490b3f10
--- /dev/null
+++ b/boards/esp8266-esp-12x/Makefile.dep
@@ -0,0 +1 @@
+include $(RIOTBOARD)/common/esp8266/Makefile.dep
diff --git a/boards/esp8266-esp-12x/Makefile.features b/boards/esp8266-esp-12x/Makefile.features
new file mode 100644
index 0000000000000000000000000000000000000000..a2f432f8823043ee661136a379d5ee152c6c1900
--- /dev/null
+++ b/boards/esp8266-esp-12x/Makefile.features
@@ -0,0 +1,3 @@
+# Board provides all common peripheral features defined for all ESP8266 boards
+
+include $(RIOTBOARD)/common/esp8266/Makefile.features
diff --git a/boards/esp8266-esp-12x/Makefile.include b/boards/esp8266-esp-12x/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..fec74c6f689fb2a01512cb5f685d79b2c462c6da
--- /dev/null
+++ b/boards/esp8266-esp-12x/Makefile.include
@@ -0,0 +1,3 @@
+USEMODULE += boards_common_esp8266
+
+include $(RIOTBOARD)/common/esp8266/Makefile.include
diff --git a/boards/esp8266-esp-12x/doc.txt b/boards/esp8266-esp-12x/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..79d5c563abb5df8e102daacb52f82679bf74b3fd
--- /dev/null
+++ b/boards/esp8266-esp-12x/doc.txt
@@ -0,0 +1,114 @@
+/**
+
+@defgroup    boards_esp8266_esp-12x  ESP-12x based boards
+@ingroup     boards_esp8266
+@brief       Support for boards that use ESP-12x modules.
+
+## Overview
+
+This board definition covers not just a single board, but rather a large set of generic boards that either use one of the AI-Tinker ESP-12x AI-Thinker ESP8266 modules or are compatible with them. ESP-12x stands for different versions of the ESP-12 module: ESP-12, ESP-12E, ESP-12E and ESP-12S.
+
+\htmlonly<style>div.image img[src="https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/ESP-12F_Module.png"]{width:200px;}</style>\endhtmlonly
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/ESP-12F_Module.png" "ESP8266 ESP-12F module"<br>
+
+Common examples for this type of boards are the [WEMOS LOLIN D1 mini V2](#wemos_lolin_d1_mini), the [NodeMCU DEVKIT](#nodemcu_devkit_esp8266) and the [Adafruit Feather HUZZAH ESP8266](#adafruit_feather_huzzah_esp8266). All these boards are characterized by using any of the ESP-12x module and breaking out all GPIO pins.
+
+@note This board definition is the most generic one and might also be used for other ESP8266 and ESP8285 boards.
+
+## MCU
+
+Most features of the boards are provided by the ESP8266EX SoC.
+
+<center>
+MCU         | ESP8266EX
+------------|----------------------------
+Family      | Tensilica Xtensa LX106
+Vendor      | Espressif
+RAM         | 80 kByte
+Flash       | 1 ... 16 MByte
+Frequency   | 80 / 160 MHz
+FPU         | no
+Timers      | 1 x 32 bit
+ADCs        | 1 x 10 bit (1 channel)
+LEDs        | 1 x GPIO2
+I2Cs        | 2 (software implementation)
+SPIs        | 1
+UARTs       | 1 (console)
+WiFi        | built in
+Vcc         | 2.5 - 3.6 V
+Datasheet   | [Datasheet](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf)
+Technical Reference | [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf)
+</center>
+<br>
+
+## Flashing the Device
+
+Flashing RIOT is quite straight forward, just connect the board using the programming port to your host computer and type:
+```
+make flash BOARD=esp8266-esp-12x ...
+```
+For detailed information about ESP8266 as well as configuring and compiling RIOT for ESP8266 boards, see \ref esp8266_riot.
+
+## <a name="wemos_lolin_d1_mini"> WEMOS LOLIN D1 mini </a>
+
+
+[WEMOS LOLIN D1 mini](https://wiki.wemos.cc/products:retired:d1_mini_v2.2.0) is a very interesting board series as it offers a stackable ESP8266 platform. This board can be easily extended with a large number of compatible peripheral shields, e.g. a micro SD card shield, an IR controller shield, a battery shield, and various sensor and actuator shields, see [D1 mini shields](https://wiki.wemos.cc/start#d1_mini_shields) for more information. This makes it possible to create different hardware configurations without the need for a soldering iron or a breadboard.
+
+\htmlonly
+<style>div.image img[src="https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_D1_mini_Stack.png?inline=false"]{width:400px;}</style>
+\endhtmlonly
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_D1_mini_Stack.png?inline=false" "WEMOS LOLIN D1 mini stack example"<br>
+
+There is also a MRF24J40 shield that can be used to extend the board with an IEEE 802.15.4 radio module, the standard networking technology in RIOT.
+
+\htmlonly
+<style>div.image img[src="https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_MRF24J40_Shield.png?inline=false"]{width:280px;}</style>
+\endhtmlonly
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_MRF24J40_Shield.png?inline=false" "MRF24J40 shield for WEMOS LOLIN D1 mini"<br>
+
+There are several versions of WEMOS LOLIN D1 mini, which only differ in the size of the flash memory and the MCU version used. All versions have a microUSB port with flash / boot / reset logic that makes flashing much easier. Their peripherals are equal and work with the default ESP8266 ESP-12x board definition.
+
+For more information, see [D1 Boards] (https://wiki.wemos.cc/start#d1_boards).
+
+<center>
+Board        | MCU       | Flash    | Antenna | Remark
+-------------|-----------|----------|---------|--------
+D1 mini V2   | ESP8266EX |  4 MByte | PCB     | retired
+D1 mini V3   | ESP8266EX |  4 MByte | PCB     | |
+D1 mini Lite | ESP8285   |  1 MByte | PCB     | |
+D1 mini Pro  | ESP8266EX | 16 MByte | ceramic | |
+</center>
+<br>
+
+Following image shows the pinout of all WEMOS LOLIN D1 mini boards. It is compatible with the WEMOS LOLIN D32 Pro ESP32 board.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_D1_mini_pinout.png?inline=false" "WEMOS LOLIN D1 min pinout"<br>
+
+## <a name="nodemcu_devkit_esp8266"> NodeMCU DEVKIT </a>
+
+NodeMCU DEVKIT is an open-source hardware project hosted on [GitHub](ttps://github.com/nodemcu/nodemcu-devkit-v1.0). Therefore, there are a lot of clones available. The board was originally designed for NodeMCU firmware development.
+
+As the other boards described here, NodeMCU ESP12 is generic board that uses ESP-12E module and breaks out all available GPIO pins. It has a Micro-USB port including a flash/boot/reset logic which makes flashing much easier.
+
+\htmlonly
+<style>div.image img[src="https://raw.githubusercontent.com/nodemcu/nodemcu-devkit-v1.0/master/Documents/NodeMCU_DEVKIT_1.0.jpg"]{width:400px;}</style>
+\endhtmlonly
+@image html "https://raw.githubusercontent.com/nodemcu/nodemcu-devkit-v1.0/master/Documents/NodeMCU_DEVKIT_1.0.jpg" "NodeMCE DEVKIT V1.0"<br>
+
+Following image shows the pinout of NodeMCU DEVKIT boards.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/NodeMCU_pinout.png?inline=false" "NodeMCE DEVKIT V1.0 pinout".
+
+## <a name="adafruit_feather_huzzah_esp8266"> Adafruit Feather HUZZAH ESP8266 </a>
+
+Feather is the new series of development boards from Adafruit. [Adafruit Feather HUZZAH ESP8266](https://www.adafruit.com/product/2821) is a ESP8266 based development board with built in WiFi, USB and battery charging. As the other boards described here, Adafruit Feather HUZZAH ESP8266 is a generic board that uses an ESP-12x module and breaks out most of the available GPIO pins. It has one additional LED connected to GPIO0 and a Micro-USB port including a flash/boot/reset logic which makes flashing much easier.
+
+\htmlonly
+<style>div.image img[src="https://cdn-shop.adafruit.com/1200x900/2821-05.jpg"]{width:400px;}</style>
+\endhtmlonly
+@image html "https://cdn-shop.adafruit.com/1200x900/2821-05.jpg" "Adafruit Feather HUZZAH ESP8266"<br>
+
+Following image shows the pinout of Adafruit Feather HUZZAH ESP8266.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Adafruit_Huzzah_ESP8266_pinout.png?inline=false" "Adafruit Feather HUZZAH ESP8266 pinout"
+*/
diff --git a/boards/esp8266-esp-12x/include/arduino_board.h b/boards/esp8266-esp-12x/include/arduino_board.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3260f957687217ef6b3d465c71de2a71c53feee
--- /dev/null
+++ b/boards/esp8266-esp-12x/include/arduino_board.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C)  2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_esp-12x
+ * @{
+ *
+ * @file
+ * @brief       Board specific configuration for the Arduino API
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#ifndef ARDUINO_BOARD_H
+#define ARDUINO_BOARD_H
+
+#include "periph/gpio.h"
+#include "periph/adc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   The on-board LED is connected to pin 2 on this board
+ */
+#define ARDUINO_LED         (GPIO2)
+
+/**
+ * @brief   Look-up table for the Arduino's digital pins
+ */
+static const gpio_t arduino_pinmap[] = {
+    GPIO1,      /* ARDUINO_PIN_0 (RxD) */
+    GPIO3,      /* ARDUINO_PIN_1 (TxD) */
+    GPIO0,      /* ARDUINO_PIN_2 */
+    GPIO2,      /* ARDUINO_PIN_3 */
+    #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT)
+    GPIO9,      /* ARDUINO_PIN_4 */
+    GPIO10,     /* ARDUINO_PIN_5 */
+    #else
+    GPIO_UNDEF, /* ARDUINO_PIN_4 */
+    GPIO_UNDEF, /* ARDUINO_PIN_5 */
+    #endif
+    GPIO_UNDEF, /* ARDUINO_PIN_6 */
+    GPIO_UNDEF, /* ARDUINO_PIN_7 */
+    GPIO_UNDEF, /* ARDUINO_PIN_8 */
+    GPIO_UNDEF, /* ARDUINO_PIN_9 */
+    GPIO15,     /* ARDUINO_PIN_10 (CS0)  */
+    GPIO13,     /* ARDUINO_PIN_11 (MOSI) */
+    GPIO12,     /* ARDUINO_PIN_12 (MISO) */
+    GPIO14,     /* ARDUINO_PIN_13 (SCK)  */
+    GPIO_UNDEF, /* ARDUINO_PIN_A0 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A1 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A2 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A3 */
+    GPIO4,      /* ARDUINO_PIN_A4 (SDA) */
+    GPIO5,      /* ARDUINO_PIN_A5 (SCL) */
+};
+
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ARDUINO_BOARD_H */
+/** @} */
diff --git a/boards/esp8266-esp-12x/include/board.h b/boards/esp8266-esp-12x/include/board.h
new file mode 100644
index 0000000000000000000000000000000000000000..eafc4051830e63453b350b19429e7d171f59c9f8
--- /dev/null
+++ b/boards/esp8266-esp-12x/include/board.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_esp-12x  ESP-12x based boards
+ * @ingroup     boards_esp8266
+ */
+
+/**
+ * @ingroup     boards_esp8266_esp-12x
+ * @brief       Board specific definitions for ESP-12x based boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    On-board LED configuration and control definitions
+ * @{
+ */
+#define LED0_PIN    GPIO2   /**< GPIO2 is used as LED Pin */
+#define LED0_ACTIVE (0)     /**< LED is low active */
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include common board definitions as last step */
+#include "board_common.h"
+
+#endif /* BOARD_H */
+/** @} */
diff --git a/boards/esp8266-esp-12x/include/gpio_params.h b/boards/esp8266-esp-12x/include/gpio_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..1eede9359059f22c3c4dc7c0fc017054906d80ac
--- /dev/null
+++ b/boards/esp8266-esp-12x/include/gpio_params.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 GPIO_PARAMS_H
+#define GPIO_PARAMS_H
+
+/**
+ * @ingroup     boards_esp8266_esp-12x
+ * @brief       Board specific configuration of direct mapped GPIOs
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#include "board.h"
+#include "saul/periph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   LED configuration
+ */
+static const  saul_gpio_params_t saul_gpio_params[] =
+{
+    {
+        .name = "LED",
+        .pin = LED0_PIN,
+        .mode = GPIO_OUT,
+        .flags = (SAUL_GPIO_INVERTED | SAUL_GPIO_INIT_CLEAR)
+    }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPIO_PARAMS_H */
+/** @} */
diff --git a/boards/esp8266-esp-12x/include/periph_conf.h b/boards/esp8266-esp-12x/include/periph_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..da08d17e5cb3785a9a78ab4858e7f001d2d05504
--- /dev/null
+++ b/boards/esp8266-esp-12x/include/periph_conf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_esp-12x
+ * @brief       Board specific configuration of MCU periphery for ESP-12x based boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef PERIPH_CONF_H
+#define PERIPH_CONF_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name   I2C configuration
+ * @{
+ */
+#ifndef I2C_NUMOF
+#define I2C_NUMOF       (1)             /**< Number of I2C interfaces */
+#endif
+#ifndef I2C0_SPEED
+#define I2C0_SPEED      I2C_SPEED_FAST  /**< I2C bus speed of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SDA
+#define I2C0_SDA        GPIO4           /**< SDA signal of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SCL
+#define I2C0_SCL        GPIO5           /**< SCL signal of I2C_DEV(0) */
+#endif
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include common peripheral definitions as last step */
+#include "periph_conf_common.h"
+
+#endif /* PERIPH_CONF_H */
+/** @} */
diff --git a/boards/esp8266-olimex-mod/Makefile b/boards/esp8266-olimex-mod/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..249af5843076285993696d5aaa52a008c957534a
--- /dev/null
+++ b/boards/esp8266-olimex-mod/Makefile
@@ -0,0 +1,5 @@
+MODULE = board
+
+DIRS = $(RIOTBOARD)/common/esp8266
+
+include $(RIOTBASE)/Makefile.base
diff --git a/boards/esp8266-olimex-mod/Makefile.dep b/boards/esp8266-olimex-mod/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..c60e4b8da17c8f9826d7b8a34f7cfe56490b3f10
--- /dev/null
+++ b/boards/esp8266-olimex-mod/Makefile.dep
@@ -0,0 +1 @@
+include $(RIOTBOARD)/common/esp8266/Makefile.dep
diff --git a/boards/esp8266-olimex-mod/Makefile.features b/boards/esp8266-olimex-mod/Makefile.features
new file mode 100644
index 0000000000000000000000000000000000000000..a2f432f8823043ee661136a379d5ee152c6c1900
--- /dev/null
+++ b/boards/esp8266-olimex-mod/Makefile.features
@@ -0,0 +1,3 @@
+# Board provides all common peripheral features defined for all ESP8266 boards
+
+include $(RIOTBOARD)/common/esp8266/Makefile.features
diff --git a/boards/esp8266-olimex-mod/Makefile.include b/boards/esp8266-olimex-mod/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..fec74c6f689fb2a01512cb5f685d79b2c462c6da
--- /dev/null
+++ b/boards/esp8266-olimex-mod/Makefile.include
@@ -0,0 +1,3 @@
+USEMODULE += boards_common_esp8266
+
+include $(RIOTBOARD)/common/esp8266/Makefile.include
diff --git a/boards/esp8266-olimex-mod/doc.txt b/boards/esp8266-olimex-mod/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ff370d1544f6d2fd497c917677d881fe3cae693c
--- /dev/null
+++ b/boards/esp8266-olimex-mod/doc.txt
@@ -0,0 +1,72 @@
+/**
+
+@defgroup    boards_esp8266_olimex-mod Olimex MOD-WIFI-ESP8266-DEV
+@ingroup     boards_esp8266
+@brief       Support for the Olimex MOD-WIFI-ESP8266-DEV board.
+
+## Overview
+
+Olimex MOD-WIFI-ESP8266-DEV is a tiny development board that is available as open-source hardware at [GitHub](https://github.com/OLIMEX/ESP8266/tree/master/HARDWARE/MOD-WIFI-ESP8266-DEV). It uses Espressif's ESP8266EX SoC and was originally designed to add WiFi capabilities to existing boards.
+
+Olimex MOD-WIFI-ESP8266-DEV belongs to the class of general purpose boards where all ESP8266EX pins are broken out for easier access. The board can either be soldered directly to a PCB or it can be used with a breadboard.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Olimex-MOD-DEV.png" "Olimex MOD-WIFI-ESP8266-DEV"<br>
+
+The board provides some pads for an UEXT interface. UEXT interface (introduced by Olimex) can be used to connect different peripherals to the board. This UEXT interface comprises the 3 serial interfaces UART, SPI and I2C. For more information about UEXT, see [UEXT](https://www.olimex.com/Products/Modules/UEXT).
+
+Together with the Olimex ESP8266-EVB evaluation board, a development platform for IoT devices is available.
+
+@image html "https://www.olimex.com/Products/IoT/ESP8266-EVB/images/ESP8266-EVB.jpg" "Olimex ESP8266-EVB"
+
+## Hardware
+
+### MCU
+
+Most features of the board are provided by the ESP8266EX SoC.
+<center>
+MCU         | ESP8266EX
+------------|----------------------------
+Family      | Tensilica Xtensa LX106
+Vendor      | Espressif
+RAM         | 80 kByte
+Flash       | 2 MByte
+Frequency   | 80 / 160 MHz
+FPU         | no
+Timers      | 1 x 32 bit
+ADCs        | 1 x 10 bit (1 channel)
+LEDs        | 1 x GPIO1
+I2Cs        | 2 (software implementation)
+SPIs        | 1
+UARTs       | 1 (console)
+WiFi        | built in
+Vcc         | 2.5 - 3.6 V
+Datasheet   | [Datasheet](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf)
+Technical Reference | [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf)
+Board Schematic | [Board Schematic](https://github.com/OLIMEX/ESP8266/raw/master/HARDWARE/MOD-WIFI-ESP8266-DEV/MOD-WIFI-ESP8266-DEV_schematic.pdf)
+</center>
+
+@note For detailed information about ESP8266, see \ref esp8266_riot.
+
+### RIOT Pin Mapping
+
+Olimex MOD-WIFI-ESP8266-DEV has 22 pin holes that can be soldered to PCB or used with a breadboard. The following figure shows the mapping of these pin holes to RIOT pins.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Olimex-MOD-DEV_pins.png" "Olimex MOD-WIFI-ESP8266-DEV pin mapping"<br>
+
+Since GPIOs 6, 7, 8, and 11 are used for flash memory, they cannot be used for other purposes. Furthermore, when flash mode ```qout``` or ```qio``` is used for flash memory, GPIOs 9 and 10 are used for flash memory additionally and cannot be used for other purposes, see section Flash Modes in \ref esp8266_riot.
+
+## Flashing the Device
+
+To flash the RIOT image, the device must be connected to the host computer through an FTDI USB to Serial adapter/cable connected to the device's UART interface, GPIO1 (TxD) and GPIO3 (RxD) ,
+
+@note Please make sure the FTDI USB to Serial adapter/cable uses 3.3 V.
+
+Once the device is connected to the host computer, it must be booted into UART mode where the firmware can be downloaded via the UART interface. For this purpose, GPIO15 (MTD0) and GPIO0 must be pulled down and GPIO2 must be pulled up while the device is restarted using the RSTB pin. Since GPIO15 (MTDO) is pulled down and GPIO0 as well as GPIO2 are pulled up by solder bridges, only GPIO0 needs to be pulled down while the device is being reset with the RSTB pin.
+
+To flash the RIOT image just type:
+```
+make flash BOARD=esp8266-olimex-mod ...
+```
+
+For detailed information about ESP8266 as well as configuring and compiling RIOT for ESP8266 boards, see \ref esp8266_riot.
+*/
diff --git a/boards/esp8266-olimex-mod/include/arduino_board.h b/boards/esp8266-olimex-mod/include/arduino_board.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0470c1a45325615ad5b689642ba358b648035e2
--- /dev/null
+++ b/boards/esp8266-olimex-mod/include/arduino_board.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C)  2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_olimex-mod
+ * @brief       Board specific configuration for the Arduino API
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef ARDUINO_BOARD_H
+#define ARDUINO_BOARD_H
+
+#include "periph/gpio.h"
+#include "periph/adc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   The on-board LED is connected to pin 2 on this board
+ */
+#define ARDUINO_LED         (GPIO1)
+
+/**
+ * @brief   Look-up table for the Arduino's digital pins
+ */
+static const gpio_t arduino_pinmap[] = {
+    GPIO1,      /* ARDUINO_PIN_0 (RxD) */
+    GPIO3,      /* ARDUINO_PIN_1 (TxD) */
+    GPIO0,      /* ARDUINO_PIN_2 */
+    GPIO4,      /* ARDUINO_PIN_3 */
+    #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT)
+    GPIO9,      /* ARDUINO_PIN_4 */
+    GPIO10,     /* ARDUINO_PIN_5 */
+    #else
+    GPIO_UNDEF, /* ARDUINO_PIN_4 */
+    GPIO_UNDEF, /* ARDUINO_PIN_5 */
+    #endif
+    GPIO5,      /* ARDUINO_PIN_6 */
+    GPIO_UNDEF, /* ARDUINO_PIN_7 */
+    GPIO_UNDEF, /* ARDUINO_PIN_8 */
+    GPIO_UNDEF, /* ARDUINO_PIN_9 */
+    GPIO15,     /* ARDUINO_PIN_10 (CS0)  */
+    GPIO13,     /* ARDUINO_PIN_11 (MOSI) */
+    GPIO12,     /* ARDUINO_PIN_12 (MISO) */
+    GPIO14,     /* ARDUINO_PIN_13 (SCK)  */
+    GPIO_UNDEF, /* ARDUINO_PIN_A0 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A1 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A2 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A3 */
+    GPIO2,      /* ARDUINO_PIN_A4 (SDA) */
+    GPIO14,     /* ARDUINO_PIN_A5 (SCL) */
+};
+
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ARDUINO_BOARD_H */
+/** @} */
diff --git a/boards/esp8266-olimex-mod/include/board.h b/boards/esp8266-olimex-mod/include/board.h
new file mode 100644
index 0000000000000000000000000000000000000000..20c0e5352713d60445dba17d9a48c137e2181a8a
--- /dev/null
+++ b/boards/esp8266-olimex-mod/include/board.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_olimex-mod Olimex MOD-WIFI-ESP8266-DEV
+ * @ingroup     boards_esp8266
+ */
+
+/**
+ * @ingroup     boards_esp8266_olimex-mod
+ * @brief       Board specific definitions for
+ *              Olimex MOD-WIFI-ESP8266-DEV boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @name    On-board LED configuration and control definitions
+ * @{
+ */
+#define LED0_PIN    GPIO1   /**< GPIO1 is used as LED Pin */
+#define LED0_ACTIVE (0)     /**< LED is low active */
+
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include common board definitions as last step */
+#include "board_common.h"
+
+#endif /* BOARD_H */
+/** @} */
diff --git a/boards/esp8266-olimex-mod/include/gpio_params.h b/boards/esp8266-olimex-mod/include/gpio_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fd075b6f20ebe61f69b790225a6a0f3381d23a5
--- /dev/null
+++ b/boards/esp8266-olimex-mod/include/gpio_params.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 GPIO_PARAMS_H
+#define GPIO_PARAMS_H
+
+/**
+ * @ingroup     boards_esp8266_olimex-mod
+ * @brief       Board specific configuration of direct mapped GPIOs
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#include "board.h"
+#include "saul/periph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   LED configuration
+ */
+static const  saul_gpio_params_t saul_gpio_params[] =
+{
+    {
+        .name = "LED",
+        .pin = LED0_PIN,
+        .mode = GPIO_OUT,
+        .flags = (SAUL_GPIO_INVERTED | SAUL_GPIO_INIT_CLEAR)
+    }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPIO_PARAMS_H */
+/** @} */
diff --git a/boards/esp8266-olimex-mod/include/periph_conf.h b/boards/esp8266-olimex-mod/include/periph_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..428e14ef4f544cb29b0e6589514ff1099e9f3e7c
--- /dev/null
+++ b/boards/esp8266-olimex-mod/include/periph_conf.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_olimex-mod
+ * @brief       Board specific configuration of MCU periphery for
+ *              Olimex MOD-WIFI-ESP8266-DEV boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef PERIPH_CONF_H
+#define PERIPH_CONF_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @name   I2C configuration
+ * @{
+ */
+#ifndef I2C_NUMOF
+#define I2C_NUMOF       (1)             /**< Number of I2C interfaces */
+#endif
+#ifndef I2C0_SPEED
+#define I2C0_SPEED      I2C_SPEED_FAST  /**< I2C bus speed of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SDA
+#define I2C0_SDA        GPIO4           /**< SDA signal of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SCL
+#define I2C0_SCL        GPIO5           /**< SCL signal of I2C_DEV(0) */
+#endif
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include common peripheral definitions as last step */
+#include "periph_conf_common.h"
+
+#endif /* PERIPH_CONF_H */
+/** @} */
diff --git a/boards/esp8266-sparkfun-thing/Makefile b/boards/esp8266-sparkfun-thing/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..249af5843076285993696d5aaa52a008c957534a
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/Makefile
@@ -0,0 +1,5 @@
+MODULE = board
+
+DIRS = $(RIOTBOARD)/common/esp8266
+
+include $(RIOTBASE)/Makefile.base
diff --git a/boards/esp8266-sparkfun-thing/Makefile.dep b/boards/esp8266-sparkfun-thing/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..c60e4b8da17c8f9826d7b8a34f7cfe56490b3f10
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/Makefile.dep
@@ -0,0 +1 @@
+include $(RIOTBOARD)/common/esp8266/Makefile.dep
diff --git a/boards/esp8266-sparkfun-thing/Makefile.features b/boards/esp8266-sparkfun-thing/Makefile.features
new file mode 100644
index 0000000000000000000000000000000000000000..a2f432f8823043ee661136a379d5ee152c6c1900
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/Makefile.features
@@ -0,0 +1,3 @@
+# Board provides all common peripheral features defined for all ESP8266 boards
+
+include $(RIOTBOARD)/common/esp8266/Makefile.features
diff --git a/boards/esp8266-sparkfun-thing/Makefile.include b/boards/esp8266-sparkfun-thing/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..fec74c6f689fb2a01512cb5f685d79b2c462c6da
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/Makefile.include
@@ -0,0 +1,3 @@
+USEMODULE += boards_common_esp8266
+
+include $(RIOTBOARD)/common/esp8266/Makefile.include
diff --git a/boards/esp8266-sparkfun-thing/doc.txt b/boards/esp8266-sparkfun-thing/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..838bc468f28295317fb2dff3cc71861a3e2a2129
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/doc.txt
@@ -0,0 +1,90 @@
+/**
+
+@defgroup    boards_esp8266_sparkfun-thing SparkFun ESP8266 Thing
+@ingroup     boards_esp8266
+@brief       Support for the SparkFun ESP8266 Thing modules.
+
+## Overview
+
+The [SparkFun ESP8266 Thing](https://www.sparkfun.com/products/13231) and [SparkFun ESP8266 Thing DEV](https://www.sparkfun.com/products/13711) are low-cost and easy to use breakout and development boards for the ESP8266. Both SparkFun ESP8266 Thing boards are relatively simple boards. The pins are simply broken out to two parallel, breadboard-compatible rows.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Sparkfun_Thing_x.png?inline=false" "SparkFun ESP8266 Thing (left) / SparkFun ESP8266 Thing DEV (right)"
+
+## Hardware
+
+### MCU
+
+Most features of the board are provided by the ESP8266EX SoC.
+
+<center>
+
+MCU         | ESP8266EX
+------------|----------------------------
+Family      | Tensilica Xtensa LX106
+Vendor      | Espressif
+RAM         | 80 kByte
+Flash       | 512 kByte
+Frequency   | 80 / 160 MHz
+FPU         | no
+Timers      | 1 x 32 bit
+ADCs        | 1 x 10 bit (1 channel)
+LEDs        | 1 x GPIO1
+I2Cs        | 2 (software implementation)
+SPIs        | 1
+UARTs       | 1 (console)
+WiFi        | built in
+Vcc         | 2.5 - 3.6 V
+Datasheet   | [Datasheet](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf)
+Technical Reference | [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf)
+Board Schematic | [ESP8266 Thing](https://cdn.sparkfun.com/datasheets/Wireless/WiFi/SparkFun_ESP8266_Thing.pdf) <br> [ESP8266 Thing Dev](https://cdn.sparkfun.com/datasheets/Wireless/WiFi/ESP8266-Thing-Dev-v10.pdf)
+
+</center>
+
+### Board Versions
+
+Although the board definition works with both boards, it's important to know that they differ slightly in some features:
+
+<center>
+
+Feature                        | ESP8266 Thing | ESP8266 Thing Dev
+-------------------------------|---------------|------------------
+USB to Serial adapter on-board | no            | yes
+I2C pull-up resistors on-board | yes (jumpable)| no [1]
+Programming interface          | FTDI USB to Serial adapter | USB
+Reset/Flash/Boot logic         | FTDI          | USB
+Battery connector              | yes           | no (can be retrofitted)
+LiPo Charger on-board          | yes           | no
+LED (GPIO5)                    | high active   | low active [2]
+GPIO15 broken out              | no            | yes
+CHIP_EN broken out             | yes           | no
+
+</center>
+
+[1] Although the SparkFun ESP8266 Thing Dev has no on-board I2C pull-up resistors, the I2C interface can be used because the ESP8266 SoC has built-in pull-up resistors that are activated by the I2C peripheral driver.
+
+[2] The board configuration defines high-active LEDs. If the SparkFun ESP8266 Thing Dev is used with this board configuration, the LED outputs must be inverted by the application.
+
+### RIOT Pin Mapping
+
+The following figures show the mapping of these pin holes to RIOT pins.
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Sparkfun_Thing_pinout.png?inline=false" "SparkFun Thin Pinout"
+
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Sparkfun_Thing_Dev_pinout.png?inline=false" "SparkFun Thin Dev Pinout"
+
+Flash SPI pins including GPIO9 and GPIO10 are not broken out. The SparkFun Thing board has solder pads for these pins at the bottom layer.
+
+## Flashing the Device
+
+To flash the RIOT image, the device has to be connected to the host computer. Since the SparkFun Thing Dev board has an USB to Serial adapter on board, this can done directly using the Micro USB. SparkFun Thin board has to be connected to the host computer using the FTDI interface and a FTDI USB to Serial adapter/cable. For more information on how to program the SparkFun Thing board, please refer the [ESP8266 Thing Hookup Guide](https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/programming-the-thing).
+
+@note Please make sure the FTDI USB to Serial adapter/cable uses 3.3 V.
+
+Both boards have a reset/flash/boot logic on-board so that flashing is quite simple. To flash the RIOT image just type:
+```
+make flash BOARD=esp8266-sparkfun-thing ...
+```
+
+
+For detailed information about ESP8266 as well as configuring and compiling RIOT for ESP8266 boards, see \ref esp8266_riot.
+*/
diff --git a/boards/esp8266-sparkfun-thing/include/arduino_board.h b/boards/esp8266-sparkfun-thing/include/arduino_board.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9a7ff0ceaef256281281d7e592658d7be3e8ba9
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/include/arduino_board.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_sparkfun-thing
+ * @brief       Board specific configuration for the Arduino API
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef ARDUINO_BOARD_H
+#define ARDUINO_BOARD_H
+
+#include "periph/gpio.h"
+#include "periph/adc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   The on-board LED is connected to pin 2 on this board
+ */
+#define ARDUINO_LED         (GPIO5)
+
+/**
+ * @brief   Look-up table for the Arduino's digital pins
+ */
+static const gpio_t arduino_pinmap[] = {
+    GPIO1,      /* ARDUINO_PIN_0 (RxD) */
+    GPIO3,      /* ARDUINO_PIN_1 (TxD) */
+    GPIO0,      /* ARDUINO_PIN_2 */
+    GPIO4,      /* ARDUINO_PIN_3 */
+    #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT)
+    GPIO9,      /* ARDUINO_PIN_4 */
+    GPIO10,     /* ARDUINO_PIN_5 */
+    #else
+    GPIO_UNDEF, /* ARDUINO_PIN_4 */
+    GPIO_UNDEF, /* ARDUINO_PIN_5 */
+    #endif
+    GPIO5,      /* ARDUINO_PIN_6 */
+    GPIO_UNDEF, /* ARDUINO_PIN_7 */
+    GPIO_UNDEF, /* ARDUINO_PIN_8 */
+    GPIO_UNDEF, /* ARDUINO_PIN_9 */
+    GPIO15,     /* ARDUINO_PIN_10 (CS0)  */
+    GPIO13,     /* ARDUINO_PIN_11 (MOSI) */
+    GPIO12,     /* ARDUINO_PIN_12 (MISO) */
+    GPIO14,     /* ARDUINO_PIN_13 (SCK)  */
+    GPIO_UNDEF, /* ARDUINO_PIN_A0 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A1 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A2 */
+    GPIO_UNDEF, /* ARDUINO_PIN_A3 */
+    GPIO2,      /* ARDUINO_PIN_A4 (SDA) */
+    GPIO14,     /* ARDUINO_PIN_A5 (SCL) */
+};
+
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ARDUINO_BOARD_H */
+/** @} */
diff --git a/boards/esp8266-sparkfun-thing/include/board.h b/boards/esp8266-sparkfun-thing/include/board.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f80ced168a643ff130b48a9714b17ada8dc90b7
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/include/board.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sparkfun-thing SparkFun ESP8266 Thing
+ * @ingroup     boards_esp8266
+ */
+
+/**
+ * @ingroup     boards_esp8266_sparkfun-thing
+ * @brief       Board specific definitions for
+ *              SparkFun ESP8266 Thing boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    On-board LED configuration and control definitions
+ * @{
+ */
+#define LED0_PIN    GPIO5   /**< GPIO5 is used as LED Pin */
+#define LED0_ACTIVE (1)     /**< LED is high active */
+
+/** @} */
+
+/**
+ * @name    SPI configuration
+ * @{
+ */
+#if defined(MODULE_PERIPH_SPI) || defined(DOXYGEN)
+/**
+ * GPIO15 is not available on SparkFun Thing Dev. Therefore another GPIO is
+ * define as default CS signal for HSPI interface SPI_DEV(0).
+ */
+#ifndef SPI0_CS0_GPIO
+#define SPI0_CS0_GPIO    GPIO16  /**< HSPI / SPI_DEV(0) CS default pin, only used when cs
+                                      parameter in spi_acquire is GPIO_UNDEF */
+#endif
+#endif /* defined(MODULE_PERIPH_SPI) || defined(DOXYGEN) */
+/** @} */
+
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/* include common board definitions as last step */
+#include "board_common.h"
+
+#endif /* BOARD_H */
+/** @} */
diff --git a/boards/esp8266-sparkfun-thing/include/gpio_params.h b/boards/esp8266-sparkfun-thing/include/gpio_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..8acc25c81822544c6c9d54f5dcd40f9f8537459d
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/include/gpio_params.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 GPIO_PARAMS_H
+#define GPIO_PARAMS_H
+
+/**
+ * @ingroup     boards_esp8266_sparkfun-thing
+ * @brief       Board specific configuration of direct mapped GPIOs
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#include "board.h"
+#include "saul/periph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   LED configuration
+ */
+static const  saul_gpio_params_t saul_gpio_params[] =
+{
+    {
+        .name = "LED",
+        .pin = LED0_PIN,
+        .mode = GPIO_OUT,
+        .flags = SAUL_GPIO_INIT_CLEAR
+    }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPIO_PARAMS_H */
+/** @} */
diff --git a/boards/esp8266-sparkfun-thing/include/periph_conf.h b/boards/esp8266-sparkfun-thing/include/periph_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..07a8e8c4de33654f3d0339a6aa091100022cfd69
--- /dev/null
+++ b/boards/esp8266-sparkfun-thing/include/periph_conf.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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     boards_esp8266_sparkfun-thing
+ * @brief       Board specific configuration of MCU periphery for
+ *              SparkFun ESP8266 Thing boards.
+ * @file
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @{
+ */
+
+#ifndef PERIPH_CONF_H
+#define PERIPH_CONF_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @name   I2C configuration
+ * @{
+ */
+#ifndef I2C_NUMOF
+#define I2C_NUMOF       (1)             /**< Number of I2C interfaces */
+#endif
+#ifndef I2C0_SPEED
+#define I2C0_SPEED      I2C_SPEED_FAST  /**< I2C bus speed of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SDA
+#define I2C0_SDA        GPIO4           /**< SDA signal of I2C_DEV(0) */
+#endif
+#ifndef I2C0_SCL
+#define I2C0_SCL        GPIO5           /**< SCL signal of I2C_DEV(0) */
+#endif
+/** @} */
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/**
+ * @brief   SPI Flash chip size can not be determined by the chip and therefore
+ *          must be explicitly set to 512 kbytes
+ */
+#define SPI_FLASH_CHIP_SIZE  0x80000
+
+/* include common peripheral definitions as last step */
+#include "periph_conf_common.h"
+
+#endif /* PERIPH_CONF_H */
+/** @} */
diff --git a/cpu/esp8266/Makefile b/cpu/esp8266/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..63d422f20d2021664d29d50c74f1f7a10a438856
--- /dev/null
+++ b/cpu/esp8266/Makefile
@@ -0,0 +1,9 @@
+# Define the module that is built:
+MODULE = cpu
+
+# Add a list of subdirectories, that should also be built:
+DIRS += periph
+DIRS += sdk
+DIRS += vendor
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/Makefile.dep b/cpu/esp8266/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..8ad433be38b0a3d376b60837ce98526a3a9bc838
--- /dev/null
+++ b/cpu/esp8266/Makefile.dep
@@ -0,0 +1,47 @@
+# additional modules dependencies
+
+ifneq (, $(filter lua, $(USEPKG)))
+    USEMODULE += newlib_syscalls_default
+    USEMODULE += xtimer
+endif
+
+ifneq (, $(filter lwip%, $(USEMODULE)))
+    USEMODULE += newlib_syscalls_default
+endif
+
+ifneq (,$(filter ndn-riot,$(USEPKG)))
+    USEMODULE += crypto
+    USEMODULE += cipher_modes
+endif
+
+ifneq (, $(filter posix%, $(USEMODULE)))
+    USEMODULE += newlib_syscalls_default
+endif
+
+ifneq (, $(filter shell, $(USEMODULE)))
+    USEMODULE += newlib_syscalls_default
+    USEMODULE += xtimer
+endif
+
+ifneq (, $(filter xtimer, $(USEMODULE)))
+    USEMODULE += newlib_syscalls_default
+endif
+
+ifneq (, $(filter vfs, $(USEMODULE)))
+    USEMODULE += newlib_syscalls_default
+    USEMODULE += xtimer
+endif
+
+ifneq (, $(filter newlib_syscalls_default, $(USEMODULE)))
+    USEMODULE += stdio_uart
+endif
+
+# network interface dependencies
+ifneq (, $(filter netdev_default, $(USEMODULE)))
+    # if NETDEV_DEFAULT is empty, we use module mrf24j40 as default network device
+    ifndef NETDEV_DEFAULT
+        USEMODULE += mrf24j40
+    else
+        USEMODULE += $(NETDEV_DEFAULT)
+    endif
+endif
diff --git a/cpu/esp8266/Makefile.features b/cpu/esp8266/Makefile.features
new file mode 100644
index 0000000000000000000000000000000000000000..d4defe30be20fc66b925f9d3e3ad7bc0b4933243
--- /dev/null
+++ b/cpu/esp8266/Makefile.features
@@ -0,0 +1,6 @@
+# MCU defined features that are provided independent on board definitions
+
+FEATURES_PROVIDED += periph_cpuid
+FEATURES_PROVIDED += periph_hwrng
+FEATURES_PROVIDED += periph_pm
+FEATURES_PROVIDED += periph_timer
diff --git a/cpu/esp8266/Makefile.include b/cpu/esp8266/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..e86af4e3765cabce2ef7ae584a56be88221d9ed3
--- /dev/null
+++ b/cpu/esp8266/Makefile.include
@@ -0,0 +1,148 @@
+# check some environment variables first
+
+ifndef ESP8266_NEWLIB_DIR
+    $(info ESP8266_NEWLIB_DIR should be defined as /path/to/newlib directory)
+    $(info ESP8266_NEWLIB_DIR is set by default to /opt/esp/newlib-xtensa)
+    export ESP8266_NEWLIB_DIR=/opt/esp/newlib-xtensa
+endif
+
+ifndef ESP8266_SDK_DIR
+    $(info ESP8266_SDK_DIR should be defined as /path/to/sdk directory)
+    $(info ESP8266_SDK_DIR is set by default to /opt/esp/esp-open-sdk/sdk)
+    export ESP8266_SDK_DIR=/opt/esp/esp-open-sdk/sdk
+endif
+
+# Options to control the compilation
+
+ifeq ($(USE_SDK), 1)
+    USEMODULE += esp_sdk
+endif
+
+ifeq ($(ENABLE_GDB), 1)
+    USEMODULE += esp_gdb
+endif
+
+ifeq ($(ENABLE_GDBSTUB), 1)
+    USEMODULE += esp_gdbstub
+    USEMODULE += esp_gdb
+endif
+
+# regular Makefile
+
+export CPU ?= esp8266
+export TARGET_ARCH ?= xtensa-lx106-elf
+
+# ESP8266 pseudomodules
+PSEUDOMODULES += esp_gdb
+PSEUDOMODULES += esp_now
+PSEUDOMODULES += esp_sdk
+PSEUDOMODULES += esp_sdk_int_handling
+PSEUDOMODULES += esp_sw_timer
+PSEUDOMODULES += esp_spiffs
+
+ifneq (, $(filter pthread, $(USEMODULE)))
+    INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include
+endif
+
+INCLUDES += -I$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/include
+INCLUDES += -I$(RIOTBOARD)/common/$(CPU)/include
+INCLUDES += -I$(RIOTCPU)/$(CPU)
+INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor
+INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/espressif
+
+CFLAGS  += -DESP_OPEN_SDK
+CFLAGS  += -Wno-unused-parameter -Wformat=0
+CFLAGS  += -mlongcalls -mtext-section-literals -fdata-sections
+ASFLAGS += --longcalls --text-section-literals
+
+ifneq (, $(filter esp_sw_timer, $(USEMODULE)))
+    USEMODULE += esp_sdk
+endif
+
+ifneq (, $(filter esp_sdk, $(USEMODULE)))
+    INCLUDES += -I$(ESP8266_SDK_DIR)/include
+    CFLAGS   += -DUSE_US_TIMER
+endif
+
+ifneq (, $(filter esp_gdbstub, $(USEMODULE)))
+    GDBSTUB_DIR ?= $(RIOTCPU)/$(CPU)/vendor/esp-gdbstub
+    CFLAGS      += -DGDBSTUB_FREERTOS=0
+    INCLUDES    += -I$(GDBSTUB_DIR)
+endif
+
+ifneq (, $(filter esp_gdb, $(USEMODULE)))
+    CFLAGS_OPT = -fzero-initialized-in-bss -Og -ggdb -g3
+else
+    CFLAGS_OPT = -fzero-initialized-in-bss -O2
+endif
+
+CFLAGS += $(CFLAGS_OPT)
+
+ifneq (, $(filter esp_spiffs, $(USEMODULE)))
+    export SPIFFS_STD_OPTION = -std=c99
+    USEMODULE += spiffs
+    USEMODULE += vfs
+endif
+
+ifeq ($(QEMU), 1)
+    CFLAGS += -DQEMU
+endif
+
+ifeq ($(FLASH_MODE), qio)
+    CFLAGS += -DFLASH_MODE_QIO
+endif
+
+ifeq ($(FLASH_MODE), qout)
+    CFLAGS += -DFLASH_MODE_QOUT
+endif
+
+LINKFLAGS += -L$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/lib
+LINKFLAGS += -L$(ESP8266_SDK_DIR)/lib
+
+ifneq (, $(filter esp_sdk, $(USEMODULE)))
+    LINKFLAGS += -Wl,--start-group $(BINDIR)/sdk.a
+    ifneq (, $(filter esp_now, $(USEMODULE)))
+        LINKFLAGS += -lespnow
+    endif
+    LINKFLAGS += -lmain -lnet80211 -lcrypto -lwpa2 -lwpa -llwip -lpp -lphy -lc -lhal
+    LINKFLAGS += -Wl,--end-group
+    LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.sdk.app.ld
+else
+    LINKFLAGS += -Wl,--start-group -lphy -lhal -lc -Wl,--end-group
+    LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.no_sdk.app.ld
+endif
+
+LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/eagle.rom.addr.v6.ld
+LINKFLAGS += -nostdlib -lgcc -u ets_run -Wl,-gc-sections # -Wl,--print-gc-sections
+LINKFLAGS += -Wl,--warn-unresolved-symbols
+
+USEMODULE += esp
+USEMODULE += mtd
+USEMODULE += periph
+USEMODULE += periph_common
+USEMODULE += ps
+USEMODULE += random
+USEMODULE += sdk
+USEMODULE += xtensa
+
+# configure preflasher to convert .elf to .bin before flashing
+FLASH_SIZE = -fs 8m
+export PREFLASHER ?= esptool.py
+export PREFFLAGS  ?= elf2image $(FLASH_SIZE) $(ELFFILE)
+export FLASHDEPS  ?= preflash
+
+# flasher configuration
+ifeq ($(QEMU), 1)
+    export FLASHER = cat
+    export FFLAGS += $(ELFFILE)-0x00000.bin /dev/zero | head -c $$((0x10000)) | cat -
+    export FFLAGS += $(ELFFILE)-0x10000.bin /dev/zero | head -c $$((0xfc000)) | cat -
+    export FFLAGS += $(RIOTCPU)/$(CPU)/bin/esp_init_data_default.bin > $(ELFFILE).bin
+else
+    FLASH_MODE ?= dout
+    export PROGRAMMER_SPEED ?= 460800
+    export FLASHER = esptool.py
+    export FFLAGS += -p $(PORT) -b $(PROGRAMMER_SPEED) write_flash
+    export FFLAGS += -fm $(FLASH_MODE)
+    export FFLAGS += 0 $(ELFFILE)-0x00000.bin
+    export FFLAGS += 0x10000 $(ELFFILE)-0x10000.bin
+endif
diff --git a/cpu/esp8266/README.md b/cpu/esp8266/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..00fc49fd5ca4bb8470d562fe7ce79fd4bf83bcc2
--- /dev/null
+++ b/cpu/esp8266/README.md
@@ -0,0 +1,734 @@
+# <a name="esp8266_riot"> RIOT-OS on ESP8266 and ESP8285 boards </a>
+
+## <a name="esp8266_toc"> Table of Contents </a>
+
+1. [Overview](#esp8266_overview)
+2. [MCU ESP8266](#esp8266_mcu_esp8266)
+3. [Toolchain](#esp8266_toolchain)
+    1. [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain)
+    2. [Precompiled Toolchain](#esp8266_precompiled_toolchain)
+    3. [Manual Toolchain Installation](#esp8266_manual_toolchain_installation)
+4. [Flashing the Device](#esp8266_flashing_the_device)
+    1. [Toolchain Usage](#esp8266_toolchain_usage)
+    2. [Compile Options](#esp8266_compile_options)
+    3. [Flash Modes](#esp8266_flash_modes)
+5. [Peripherals](#esp8266_peripherals)
+    1. [GPIO pins](#esp8266_gpio_pins)
+    2. [ADC Channels](#esp8266_adc_channels)
+    3. [SPI Interfaces](#esp8266_spi_interfaces)
+    4. [I2C Interfaces](#esp8266_i2c_interfaces)
+    5. [PWM Channels](#esp8266_pwm_channels)
+    6. [Timers](#esp8266_timers)
+    7. [SPIFFS Device](#esp8266_spiffs_device)
+    8. [Other Peripherals](#esp8266_other_peripherals)
+6. [Preconfigured Devices](#esp8266_preconfigured_devices)
+    1. [Network Devices](#esp8266_network_devices)
+    2. [SD-Card Device](#esp8266_sd_card_device)
+7. [Application-Specific Configurations](#esp8266_application_specific_configurations)
+    1. [Application-Specific Board Configuration](#esp8266_application_specific_board_configuration)
+    2. [Application-Specific Driver Configuration](#esp8266_application_specific_driver_configuration)
+8. [SDK Task Handling](#esp8266_sdk_task_handling)
+9. [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb)
+
+# <a name="esp8266_overview"> Overview </a> &nbsp;&nbsp; [[TOC](#esp8266_toc)]
+
+There are two implementations that can be used:
+
+- the **SDK version** which is realized on top of an SDK (*esp-open-sdk* or *ESP8266_NONOS_SDK*) and
+- the **non-SDK version** which is realized without the SDK.
+
+The non-SDK version produces a much smaller code size than the SDK version and is more efficient in execution because it does not need to run additional SDK functions to keep the SDK system alive.
+
+The **non-SDK version** is probably the **best choice if you do not need the built-in WiFi module**, for example, when you plan to connect an IEEE 802.15.4 radio module to the MCU for communication.
+
+By **default**, the **non-SDK version** is compiled. To compile the SDK version, add ```USE_SDK=1``` to the make command line, e.g.,
+
+```
+make flash BOARD=esp8266-esp-12x -C tests/shell USE_SDK=1 ...
+```
+
+For more information about the make command variables, see section [Compile Options](#esp8266_compile_options).
+
+# <a name=esp8266_mcu_esp8266> MCU ESP8266 </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 is a low-cost, ultra-low-power, single-core SoCs with an integrated WiFi module from Espressif Systems. The processor core is based on the Tensilica Xtensa Diamond Standard 106Micro 32-bit Controller Processor Core, which Espressif calls L106. The key features of ESP8266 are:
+
+<center>
+
+MCU         | ESP8266EX
+------------|----------------------------
+Vendor      | Espressif
+Cores       | 1 x Tensilica Xtensa LX106
+FPU         | no
+RAM         | 80 kByte user-data RAM <br> 32 kByte instruction RAM <br> 32 kByte instruction cache <br/> 16 kByte EST system-data RAM
+Flash       | 512 kByte ... 16 MByte
+Frequency   | 80 MHz or 160 MHz
+Power Consumption | 70 mA in normal operating mode <br> 20 uA in deep sleep mode
+Timers      | 1 x 32 bit
+ADCs        | 1 x 10 bit (1 channel)
+GPIOs       | 16
+I2Cs        | 2 (software implementation)
+SPIs        | 2
+UARTs       | 1 (console) + 1 transmit-only
+WiFi        | IEEE 802.11 b/g/n built in
+Vcc         | 2.5 - 3.6 V
+Datasheet   | [Datasheet](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf)
+Technical Reference | [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf)
+
+</center><br>
+
+@note ESP8285 is simply an ESP8266 SoC with 1 MB built-in flash. Therefore, the documentation also applies to the SoC ESP8285, even if only the ESP8266 SoC is described below.
+
+# <a name="esp8266_toolchain"> Toolchain</a> &nbsp;[[TOC](#esp8266_toc)]
+
+To compile RIOT for The ESP8266 SoC, the following software components are required:
+
+- **esp-open-sdk** which includes the **Xtensa GCC** compiler toolchain, the hardware abstraction library **libhal** for Xtensa LX106, and the flash programmer tool <b>```esptool.py```</b>
+- **newlib-c** library for Xtensa (esp-open-rtos version)
+- **SDK (optional)**, either as part of <b>```esp-open-sdk```</b> or the <b>```ESP8266_NONOS_SDK```</b>
+
+You have the following options to install the Toolchain:
+
+- <b>```riotdocker```</b> image and <b>```esptool.py```</b>, see section [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain)
+- **precompiled toolchain** installation from GIT, see section [Precompiled Toolchain](#esp8266_toolchain_installation)
+- **manual installation**, see section [Manual Toolchain Installation](#esp8266_manual_toolchain_installation)
+
+## <a name="esp8266_riot_docker_toolchain"> RIOT Docker Toolchain (riotdocker) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The easiest use the toolchain is Docker.
+
+### <a name="esp8266_preparing_the_environment"> Preparing the Environment </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using RIOT Docker requires at least the following software:
+
+- <b>```Docker```</b> container virtualization software
+- RIOT Docker (<b>```riotdocker```</b>) image
+- flasher tool <b>```esptool.py```</b>
+
+For information about installing Docker on your host, refer to the appropriate manuals for your operating system. For example, the easiest way to install Docker on the Ubuntu/Debian system is:
+```
+sudo apt-get install docker.io
+```
+
+The ESP Flasher tool <b>```esptool.py```</b> is available at [GitHub](https://github.com/espressif/esptool). To install the tool, either Python 2.7 or Python 3.4 or later must be installed. The latest stable version of ```esptool.py``` can be installed with ```pip```:
+```
+pip install esptool
+```
+
+<b>```esptool.py```</b> depends on ```pySerial``` which can be installed either using ```pip```
+
+```
+pip install pyserial
+```
+or the package manager of your OS, for example on Debian/Ubuntu systems:
+```
+apt-get install pyserial
+```
+For more information on ```esptool.py```, please refer the [git repository](https://github.com/espressif/esptool)
+
+Please make sure that ```esptool.py``` is in your ```PATH``` variable.
+
+### <a name="esp8266_generating_docker_image"> Generating a riotdocker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+A ```riotdocker``` fork that only installs the ```RIOT-Xtensa-ESP8266-toolchain``` is available at [GitHub](https://github.com/gschorcht/riotdocker-Xtensa-ESP.git). After cloning this git repository, you can use branch ```esp8266_only``` to generate a Docker image with a size of "only" 990 MByte:
+
+```
+git clone https://github.com/gschorcht/riotdocker-Xtensa-ESP.git
+cd riotdocker-Xtensa-ESP
+git checkout esp8266_only
+docker build -t riotbuild .
+```
+A ```riotdocker``` version that contains the toolchains for all different RIOT platforms can be found at [GitHub](https://github.com/RIOT-OS/riotdocker). However, the Docker image generated from the this Docker file has a size of about 1.5 GByte.
+
+Once a Docker image has been created, it can be started with the following commands while in the RIOT root directory:
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riotbuild
+```
+@note RIOT's root directory ```/path/to/RIOT``` becomes visible as the home directory of the ```riotbuild``` user in the Docker image. That is, the output of compilations performed in RIOT Docker is also accessible on the host system.
+
+Please refer the [RIOT wiki](https://github.com/RIOT-OS/RIOT/wiki/Use-Docker-to-build-RIOT) on how to use the Docker image to compile RIOT OS.
+
+### <a name="esp8266_using_existing_docker_image"> Using an Existing riotdocker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Alternatively, an existing Docker image from Docker Hub can be used. You can either pull and start the [schorcht/riotbuild_esp8266](https://hub.docker.com/r/schorcht/riotbuild_esp8266) Docker image which only contains the ```RIOT-Xtensa-ESP8266-toolchain``` using
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild schorcht/riotbuild_esp8266
+```
+or the [riot/riotbuild](https://hub.docker.com/r/riot/riotbuild/) Docker image (size is about 1.5 GB) which contains the toolchains for all platforms using
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riot/riotbuild
+```
+### <a name="esp8266_flashing_using_docker"> Make Process with Docker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using Docker, the make process consists of the following two steps:
+
+1. **making** the RIOT binary **within a RIOT Docker image**
+2. **flashing** the RIOT binary using a flasher program **on the host system**
+
+Once the RIOT Docker image has been started from RIOT's root directory, a RIOT application can be compiled inside the Docker using the make command as usual, for example:
+
+```
+make BOARD=esp8266-esp-12x -C tests/shell ...
+```
+This will generate a RIOT binary in ELF format.
+
+@note You can't use the ```flash``` target inside the Docker image.
+
+The RIOT binary has to be flash outside docker on the host system. Since the Docker image was stared while in RIOT's root directory, the output of the compilations is also accessible on the host system. On the host system, the ```flash-only``` target can then be used to flash the binary.
+```
+make flash-only BOARD=esp8266-esp-12x -C tests/shell
+```
+
+
+## <a name="esp8266_precompiled_toolchain"> Precompiled Toolchain </a> &nbsp;[[TOC](#esp8266_toc)]
+
+You can get a precompiled version of the whole toolchain from the GIT repository [RIOT-Xtensa-ESP8266-toolchain](https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain). This repository contains the precompiled toolchain including all libraries that are necessary to compile RIOT-OS for ESP8266.
+
+@note To use the precompiled toolchain the following packages (Debian/Ubuntu) have to be installed:<br> ```cppcheck``` ```coccinelle``` ```curl``` ```doxygen``` ```git``` ```graphviz``` ```make``` ```pcregrep``` ```python``` ```python-serial``` ```python3``` ```python3-flake8``` ```unzip``` ```wget```
+
+To install the toolchain use the following commands:
+```
+cd /opt
+sudo git clone https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain.git esp
+```
+After the installation, all components of the toolchain are installed in directory ```/opt/esp```. Of course, you can use any other location for the installation.
+
+To use the toolchain, you have to add the path of the binaries to your ```PATH``` variable according to your toolchain location
+
+```
+export PATH=$PATH:/path/to/toolchain/esp-open-sdk/xtensa-lx106-elf/bin
+```
+where ```/path/to/toolchain/``` is the directory you selected for the installation of the toolchain. For the default installation in ```/opt/esp``` this would be:
+```
+export PATH=$PATH:/opt/esp/esp-open-sdk/xtensa-lx106-elf/bin
+```
+
+Furthermore, you have to set variables ```ESP8266_SDK_DIR``` and ```ESP8266_NEWLIB_DIR``` according to the location of the toolchain.
+```
+export ESP8266_SDK_DIR=/path/to/toolchain/esp-open-sdk/sdk
+export ESP8266_NEWLIB_DIR=/path/to/toolchain/newlib-xtensa
+```
+If you have used ```/opt/esp``` as installation directory, it is not necessary to set these variables since makefiles use them as default directories.
+
+## <a name="esp8266_manual_toolchain_installation"> Manual Toolchain Installation </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The most difficult way to install the toolchain is the manual installation of required components as described below.
+
+@note Manual toolchain installation requires that the following packages (Debian/Ubuntu) are installed: ```autoconf``` ```automake``` ```bash``` ```bison``` ```build-essential``` ```bzip2``` ```coccinelle``` ```cppcheck``` ```curl``` ```doxygen``` ```g++``` ```gperf``` ```gawk``` ```gcc``` ```git``` ```graphviz``` ```help2man``` ```flex``` ```libexpat-dev``` ```libtool``` ```libtool-bin``` ```make``` ```ncurses-dev``` ```pcregrep``` ```python``` ```python-dev``` ```python-serial``` ```python3``` ```python3-flake8``` ```sed``` ```texinfo``` ```unrar-free``` ```unzip wget```
+
+### <a name="esp8266_installation_of_esp_open_sdk"> Installation of esp-open-sdk </a> &nbsp;[[TOC](#esp8266_toc)]
+
+esp-open-sdk is directly installed inside its source directory. Therefore, change directly to the target directory of the toolchain to build it.
+
+```
+cd /path/to/esp
+git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
+cd esp-open-sdk
+export ESP_OPEN_SDK_DIR=$PWD
+```
+
+If you plan to use the SDK version of the RIOT port and to use the SDK as part of esp-open-sdk, simply build its standalone version.
+
+```
+make STANDALONE=y
+```
+
+If you only plan to use the non-SDK version of the RIOT port or if you want to use one of Espressif's original SDKs, it is enough to build the toolchain.
+
+```
+make toolchain esptool libhal STANDALONE=n
+```
+
+Once compilation has been finished, the toolchain is available in ```$PWD/xtensa-lx106-elf/bin```. To use it, set the ```PATH``` variable accordingly.
+
+```
+export PATH=$ESP_OPEN_SDK_DIR/xtensa-lx106-elf/bin:$PATH
+```
+
+If you have compiled the standalone version of esp-open-sdk and you plan to use this SDK version, set additionally the ```ESP8266_SDK_DIR``` variable.
+
+```
+export ESP8266_SDK_DIR=$ESP_OPEN_SDK_DIR/sdk
+```
+
+### <a name="esp8266_installation_of_newlib-c"> Installation of newlib-c </a> &nbsp;[[TOC](#esp8266_toc)]
+
+First, set the target directory for the installation.
+
+```
+export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa
+```
+
+Please take care, to use the newlib-c version that was modified for esp-open-rtos since it includes ```stdatomic.h```.
+
+```
+cd /my/source/dir
+git clone https://github.com/ourairquality/newlib.git
+```
+
+Once you have cloned the GIT repository, build and install it with following commands.
+```
+cd newlib
+./configure --prefix=$ESP8266_NEWLIB_DIR --with-newlib --enable-multilib --disable-newlib-io-c99-formats --enable-newlib-supplied-syscalls --enable-target-optspace --program-transform-name="s&^&xtensa-lx106-elf-&" --disable-option-checking --with-target-subdir=xtensa-lx106-elf --target=xtensa-lx106-elf --enable-newlib-nano-formatted-io --enable-newlib-reent-small
+make
+make install
+```
+
+### <a name="esp8266_installation_of_espressif_original_sdk"> Installation of Espressif original SDK (optional) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+If you plan to use the SDK version of the RIOT port and if you want to use one of Espressif's original SDKs, you have to install it.
+
+First, download the _ESP8266_NONOS_SDK_ version 2.1.0 from the [Espressif web site](https://github.com/espressif/ESP8266_NONOS_SDK/releases/tag/v2.1.0). Probably other version might also work. However, RIOT port is tested with version 2.1.0.
+
+Once you have downloaded it, you can install it with following commands.
+
+```
+cd /path/to/esp
+tar xvfz /downloads/ESP8266_NONOS_SDK-2.1.0.tar.gz
+```
+
+To use the installed SDK, set variable ```ESP8266_SDK_DIR``` accordingly.
+
+```
+export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0
+```
+
+# <a name="esp8266_flashing_the_device"> Flashing the Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+## <a name="esp8266_toolchain_usage"> Toolchain Usage </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Once you have installed all required components, you should have the following directories.
+
+```
+/path/to/esp/esp-open-sdk
+/path/to/esp/newlib-xtensa
+/path/to/esp/ESP8266_NONOS_SDK-2.1.0 (optional)
+```
+
+To use the toolchain and optionally the SDK, please check that your environment variables are set correctly to
+
+```
+export PATH=/path/to/esp/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
+export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa
+```
+and
+```
+export ESP8266_SDK_DIR=/path/to/esp/esp-open-sdk/sdk
+```
+or
+
+```
+export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0
+```
+
+## <a name="esp8266_compile_options"> Compile Options </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The compilation process can be controlled by a number of variables for the make command:
+
+<center>
+
+Option | Values | Default | Description
+-------|--------|---------|------------
+ENABLE_GDB | 0, 1 | 0 | Enable compilation with debug information for debugging with QEMU (```QEMU=1```), see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb)
+FLASH_MODE | dout, dio, qout, qio | dout | Set the flash mode, please take care with your module, see section [Flash Modes](#esp8266_flash_modes)
+NETDEV_DEFAULT | module name | mrf24j40 | Set the module that is used as default network device, see section [Network Devices](#esp8266_network_devices)
+PORT | /dev/ttyUSBx | /dev/ttyUSB0 | Set the USB port for flashing the firmware
+QEMU | 0, 1 | 0 | Generate an image for QEMU, see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb).
+USE_SDK | 0, 1 | 0 | Compile the SDK version (```USE_SDK=1```), see section [SDK Task Handling](#esp8266_sdk_task_handling)
+
+</center><br>
+
+Optional features of ESP8266 can be enabled by ```USEMODULE``` definitions in the makefile of the application. These are:
+
+<center>
+
+Module | Description
+-------|------------
+esp_spiffs | Enables the SPIFFS file system, see section [SPIFFS Device](#esp8266_spiffs_device)
+esp_sw_timer | Enables software timer implementation, implies the setting ```USE_SDK=1```, see section [Timers](#esp8266_timers)
+
+</center><br>
+
+## <a name="esp8266_flash_modes"> Flash Modes </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ```FLASH_MODE``` make command variable determines the mode that is used for flash access in normal operation.
+
+The flash mode determines whether 2 data lines (```dio``` and ```dout```) or 4 data lines (```qio``` and ```qout```) for addressing and data access. For each data line, one GPIO is required. Therefore, using ```qio``` or ```qout``` increases the performance of SPI Flash data transfers, but uses two additional GPIOs (GPIO9 and GPIO10). That is, in this flash modes these GPIOs are not available for other purposes. If you can live with lower flash data transfer rates, you should always use ```dio``` or ```dout``` to keep GPIO9 and GPIO10 free for other purposes.
+
+For more information about these flash modes, refer the documentation of [esptool.py](https://github.com/espressif/esptool/wiki/SPI-Flash-Modes).
+
+@note While ESP8266 modules can be flashed with ```qio```, ```qout```, ```dio``` and ```dout```, ESP8285 modules have to be always flashed in ```dout``` mode. The default flash mode is ```dout```.
+
+
+# <a name="esp8266_peripherals"> Peripherals </a> &nbsp;[[TOC](#esp8266_toc)]
+
+## <a name="esp8266_gpio_pins"> GPIO pins </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 has 17 GPIO pins, which are all digital pins. Some of them can not be used at all or have bootstrapping capabilities and are therefore not available on all boards.
+
+<center>
+
+Pin    | Remarks
+-------|--------
+GPIO0  | usually pulled up
+GPIO1  | UART TxD
+GPIO2  | usually pulled up
+GPIO3  | UART RxD
+GPIO4  | |
+GPIO5  | |
+GPIO6  | Flash SPI
+GPIO7  | Flash SPI
+GPIO8  | Flash SPI
+GPIO9  | Flash SPI in ```qout``` and ```qio``` mode, see section [Flash Modes](#esp8266_flash_modes)
+GPIO10 | Flash SPI in ```qout``` and ```qio``` mode, see section [Flash Modes](#esp8266_flash_modes)
+GPIO11 | Flash SPI
+GPIO12 | |
+GPIO13 | |
+GPIO14 | |
+GPIO15 | usually pulled down
+GPIO16 | RTC pin and wake up signal in deep sleep mode
+
+</center>
+
+GPIO0, GPIO2, and GPIO15 are bootstrapping pins which are used to boot ESP8266 in different modes:
+
+<center>
+
+GPIO0 | GPIO2 | GPIO15 (MTDO) | Mode
+:----:|:-----:|:-------------:|:------------------
+1     | X     | X             | boot in SDIO mode to start OCD
+0     | 0     | 1             | boot in UART mode for flashing the firmware
+0     | 1     | 1             | boot in FLASH mode to boot the firmware from flash (default mode)
+
+</center>
+
+## <a name="esp8266_adc_channels"> ADC Channels </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 has **one dedicated ADC** pin with a resolution of 10 bits. This ADC pin can measure voltages in the range of **0 V ... 1.1 V**.
+
+@note Some boards have voltage dividers to scale this range to a maximum of 3.3 V. For more information, see the hardware manual for the board.
+
+## <a name="esp8266_spi_interfaces"> SPI Interfaces </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 provides two hardware SPI interfaces:
+
+- _FSPI_ for flash memory access that is usually simply referred to as _SPI_
+- _HSPI_ for peripherals
+
+Even though _FSPI_ (or simply _SPI_) is a normal SPI interface, it is not possible to use it for peripherals. **HSPI is therefore the only usable SPI interface** available for peripherals as RIOT's ```SPI_DEV(0)```.
+
+The pin configuration of the _HSPI_ interface ```SPI_DEV(0)``` is fixed. The only pin definition that can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration) is the CS signal defined by ```SPI0_CS0_GPIO```.
+
+<center>
+
+Signal of _HSPI_ | Pin
+-----------------|-------
+MISO | GPIO12
+MOSI | GPIO13
+SCK  | GPIO14
+CS   | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in ```dout``` and ```dio``` flash mode)
+
+</center>
+
+When the SPI is enabled using module ```periph_spi```, these GPIOs cannot be used for any other purpose. GPIOs 0, 2, 4, 5, 15, and 16 can be used as CS signal. In ```dio``` and ```dout``` flash modes (see section [Flash Modes](#esp8266_flash_modes)), GPIOs 9 and 10 can also be used as CS signal.
+
+## <a name="esp8266_i2c_interfaces"> I2C Interfaces </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Since the ESP8266 does not or only partially support the I2C in hardware, I2C interfaces are realized as **bit-banging protocol in software**. The maximum usable bus speed is therefore ```I2C_SPEED_FAST_PLUS```. The maximum number of buses that can be defined is 2, ```I2C_DEV(0)``` ... ```I2C_DEV(1)```.
+
+Number of I2C buses (```I2C_NUMOF```) and used GPIO pins (```I2Cx_SCL``` and ```I2Cx_SDA``` where ```x``` stands for the bus device ```x```) have to be defined in the board-specific peripheral configuration in ```$BOARD/periph_conf.h```. Furthermore, the default I2C bus speed (```I2Cx_SPEED```) that is used for bus ```x``` has to be defined.
+
+In the following example, only one I2C bus is defined:
+
+```
+#define I2C_NUMOF      (1)
+
+#define I2C0_SPEED     I2C_SPEED_FAST
+#define I2C0_SDA       GPIO4
+#define I2C0_SCL       GPIO5
+```
+A configuration with two I2C buses would look like the following:
+
+```
+#define I2C_NUMOF      (2)
+
+#define I2C0_SPEED     I2C_SPEED_FAST
+#define I2C0_SDA       GPIO4
+#define I2C0_SCL       GPIO5
+
+#define I2C1_SPEED     I2C_SPEED_NORMAL
+#define I2C1_SDA       GPIO2
+#define I2C1_SCL       GPIO14
+```
+
+All these configurations can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+## <a name="esp8266_pwm_channels"> PWM Channels </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The hardware implementation of ESP8266 PWM supports only frequencies as power of two. Therefore, a **software implementation** of **one PWM device** (```PWM_DEV(0)```) with up to **8 PWM channels** (```PWM_CHANNEL_NUM_MAX```) is used.
+
+@note The minimum PWM period that can be realized with this software implementation is 10 us or 100.000 PWM clock cycles per second. Therefore, the product of frequency and resolution should not be greater than 100.000. Otherwise the frequency is scaled down automatically.
+
+GPIOs that can be used as channels of the PWM device ```PWM_DEV(0)``` are defined by ```PWM0_CHANNEL_GPIOS```. By default, GPIOs 2, 4 and 5 are defined as PWM channels. As long as these channels are not started with function ```pwm_set```, they can be used as normal GPIOs for other purposes.
+
+GPIOs in ```PWM0_CHANNEL_GPIOS``` with a duty cycle value of 0 can be used as normal GPIOs for other purposes. GPIOs in ```PWM0_CHANNEL_GPIOS``` that are used for other purposes, e.g., I2C or SPI, are no longer available as PWM channels.
+
+To define other GPIOs as PWM channels, just overwrite the definition of ```PWM_CHANNEL_GPIOS``` in an [application-specific board configuration](#esp8266_application_specific_board_configuration)
+
+```
+#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 }
+```
+
+## <a name="esp8266_timers"> Timers </a> &nbsp;[[TOC](#esp8266_toc)]
+
+There are two timer implementations:
+
+- **hardware timer** implementation with **1 timer device** and only **1 channel**, the default
+- **software timer** implementation with **1 timer device** and only **10 channels**
+
+By default, the **hardware timer implementation** is used.
+
+When the SDK version of the RIOT port (```USE_SDK=1```) is used, the **software timer** implementation is activated by using module ```esp_sw_timer```.
+
+The software timer uses SDK's software timers to implement the timer channels. Although these SDK timers usually have a precision of a few microseconds, they can deviate up to 500 microseconds. So if you need a timer with high accuracy, you'll need to use the hardware timer with only one timer channel.
+
+@note When module ```esp_sw_timer``` is used, the SDK version is automatically compiled (```USE_SDK=1```).
+
+## <a name="esp8266_spiffs_device"> SPIFFS Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+If SPIFFS module is enabled (```USEMODULE += esp_spiffs```), the implemented MTD device ```mtd0``` for the on-board SPI flash memory is used together with modules ```spiffs``` and ```vfs``` to realize a persistent file system.
+
+For this purpose, the flash memory is formatted as SPIFFS starting at the address ```0x80000``` (512 kByte) on first boot. All sectors up to the last 5 sectors of the flash memory are then used for the file system. With a fixed sector size of 4096 bytes, the top address of the SPIFF is ```flash_size - 5 * 4096```, e.g., ```0xfb000``` for a flash memory of 1 MByte. The size of the SPIFF then results from:
+```
+flash_size - 5 * 4096 - 512 kByte
+```
+
+Please refer file ```$RIOTBASE/tests/unittests/test-spiffs/tests-spiffs.c``` for more information on how to use SPIFFS and VFS together with a MTD device ```mtd0``` alias ```MTD_0```.
+
+## <a name="esp8266_other_peripherals"> Other Peripherals </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ESP8266 port of RIOT also supports
+
+- one hardware number generator with 32 bit,
+- one UART interface (GPIO1 and GPIO3),
+- a CPU-ID function, and
+- power management functions.
+
+RTC is not yet implemented.
+
+# <a name="esp8266_preconfigured_devices"> Preconfigured Devices </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ESP8266 port of RIOT has been tested with several common external devices that can be connected to ESP8266 boards and are preconfigured accordingly.
+
+## <a name="esp8266_network_devices"> Network Devices </a> &nbsp;[[TOC](#esp8266_toc)]
+
+RIOT provides a number of driver modules for different types of network devices, e.g., IEEE 802.15.4 radio modules and Ethernet modules. The RIOT ESP8266 port has been tested with the following network devices and is preconfigured to create RIOT network applications with these devices:
+
+- [mrf24j40](http://riot-os.org/api/group__drivers__mrf24j40.html) (driver for Microchip MRF24j40 based IEEE 802.15.4
+- [enc28j60](http://riot-os.org/api/group__drivers__enc28j60.html) (driver for Microchip ENC28J60 based Ethernet modules)
+
+If the RIOT network application uses a default network device (module ```netdev_default```), the ```NETDEV_DEFAULT``` make command variable can be used to define the device that will be used as the default network device. The value of this variable must match the name of the driver module for this network device. If ```NETDEV_DEFAULT``` is not defined, the ```mrf24j40```  module is used as default network device.
+
+### <a name="esp8266_using_mrf24j40"> Using MRF24J40 (module ```mrf24j40```) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To use MRF24J40 based IEEE 802.15.4 modules as network device, module ```mrf24j40``` has to be added to a makefile:
+
+```
+USEMODULE += mrf24j40
+```
+
+@note If module ```netdev_default``` is used (which is usually the case in all networking applications), module ```mrf24j40``` is added automatically.
+
+Module ```mrf24j40``` uses the following interface parameters by default:
+
+<center>
+
+Parameter              | Default      | Remarks
+-----------------------|--------------|----------------------------
+MRF24J40_PARAM_SPI     | SPI_DEV(0)   | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+MRF24J40_PARAM_SPI_CLK | SPI_CLK_1MHZ | fix
+MRF24J40_PARAM_CS      | GPIO16       | can be overridden
+MRF24J40_PARAM_INT     | GPIO0        | can be overridden
+MRF24J40_PARAM_RESET   | GPIO2        | can be overridden
+
+</center><br>
+
+Used GPIOs can be overridden by corresponding make command variables, e.g,:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking MRF24J40_PARAM_CS=GPIO15
+```
+or by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+### <a name="esp8266_using_enc28j60"> Using ENC28J60 (module ```enc28j60```) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To use ENC28J60 Ethernet modules as network device, module ```enc28j60``` has to be added to your makefile:
+
+```
+USEMODULE += enc28j60
+```
+
+Module ```enc28j60``` uses the following interface parameters by default:
+
+<center>
+
+Parameter            | Default      | Remarks
+---------------------|--------------|----------------------------
+ENC28J60_PARAM_SPI   | SPI_DEV(0)   | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+ENC28J60_PARAM_CS    | GPIO4        | can be overridden
+ENC28J60_PARAM_INT   | GPIO9        | can be overridden
+ENC28J60_PARAM_RESET | GPIO10       | can be overridden
+
+</center>
+
+Used GPIOs can be overridden by corresponding make command variables, e.g.:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking ENC28J60_PARAM_CS=GPIO15
+```
+or by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+To use module ```enc28j60``` as default network device, the ```NETDEV_DEFAULT``` make command variable has to set, for example:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking NETDEV_DEFAULT=enc28j60
+```
+
+## <a name="esp8266_sd_card_device"> SD-Card Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 port of RIOT is preconfigured for RIOT applications that use the [SPI SD-Card driver](http://riot-os.org/api/group__drivers__sdcard__spi.html). To use SPI SD-Card driver, the ```sdcard_spi``` module has to be added to a makefile:
+
+```
+USEMODULE += sdcard_spi
+```
+
+Module ```sdcard_spi``` uses the following interface parameters by default:
+
+<center>
+
+Parameter              | Default       | Remarks
+-----------------------|---------------|----------------------------
+SDCARD_SPI_PARAM_SPI   | SPI0_DEV      | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+SDCARD_SPI_PARAM_CS    | SPI0_CS0_GPIO | can be overridden
+
+</center>
+
+The GPIO used as CS signal can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+
+# <a name="esp8266_application_specific_configurations"> Application-Specific Configurations </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Configuration used for peripheral devices and for device driver modules, such as GPIO pins, bus interfaces or bus speeds are typically defined in the board-specific configurations ```board.h``` and ```periph_conf.h``` or in the driver parameter configuration ```< driver>_params.h```. Most of these definitions are enclosed by
+```
+#ifndef ANY_PARAMETER
+...
+#endif
+```
+constructs, so it is possible to override them by defining them in front of these constructs.
+
+## <a name="esp8266_application_specific_board_configuration"> Application-Specific Board Configuration </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To override standard board configurations, simply create an application-specific board configuration file ```$APPDIR/board.h``` in the source directory of the application ```$APPDIR``` and add the definitions to be overridden. To force the preprocessor to include board's original ```board.h``` after that, add the ```include_next``` preprocessor directive as the **last** line.
+
+For example to override the default definition of the GPIOs that are used as PWM channels, the application-specific board configuration file ```$APPDIR/board.h``` could look like the following:
+```
+#ifdef CPU_ESP8266
+#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 }
+#endif
+
+#include_next "board.h"
+```
+
+To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 card, you should always enclose these definitions in the following constructs:
+```
+#ifdef CPU_ESP8266
+...
+#endif
+
+#ifdef BOARD_ESP8266_ESP_12X
+...
+#endif
+```
+To ensure that the application-specific board configuration ```$APPDIR/board.h``` is included first, insert the following line as the **first** line to the application makefile ```$APPDIR/Makefile```.
+```
+INCLUDES += -I$(APPDIR)
+```
+
+## <a name="esp8266_application_specific_driver_configuration"> Application-Specific Driver Configuration </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using the approach for overriding board configurations, the parameters of drivers that are typically defined in ```drivers/<device>/include/<device>_params.h``` can also be overridden. For that purpose just create an application-specific driver parameter file ```$APPDIR/<device>_params.h``` in the source directory ```$APPDIR``` of the application and add the definitions to be overridden. To force the preprocessor to include driver's original ```<device>_params.h``` after that, add the ```include_next``` preprocessor directive as the **last** line.
+
+For example, to override a GPIO used for LIS3DH sensor, the application-specific driver parameter file ```$APPDIR/<device>_params.h``` could look like the following:
+```
+#ifdef CPU_ESP8266
+#define LIS3DH_PARAM_INT2           (GPIO_PIN(0, 4))
+#endif
+
+#include_next "lis3dh_params.h"
+```
+To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 card, you should always enclose these definitions in the following constructs:
+```
+#ifdef CPU_ESP8266
+...
+#endif
+
+#ifdef BOARD_ESP8266_ESP_12X
+...
+#endif
+```
+To ensure that the application-specific driver parameter file ```$APPDIR/<device>_params.h``` is included first, insert the following line as the **first** line to the application makefile ```$APPDIR/Makefile```.
+```
+INCLUDES += -I$(APPDIR)
+```
+
+# <a name="esp8266_sdk_task_handling"> SDK Task Handling </a> &nbsp;[[TOC](#esp8266_toc)]
+
+With make command variable ```USE_SDK=1``` the Espressif SDK is used. This is necessary, for example, if you want to use the built-in WLAN module. The SDK internally uses its own tasks (SDK tasks) and its own scheduling mechanism to realize event-driven SDK functions such as WiFi functions and software timers, and to keep the system alive. For this purpose, the SDK regularly executes SDK tasks with pending events in an endless loop using the ROM function ```ets_run```.
+
+Interrupt service routines do not process interrupts directly but use the ```ets_post``` ROM function to send an event to one of these SDK tasks, which then processes the interrupts asynchronously. A context switch is not possible in the interrupt service routines.
+
+In the RIOT port, the task management of the SDK is replaced by the task management of the RIOT. To handle SDK tasks with pending events so that the SDK functions work and the system keeps alive, the ROM functions ```ets_run``` and ```ets_post``` are overwritten. The ```ets_run``` function performs all SDK tasks with pending events exactly once. It is executed at the end of the ```ets_post``` function and thus usually at the end of an SDK interrupt service routine or before the system goes into the lowest power mode.
+
+@note Since the non-SDK version of RIOT is much smaller and faster than the SDK version, you should always compile your application without the SDK (```USE_SDK=0```, the default) if you don't need the built-in WiFi module.
+
+# <a name="esp8266_qemu_mode_and_gdb"> QEMU Mode and GDB </a> &nbsp;[[TOC](#esp8266_toc)]
+
+When QEMU mode is enabled (```QEMU=1```), instead of loading the image to the target hardware, a binary image ```$ELFFILE.bin``` is created in the target directory. This binary image file can be used together with QEMU to debug the code in GDB.
+
+The binary image can be compiled with debugging information (```ENABLE_GDB=1```) or optimized without debugging information (```ENABLE_GDB=0```). The latter one is the default. The version with debugging information can be debugged in source code while the optimized version can only be debugged in assembler mode.
+
+To use QEMU, you have to install QEMU for Xtensa with ESP8266 machine implementation as following.
+
+```
+cd /my/source/dir
+git clone https://github.com/gschorcht/qemu-xtensa
+cd qemu-xtensa/
+git checkout xtensa-esp8266
+export QEMU=/path/to/esp/qemu
+./configure --prefix=$QEMU --target-list=xtensa-softmmu --disable-werror
+make
+make install
+```
+
+Once the compilation has been finished, QEMU for Xtensa with ESP8266 machine implementation should be available in ```/path/to/esp/qemu/bin``` and you can start it with
+
+```
+$QEMU/bin/qemu-system-xtensa -M esp8266 -nographic -serial stdio -monitor none -s -S -kernel /path/to/the/target/image.elf.bin
+```
+
+where ```/path/to/the/target/image.elf.bin``` is the path to the binary image as generated by the ```make``` command as ```$ELFFILE.bin```. After that you can start GDB in another terminal window using command:
+
+```
+xtensa-lx106-elf-gdb
+```
+
+If you have compiled your binary image with debugging information, you can load the ELF file in gdb with:
+
+```
+(gdb) file /path/to/the/target/image.elf
+```
+
+To start debugging, you have to connect to QEMU with command:
+```
+(gdb) target remote :1234
+```
diff --git a/cpu/esp8266/bin/blank.bin b/cpu/esp8266/bin/blank.bin
new file mode 100644
index 0000000000000000000000000000000000000000..7de9e36a64119c698897e5d1f9b66fbfa7f3243d
--- /dev/null
+++ b/cpu/esp8266/bin/blank.bin
@@ -0,0 +1 @@
+����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
\ No newline at end of file
diff --git a/cpu/esp8266/bin/esp_init_data_default.bin b/cpu/esp8266/bin/esp_init_data_default.bin
new file mode 100644
index 0000000000000000000000000000000000000000..0df65445ba1c4d08d13a2f683b7619fc22a8c05c
Binary files /dev/null and b/cpu/esp8266/bin/esp_init_data_default.bin differ
diff --git a/cpu/esp8266/bin/null.bin b/cpu/esp8266/bin/null.bin
new file mode 100644
index 0000000000000000000000000000000000000000..08e7df176454f3ee5eeda13efa0adaa54828dfd8
Binary files /dev/null and b/cpu/esp8266/bin/null.bin differ
diff --git a/cpu/esp8266/bin/wifi_cfg_default.bin b/cpu/esp8266/bin/wifi_cfg_default.bin
new file mode 100644
index 0000000000000000000000000000000000000000..a763716bdbc95599c7c5c52b6b5502c896f1e415
Binary files /dev/null and b/cpu/esp8266/bin/wifi_cfg_default.bin differ
diff --git a/cpu/esp8266/doc.txt b/cpu/esp8266/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f32b207a8a114b2aae72250b2091b93d4a290443
--- /dev/null
+++ b/cpu/esp8266/doc.txt
@@ -0,0 +1,740 @@
+/**
+@defgroup        cpu_esp8266 ESP8266 / ESP8285 MCU
+@ingroup         cpu
+@brief           RIOT-OS port for Espressif's ESP8266 / ESP8285 MCUs
+
+\section esp8266_riot  RIOT-OS on ESP8266 and ESP8285 boards
+
+## <a name="esp8266_toc"> Table of Contents </a>
+
+1. [Overview](#esp8266_overview)
+2. [MCU ESP8266](#esp8266_mcu_esp8266)
+3. [Toolchain](#esp8266_toolchain)
+    1. [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain)
+    2. [Precompiled Toolchain](#esp8266_precompiled_toolchain)
+    3. [Manual Toolchain Installation](#esp8266_manual_toolchain_installation)
+4. [Flashing the Device](#esp8266_flashing_the_device)
+    1. [Toolchain Usage](#esp8266_toolchain_usage)
+    2. [Compile Options](#esp8266_compile_options)
+    3. [Flash Modes](#esp8266_flash_modes)
+5. [Peripherals](#esp8266_peripherals)
+    1. [GPIO pins](#esp8266_gpio_pins)
+    2. [ADC Channels](#esp8266_adc_channels)
+    3. [SPI Interfaces](#esp8266_spi_interfaces)
+    4. [I2C Interfaces](#esp8266_i2c_interfaces)
+    5. [PWM Channels](#esp8266_pwm_channels)
+    6. [Timers](#esp8266_timers)
+    7. [SPIFFS Device](#esp8266_spiffs_device)
+    8. [Other Peripherals](#esp8266_other_peripherals)
+6. [Preconfigured Devices](#esp8266_preconfigured_devices)
+    1. [Network Devices](#esp8266_network_devices)
+    2. [SD-Card Device](#esp8266_sd_card_device)
+7. [Application-Specific Configurations](#esp8266_application_specific_configurations)
+    1. [Application-Specific Board Configuration](#esp8266_application_specific_board_configuration)
+    2. [Application-Specific Driver Configuration](#esp8266_application_specific_driver_configuration)
+8. [SDK Task Handling](#esp8266_sdk_task_handling)
+9. [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb)
+
+# <a name="esp8266_overview"> Overview </a> &nbsp;&nbsp; [[TOC](#esp8266_toc)]
+
+There are two implementations that can be used:
+
+- the **SDK version** which is realized on top of an SDK (*esp-open-sdk* or *ESP8266_NONOS_SDK*) and
+- the **non-SDK version** which is realized without the SDK.
+
+The non-SDK version produces a much smaller code size than the SDK version and is more efficient in execution because it does not need to run additional SDK functions to keep the SDK system alive.
+
+The **non-SDK version** is probably the **best choice if you do not need the built-in WiFi module**, for example, when you plan to connect an IEEE 802.15.4 radio module to the MCU for communication.
+
+By **default**, the **non-SDK version** is compiled. To compile the SDK version, add ```USE_SDK=1``` to the make command line, e.g.,
+
+```
+make flash BOARD=esp8266-esp-12x -C tests/shell USE_SDK=1 ...
+```
+
+For more information about the make command variables, see section [Compile Options](#esp8266_compile_options).
+
+# <a name=esp8266_mcu_esp8266> MCU ESP8266 </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 is a low-cost, ultra-low-power, single-core SoCs with an integrated WiFi module from Espressif Systems. The processor core is based on the Tensilica Xtensa Diamond Standard 106Micro 32-bit Controller Processor Core, which Espressif calls L106. The key features of ESP8266 are:
+
+<center>
+
+MCU         | ESP8266EX
+------------|----------------------------
+Vendor      | Espressif
+Cores       | 1 x Tensilica Xtensa LX106
+FPU         | no
+RAM         | 80 kByte user-data RAM <br> 32 kByte instruction RAM <br> 32 kByte instruction cache <br/> 16 kByte EST system-data RAM
+Flash       | 512 kByte ... 16 MByte
+Frequency   | 80 MHz or 160 MHz
+Power Consumption | 70 mA in normal operating mode <br> 20 uA in deep sleep mode
+Timers      | 1 x 32 bit
+ADCs        | 1 x 10 bit (1 channel)
+GPIOs       | 16
+I2Cs        | 2 (software implementation)
+SPIs        | 2
+UARTs       | 1 (console) + 1 transmit-only
+WiFi        | IEEE 802.11 b/g/n built in
+Vcc         | 2.5 - 3.6 V
+Datasheet   | [Datasheet](https://www.espressif.com/sites/default/files/documentation/0a-esp8266ex_datasheet_en.pdf)
+Technical Reference | [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf)
+
+</center><br>
+
+@note ESP8285 is simply an ESP8266 SoC with 1 MB built-in flash. Therefore, the documentation also applies to the SoC ESP8285, even if only the ESP8266 SoC is described below.
+
+# <a name="esp8266_toolchain"> Toolchain</a> &nbsp;[[TOC](#esp8266_toc)]
+
+To compile RIOT for The ESP8266 SoC, the following software components are required:
+
+- **esp-open-sdk** which includes the **Xtensa GCC** compiler toolchain, the hardware abstraction library **libhal** for Xtensa LX106, and the flash programmer tool <b>```esptool.py```</b>
+- **newlib-c** library for Xtensa (esp-open-rtos version)
+- **SDK (optional)**, either as part of <b>```esp-open-sdk```</b> or the <b>```ESP8266_NONOS_SDK```</b>
+
+You have the following options to install the Toolchain:
+
+- <b>```riotdocker```</b> image and <b>```esptool.py```</b>, see section [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain)
+- **precompiled toolchain** installation from GIT, see section [Precompiled Toolchain](#esp8266_toolchain_installation)
+- **manual installation**, see section [Manual Toolchain Installation](#esp8266_manual_toolchain_installation)
+
+## <a name="esp8266_riot_docker_toolchain"> RIOT Docker Toolchain (riotdocker) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The easiest use the toolchain is Docker.
+
+### <a name="esp8266_preparing_the_environment"> Preparing the Environment </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using RIOT Docker requires at least the following software:
+
+- <b>```Docker```</b> container virtualization software
+- RIOT Docker (<b>```riotdocker```</b>) image
+- flasher tool <b>```esptool.py```</b>
+
+For information about installing Docker on your host, refer to the appropriate manuals for your operating system. For example, the easiest way to install Docker on the Ubuntu/Debian system is:
+```
+sudo apt-get install docker.io
+```
+
+The ESP Flasher tool <b>```esptool.py```</b> is available at [GitHub](https://github.com/espressif/esptool). To install the tool, either Python 2.7 or Python 3.4 or later must be installed. The latest stable version of ```esptool.py``` can be installed with ```pip```:
+```
+pip install esptool
+```
+
+<b>```esptool.py```</b> depends on ```pySerial``` which can be installed either using ```pip```
+
+```
+pip install pyserial
+```
+or the package manager of your OS, for example on Debian/Ubuntu systems:
+```
+apt-get install pyserial
+```
+For more information on ```esptool.py```, please refer the [git repository](https://github.com/espressif/esptool)
+
+Please make sure that ```esptool.py``` is in your ```PATH``` variable.
+
+### <a name="esp8266_generating_docker_image"> Generating a riotdocker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+A ```riotdocker``` fork that only installs the ```RIOT-Xtensa-ESP8266-toolchain``` is available at [GitHub](https://github.com/gschorcht/riotdocker-Xtensa-ESP.git). After cloning this git repository, you can use branch ```esp8266_only``` to generate a Docker image with a size of "only" 990 MByte:
+
+```
+git clone https://github.com/gschorcht/riotdocker-Xtensa-ESP.git
+cd riotdocker-Xtensa-ESP
+git checkout esp8266_only
+docker build -t riotbuild .
+```
+A ```riotdocker``` version that contains the toolchains for all different RIOT platforms can be found at [GitHub](https://github.com/RIOT-OS/riotdocker). However, the Docker image generated from the this Docker file has a size of about 1.5 GByte.
+
+Once a Docker image has been created, it can be started with the following commands while in the RIOT root directory:
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riotbuild
+```
+@note RIOT's root directory ```/path/to/RIOT``` becomes visible as the home directory of the ```riotbuild``` user in the Docker image. That is, the output of compilations performed in RIOT Docker is also accessible on the host system.
+
+Please refer the [RIOT wiki](https://github.com/RIOT-OS/RIOT/wiki/Use-Docker-to-build-RIOT) on how to use the Docker image to compile RIOT OS.
+
+### <a name="esp8266_using_existing_docker_image"> Using an Existing riotdocker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Alternatively, an existing Docker image from Docker Hub can be used. You can either pull and start the [schorcht/riotbuild_esp8266](https://hub.docker.com/r/schorcht/riotbuild_esp8266) Docker image which only contains the ```RIOT-Xtensa-ESP8266-toolchain``` using
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild schorcht/riotbuild_esp8266
+```
+or the [riot/riotbuild](https://hub.docker.com/r/riot/riotbuild/) Docker image (size is about 1.5 GB) which contains the toolchains for all platforms using
+```
+cd /path/to/RIOT
+docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riot/riotbuild
+```
+### <a name="esp8266_flashing_using_docker"> Make Process with Docker Image </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using Docker, the make process consists of the following two steps:
+
+1. **making** the RIOT binary **within a RIOT Docker image**
+2. **flashing** the RIOT binary using a flasher program **on the host system**
+
+Once the RIOT Docker image has been started from RIOT's root directory, a RIOT application can be compiled inside the Docker using the make command as usual, for example:
+
+```
+make BOARD=esp8266-esp-12x -C tests/shell ...
+```
+This will generate a RIOT binary in ELF format.
+
+@note You can't use the ```flash``` target inside the Docker image.
+
+The RIOT binary has to be flash outside docker on the host system. Since the Docker image was stared while in RIOT's root directory, the output of the compilations is also accessible on the host system. On the host system, the ```flash-only``` target can then be used to flash the binary.
+```
+make flash-only BOARD=esp8266-esp-12x -C tests/shell
+```
+
+
+## <a name="esp8266_precompiled_toolchain"> Precompiled Toolchain </a> &nbsp;[[TOC](#esp8266_toc)]
+
+You can get a precompiled version of the whole toolchain from the GIT repository [RIOT-Xtensa-ESP8266-toolchain](https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain). This repository contains the precompiled toolchain including all libraries that are necessary to compile RIOT-OS for ESP8266.
+
+@note To use the precompiled toolchain the following packages (Debian/Ubuntu) have to be installed:<br> ```cppcheck``` ```coccinelle``` ```curl``` ```doxygen``` ```git``` ```graphviz``` ```make``` ```pcregrep``` ```python``` ```python-serial``` ```python3``` ```python3-flake8``` ```unzip``` ```wget```
+
+To install the toolchain use the following commands:
+```
+cd /opt
+sudo git clone https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain.git esp
+```
+After the installation, all components of the toolchain are installed in directory ```/opt/esp```. Of course, you can use any other location for the installation.
+
+To use the toolchain, you have to add the path of the binaries to your ```PATH``` variable according to your toolchain location
+
+```
+export PATH=$PATH:/path/to/toolchain/esp-open-sdk/xtensa-lx106-elf/bin
+```
+where ```/path/to/toolchain/``` is the directory you selected for the installation of the toolchain. For the default installation in ```/opt/esp``` this would be:
+```
+export PATH=$PATH:/opt/esp/esp-open-sdk/xtensa-lx106-elf/bin
+```
+
+Furthermore, you have to set variables ```ESP8266_SDK_DIR``` and ```ESP8266_NEWLIB_DIR``` according to the location of the toolchain.
+```
+export ESP8266_SDK_DIR=/path/to/toolchain/esp-open-sdk/sdk
+export ESP8266_NEWLIB_DIR=/path/to/toolchain/newlib-xtensa
+```
+If you have used ```/opt/esp``` as installation directory, it is not necessary to set these variables since makefiles use them as default directories.
+
+## <a name="esp8266_manual_toolchain_installation"> Manual Toolchain Installation </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The most difficult way to install the toolchain is the manual installation of required components as described below.
+
+@note Manual toolchain installation requires that the following packages (Debian/Ubuntu) are installed: ```autoconf``` ```automake``` ```bash``` ```bison``` ```build-essential``` ```bzip2``` ```coccinelle``` ```cppcheck``` ```curl``` ```doxygen``` ```g++``` ```gperf``` ```gawk``` ```gcc``` ```git``` ```graphviz``` ```help2man``` ```flex``` ```libexpat-dev``` ```libtool``` ```libtool-bin``` ```make``` ```ncurses-dev``` ```pcregrep``` ```python``` ```python-dev``` ```python-serial``` ```python3``` ```python3-flake8``` ```sed``` ```texinfo``` ```unrar-free``` ```unzip wget```
+
+### <a name="esp8266_installation_of_esp_open_sdk"> Installation of esp-open-sdk </a> &nbsp;[[TOC](#esp8266_toc)]
+
+esp-open-sdk is directly installed inside its source directory. Therefore, change directly to the target directory of the toolchain to build it.
+
+```
+cd /path/to/esp
+git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
+cd esp-open-sdk
+export ESP_OPEN_SDK_DIR=$PWD
+```
+
+If you plan to use the SDK version of the RIOT port and to use the SDK as part of esp-open-sdk, simply build its standalone version.
+
+```
+make STANDALONE=y
+```
+
+If you only plan to use the non-SDK version of the RIOT port or if you want to use one of Espressif's original SDKs, it is enough to build the toolchain.
+
+```
+make toolchain esptool libhal STANDALONE=n
+```
+
+Once compilation has been finished, the toolchain is available in ```$PWD/xtensa-lx106-elf/bin```. To use it, set the ```PATH``` variable accordingly.
+
+```
+export PATH=$ESP_OPEN_SDK_DIR/xtensa-lx106-elf/bin:$PATH
+```
+
+If you have compiled the standalone version of esp-open-sdk and you plan to use this SDK version, set additionally the ```ESP8266_SDK_DIR``` variable.
+
+```
+export ESP8266_SDK_DIR=$ESP_OPEN_SDK_DIR/sdk
+```
+
+### <a name="esp8266_installation_of_newlib-c"> Installation of newlib-c </a> &nbsp;[[TOC](#esp8266_toc)]
+
+First, set the target directory for the installation.
+
+```
+export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa
+```
+
+Please take care, to use the newlib-c version that was modified for esp-open-rtos since it includes ```stdatomic.h```.
+
+```
+cd /my/source/dir
+git clone https://github.com/ourairquality/newlib.git
+```
+
+Once you have cloned the GIT repository, build and install it with following commands.
+```
+cd newlib
+./configure --prefix=$ESP8266_NEWLIB_DIR --with-newlib --enable-multilib --disable-newlib-io-c99-formats --enable-newlib-supplied-syscalls --enable-target-optspace --program-transform-name="s&^&xtensa-lx106-elf-&" --disable-option-checking --with-target-subdir=xtensa-lx106-elf --target=xtensa-lx106-elf --enable-newlib-nano-formatted-io --enable-newlib-reent-small
+make
+make install
+```
+
+### <a name="esp8266_installation_of_espressif_original_sdk"> Installation of Espressif original SDK (optional) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+If you plan to use the SDK version of the RIOT port and if you want to use one of Espressif's original SDKs, you have to install it.
+
+First, download the _ESP8266_NONOS_SDK_ version 2.1.0 from the [Espressif web site](https://github.com/espressif/ESP8266_NONOS_SDK/releases/tag/v2.1.0). Probably other version might also work. However, RIOT port is tested with version 2.1.0.
+
+Once you have downloaded it, you can install it with following commands.
+
+```
+cd /path/to/esp
+tar xvfz /downloads/ESP8266_NONOS_SDK-2.1.0.tar.gz
+```
+
+To use the installed SDK, set variable ```ESP8266_SDK_DIR``` accordingly.
+
+```
+export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0
+```
+
+# <a name="esp8266_flashing_the_device"> Flashing the Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+## <a name="esp8266_toolchain_usage"> Toolchain Usage </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Once you have installed all required components, you should have the following directories.
+
+```
+/path/to/esp/esp-open-sdk
+/path/to/esp/newlib-xtensa
+/path/to/esp/ESP8266_NONOS_SDK-2.1.0 (optional)
+```
+
+To use the toolchain and optionally the SDK, please check that your environment variables are set correctly to
+
+```
+export PATH=/path/to/esp/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
+export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa
+```
+and
+```
+export ESP8266_SDK_DIR=/path/to/esp/esp-open-sdk/sdk
+```
+or
+
+```
+export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0
+```
+
+## <a name="esp8266_compile_options"> Compile Options </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The compilation process can be controlled by a number of variables for the make command:
+
+<center>
+
+Option | Values | Default | Description
+-------|--------|---------|------------
+ENABLE_GDB | 0, 1 | 0 | Enable compilation with debug information for debugging with QEMU (```QEMU=1```), see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb)
+FLASH_MODE | dout, dio, qout, qio | dout | Set the flash mode, please take care with your module, see section [Flash Modes](#esp8266_flash_modes)
+NETDEV_DEFAULT | module name | mrf24j40 | Set the module that is used as default network device, see section [Network Devices](#esp8266_network_devices)
+PORT | /dev/ttyUSBx | /dev/ttyUSB0 | Set the USB port for flashing the firmware
+QEMU | 0, 1 | 0 | Generate an image for QEMU, see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb).
+USE_SDK | 0, 1 | 0 | Compile the SDK version (```USE_SDK=1```), see section [SDK Task Handling](#esp8266_sdk_task_handling)
+
+</center><br>
+
+Optional features of ESP8266 can be enable by ```USEMODULE``` definitions in the makefile of the application. These are:
+
+<center>
+
+Module | Description
+-------|------------
+esp_spiffs | Enables the SPIFFS file system, see section [SPIFFS Device](#esp8266_spiffs_device)
+esp_sw_timer | Enables software timer implementation, implies the setting ```USE_SDK=1```, see section [Timers](#esp8266_timers)
+
+</center><br>
+
+## <a name="esp8266_flash_modes"> Flash Modes </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ```FLASH_MODE``` make command variable determines the mode that is used for flash access in normal operation.
+
+The flash mode determines whether 2 data lines (```dio``` and ```dout```) or 4 data lines (```qio``` and ```qout```) for addressing and data access. For each data line, one GPIO is required. Therefore, using ```qio``` or ```qout``` increases the performance of SPI Flash data transfers, but uses two additional GPIOs (GPIO9 and GPIO10). That is, in this flash modes these GPIOs are not available for other purposes. If you can live with lower flash data transfer rates, you should always use ```dio``` or ```dout``` to keep GPIO9 and GPIO10 free for other purposes.
+
+For more information about these flash modes, refer the documentation of [esptool.py](https://github.com/espressif/esptool/wiki/SPI-Flash-Modes).
+
+@note While ESP8266 modules can be flashed with ```qio```, ```qout```, ```dio``` and ```dout```, ESP8285 modules have to be always flashed in ```dout``` mode. The default flash mode is ```dout```.
+
+
+# <a name="esp8266_peripherals"> Peripherals </a> &nbsp;[[TOC](#esp8266_toc)]
+
+## <a name="esp8266_gpio_pins"> GPIO pins </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 has 17 GPIO pins, which are all digital pins. Some of them can not be used at all or have bootstrapping capabilities and are therefore not available on all boards.
+
+<center>
+
+Pin    | Remarks
+-------|--------
+GPIO0  | usually pulled up
+GPIO1  | UART TxD
+GPIO2  | usually pulled up
+GPIO3  | UART RxD
+GPIO4  | |
+GPIO5  | |
+GPIO6  | Flash SPI
+GPIO7  | Flash SPI
+GPIO8  | Flash SPI
+GPIO9  | Flash SPI in ```qout``` and ```qio``` mode, see section [Flash Modes](#esp8266_flash_modes)
+GPIO10 | Flash SPI in ```qout``` and ```qio``` mode, see section [Flash Modes](#esp8266_flash_modes)
+GPIO11 | Flash SPI
+GPIO12 | |
+GPIO13 | |
+GPIO14 | |
+GPIO15 | usually pulled down
+GPIO16 | RTC pin and wake up signal in deep sleep mode
+
+</center>
+
+GPIO0, GPIO2, and GPIO15 are bootstrapping pins which are used to boot ESP8266 in different modes:
+
+<center>
+
+GPIO0 | GPIO2 | GPIO15 (MTDO) | Mode
+:----:|:-----:|:-------------:|:------------------
+1     | X     | X             | boot in SDIO mode to start OCD
+0     | 0     | 1             | boot in UART mode for flashing the firmware
+0     | 1     | 1             | boot in FLASH mode to boot the firmware from flash (default mode)
+
+</center>
+
+## <a name="esp8266_adc_channels"> ADC Channels </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 has **one dedicated ADC** pin with a resolution of 10 bits. This ADC pin can measure voltages in the range of **0 V ... 1.1 V**.
+
+@note Some boards have voltage dividers to scale this range to a maximum of 3.3 V. For more information, see the hardware manual for the board.
+
+## <a name="esp8266_spi_interfaces"> SPI Interfaces </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 provides two hardware SPI interfaces:
+
+- _FSPI_ for flash memory access that is usually simply referred to as _SPI_
+- _HSPI_ for peripherals
+
+Even though _FSPI_ (or simply _SPI_) is a normal SPI interface, it is not possible to use it for peripherals. **HSPI is therefore the only usable SPI interface** available for peripherals as RIOT's ```SPI_DEV(0)```.
+
+The pin configuration of the _HSPI_ interface ```SPI_DEV(0)``` is fixed. The only pin definition that can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration) is the CS signal defined by ```SPI0_CS0_GPIO```.
+
+<center>
+
+Signal of _HSPI_ | Pin
+-----------------|-------
+MISO | GPIO12
+MOSI | GPIO13
+SCK  | GPIO14
+CS   | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in ```dout``` and ```dio``` flash mode)
+
+</center>
+
+When the SPI is enabled using module ```periph_spi```, these GPIOs cannot be used for any other purpose. GPIOs 0, 2, 4, 5, 15, and 16 can be used as CS signal. In ```dio``` and ```dout``` flash modes (see section [Flash Modes](#esp8266_flash_modes)), GPIOs 9 and 10 can also be used as CS signal.
+
+## <a name="esp8266_i2c_interfaces"> I2C Interfaces </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Since the ESP8266 does not or only partially support the I2C in hardware, I2C interfaces are realized as **bit-banging protocol in software**. The maximum usable bus speed is therefore ```I2C_SPEED_FAST_PLUS```. The maximum number of buses that can be defined is 2, ```I2C_DEV(0)``` ... ```I2C_DEV(1)```.
+
+Number of I2C buses (```I2C_NUMOF```) and used GPIO pins (```I2Cx_SCL``` and ```I2Cx_SDA``` where ```x``` stands for the bus device ```x```) have to be defined in the board-specific peripheral configuration in ```$BOARD/periph_conf.h```. Furthermore, the default I2C bus speed (```I2Cx_SPEED```) that is used for bus ```x``` has to be defined.
+
+In the following example, only one I2C bus is defined:
+
+```
+#define I2C_NUMOF      (1)
+
+#define I2C0_SPEED     I2C_SPEED_FAST
+#define I2C0_SDA       GPIO4
+#define I2C0_SCL       GPIO5
+```
+A configuration with two I2C buses would look like the following:
+
+```
+#define I2C_NUMOF      (2)
+
+#define I2C0_SPEED     I2C_SPEED_FAST
+#define I2C0_SDA       GPIO4
+#define I2C0_SCL       GPIO5
+
+#define I2C1_SPEED     I2C_SPEED_NORMAL
+#define I2C1_SDA       GPIO2
+#define I2C1_SCL       GPIO14
+```
+
+All these configurations can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+## <a name="esp8266_pwm_channels"> PWM Channels </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The hardware implementation of ESP8266 PWM supports only frequencies as power of two. Therefore, a **software implementation** of **one PWM device** (```PWM_DEV(0)```) with up to **8 PWM channels** (```PWM_CHANNEL_NUM_MAX```) is used.
+
+@note The minimum PWM period that can be realized with this software implementation is 10 us or 100.000 PWM clock cycles per second. Therefore, the product of frequency and resolution should not be greater than 100.000. Otherwise the frequency is scaled down automatically.
+
+GPIOs that can be used as channels of the PWM device ```PWM_DEV(0)``` are defined by ```PWM0_CHANNEL_GPIOS```. By default, GPIOs 2, 4 and 5 are defined as PWM channels. As long as these channels are not started with function ```pwm_set```, they can be used as normal GPIOs for other purposes.
+
+GPIOs in ```PWM0_CHANNEL_GPIOS``` with a duty cycle value of 0 can be used as normal GPIOs for other purposes. GPIOs in ```PWM0_CHANNEL_GPIOS``` that are used for other purposes, e.g., I2C or SPI, are no longer available as PWM channels.
+
+To define other GPIOs as PWM channels, just overwrite the definition of ```PWM_CHANNEL_GPIOS``` in an [application-specific board configuration](#esp8266_application_specific_board_configuration)
+
+```
+#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 }
+```
+
+## <a name="esp8266_timers"> Timers </a> &nbsp;[[TOC](#esp8266_toc)]
+
+There are two timer implementations:
+
+- **hardware timer** implementation with **1 timer device** and only **1 channel**, the default
+- **software timer** implementation with **1 timer device** and only **10 channels**
+
+By default, the **hardware timer implementation** is used.
+
+When the SDK version of the RIOT port (```USE_SDK=1```) is used, the **software timer** implementation is activated by using module ```esp_sw_timer```.
+
+The software timer uses SDK's software timers to implement the timer channels. Although these SDK timers usually have a precision of a few microseconds, they can deviate up to 500 microseconds. So if you need a timer with high accuracy, you'll need to use the hardware timer with only one timer channel.
+
+@note When module ```esp_sw_timer``` is used, the SDK version is automatically compiled (```USE_SDK=1```).
+
+## <a name="esp8266_spiffs_device"> SPIFFS Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+If SPIFFS module is enabled (```USE_SPIFFS=1```), the implemented MTD device ```mtd0``` for the on-board SPI flash memory is used together with modules ```spiffs``` and ```vfs``` to realize a persistent file system.
+
+For this purpose, the flash memory is formatted as SPIFFS starting at the address ```0x80000``` (512 kByte) on first boot. All sectors up to the last 5 sectors of the flash memory are then used for the file system. With a fixed sector size of 4096 bytes, the top address of the SPIFF is ```flash_size - 5 * 4096```, e.g., ```0xfb000``` for a flash memory of 1 MByte. The size of the SPIFF then results from:
+```
+flash_size - 5 * 4096 - 512 kByte
+```
+
+Please refer file ```$RIOTBASE/tests/unittests/test-spiffs/tests-spiffs.c``` for more information on how to use SPIFFS and VFS together with a MTD device ```mtd0``` alias ```MTD_0```.
+
+## <a name="esp8266_other_peripherals"> Other Peripherals </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ESP8266 port of RIOT also supports
+
+- one hardware number generator with 32 bit,
+- one UART interface (GPIO1 and GPIO3),
+- a CPU-ID function, and
+- power management functions.
+
+RTC is not yet implemented.
+
+# <a name="esp8266_preconfigured_devices"> Preconfigured Devices </a> &nbsp;[[TOC](#esp8266_toc)]
+
+The ESP8266 port of RIOT has been tested with several common external devices that can be connected to ESP8266 boards and are preconfigured accordingly.
+
+## <a name="esp8266_network_devices"> Network Devices </a> &nbsp;[[TOC](#esp8266_toc)]
+
+RIOT provides a number of driver modules for different types of network devices, e.g., IEEE 802.15.4 radio modules and Ethernet modules. The RIOT ESP8266 port has been tested with the following network devices and is preconfigured to create RIOT network applications with these devices:
+
+- [mrf24j40](http://riot-os.org/api/group__drivers__mrf24j40.html) (driver for Microchip MRF24j40 based IEEE 802.15.4
+- [enc28j60](http://riot-os.org/api/group__drivers__enc28j60.html) (driver for Microchip ENC28J60 based Ethernet modules)
+
+If the RIOT network application uses a default network device (module ```netdev_default```), the ```NETDEV_DEFAULT``` make command variable can be used to define the device that will be used as the default network device. The value of this variable must match the name of the driver module for this network device. If ```NETDEV_DEFAULT``` is not defined, the ```mrf24j40```  module is used as default network device.
+
+### <a name="esp8266_using_mrf24j40"> Using MRF24J40 (module ```mrf24j40```) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To use MRF24J40 based IEEE 802.15.4 modules as network device, module ```mrf24j40``` has to be added to a makefile:
+
+```
+USEMODULE += mrf24j40
+```
+
+@note If module ```netdev_default``` is used (which is usually the case in all networking applications), module ```mrf24j40``` is added automatically.
+
+Module ```mrf24j40``` uses the following interface parameters by default:
+
+<center>
+
+Parameter              | Default      | Remarks
+-----------------------|--------------|----------------------------
+MRF24J40_PARAM_SPI     | SPI_DEV(0)   | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+MRF24J40_PARAM_SPI_CLK | SPI_CLK_1MHZ | fix
+MRF24J40_PARAM_CS      | GPIO16       | can be overridden
+MRF24J40_PARAM_INT     | GPIO0        | can be overridden
+MRF24J40_PARAM_RESET   | GPIO2        | can be overridden
+
+</center><br>
+
+Used GPIOs can be overridden by corresponding make command variables, e.g,:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking MRF24J40_PARAM_CS=GPIO15
+```
+or by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+### <a name="esp8266_using_enc28j60"> Using ENC28J60 (module ```enc28j60```) </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To use ENC28J60 Ethernet modules as network device, module ```enc28j60``` has to be added to your makefile:
+
+```
+USEMODULE += enc28j60
+```
+
+Module ```enc28j60``` uses the following interface parameters by default:
+
+<center>
+
+Parameter            | Default      | Remarks
+---------------------|--------------|----------------------------
+ENC28J60_PARAM_SPI   | SPI_DEV(0)   | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+ENC28J60_PARAM_CS    | GPIO4        | can be overridden
+ENC28J60_PARAM_INT   | GPIO9        | can be overridden
+ENC28J60_PARAM_RESET | GPIO10       | can be overridden
+
+</center>
+
+Used GPIOs can be overridden by corresponding make command variables, e.g.:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking ENC28J60_PARAM_CS=GPIO15
+```
+or by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+To use module ```enc28j60``` as default network device, the ```NETDEV_DEFAULT``` make command variable has to set, for example:
+```
+make flash BOARD=esp8266-esp-12x -C examples/gnrc_networking NETDEV_DEFAULT=enc28j60
+```
+
+## <a name="esp8266_sd_card_device"> SD-Card Device </a> &nbsp;[[TOC](#esp8266_toc)]
+
+ESP8266 port of RIOT is preconfigured for RIOT applications that use the [SPI SD-Card driver](http://riot-os.org/api/group__drivers__sdcard__spi.html). To use SPI SD-Card driver, the ```sdcard_spi``` module has to be added to a makefile:
+
+```
+USEMODULE += sdcard_spi
+```
+
+Module ```sdcard_spi``` uses the following interface parameters by default:
+
+<center>
+
+Parameter              | Default       | Remarks
+-----------------------|---------------|----------------------------
+SDCARD_SPI_PARAM_SPI   | SPI0_DEV      | fix, see section [SPI Interfaces](#esp8266_spi_interfaces)
+SDCARD_SPI_PARAM_CS    | SPI0_CS0_GPIO | can be overridden
+
+</center>
+
+The GPIO used as CS signal can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration).
+
+# <a name="esp8266_application_specific_configurations"> Application-Specific Configurations </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Configuration used for peripheral devices and for device driver modules, such as GPIO pins, bus interfaces or bus speeds are typically defined in the board-specific configurations ```board.h``` and ```periph_conf.h``` or in the driver parameter configuration ```< driver>_params.h```. Most of these definitions are enclosed by
+```
+#ifndef ANY_PARAMETER
+...
+#endif
+```
+constructs, so it is possible to override them by defining them in front of these constructs.
+
+\anchor esp8266_app_spec_conf
+## <a name="esp8266_application_specific_board_configuration"> Application-Specific Board Configuration </a> &nbsp;[[TOC](#esp8266_toc)]
+
+To override standard board configurations, simply create an application-specific board configuration file ```$APPDIR/board.h``` in the source directory of the application ```$APPDIR``` and add the definitions to be overridden. To force the preprocessor to include board's original ```board.h``` after that, add the ```include_next``` preprocessor directive as the **last** line.
+
+For example to override the default definition of the GPIOs that are used as PWM channels, the application-specific board configuration file ```$APPDIR/board.h``` could look like the following:
+```
+#ifdef CPU_ESP8266
+#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 }
+#endif
+
+#include_next "board.h"
+```
+
+To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 card, you should always enclose these definitions in the following constructs:
+```
+#ifdef CPU_ESP8266
+...
+#endif
+
+#ifdef BOARD_ESP8266_ESP_12X
+...
+#endif
+```
+To ensure that the application-specific board configuration ```$APPDIR/board.h``` is included first, insert the following line as the **first** line to the application makefile ```$APPDIR/Makefile```.
+```
+INCLUDES += -I$(APPDIR)
+```
+
+## <a name="esp8266_application_specific_driver_configuration"> Application-Specific Driver Configuration </a> &nbsp;[[TOC](#esp8266_toc)]
+
+Using the approach for overriding board configurations, the parameters of drivers that are typically defined in ```drivers/<device>/include/<device>_params.h``` can also be overridden. For that purpose just create an application-specific driver parameter file ```$APPDIR/<device>_params.h``` in the source directory ```$APPDIR``` of the application and add the definitions to be overridden. To force the preprocessor to include driver's original ```<device>_params.h``` after that, add the ```include_next``` preprocessor directive as the **last** line.
+
+For example, to override a GPIO used for LIS3DH sensor, the application-specific driver parameter file ```$APPDIR/<device>_params.h``` could look like the following:
+```
+#ifdef CPU_ESP8266
+#define LIS3DH_PARAM_INT2           (GPIO_PIN(0, 4))
+#endif
+
+#include_next "lis3dh_params.h"
+```
+To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 card, you should always enclose these definitions in the following constructs:
+```
+#ifdef CPU_ESP8266
+...
+#endif
+
+#ifdef BOARD_ESP8266_ESP_12X
+...
+#endif
+```
+To ensure that the application-specific driver parameter file ```$APPDIR/<device>_params.h``` is included first, insert the following line as the **first** line to the application makefile ```$APPDIR/Makefile```.
+```
+INCLUDES += -I$(APPDIR)
+```
+
+# <a name="esp8266_sdk_task_handling"> SDK Task Handling </a> &nbsp;[[TOC](#esp8266_toc)]
+
+With make command variable ```USE_SDK=1``` the Espressif SDK is used. This is necessary, for example, if you want to use the built-in WLAN module. The SDK internally uses its own tasks (SDK tasks) and its own scheduling mechanism to realize event-driven SDK functions such as WiFi functions and software timers, and to keep the system alive. For this purpose, the SDK regularly executes SDK tasks with pending events in an endless loop using the ROM function ```ets_run```.
+
+Interrupt service routines do not process interrupts directly but use the ```ets_post``` ROM function to send an event to one of these SDK tasks, which then processes the interrupts asynchronously. A context switch is not possible in the interrupt service routines.
+
+In the RIOT port, the task management of the SDK is replaced by the task management of the RIOT. To handle SDK tasks with pending events so that the SDK functions work and the system keeps alive, the ROM functions ```ets_run``` and ```ets_post``` are overwritten. The ```ets_run``` function performs all SDK tasks with pending events exactly once. It is executed at the end of the ```ets_post``` function and thus usually at the end of an SDK interrupt service routine or before the system goes into the lowest power mode.
+
+@note Since the non-SDK version of RIOT is much smaller and faster than the SDK version, you should always compile your application without the SDK (```USE_SDK=0```, the default) if you don't need the built-in WiFi module.
+
+# <a name="esp8266_qemu_mode_and_gdb"> QEMU Mode and GDB </a> &nbsp;[[TOC](#esp8266_toc)]
+
+When QEMU mode is enabled (```QEMU=1```), instead of loading the image to the target hardware, a binary image ```$ELFFILE.bin``` is created in the target directory. This binary image file can be used together with QEMU to debug the code in GDB.
+
+The binary image can be compiled with debugging information (```ENABLE_GDB=1```) or optimized without debugging information (```ENABLE_GDB=0```). The latter one is the default. The version with debugging information can be debugged in source code while the optimized version can only be debugged in assembler mode.
+
+To use QEMU, you have to install QEMU for Xtensa with ESP8266 machine implementation as following.
+
+```
+cd /my/source/dir
+git clone https://github.com/gschorcht/qemu-xtensa
+cd qemu-xtensa/
+git checkout xtensa-esp8266
+export QEMU=/path/to/esp/qemu
+./configure --prefix=$QEMU --target-list=xtensa-softmmu --disable-werror
+make
+make install
+```
+
+Once the compilation has been finished, QEMU for Xtensa with ESP8266 machine implementation should be available in ```/path/to/esp/qemu/bin``` and you can start it with
+
+```
+$QEMU/bin/qemu-system-xtensa -M esp8266 -nographic -serial stdio -monitor none -s -S -kernel /path/to/the/target/image.elf.bin
+```
+
+where ```/path/to/the/target/image.elf.bin``` is the path to the binary image as generated by the ```make``` command as ```$ELFFILE.bin```. After that you can start GDB in another terminal window using command:
+
+```
+xtensa-lx106-elf-gdb
+```
+
+If you have compiled your binary image with debugging information, you can load the ELF file in gdb with:
+
+```
+(gdb) file /path/to/the/target/image.elf
+```
+
+To start debugging, you have to connect to QEMU with command:
+```
+(gdb) target remote :1234
+```
+*/
diff --git a/cpu/esp8266/exceptions.c b/cpu/esp8266/exceptions.c
new file mode 100644
index 0000000000000000000000000000000000000000..1bdc44e671275b9e5d55d641f0372912271e0990
--- /dev/null
+++ b/cpu/esp8266/exceptions.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 exception handling
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#define ENABLE_DEBUG  0
+#include "debug.h"
+
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "log.h"
+#include "periph/pm.h"
+#include "ps.h"
+
+#include "esp/common_macros.h"
+#include "esp/xtensa_ops.h"
+#include "sdk/ets.h"
+#include "xtensa/corebits.h"
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING
+#include "xtensa/xtensa_api.h"
+#endif
+
+extern void malloc_stats (void);
+extern unsigned int get_free_heap_size (void);
+extern uint8_t _eheap;  /* end of heap (defined in esp8266.riot-os.app.ld) */
+extern uint8_t _sheap;  /* start of heap (defined in esp8266.riot-os.app.ld) */
+
+static const char* exception_names [] =
+{
+        "IllegalInstructionCause",     /* 0 */
+        "SyscallCause",                /* 1 */
+        "InstructionFetchErrorCause",  /* 2 */
+        "LoadStoreErrorCause",         /* 3 */
+        "Level1InterruptCause",        /* 4 */
+        "AllocaCause",                 /* 5 */
+        "IntegerDivideByZeroCause",    /* 6 */
+        "",                            /* 7 - reserved */
+        "PrivilegedCause",             /* 8 */
+        "LoadStoreAlignmentCause",     /* 9 */
+        "",                            /* 10 - reserved */
+        "",                            /* 11 - reserved */
+        "InstrPIFDataErrorCause",      /* 12 */
+        "LoadStorePIFDataErrorCause",  /* 13 */
+        "InstrPIFAddrErrorCause",      /* 14 */
+        "LoadStorePIFAddrErrorCause",  /* 15 */
+        "InstTLBMissCause",            /* 16 */
+        "InstTLBMultiHitCause",        /* 17 */
+        "InstFetchPrivilegeCause",     /* 18 */
+        "",                            /* 19 - reserved */
+        "InstFetchProhibitedCause",    /* 20 */
+        "",                            /* 21 - reserved */
+        "",                            /* 22 - reserved */
+        "",                            /* 23 - reserved */
+        "LoadStoreTLBMissCause",       /* 24 */
+        "LoadStoreTLBMultiHitCause",   /* 25 */
+        "LoadStorePrivilegeCause",     /* 26 */
+        "",                            /* 27 - reserved */
+        "LoadProhibitedCause",         /* 28 */
+        "StoreProhibitedCause",        /* 29 */
+        "",                            /* 30 - reserved */
+        "",                            /* 31 - reserved */
+        "Coprocessor0Disabled",        /* 32 */
+        "Coprocessor1Disabled",        /* 33 */
+        "Coprocessor2Disabled",        /* 34 */
+        "Coprocessor3Disabled",        /* 35 */
+        "Coprocessor4Disabled",        /* 36 */
+        "Coprocessor5Disabled",        /* 37 */
+        "Coprocessor6Disabled",        /* 38 */
+        "Coprocessor7Disabled",        /* 39 */
+};
+
+#ifdef MODULE_ESP_SDK_INT_HANDLING
+
+void IRAM NORETURN exception_handler (void *arg)
+{
+    (void)arg;
+    uint32_t excsave1;
+    uint32_t excvaddr;
+    uint32_t exccause;
+    RSR(excsave1, excsave1);
+    RSR(excvaddr, excvaddr);
+    RSR(exccause, exccause);
+    (void)exception_names;
+
+    ets_printf("EXCEPTION!! exccause=%d (%s) @%08lx excvaddr=%08lx\n",
+               exccause, exception_names[exccause],
+               excsave1, excvaddr);
+
+    #if defined(DEVELHELP)
+    #if defined(MODULE_PS)
+    ps();
+    #endif
+    struct mallinfo minfo = mallinfo();
+    ets_printf("heap: %lu (free %lu) byte\n", &_eheap - &_sheap, get_free_heap_size());
+    ets_printf("sysmem: %d (used %d, free %d)\n", minfo.arena, minfo.uordblks, minfo.fordblks);
+    #endif
+    /* flushing the buffer */
+    ets_printf("                                                          \n");
+    ets_printf("                                                          \n");
+    ets_printf("                                                          \n");
+
+    /* hard reset */
+    __asm__ volatile (" call0 0x40000080 ");
+
+    UNREACHABLE();
+}
+
+void init_exceptions (void)
+{
+    _xtos_set_exception_handler(EXCCAUSE_UNALIGNED, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_ILLEGAL, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_INSTR_ERROR, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_LOAD_PROHIBITED, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_STORE_PROHIBITED, exception_handler);
+    _xtos_set_exception_handler(EXCCAUSE_PRIVILEGED, exception_handler);
+}
+
+#else /* MODULE_ESP_SDK_INT_HANDLING */
+
+void IRAM NORETURN exception_handler (XtExcFrame *frame)
+{
+    uint32_t excsave1;
+    RSR(excsave1, excsave1);
+
+    ets_printf("EXCEPTION!! exccause=%d (%s) @%08lx excvaddr=%08lx\n",
+               frame->exccause, exception_names[frame->exccause],
+               excsave1, frame->excvaddr);
+    #if defined(DEVELHELP)
+    #if defined(MODULE_PS)
+    ps();
+    #endif
+    struct mallinfo minfo = mallinfo();
+    ets_printf("heap: %lu (free %lu) byte\n", &_eheap - &_sheap, get_free_heap_size());
+    ets_printf("sysmem: %d (used %d, free %d)\n", minfo.arena, minfo.uordblks, minfo.fordblks);
+    #endif
+    /* flushing the buffer */
+    ets_printf("                                                          \n");
+    ets_printf("                                                          \n");
+    ets_printf("                                                          \n");
+
+    /* hard reset */
+    __asm__ volatile (" call0 0x40000080 ");
+
+    UNREACHABLE();
+}
+
+void init_exceptions (void)
+{
+    xt_set_exception_handler(EXCCAUSE_UNALIGNED, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_ILLEGAL, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_INSTR_ERROR, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_LOAD_PROHIBITED, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_STORE_PROHIBITED, exception_handler);
+    xt_set_exception_handler(EXCCAUSE_PRIVILEGED, exception_handler);
+}
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
+
+void IRAM NORETURN panic_arch(void)
+{
+    #if defined(DEVELHELP)
+    struct mallinfo minfo = mallinfo();
+    ets_printf("heap: %lu (free %lu) byte\n", &_eheap - &_sheap, get_free_heap_size());
+    ets_printf("sysmem: %d (used %d, free %d)\n", minfo.arena, minfo.uordblks, minfo.fordblks);
+    ets_printf("                                                          \n");
+    ets_printf("                                                          \n");
+    #endif
+
+    /* hard reset */
+    __asm__ volatile (" call0 0x40000080 ");
+
+    UNREACHABLE();
+}
diff --git a/cpu/esp8266/include/common.h b/cpu/esp8266/include/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..520285d70ec896a4bbbb1aed3bda90e896fa84f2
--- /dev/null
+++ b/cpu/esp8266/include/common.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Common helper macros
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** string representation of x */
+#ifndef XTSTR
+#define _XTSTR(x)    # x
+#define XTSTR(x)    _XTSTR(x)
+#endif
+#endif
+
+#if !defined(ICACHE_FLASH) || defined (DOXYGEN)
+
+#ifndef ICACHE_RAM_ATTR
+/** Places the code with this attribute in the IRAM. */
+#define ICACHE_RAM_ATTR  __attribute__((section(".iram.text")))
+#endif
+#else
+#ifndef ICACHE_RAM_ATTR
+#define ICACHE_RAM_ATTR
+#endif
+#endif
+
+/** Print out a message that function is not yet implementd */
+#define NOT_YET_IMPLEMENTED()     LOG_INFO("%s not yet implemented\n", __func__)
+/** Print out a message that function is not supported */
+#define NOT_SUPPORTED()           LOG_INFO("%s not supported\n", __func__)
+
+
+#if defined(ENABLE_DEBUG) || defined(DOXYGEN)
+/**
+  * @brief  Parameter check with return a value.
+  *
+  * If ENABLE_DEBUG is true, the macro checks a condition and returns with a value
+  * if the condition is not fulfilled.
+  * @param  cond    the condition
+  * @param  err     the return value in the case the condition is not fulfilled.
+  */
+#define CHECK_PARAM_RET(cond,err) if (!(cond)) \
+                                  { \
+                                    DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \
+                                    return err; \
+                                  }
+
+/**
+ * @brief  Parameter check without return value.
+ *
+ * If ENABLE_DEBUG is true, the macro checks a condition and returns without a
+ * value if the condition is not fulfilled.
+ * @param  cond    the condition
+ */
+#define CHECK_PARAM(cond)         if (!(cond)) \
+                                  { \
+                                    DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \
+                                    return; \
+                                  }
+#else
+#define CHECK_PARAM_RET(cond,err) if (!(cond)) return err;
+#define CHECK_PARAM(cond)         if (!(cond)) return;
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMMON_H */
diff --git a/cpu/esp8266/include/cpu.h b/cpu/esp8266/include/cpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0e7747f7da10828a7a1e25f2eab05fa67fe47d4
--- /dev/null
+++ b/cpu/esp8266/include/cpu.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       CPU common functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#ifndef CPU_H
+#define CPU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include "irq.h"
+
+#define PROVIDES_PM_SET_LOWEST
+
+/**
+ * @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 /* CPU_H */
+/** @} */
diff --git a/cpu/esp8266/include/cpu_conf.h b/cpu/esp8266/include/cpu_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..7623e9b8e2fae30d326761705c5ec957ed5d635e
--- /dev/null
+++ b/cpu/esp8266/include/cpu_conf.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       CPU specific configuration options
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#ifndef CPU_CONF_H
+#define CPU_CONF_H
+
+#include "xtensa_conf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Stack size configuration
+ * @{
+ */
+#ifdef MODULE_ESP_SDK_INT_HANDLING
+#define THREAD_EXTRA_STACKSIZE_PRINTF (0)
+#define THREAD_STACKSIZE_DEFAULT      (2048)
+#define THREAD_STACKSIZE_IDLE         (2048)
+#else
+#define THREAD_EXTRA_STACKSIZE_PRINTF (0)
+#define THREAD_STACKSIZE_DEFAULT      (2048)
+#define THREAD_STACKSIZE_IDLE         (2048)
+#endif
+/** @} */
+
+/**
+ * Buffer size used for printf functions (maximum length of formatted output).
+ */
+#define PRINTF_BUFSIZ 256
+
+/* Following include is neccessary to overwrite newlib's PRI*8 and PRI*32. */
+/* PLEASE NOTE: ets_vprintf does not understand %i %li, or %hi */
+#ifndef DOXYGEN
+#include <inttypes.h>
+#undef  __INT8
+#define __INT8
+#undef  __INT32
+#define __INT32
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* CPU_CONF_H */
+
+#endif /* CPU_CONF_H */
+/** @} */
diff --git a/cpu/esp8266/include/exceptions.h b/cpu/esp8266/include/exceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..e159bf1050e442a316710e6a72ce44897805e629
--- /dev/null
+++ b/cpu/esp8266/include/exceptions.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 exception handling
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef EXCEPTIONS_H
+#define EXCEPTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initalize exception handler */
+extern void init_exceptions(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXCEPTIONS_H */
diff --git a/cpu/esp8266/include/gpio_common.h b/cpu/esp8266/include/gpio_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..25279de745937820f9131a2c3d512433d38bc089
--- /dev/null
+++ b/cpu/esp8266/include/gpio_common.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_gpio
+ * @{
+ *
+ * @file
+ * @brief       Low-level GPIO driver implementation for ESP8266
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef GPIO_COMMON_H
+#define GPIO_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Map of GPIO pin numbers to IOMUX pin numbers */
+extern const uint8_t _gpio_to_iomux[];
+/** Map of IOMUX pin numbers to GPIO pin numbers */
+extern const uint8_t _iomux_to_gpio[];
+
+/**
+ * @brief   Definition of possible GPIO usage types
+ */
+typedef enum
+{
+    _GPIO = 0,  /**< pin used as standard GPIO */
+    _I2C,       /**< pin used as I2C signal */
+    _PWM,       /**< pin used as PWM output */
+    _SPI,       /**< pin used as SPI interface */
+    _SPIF,      /**< pin used as SPI flash interface */
+    _UART,      /**< pin used as UART interface */
+} _gpio_pin_usage_t;
+
+/**
+ * Holds the usage type of each GPIO pin
+ */
+extern _gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GPIO_COMMON_H */
diff --git a/cpu/esp8266/include/irq_arch.h b/cpu/esp8266/include/irq_arch.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0e3c7020ee5267d3ebfc92d065afb4373019b7e
--- /dev/null
+++ b/cpu/esp8266/include/irq_arch.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the kernels irq interface
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#ifndef IRQ_ARCH_H
+#define IRQ_ARCH_H
+
+#include "irq.h"
+#include "sched.h"
+#include "thread.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Indicates the interrupt nesting depth
+ *
+ * The variable is increment on entry into and decremented on exit from an ISR.
+ */
+extern uint32_t irq_interrupt_nesting;
+
+#if defined(MODULE_ESP_SDK_INT_HANDLING) || defined(DOXYGEN)
+/**
+ * @brief   Macros that have to be used on entry into and reset from an ISR
+ *
+ * NOTE: since they use a local variable they can be used only in same function
+ * @{
+ */
+/** Macro that has to be used at the entry point of an ISR */
+#define irq_isr_enter()    int _irq_state = irq_disable (); \
+                           irq_interrupt_nesting++;
+
+/** Macro that has to be used at the exit point of an ISR */
+#define irq_isr_exit()     if (irq_interrupt_nesting) \
+                               irq_interrupt_nesting--; \
+                           irq_restore (_irq_state); \
+                           if (sched_context_switch_request) \
+                               thread_yield();
+
+#else /* MODULE_ESP_SDK_INT_HANDLING */
+
+/* in non SDK task handling all the stuff is done in _frxt_int_enter and _frxt_int_exit */
+#define irq_isr_enter() /* int _irq_state = irq_disable (); \
+                           irq_interrupt_nesting++; */
+
+#define irq_isr_exit()  /* if (irq_interrupt_nesting) \
+                               irq_interrupt_nesting--; \
+                           irq_restore (_irq_state); */
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
+
+/**
+ * @brief   Macros to enter and exit from critical region
+ *
+ * NOTE: since they use a local variable they can be used only in same function
+ * @{
+ */
+#define critical_enter()   int _irq_state = irq_disable ()
+#define critical_exit()    irq_restore(_irq_state)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IRQ_ARCH_H */
diff --git a/cpu/esp8266/include/periph_cpu.h b/cpu/esp8266/include/periph_cpu.h
new file mode 100644
index 0000000000000000000000000000000000000000..d92ad0a2c03d634210ae7b05584d5835a4255760
--- /dev/null
+++ b/cpu/esp8266/include/periph_cpu.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       CPU specific definitions and functions for peripheral handling
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#ifndef PERIPH_CPU_H
+#define PERIPH_CPU_H
+
+#include <stdint.h>
+
+#include "eagle_soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Override the ADC resolution configuration
+ * @{
+ */
+#define HAVE_ADC_RES_T
+typedef enum {
+    ADC_RES_10BIT      /* only one resolution is supported */
+} adc_res_t;
+/** @} */
+
+/**
+ * @brief   Length of the CPU_ID in octets
+ */
+#define CPUID_LEN           (4U)
+
+/**
+ * @name    GPIO configuration of ESP8266
+ * @{
+ */
+
+/**
+ * @brief   Available ports on the ESP8266
+ * @{
+ */
+#define PORT_GPIO 0       /**< port GPIO */
+/** @} */
+
+/**
+ * @brief   Definition of a fitting UNDEF value
+ */
+#define GPIO_UNDEF (GPIO_ID_NONE)
+
+/**
+ * @brief   Define CPU specific GPIO pin generator macro
+ */
+#define GPIO_PIN(x, y)  ((x << 4) | y)
+
+/**
+ * @brief   Define CPU specific number of GPIO pins
+ */
+#define GPIO_PIN_NUMOF  GPIO_PIN_COUNT+1
+
+/**
+ * @name   Predefined GPIO names
+ * @{
+ */
+#define GPIO0       (GPIO_PIN(PORT_GPIO,0))
+#define GPIO1       (GPIO_PIN(PORT_GPIO,1))
+#define GPIO2       (GPIO_PIN(PORT_GPIO,2))
+#define GPIO3       (GPIO_PIN(PORT_GPIO,3))
+#define GPIO4       (GPIO_PIN(PORT_GPIO,4))
+#define GPIO5       (GPIO_PIN(PORT_GPIO,5))
+#define GPIO6       (GPIO_PIN(PORT_GPIO,6))
+#define GPIO7       (GPIO_PIN(PORT_GPIO,7))
+#define GPIO8       (GPIO_PIN(PORT_GPIO,8))
+#define GPIO9       (GPIO_PIN(PORT_GPIO,9))
+#define GPIO10      (GPIO_PIN(PORT_GPIO,10))
+#define GPIO11      (GPIO_PIN(PORT_GPIO,11))
+#define GPIO12      (GPIO_PIN(PORT_GPIO,12))
+#define GPIO13      (GPIO_PIN(PORT_GPIO,13))
+#define GPIO14      (GPIO_PIN(PORT_GPIO,14))
+#define GPIO15      (GPIO_PIN(PORT_GPIO,15))
+#define GPIO16      (GPIO_PIN(PORT_GPIO,16))
+/** @} */
+
+#ifndef DOXYGEN
+#define GPIO0_MASK  (BIT(0))
+#define GPIO1_MASK  (BIT(1))
+#define GPIO2_MASK  (BIT(2))
+#define GPIO3_MASK  (BIT(3))
+#define GPIO4_MASK  (BIT(4))
+#define GPIO5_MASK  (BIT(5))
+#define GPIO6_MASK  (BIT(6))
+#define GPIO7_MASK  (BIT(7))
+#define GPIO8_MASK  (BIT(8))
+#define GPIO9_MASK  (BIT(9))
+#define GPIO10_MASK (BIT(10))
+#define GPIO11_MASK (BIT(11))
+#define GPIO12_MASK (BIT(12))
+#define GPIO13_MASK (BIT(13))
+#define GPIO14_MASK (BIT(14))
+#define GPIO15_MASK (BIT(15))
+#define GPIO16_MASK (BIT(16))
+
+/**
+ * @brief   Override flank selection values
+ * @{
+ */
+#define HAVE_GPIO_FLANK_T
+typedef enum {
+    GPIO_NONE    = 0,
+    GPIO_RISING  = 1,        /**< emit interrupt on rising flank  */
+    GPIO_FALLING = 2,        /**< emit interrupt on falling flank */
+    GPIO_BOTH    = 3,        /**< emit interrupt on both flanks   */
+    GPIO_LOW     = 4,        /**< emit interrupt on low level     */
+    GPIO_HIGH    = 5         /**< emit interrupt on low level     */
+} gpio_flank_t;
+/** @} */
+#endif /* DOXYGEN */
+
+/** @} */
+
+/**
+ * @name   I2C configuration
+ * @{
+ */
+#define PERIPH_I2C_NEED_READ_REG
+#define PERIPH_I2C_NEED_READ_REGS
+#define PERIPH_I2C_NEED_WRITE_REG
+#define PERIPH_I2C_NEED_WRITE_REGS
+/** @} */
+
+/**
+ * @name    Power management configuration
+ * @{
+ */
+#define PROVIDES_PM_SET_LOWEST
+#define PROVIDES_PM_RESTART
+#define PROVIDES_PM_OFF
+/** @} */
+
+/**
+ * @name   SPI configuration
+ * @{
+ */
+#if defined(MODULE_PERIPH_SPI)
+
+#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
+#define PERIPH_SPI_NEEDS_TRANSFER_REG
+#define PERIPH_SPI_NEEDS_TRANSFER_REGS
+
+#endif /* MODULE_PERIPH_SPI */
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PERIPH_CPU_H */
+/** @} */
diff --git a/cpu/esp8266/include/sys/_intsup.h b/cpu/esp8266/include/sys/_intsup.h
new file mode 100644
index 0000000000000000000000000000000000000000..633b2328899beeb1f6dde0327d2a0d7a038a594d
--- /dev/null
+++ b/cpu/esp8266/include/sys/_intsup.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2004, 2005 by
+ * Ralf Corsepius, Ulm/Germany. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * is freely granted, provided that this notice is preserved.
+ */
+
+/**
+ * @brief Modified _intsup.h for compilation with RIOT OS
+ * Source: /path/to/newlib-xtensa/xtensa-lx106-elf/include/sys
+ * Changes: __INT32 (see below)
+ */
+
+#ifndef SYS__INTSUP_H
+#define SYS__INTSUP_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* additional header guard to avoid conflicts if original file is included later */
+#ifndef _SYS__INTSUP_H
+#define _SYS__INTSUP_H
+
+#include <sys/features.h>
+
+#if __GNUC_PREREQ (3, 2)
+/* gcc > 3.2 implicitly defines the values we are interested */
+#define __STDINT_EXP(x) __##x##__
+#else
+#define __STDINT_EXP(x) x
+#include <limits.h>
+#endif
+
+/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc
+   for this target.  This is used to determine the correct printf() constant in
+   inttypes.h and other  constants in stdint.h.
+   So we end up with
+   ?(signed|unsigned) char == 0
+   ?(signed|unsigned) short == 1
+   ?(signed|unsigned) int == 2
+   ?(signed|unsigned) short int == 3
+   ?(signed|unsigned) long == 4
+   ?(signed|unsigned) long int == 6
+   ?(signed|unsigned) long long == 8
+   ?(signed|unsigned) long long int == 10
+ */
+#pragma push_macro("signed")
+#pragma push_macro("unsigned")
+#pragma push_macro("char")
+#pragma push_macro("short")
+#pragma push_macro("__int20")
+#pragma push_macro("int")
+#pragma push_macro("long")
+#undef signed
+#undef unsigned
+#undef char
+#undef short
+#undef int
+#undef __int20
+#undef long
+#define signed +0
+#define unsigned +0
+#define char +0
+#define short +1
+#define __int20 +2
+#define int +2
+#define long +4
+#if (__INTPTR_TYPE__ == 8 || __INTPTR_TYPE__ == 10)
+#define _INTPTR_EQ_LONGLONG
+#elif (__INTPTR_TYPE__ == 4 || __INTPTR_TYPE__ == 6)
+#define _INTPTR_EQ_LONG
+/* Note - the tests for _INTPTR_EQ_INT and _INTPTR_EQ_SHORT are currently
+   redundant as the values are not used.  But one day they may be needed
+   and so the tests remain.  */
+#elif __INTPTR_TYPE__ == 2
+#define _INTPTR_EQ_INT
+#elif (__INTPTR_TYPE__ == 1 || __INTPTR_TYPE__ == 3)
+#define _INTPTR_EQ_SHORT
+#else
+#error "Unable to determine type definition of intptr_t"
+#endif
+#if (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6)
+#define _INT32_EQ_LONG
+#elif __INT32_TYPE__ == 2
+/* Nothing to define because int32_t is safe to print as an int. */
+#else
+#error "Unable to determine type definition of int32_t"
+#endif
+
+#if (__INT8_TYPE__ == 0)
+#define __INT8 "hh"
+#elif (__INT8_TYPE__ == 1 || __INT8_TYPE__ == 3)
+#define __INT8 "h"
+#elif (__INT8_TYPE__ == 2)
+#define __INT8
+#elif (__INT8_TYPE__ == 4 || __INT8_TYPE__ == 6)
+#define __INT8 "l"
+#elif (__INT8_TYPE__ == 8 || __INT8_TYPE__ == 10)
+#define __INT8 "ll"
+#endif
+#if (__INT16_TYPE__ == 1 || __INT16_TYPE__ == 3)
+#define __INT16 "h"
+#elif (__INT16_TYPE__ == 2)
+#define __INT16
+#elif (__INT16_TYPE__ == 4 || __INT16_TYPE__ == 6)
+#define __INT16 "l"
+#elif (__INT16_TYPE__ == 8 || __INT16_TYPE__ == 10)
+#define __INT16 "ll"
+#endif
+#if (__INT32_TYPE__ == 2)
+#define __INT32
+#elif (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6)
+/**
+ * Definition of __INT32 had to be changed since to avoid format warnings/
+ * errors since xtensa-lx106-elf-gcc defines *__INT32_TYPE__* as *long int*
+ * while newlib defines *int32_t* as *signed int*. PRI*32 there throw format
+ * warnings/errors.
+ */
+#if 0
+#define __INT32 "l"
+#else
+#define __INT32
+#endif
+#elif (__INT32_TYPE__ == 8 || __INT32_TYPE__ == 10)
+#define __INT32 "ll"
+#endif
+#if (__INT64_TYPE__ == 2)
+#define __INT64
+#elif (__INT64_TYPE__ == 4 || __INT64_TYPE__ == 6)
+#define __INT64 "l"
+#elif (__INT64_TYPE__ == 8 || __INT64_TYPE__ == 10)
+#define __INT64 "ll"
+#endif
+#if (__INT_FAST8_TYPE__ == 0)
+#define __FAST8 "hh"
+#elif (__INT_FAST8_TYPE__ == 1 || __INT_FAST8_TYPE__ == 3)
+#define __FAST8 "h"
+#elif (__INT_FAST8_TYPE__ == 2)
+#define __FAST8
+#elif (__INT_FAST8_TYPE__ == 4 || __INT_FAST8_TYPE__ == 6)
+#define __FAST8 "l"
+#elif (__INT_FAST8_TYPE__ == 8 || __INT_FAST8_TYPE__ == 10)
+#define __FAST8 "ll"
+#endif
+#if (__INT_FAST16_TYPE__ == 1 || __INT_FAST16_TYPE__ == 3)
+#define __FAST16 "h"
+#elif (__INT_FAST16_TYPE__ == 2)
+#define __FAST16
+#elif (__INT_FAST16_TYPE__ == 4 || __INT_FAST16_TYPE__ == 6)
+#define __FAST16 "l"
+#elif (__INT_FAST16_TYPE__ == 8 || __INT_FAST16_TYPE__ == 10)
+#define __FAST16 "ll"
+#endif
+#if (__INT_FAST32_TYPE__ == 2)
+#define __FAST32
+#elif (__INT_FAST32_TYPE__ == 4 || __INT_FAST32_TYPE__ == 6)
+#define __FAST32 "l"
+#elif (__INT_FAST32_TYPE__ == 8 || __INT_FAST32_TYPE__ == 10)
+#define __FAST32 "ll"
+#endif
+#if (__INT_FAST64_TYPE__ == 2)
+#define __FAST64
+#elif (__INT_FAST64_TYPE__ == 4 || __INT_FAST64_TYPE__ == 6)
+#define __FAST64 "l"
+#elif (__INT_FAST64_TYPE__ == 8 || __INT_FAST64_TYPE__ == 10)
+#define __FAST64 "ll"
+#endif
+
+#if (__INT_LEAST8_TYPE__ == 0)
+#define __LEAST8 "hh"
+#elif (__INT_LEAST8_TYPE__ == 1 || __INT_LEAST8_TYPE__ == 3)
+#define __LEAST8 "h"
+#elif (__INT_LEAST8_TYPE__ == 2)
+#define __LEAST8
+#elif (__INT_LEAST8_TYPE__ == 4 || __INT_LEAST8_TYPE__ == 6)
+#define __LEAST8 "l"
+#elif (__INT_LEAST8_TYPE__ == 8 || __INT_LEAST8_TYPE__ == 10)
+#define __LEAST8 "ll"
+#endif
+#if (__INT_LEAST16_TYPE__ == 1 || __INT_LEAST16_TYPE__ == 3)
+#define __LEAST16 "h"
+#elif (__INT_LEAST16_TYPE__ == 2)
+#define __LEAST16
+#elif (__INT_LEAST16_TYPE__ == 4 || __INT_LEAST16_TYPE__ == 6)
+#define __LEAST16 "l"
+#elif (__INT_LEAST16_TYPE__ == 8 || __INT_LEAST16_TYPE__ == 10)
+#define __LEAST16 "ll"
+#endif
+#if (__INT_LEAST32_TYPE__ == 2)
+#define __LEAST32
+#elif (__INT_LEAST32_TYPE__ == 4 || __INT_LEAST32_TYPE__ == 6)
+#define __LEAST32 "l"
+#elif (__INT_LEAST32_TYPE__ == 8 || __INT_LEAST32_TYPE__ == 10)
+#define __LEAST32 "ll"
+#endif
+#if (__INT_LEAST64_TYPE__ == 2)
+#define __LEAST64
+#elif (__INT_LEAST64_TYPE__ == 4 || __INT_LEAST64_TYPE__ == 6)
+#define __LEAST64 "l"
+#elif (__INT_LEAST64_TYPE__ == 8 || __INT_LEAST64_TYPE__ == 10)
+#define __LEAST64 "ll"
+#endif
+#undef signed
+#undef unsigned
+#undef char
+#undef short
+#undef int
+#undef long
+#pragma pop_macro("signed")
+#pragma pop_macro("unsigned")
+#pragma pop_macro("char")
+#pragma pop_macro("short")
+#pragma pop_macro("__int20")
+#pragma pop_macro("int")
+#pragma pop_macro("long")
+
+#endif /* _SYS__INTSUP_H */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* SYS__INTSUP_H */
diff --git a/cpu/esp8266/include/syscalls.h b/cpu/esp8266/include/syscalls.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf5249f58a770bd25b3e3ded63654c35b9b65f1f
--- /dev/null
+++ b/cpu/esp8266/include/syscalls.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of required system calls
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#ifndef SYSCALLS_H
+#define SYSCALLS_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Necessary initializations of system call functions */
+extern void syscalls_init (void);
+
+/** System standard printf function */
+extern int printf(const char* format, ...);
+
+/** System standard puts function */
+extern int puts(const char * str);
+
+/** Determine free heap size */
+extern unsigned int get_free_heap_size (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYSCALLS_H */
diff --git a/cpu/esp8266/include/thread_arch.h b/cpu/esp8266/include/thread_arch.h
new file mode 100644
index 0000000000000000000000000000000000000000..b525a6d94cb6b2a7b74ba4eea10efde7d96ca189
--- /dev/null
+++ b/cpu/esp8266/include/thread_arch.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the kernel's architecture dependent thread interface
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#ifndef THREAD_ARCH_H
+#define THREAD_ARCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Initializes the ISR stack
+ * Initializes the ISR stack with predefined values (address value) to be able to
+ * measure used ISR stack size.
+ */
+extern void thread_isr_stack_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* THREAD_ARCH_H */
diff --git a/cpu/esp8266/include/tools.h b/cpu/esp8266/include/tools.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6a6f650bf40a1bb64abdba3423a20e7b0778970
--- /dev/null
+++ b/cpu/esp8266/include/tools.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of some tools
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#ifndef TOOLS_H
+#define TOOLS_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Hexdump of memory
+ * @param[in]  addr      start address in memory
+ * @param[in]  num       number of items to dump
+ * @param[in]  width     format of the items
+ * @param[in]  per_line  number of items per line
+ */
+extern void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TOOLS_H */
diff --git a/cpu/esp8266/include/user_config.h b/cpu/esp8266/include/user_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a53d4e0f057002d1eed08eac38c4cca623cc121
--- /dev/null
+++ b/cpu/esp8266/include/user_config.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 USER_CONFIG_H
+#define USER_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This file is just to satisfy SDK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USER_CONFIG_H */
diff --git a/cpu/esp8266/include/xtensa_conf.h b/cpu/esp8266/include/xtensa_conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..d622428bb4be2b867ad4fc8ab1c5147bf90d42c6
--- /dev/null
+++ b/cpu/esp8266/include/xtensa_conf.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Xtensa ASM code specific configuration options
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#ifndef XTENSA_CONF_H
+#define XTENSA_CONF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Xtensa ASM code specific default stack sizes
+ * @{
+ */
+#if defined(MODULE_ESP_SDK_INT_HANDLING)
+#define ISR_STACKSIZE                 (8)
+#else
+#define ISR_STACKSIZE                 (2048)
+#endif
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* XTENSA_CONF_H */
+/** @} */
diff --git a/cpu/esp8266/irq_arch.c b/cpu/esp8266/irq_arch.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7563b5d54a9428fab7d35dddf60eeaf70ccc0d4
--- /dev/null
+++ b/cpu/esp8266/irq_arch.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the kernels irq interface
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG    0
+#include "debug.h"
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "irq.h"
+#include "cpu.h"
+
+#include "common.h"
+#include "esp/common_macros.h"
+#include "esp/xtensa_ops.h"
+#include "sdk/ets.h"
+#include "xtensa/xtensa_context.h"
+
+/**
+ * @brief Set on entry into and reset on exit from an ISR
+ */
+volatile uint32_t irq_interrupt_nesting = 0;
+
+/**
+ * @brief Disable all maskable interrupts
+ */
+unsigned int IRAM irq_disable(void)
+{
+    uint32_t _saved_interrupt_level;
+
+    /* read and set interrupt level (RSIL) */
+    __asm__ volatile ("rsil %0, " XTSTR(XCHAL_NUM_INTLEVELS+1) : "=a" (_saved_interrupt_level));
+    DEBUG ("%s %02x(%02x)\n", __func__,
+           (_saved_interrupt_level & 0xfffffff0) | (XCHAL_NUM_INTLEVELS+1),
+           _saved_interrupt_level);
+    return _saved_interrupt_level;
+}
+
+/**
+ * @brief Enable all maskable interrupts
+ */
+unsigned int IRAM irq_enable(void)
+{
+    uint32_t _saved_interrupt_level;
+
+    /* read and set interrupt level (RSIL) */
+    __asm__ volatile ("rsil %0, 0" : "=a" (_saved_interrupt_level));
+    DEBUG ("%s %02x(%02x)\n", __func__,
+           _saved_interrupt_level & 0xfffffff0, _saved_interrupt_level);
+    return _saved_interrupt_level;
+}
+
+/**
+ * @brief Restore the state of the IRQ flags
+ */
+void IRAM irq_restore(unsigned int state)
+{
+    /* write interrupt level and sync */
+    DEBUG ("%s %02x\n", __func__, state);
+    __asm__ volatile ("wsr %0, ps; rsync" :: "a" (state));
+}
+
+/**
+ * @brief See if the current context is inside an ISR
+ */
+int IRAM irq_is_in(void)
+{
+    DEBUG("irq_interrupt_nesting = %d\n", irq_interrupt_nesting);
+    return irq_interrupt_nesting;
+}
diff --git a/cpu/esp8266/ld/eagle.rom.addr.v6.ld b/cpu/esp8266/ld/eagle.rom.addr.v6.ld
new file mode 100644
index 0000000000000000000000000000000000000000..282acfe168e2ed59ce6616765c5b6a9d23d6650a
--- /dev/null
+++ b/cpu/esp8266/ld/eagle.rom.addr.v6.ld
@@ -0,0 +1,350 @@
+PROVIDE ( Cache_Read_Disable = 0x400047f0 );
+PROVIDE ( Cache_Read_Enable = 0x40004678 );
+PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 );
+PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c );
+PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 );
+PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 );
+PROVIDE ( GetUartDevice = 0x40003f4c );
+PROVIDE ( MD5Final = 0x40009900 );
+PROVIDE ( MD5Init = 0x40009818 );
+PROVIDE ( MD5Update = 0x40009834 );
+PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 );
+PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c );
+PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 );
+PROVIDE ( RcvMsg = 0x40003eac );
+PROVIDE ( SHA1Final = 0x4000b648 );
+PROVIDE ( SHA1Init = 0x4000b584 );
+PROVIDE ( SHA1Transform = 0x4000a364 );
+PROVIDE ( SHA1Update = 0x4000b5a8 );
+PROVIDE ( SPI_read_status = 0x400043c8 );
+PROVIDE ( SPI_write_status = 0x40004400 );
+PROVIDE ( SPI_write_enable = 0x4000443c );
+PROVIDE ( Wait_SPI_Idle = 0x4000448c );
+PROVIDE ( Enable_QMode = 0x400044c0 );
+PROVIDE ( SPIEraseArea = 0x40004b44 );
+PROVIDE ( SPIEraseBlock = 0x400049b4 );
+PROVIDE ( SPIEraseChip = 0x40004984 );
+PROVIDE ( SPIEraseSector = 0x40004a00 );
+PROVIDE ( SPILock = 0x400048a8 );
+PROVIDE ( SPIParamCfg = 0x40004c2c );
+PROVIDE ( SPIRead = 0x40004b1c );
+PROVIDE ( SPIReadModeCnfig = 0x400048ec );
+PROVIDE ( SPIUnlock = 0x40004878 );
+PROVIDE ( SPIWrite = 0x40004a4c );
+PROVIDE ( SelectSpiFunction = 0x40003f58 );
+PROVIDE ( SendMsg = 0x40003cf4 );
+PROVIDE ( UartConnCheck = 0x40003230 );
+PROVIDE ( UartConnectProc = 0x400037a0 );
+PROVIDE ( UartDwnLdProc = 0x40003368 );
+PROVIDE ( UartGetCmdLn = 0x40003ef4 );
+PROVIDE ( UartRegReadProc = 0x4000381c );
+PROVIDE ( UartRegWriteProc = 0x400037ac );
+PROVIDE ( UartRxString = 0x40003c30 );
+PROVIDE ( Uart_Init = 0x40003a14 );
+PROVIDE ( _DebugExceptionVector = 0x40000010 );
+PROVIDE ( _DoubleExceptionVector = 0x40000070 );
+PROVIDE ( _KernelExceptionVector = 0x40000030 );
+PROVIDE ( _NMIExceptionVector = 0x40000020 );
+PROVIDE ( _ResetHandler = 0x400000a4 );
+PROVIDE ( _ResetVector = 0x40000080 );
+PROVIDE ( _UserExceptionVector = 0x40000050 );
+PROVIDE ( __adddf3 = 0x4000c538 );
+PROVIDE ( __addsf3 = 0x4000c180 );
+PROVIDE ( __divdf3 = 0x4000cb94 );
+PROVIDE ( __divdi3 = 0x4000ce60 );
+PROVIDE ( __divsi3 = 0x4000dc88 );
+PROVIDE ( __extendsfdf2 = 0x4000cdfc );
+PROVIDE ( __fixdfsi = 0x4000ccb8 );
+PROVIDE ( __fixunsdfsi = 0x4000cd00 );
+PROVIDE ( __fixunssfsi = 0x4000c4c4 );
+PROVIDE ( __floatsidf = 0x4000e2f0 );
+PROVIDE ( __floatsisf = 0x4000e2ac );
+PROVIDE ( __floatunsidf = 0x4000e2e8 );
+PROVIDE ( __floatunsisf = 0x4000e2a4 );
+PROVIDE ( __muldf3 = 0x4000c8f0 );
+PROVIDE ( __muldi3 = 0x40000650 );
+PROVIDE ( __mulsf3 = 0x4000c3dc );
+PROVIDE ( __subdf3 = 0x4000c688 );
+PROVIDE ( __subsf3 = 0x4000c268 );
+PROVIDE ( __truncdfsf2 = 0x4000cd5c );
+PROVIDE ( __udivdi3 = 0x4000d310 );
+PROVIDE ( __udivsi3 = 0x4000e21c );
+PROVIDE ( __umoddi3 = 0x4000d770 );
+PROVIDE ( __umodsi3 = 0x4000e268 );
+PROVIDE ( __umulsidi3 = 0x4000dcf0 );
+PROVIDE ( _rom_store = 0x4000e388 );
+PROVIDE ( _rom_store_table = 0x4000e328 );
+PROVIDE ( _start = 0x4000042c );
+PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 );
+PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 );
+PROVIDE ( _xtos_cause3_handler = 0x40000590 );
+PROVIDE ( _xtos_ints_off = 0x4000bda4 );
+PROVIDE ( _xtos_ints_on = 0x4000bd84 );
+PROVIDE ( _xtos_l1int_handler = 0x4000048c );
+PROVIDE ( _xtos_p_none = 0x4000dbf8 );
+PROVIDE ( _xtos_restore_intlevel = 0x4000056c );
+PROVIDE ( _xtos_return_from_exc = 0x4000dc54 );
+PROVIDE ( _xtos_set_exception_handler = 0x40000454 );
+PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 );
+PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 );
+PROVIDE ( _xtos_set_intlevel = 0x4000dbfc );
+PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 );
+PROVIDE ( _xtos_set_vpri = 0x40000574 );
+PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 );
+PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 );
+PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c );
+PROVIDE ( aes_decrypt = 0x400092d4 );
+PROVIDE ( aes_decrypt_deinit = 0x400092e4 );
+PROVIDE ( aes_decrypt_init = 0x40008ea4 );
+PROVIDE ( aes_unwrap = 0x40009410 );
+PROVIDE ( base64_decode = 0x40009648 );
+PROVIDE ( base64_encode = 0x400094fc );
+PROVIDE ( bzero = 0x4000de84 );
+PROVIDE ( cmd_parse = 0x40000814 );
+PROVIDE ( conv_str_decimal = 0x40000b24 );
+PROVIDE ( conv_str_hex = 0x40000cb8 );
+PROVIDE ( convert_para_str = 0x40000a60 );
+PROVIDE ( dtm_get_intr_mask = 0x400026d0 );
+PROVIDE ( dtm_params_init = 0x4000269c );
+PROVIDE ( dtm_set_intr_mask = 0x400026c8 );
+PROVIDE ( dtm_set_params = 0x400026dc );
+PROVIDE ( eprintf = 0x40001d14 );
+PROVIDE ( eprintf_init_buf = 0x40001cb8 );
+PROVIDE ( eprintf_to_host = 0x40001d48 );
+PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 );
+PROVIDE ( est_reset_printf_buf_len = 0x4000249c );
+PROVIDE ( ets_bzero = 0x40002ae8 );
+PROVIDE ( ets_char2xdigit = 0x40002b74 );
+PROVIDE ( ets_delay_us = 0x40002ecc );
+PROVIDE ( ets_enter_sleep = 0x400027b8 );
+PROVIDE ( ets_external_printf = 0x40002578 );
+PROVIDE ( ets_get_cpu_frequency = 0x40002f0c );
+PROVIDE ( ets_getc = 0x40002bcc );
+PROVIDE ( ets_install_external_printf = 0x40002450 );
+PROVIDE ( ets_install_putc1 = 0x4000242c );
+PROVIDE ( ets_install_putc2 = 0x4000248c );
+PROVIDE ( ets_install_uart_printf = 0x40002438 );
+PROVIDE ( ets_intr_lock = 0x40000f74 );
+PROVIDE ( ets_intr_unlock = 0x40000f80 );
+PROVIDE ( ets_isr_attach = 0x40000f88 );
+PROVIDE ( ets_isr_mask = 0x40000f98 );
+PROVIDE ( ets_isr_unmask = 0x40000fa8 );
+PROVIDE ( ets_memcmp = 0x400018d4 );
+PROVIDE ( ets_memcpy = 0x400018b4 );
+PROVIDE ( ets_memmove = 0x400018c4 );
+PROVIDE ( ets_memset = 0x400018a4 );
+PROVIDE ( ets_post = 0x40000e24 );
+PROVIDE ( ets_printf = 0x400024cc );
+PROVIDE ( ets_putc = 0x40002be8 );
+PROVIDE ( ets_rtc_int_register = 0x40002a40 );
+PROVIDE ( ets_run = 0x40000e04 );
+PROVIDE ( ets_set_idle_cb = 0x40000dc0 );
+PROVIDE ( ets_set_user_start = 0x40000fbc );
+PROVIDE ( ets_str2macaddr = 0x40002af8 );
+PROVIDE ( ets_strcmp = 0x40002aa8 );
+PROVIDE ( ets_strcpy = 0x40002a88 );
+PROVIDE ( ets_strlen = 0x40002ac8 );
+PROVIDE ( ets_strncmp = 0x40002ab8 );
+PROVIDE ( ets_strncpy = 0x40002a98 );
+PROVIDE ( ets_strstr = 0x40002ad8 );
+PROVIDE ( ets_task = 0x40000dd0 );
+PROVIDE ( ets_timer_arm = 0x40002cc4 );
+PROVIDE ( ets_timer_disarm = 0x40002d40 );
+PROVIDE ( ets_timer_done = 0x40002d80 );
+PROVIDE ( ets_timer_handler_isr = 0x40002da8 );
+PROVIDE ( ets_timer_init = 0x40002e68 );
+PROVIDE ( ets_timer_setfn = 0x40002c48 );
+PROVIDE ( ets_uart_printf = 0x40002544 );
+PROVIDE ( ets_update_cpu_frequency = 0x40002f04 );
+PROVIDE ( ets_vprintf = 0x40001f00 );
+PROVIDE ( ets_wdt_disable = 0x400030f0 );
+PROVIDE ( ets_wdt_enable = 0x40002fa0 );
+PROVIDE ( ets_wdt_get_mode = 0x40002f34 );
+PROVIDE ( ets_wdt_init = 0x40003170 );
+PROVIDE ( ets_wdt_restore = 0x40003158 );
+PROVIDE ( ets_write_char = 0x40001da0 );
+PROVIDE ( get_first_seg = 0x4000091c );
+PROVIDE ( gpio_init = 0x40004c50 );
+PROVIDE ( gpio_input_get = 0x40004cf0 );
+PROVIDE ( gpio_intr_ack = 0x40004dcc );
+PROVIDE ( gpio_intr_handler_register = 0x40004e28 );
+PROVIDE ( gpio_intr_pending = 0x40004d88 );
+PROVIDE ( gpio_intr_test = 0x40004efc );
+PROVIDE ( gpio_output_set = 0x40004cd0 );
+PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 );
+PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 );
+PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 );
+PROVIDE ( gpio_register_get = 0x40004d5c );
+PROVIDE ( gpio_register_set = 0x40004d04 );
+PROVIDE ( hmac_md5 = 0x4000a2cc );
+PROVIDE ( hmac_md5_vector = 0x4000a160 );
+PROVIDE ( hmac_sha1 = 0x4000ba28 );
+PROVIDE ( hmac_sha1_vector = 0x4000b8b4 );
+PROVIDE ( lldesc_build_chain = 0x40004f40 );
+PROVIDE ( lldesc_num2link = 0x40005050 );
+PROVIDE ( lldesc_set_owner = 0x4000507c );
+PROVIDE ( main = 0x40000fec );
+PROVIDE ( md5_vector = 0x400097ac );
+PROVIDE ( mem_calloc = 0x40001c2c );
+PROVIDE ( mem_free = 0x400019e0 );
+PROVIDE ( mem_init = 0x40001998 );
+PROVIDE ( mem_malloc = 0x40001b40 );
+PROVIDE ( mem_realloc = 0x40001c6c );
+PROVIDE ( mem_trim = 0x40001a14 );
+PROVIDE ( mem_zalloc = 0x40001c58 );
+PROVIDE ( memcmp = 0x4000dea8 );
+PROVIDE ( memcpy = 0x4000df48 );
+PROVIDE ( memmove = 0x4000e04c );
+PROVIDE ( memset = 0x4000e190 );
+PROVIDE ( multofup = 0x400031c0 );
+PROVIDE ( pbkdf2_sha1 = 0x4000b840 );
+PROVIDE ( phy_get_romfuncs = 0x40006b08 );
+PROVIDE ( rand = 0x40000600 );
+PROVIDE ( rc4_skip = 0x4000dd68 );
+PROVIDE ( recv_packet = 0x40003d08 );
+PROVIDE ( remove_head_space = 0x40000a04 );
+PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 );
+PROVIDE ( rijndaelKeySetupEnc = 0x40009300 );
+PROVIDE ( rom_abs_temp = 0x400060c0 );
+PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 );
+PROVIDE ( rom_cal_tos_v50 = 0x40007a28 );
+PROVIDE ( rom_chip_50_set_channel = 0x40006f84 );
+PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 );
+PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec );
+PROVIDE ( rom_chip_v5_rx_init = 0x4000711c );
+PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c );
+PROVIDE ( rom_chip_v5_tx_init = 0x4000718c );
+PROVIDE ( rom_dc_iq_est = 0x4000615c );
+PROVIDE ( rom_en_pwdet = 0x400061b8 );
+PROVIDE ( rom_get_bb_atten = 0x40006238 );
+PROVIDE ( rom_get_corr_power = 0x40006260 );
+PROVIDE ( rom_get_fm_sar_dout = 0x400062dc );
+PROVIDE ( rom_get_noisefloor = 0x40006394 );
+PROVIDE ( rom_get_power_db = 0x400063b0 );
+PROVIDE ( rom_i2c_readReg = 0x40007268 );
+PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c );
+PROVIDE ( rom_i2c_writeReg = 0x400072d8 );
+PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c );
+PROVIDE ( rom_iq_est_disable = 0x40006400 );
+PROVIDE ( rom_iq_est_enable = 0x40006430 );
+PROVIDE ( rom_linear_to_db = 0x40006484 );
+PROVIDE ( rom_mhz2ieee = 0x400065a4 );
+PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 );
+PROVIDE ( rom_pbus_debugmode = 0x4000737c );
+PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 );
+PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 );
+PROVIDE ( rom_pbus_force_test = 0x4000747c );
+PROVIDE ( rom_pbus_rd = 0x400074d8 );
+PROVIDE ( rom_pbus_set_rxgain = 0x4000754c );
+PROVIDE ( rom_pbus_set_txgain = 0x40007610 );
+PROVIDE ( rom_pbus_workmode = 0x40007648 );
+PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 );
+PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc );
+PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc );
+PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 );
+PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 );
+PROVIDE ( rom_phy_reset_req = 0x40007804 );
+PROVIDE ( rom_restart_cal = 0x4000781c );
+PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 );
+PROVIDE ( rom_rfcal_rxiq = 0x4000804c );
+PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 );
+PROVIDE ( rom_rfcal_txcap = 0x40008388 );
+PROVIDE ( rom_rfcal_txiq = 0x40008610 );
+PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 );
+PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 );
+PROVIDE ( rom_rfpll_reset = 0x40007868 );
+PROVIDE ( rom_rfpll_set_freq = 0x40007968 );
+PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c );
+PROVIDE ( rom_rxiq_get_mis = 0x40006628 );
+PROVIDE ( rom_sar_init = 0x40006738 );
+PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c );
+PROVIDE ( rom_set_channel_freq = 0x40006c50 );
+PROVIDE ( rom_set_loopback_gain = 0x400067c8 );
+PROVIDE ( rom_set_noise_floor = 0x40006830 );
+PROVIDE ( rom_set_rxclk_en = 0x40006550 );
+PROVIDE ( rom_set_txbb_atten = 0x40008c6c );
+PROVIDE ( rom_set_txclk_en = 0x4000650c );
+PROVIDE ( rom_set_txiq_cal = 0x40008d34 );
+PROVIDE ( rom_start_noisefloor = 0x40006874 );
+PROVIDE ( rom_start_tx_tone = 0x400068b4 );
+PROVIDE ( rom_stop_tx_tone = 0x4000698c );
+PROVIDE ( rom_tx_mac_disable = 0x40006a98 );
+PROVIDE ( rom_tx_mac_enable = 0x40006ad4 );
+PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c );
+PROVIDE ( rom_write_rfpll_sdm = 0x400078dc );
+PROVIDE ( roundup2 = 0x400031b4 );
+PROVIDE ( rtc_enter_sleep = 0x40002870 );
+PROVIDE ( rtc_get_reset_reason = 0x400025e0 );
+PROVIDE ( rtc_intr_handler = 0x400029ec );
+PROVIDE ( rtc_set_sleep_mode = 0x40002668 );
+PROVIDE ( save_rxbcn_mactime = 0x400027a4 );
+PROVIDE ( save_tsf_us = 0x400027ac );
+PROVIDE ( send_packet = 0x40003c80 );
+PROVIDE ( sha1_prf = 0x4000ba48 );
+PROVIDE ( sha1_vector = 0x4000a2ec );
+PROVIDE ( sip_alloc_to_host_evt = 0x40005180 );
+PROVIDE ( sip_get_ptr = 0x400058a8 );
+PROVIDE ( sip_get_state = 0x40005668 );
+PROVIDE ( sip_init_attach = 0x4000567c );
+PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c );
+PROVIDE ( sip_install_rx_data_cb = 0x4000545c );
+PROVIDE ( sip_post = 0x400050fc );
+PROVIDE ( sip_post_init = 0x400056c4 );
+PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c );
+PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 );
+PROVIDE ( sip_send = 0x40005808 );
+PROVIDE ( sip_to_host_chain_append = 0x40005864 );
+PROVIDE ( sip_to_host_evt_send_done = 0x40005234 );
+PROVIDE ( slc_add_credits = 0x400060ac );
+PROVIDE ( slc_enable = 0x40005d90 );
+PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 );
+PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 );
+PROVIDE ( slc_init_attach = 0x40005c50 );
+PROVIDE ( slc_init_credit = 0x4000608c );
+PROVIDE ( slc_pause_from_host = 0x40006014 );
+PROVIDE ( slc_reattach = 0x40005c1c );
+PROVIDE ( slc_resume_from_host = 0x4000603c );
+PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 );
+PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 );
+PROVIDE ( slc_send_to_host_chain = 0x40005de4 );
+PROVIDE ( slc_set_host_io_max_window = 0x40006068 );
+PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 );
+PROVIDE ( software_reset = 0x4000264c );
+PROVIDE ( spi_flash_attach = 0x40004644 );
+PROVIDE ( srand = 0x400005f0 );
+PROVIDE ( strcmp = 0x4000bdc8 );
+PROVIDE ( strcpy = 0x4000bec8 );
+PROVIDE ( strlen = 0x4000bf4c );
+PROVIDE ( strncmp = 0x4000bfa8 );
+PROVIDE ( strncpy = 0x4000c0a0 );
+PROVIDE ( strstr = 0x4000e1e0 );
+PROVIDE ( timer_insert = 0x40002c64 );
+PROVIDE ( uartAttach = 0x4000383c );
+PROVIDE ( uart_baudrate_detect = 0x40003924 );
+PROVIDE ( uart_buff_switch = 0x400038a4 );
+PROVIDE ( uart_div_modify = 0x400039d8 );
+PROVIDE ( uart_rx_intr_handler = 0x40003bbc );
+PROVIDE ( uart_rx_one_char = 0x40003b8c );
+PROVIDE ( uart_rx_one_char_block = 0x40003b64 );
+PROVIDE ( uart_rx_readbuff = 0x40003ec8 );
+PROVIDE ( uart_tx_one_char = 0x40003b30 );
+PROVIDE ( wepkey_128 = 0x4000bc40 );
+PROVIDE ( wepkey_64 = 0x4000bb3c );
+PROVIDE ( xthal_bcopy = 0x40000688 );
+PROVIDE ( xthal_copy123 = 0x4000074c );
+PROVIDE ( xthal_get_ccompare = 0x4000dd4c );
+PROVIDE ( xthal_get_ccount = 0x4000dd38 );
+PROVIDE ( xthal_get_interrupt = 0x4000dd58 );
+PROVIDE ( xthal_get_intread = 0x4000dd58 );
+PROVIDE ( xthal_memcpy = 0x400006c4 );
+PROVIDE ( xthal_set_ccompare = 0x4000dd40 );
+PROVIDE ( xthal_set_intclear = 0x4000dd60 );
+PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 );
+PROVIDE ( xthal_window_spill = 0x4000e324 );
+PROVIDE ( xthal_window_spill_nw = 0x4000e320 );
+
+PROVIDE ( Te0 = 0x3fffccf0 );
+PROVIDE ( Td0 = 0x3fffd100 );
+PROVIDE ( Td4s = 0x3fffd500);
+PROVIDE ( rcons = 0x3fffd0f0);
+PROVIDE ( UartDev = 0x3fffde10 );
diff --git a/cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld b/cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld
new file mode 100644
index 0000000000000000000000000000000000000000..e7b7e0d550d7db4039d64fd19ed81435fd9c76a1
--- /dev/null
+++ b/cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld
@@ -0,0 +1,295 @@
+/**
+  * This linker script is a modified version of eagle.app.v6.ld that
+  * was generated from xt-genldscripts.tpp for LSP and shipped with
+  * ESP8266_NONOS_SDK
+  */
+
+/* Linker Script for ld -N */
+
+MEMORY
+{
+  dport0_0_seg : org = 0x3FF00000, len = 0x10
+  dram0_0_seg :  org = 0x3FFE8000, len = 0x14000
+  iram1_0_seg :  org = 0x40100000, len = 0x8000
+  irom0_0_seg :  org = 0x40210000, len = 0x5C000
+}
+
+PHDRS
+{
+  dport0_0_phdr PT_LOAD;
+  dram0_0_phdr PT_LOAD;
+  dram0_0_bss_phdr PT_LOAD;
+  iram1_0_phdr PT_LOAD;
+  irom0_0_phdr PT_LOAD;
+}
+
+
+/*  Default entry point:  */
+ENTRY(_call_user_start)
+EXTERN(_DebugExceptionVector)
+EXTERN(_DoubleExceptionVector)
+EXTERN(_KernelExceptionVector)
+EXTERN(_NMIExceptionVector)
+EXTERN(_UserExceptionVector)
+PROVIDE(_memmap_vecbase_reset = 0x40000000);
+/* Various memory-map dependent cache attribute settings: */
+_memmap_cacheattr_wb_base = 0x00000110;
+_memmap_cacheattr_wt_base = 0x00000110;
+_memmap_cacheattr_bp_base = 0x00000220;
+_memmap_cacheattr_unused_mask = 0xFFFFF00F;
+_memmap_cacheattr_wb_trapnull = 0x2222211F;
+_memmap_cacheattr_wba_trapnull = 0x2222211F;
+_memmap_cacheattr_wbna_trapnull = 0x2222211F;
+_memmap_cacheattr_wt_trapnull = 0x2222211F;
+_memmap_cacheattr_bp_trapnull = 0x2222222F;
+_memmap_cacheattr_wb_strict = 0xFFFFF11F;
+_memmap_cacheattr_wt_strict = 0xFFFFF11F;
+_memmap_cacheattr_bp_strict = 0xFFFFF22F;
+_memmap_cacheattr_wb_allvalid = 0x22222112;
+_memmap_cacheattr_wt_allvalid = 0x22222112;
+_memmap_cacheattr_bp_allvalid = 0x22222222;
+PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
+
+/* ROM variables */
+/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */
+PROVIDE( ets_task_min_prio = 0x3fffc6fc );
+PROVIDE( ets_idle_cb = 0x3fffdab0 );
+PROVIDE( ets_idle_arg = 0x3fffdab4 );
+PROVIDE( ets_task_exec_mask = 0x3fffdab8 );
+PROVIDE( ets_task_tab = 0x3fffdac0 );
+PROVIDE( flashchip = 0x3fffc714 );
+PROVIDE( sdk_flashchip = 0x3fffc718 );
+PROVIDE( ets_phy_mactime = 0x3ff20a00 );
+
+SECTIONS
+{
+
+  .dport0.rodata : ALIGN(4)
+  {
+    _dport0_rodata_start = ABSOLUTE(.);
+    *(.dport0.rodata)
+    *(.dport.rodata)
+    _dport0_rodata_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .dport0.literal : ALIGN(4)
+  {
+    _dport0_literal_start = ABSOLUTE(.);
+    *(.dport0.literal)
+    *(.dport.literal)
+    _dport0_literal_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .dport0.data : ALIGN(4)
+  {
+    _dport0_data_start = ABSOLUTE(.);
+    *(.dport0.data)
+    *(.dport.data)
+    _dport0_data_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .data : ALIGN(4)
+  {
+    _data_start = ABSOLUTE(.);
+    *(.data)
+    *(.data.*)
+    *(.gnu.linkonce.d.*)
+    *(.data1)
+    *(.sdata)
+    *(.sdata.*)
+    *(.gnu.linkonce.s.*)
+    *(.sdata2)
+    *(.sdata2.*)
+    *(.gnu.linkonce.s2.*)
+    *(.jcr)
+    _data_end = ABSOLUTE(.);
+  } >dram0_0_seg :dram0_0_phdr
+
+  .rodata : ALIGN(4)
+  {
+    _rodata_start = ABSOLUTE(.);
+    *(.sdk.version)
+    /* TODO put only necessary .rodata to dram
+    *libc.a:*.o(.rodata.* .rodata)
+    *core.a:*(.rodata.* .rodata)
+    *cpu.a:*(.rodata .rodata.*)
+    */
+    *(.rodata .rodata.*)
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
+    *(.xt_except_table)
+    *(.gcc_except_table)
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    *(.eh_frame)
+    /*  C++ constructor and destructor tables, properly ordered:  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    /*  C++ exception handlers table:  */
+    __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    . = ALIGN(4);		/* this table MUST be 4-byte aligned */
+    _bss_table_start = ABSOLUTE(.);
+    LONG(_bss_start)
+    LONG(_bss_end)
+    _bss_table_end = ABSOLUTE(.);
+    _rodata_end = ABSOLUTE(.);
+  } >dram0_0_seg :dram0_0_phdr
+
+  .bss ALIGN(8) (NOLOAD) : ALIGN(4)
+  {
+    . = ALIGN (8);
+    _bss_start = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    *(.bss)
+    *(.bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    . = ALIGN (8);
+    _bss_end = ABSOLUTE(.);
+    _sheap = ABSOLUTE(.);
+    _heap_start = ABSOLUTE(.);
+
+  } >dram0_0_seg :dram0_0_bss_phdr
+
+  /* ETS system memory starts at 0x3FFFC000 which is the top of the heap for the app */
+  . = 0x3FFFC000;
+  _heap_top = ABSOLUTE(.);
+  _eheap = ABSOLUTE(.);
+
+  .text : ALIGN(4)
+  {
+    _stext = .;
+    _text_start = ABSOLUTE(.);
+    *(.UserEnter.text)
+    . = ALIGN(16);
+    *(.DebugExceptionVector.text)
+    . = ALIGN(16);
+    *(.NMIExceptionVector.text)
+    . = ALIGN(16);
+    *(.KernelExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN(16);
+    *(.UserExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN(16);
+    *(.DoubleExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN (16);
+    *(.entry.text)
+    *(.init.literal)
+    *(.init)
+
+    /* normal code should be in irom0 */
+    /*
+    *(.literal .text .literal.* .text.* .stub)
+    *(.gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+    */
+
+    /* RIOT-OS compiled source files that use the .iram1.* section names for IRAM
+       functions, etc. */
+    *(.iram1.*)
+
+    /* SDK libraries expect their .text sections to link to iram, not irom */
+    *libcrypto.a:*(.literal .text)
+    *libmain.a:*(.literal .text .literal.* .text.*)
+    *libnet80211.a:*(.literal .text)
+    *libpp.a:*(.literal .text .literal.* .text.*)
+    *libphy.a:*(.literal .text .literal.* .text.*)
+    *libwpa.a:*(.literal .text)
+    *libwpa2.a:*(.literal .text)
+    *liblwip.a:*(.literal .text)
+
+    /* Xtensa basic functionality written in assembler should be placed in iram */
+    *xtensa.a:*(.literal .text .literal.* .text.*)
+
+    /* libgcc integer functions also need to be in .text, as some are called before
+       flash is mapped (also performance)
+    */
+    *libgcc.a:*i3.o(.literal .text .literal.* .text.*)
+
+    *libgcc.a:*mulsf3.o(.literal .text .literal.* .text.*)
+    *libgcc.a:*divsf3.o(.literal .text .literal.* .text.*)
+    *libgcc.a:*fixsfsi.o(.literal .text .literal.* .text.*)
+
+    /* libc also in IRAM */
+    *libc.a:*malloc.o(.literal .text .literal.* .text.*)
+    *libc.a:*mallocr.o(.literal .text .literal.* .text.*)
+    *libc.a:*freer.o(.literal .text .literal.* .text.*)
+    *libc.a:*memcpy.o(.literal .text .literal.* .text.*)
+    *libc.a:*memchr.o(.literal .text .literal.* .text.*)
+    *libc.a:*memset.o(.literal .text .literal.* .text.*)
+    *libc.a:*memcmp.o(.literal .text .literal.* .text.*)
+    *libc.a:*memmove.o(.literal .text .literal.* .text.*)
+    *libc.a:*rand.o(.literal .text .literal.* .text.*)
+    *libc.a:*bzero.o(.literal .text .literal.* .text.*)
+    *libc.a:*lock.o(.literal .text .literal.* .text.*)
+
+    *libc.a:*printf.o(.literal .text .literal.* .text.*)
+    *libc.a:*findfp.o(.literal .text .literal.* .text.*)
+    *libc.a:*fputwc.o(.literal .text .literal.* .text.*)
+
+    enc28j60.a:*(.literal .text .literal.* .text.*)
+
+    *(.fini.literal)
+    *(.fini)
+    *(.gnu.version)
+    _text_end = ABSOLUTE(.);
+    _etext = .;
+  } >iram1_0_seg :iram1_0_phdr
+
+  .irom0.text : ALIGN(4)
+  {
+    _irom0_text_start = ABSOLUTE(.);
+
+    *libmbedtls.a:(.literal .text .literal.* .text.*)
+
+    /* RIOT-OS compiled code goes into IROM by default
+       (except for libgcc which is matched above.) */
+    *(.literal .text .literal.* .text.* .rodata .rodata.*)
+
+    /* Anything explicitly marked as "irom" or "irom0" should go here */
+    *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
+
+    _irom0_text_end = ABSOLUTE(.);
+  } >irom0_0_seg :irom0_0_phdr
+
+  .lit4 : ALIGN(4)
+  {
+    _lit4_start = ABSOLUTE(.);
+    *(*.lit4)
+    *(.lit4.*)
+    *(.gnu.linkonce.lit4.*)
+    _lit4_end = ABSOLUTE(.);
+  } >iram1_0_seg :iram1_0_phdr
+}
diff --git a/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld b/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld
new file mode 100644
index 0000000000000000000000000000000000000000..5a3bf0f3da02a5a384bf238eb7d85ee79bedbeff
--- /dev/null
+++ b/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld
@@ -0,0 +1,293 @@
+/**
+  * This linker script is a modified version of eagle.app.v6.ld that
+  * was generated from xt-genldscripts.tpp for LSP and shipped with
+  * ESP8266_NONOS_SDK
+  */
+
+/* Linker Script for ld -N */
+
+MEMORY
+{
+  dport0_0_seg : org = 0x3FF00000, len = 0x10
+  dram0_0_seg :  org = 0x3FFE8000, len = 0x14000
+  iram1_0_seg :  org = 0x40100000, len = 0x8000
+  irom0_0_seg :  org = 0x40210000, len = 0x5C000
+}
+
+PHDRS
+{
+  dport0_0_phdr PT_LOAD;
+  dram0_0_phdr PT_LOAD;
+  dram0_0_bss_phdr PT_LOAD;
+  iram1_0_phdr PT_LOAD;
+  irom0_0_phdr PT_LOAD;
+}
+
+
+/*  Default entry point:  */
+ENTRY(call_user_start)
+EXTERN(_DebugExceptionVector)
+EXTERN(_DoubleExceptionVector)
+EXTERN(_KernelExceptionVector)
+EXTERN(_NMIExceptionVector)
+EXTERN(_UserExceptionVector)
+PROVIDE(_memmap_vecbase_reset = 0x40000000);
+/* Various memory-map dependent cache attribute settings: */
+_memmap_cacheattr_wb_base = 0x00000110;
+_memmap_cacheattr_wt_base = 0x00000110;
+_memmap_cacheattr_bp_base = 0x00000220;
+_memmap_cacheattr_unused_mask = 0xFFFFF00F;
+_memmap_cacheattr_wb_trapnull = 0x2222211F;
+_memmap_cacheattr_wba_trapnull = 0x2222211F;
+_memmap_cacheattr_wbna_trapnull = 0x2222211F;
+_memmap_cacheattr_wt_trapnull = 0x2222211F;
+_memmap_cacheattr_bp_trapnull = 0x2222222F;
+_memmap_cacheattr_wb_strict = 0xFFFFF11F;
+_memmap_cacheattr_wt_strict = 0xFFFFF11F;
+_memmap_cacheattr_bp_strict = 0xFFFFF22F;
+_memmap_cacheattr_wb_allvalid = 0x22222112;
+_memmap_cacheattr_wt_allvalid = 0x22222112;
+_memmap_cacheattr_bp_allvalid = 0x22222222;
+PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
+
+/* System task handling variables */
+/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */
+PROVIDE( ets_task_min_prio = 0x3fffc6fc );
+PROVIDE( ets_idle_cb = 0x3fffdab0 );
+PROVIDE( ets_idle_arg = 0x3fffdab4 );
+PROVIDE( ets_task_exec_mask = 0x3fffdab8 );
+PROVIDE( ets_task_tab = 0x3fffdac0 );
+PROVIDE( flashchip = 0x3fffc714 );
+PROVIDE( sdk_flashchip = 0x3fffc718 );
+PROVIDE( _xt_interrupt_table = 0x3fffc200 );
+
+SECTIONS
+{
+
+  .dport0.rodata : ALIGN(4)
+  {
+    _dport0_rodata_start = ABSOLUTE(.);
+    *(.dport0.rodata)
+    *(.dport.rodata)
+    _dport0_rodata_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .dport0.literal : ALIGN(4)
+  {
+    _dport0_literal_start = ABSOLUTE(.);
+    *(.dport0.literal)
+    *(.dport.literal)
+    _dport0_literal_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .dport0.data : ALIGN(4)
+  {
+    _dport0_data_start = ABSOLUTE(.);
+    *(.dport0.data)
+    *(.dport.data)
+    _dport0_data_end = ABSOLUTE(.);
+  } >dport0_0_seg :dport0_0_phdr
+
+  .data : ALIGN(4)
+  {
+    _data_start = ABSOLUTE(.);
+    *(.data)
+    *(.data.*)
+    *(.gnu.linkonce.d.*)
+    *(.data1)
+    *(.sdata)
+    *(.sdata.*)
+    *(.gnu.linkonce.s.*)
+    *(.sdata2)
+    *(.sdata2.*)
+    *(.gnu.linkonce.s2.*)
+    *(.jcr)
+    _data_end = ABSOLUTE(.);
+  } >dram0_0_seg :dram0_0_phdr
+
+  .rodata : ALIGN(4)
+  {
+    _rodata_start = ABSOLUTE(.);
+    *(.sdk.version)
+    /* TODO put only necessary .rodata to dram
+    *libc.a:*.o(.rodata.* .rodata)
+    *core.a:*(.rodata.* .rodata)
+    *cpu.a:*(.rodata .rodata.*)
+    */
+    *(.rodata .rodata.*)
+    *(.gnu.linkonce.r.*)
+    *(.rodata1)
+    __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
+    *(.xt_except_table)
+    *(.gcc_except_table)
+    *(.gnu.linkonce.e.*)
+    *(.gnu.version_r)
+    *(.eh_frame)
+    /*  C++ constructor and destructor tables, properly ordered:  */
+    KEEP (*crtbegin.o(.ctors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    /*  C++ exception handlers table:  */
+    __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
+    *(.xt_except_desc)
+    *(.gnu.linkonce.h.*)
+    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+    *(.xt_except_desc_end)
+    *(.dynamic)
+    *(.gnu.version_d)
+    . = ALIGN(4);		/* this table MUST be 4-byte aligned */
+    _bss_table_start = ABSOLUTE(.);
+    LONG(_bss_start)
+    LONG(_bss_end)
+    _bss_table_end = ABSOLUTE(.);
+    _rodata_end = ABSOLUTE(.);
+  } >dram0_0_seg :dram0_0_phdr
+
+  .bss ALIGN(8) (NOLOAD) : ALIGN(4)
+  {
+    . = ALIGN (8);
+    _bss_start = ABSOLUTE(.);
+    *(.dynsbss)
+    *(.sbss)
+    *(.sbss.*)
+    *(.gnu.linkonce.sb.*)
+    *(.scommon)
+    *(.sbss2)
+    *(.sbss2.*)
+    *(.gnu.linkonce.sb2.*)
+    *(.dynbss)
+    *(.bss)
+    *(.bss.*)
+    *(.gnu.linkonce.b.*)
+    *(COMMON)
+
+    . = ALIGN (8);
+    _bss_end = ABSOLUTE(.);
+    _sheap = ABSOLUTE(.);
+    _heap_start = ABSOLUTE(.);
+
+  } >dram0_0_seg :dram0_0_bss_phdr
+
+  /* ETS system memory starts at 0x3FFFC000 which is the top of the heap for the app */
+  . = 0x3FFFC000;
+  _heap_top = ABSOLUTE(.);
+  _eheap = ABSOLUTE(.);
+
+  .text : ALIGN(4)
+  {
+    _stext = .;
+    _text_start = ABSOLUTE(.);
+    *(.UserEnter.text)
+    . = ALIGN(16);
+    *(.DebugExceptionVector.text)
+    . = ALIGN(16);
+    *(.NMIExceptionVector.text)
+    . = ALIGN(16);
+    *(.KernelExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN(16);
+    *(.UserExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN(16);
+    *(.DoubleExceptionVector.text)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    LONG(0)
+    . = ALIGN (16);
+    *(.entry.text)
+    *(.init.literal)
+    *(.init)
+
+    /* normal code should be in irom0 */
+    /*
+    *(.literal .text .literal.* .text.* .stub)
+    *(.gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+    */
+
+    /* RIOT-OS compiled source files that use the .iram1.* section names for IRAM
+       functions, etc. */
+    *(.iram1.*)
+
+    /* SDK libraries expect their .text sections to link to iram, not irom */
+    *libcrypto.a:*(.literal .text)
+    *libmain.a:*(.literal .text .literal.* .text.*)
+    *libnet80211.a:*(.literal .text)
+    *libpp.a:*(.literal .text .literal.* .text.*)
+    *libphy.a:*(.literal .text .literal.* .text.*)
+    *libwpa.a:*(.literal .text)
+    *libwpa2.a:*(.literal .text)
+    *liblwip.a:*(.literal .text)
+
+    /* Xtensa basic functionality written in assembler should be placed in iram */
+    *xtensa.a:*(.literal .text .literal.* .text.*)
+
+    /* libgcc integer functions also need to be in .text, as some are called before
+       flash is mapped (also performance) */
+    *libgcc.a:*i3.o(.literal .text .literal.* .text.*)
+
+    *libgcc.a:*mulsf3.o(.literal .text .literal.* .text.*)
+    *libgcc.a:*divsf3.o(.literal .text .literal.* .text.*)
+    *libgcc.a:*fixsfsi.o(.literal .text .literal.* .text.*)
+
+    /* libc also in IRAM */
+    *libc.a:*malloc.o(.literal .text .literal.* .text.*)
+    *libc.a:*mallocr.o(.literal .text .literal.* .text.*)
+    *libc.a:*freer.o(.literal .text .literal.* .text.*)
+    *libc.a:*memchr.o(.literal .text .literal.* .text.*)
+    *libc.a:*memcpy.o(.literal .text .literal.* .text.*)
+    *libc.a:*memset.o(.literal .text .literal.* .text.*)
+    *libc.a:*memcmp.o(.literal .text .literal.* .text.*)
+    *libc.a:*memmove.o(.literal .text .literal.* .text.*)
+    *libc.a:*rand.o(.literal .text .literal.* .text.*)
+    *libc.a:*bzero.o(.literal .text .literal.* .text.*)
+    *libc.a:*lock.o(.literal .text .literal.* .text.*)
+
+    *libc.a:*findfp.o(.literal .text .literal.* .text.*)
+    *libc.a:*fputwc.o(.literal .text .literal.* .text.*)
+
+    enc28j60.a:*(.literal .text .literal.* .text.*)
+
+    *(.fini.literal)
+    *(.fini)
+    *(.gnu.version)
+    _text_end = ABSOLUTE(.);
+    _etext = .;
+  } >iram1_0_seg :iram1_0_phdr
+
+  .irom0.text : ALIGN(4)
+  {
+    _irom0_text_start = ABSOLUTE(.);
+
+    *libmbedtls.a:(.literal .text .literal.* .text.*)
+
+    /* RIOT-OS compiled code goes into IROM by default
+       (except for functions with section names defined in .text above.) */
+    *(.literal .text .literal.* .text.* .rodata .rodata.*)
+
+    /* Anything explicitly marked as "irom" or "irom0" should go here */
+    *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
+
+    _irom0_text_end = ABSOLUTE(.);
+  } >irom0_0_seg :irom0_0_phdr
+
+  .lit4 : ALIGN(4)
+  {
+    _lit4_start = ABSOLUTE(.);
+    *(*.lit4)
+    *(.lit4.*)
+    *(.gnu.linkonce.lit4.*)
+    _lit4_end = ABSOLUTE(.);
+  } >iram1_0_seg :iram1_0_phdr
+}
diff --git a/cpu/esp8266/periph/Makefile b/cpu/esp8266/periph/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..6d1887b640099d130c5a6400e3f878f0c65aa6f1
--- /dev/null
+++ b/cpu/esp8266/periph/Makefile
@@ -0,0 +1,3 @@
+MODULE = periph
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/periph/adc.c b/cpu/esp8266/periph/adc.c
new file mode 100644
index 0000000000000000000000000000000000000000..8e367a005e4ecc18801ca412acbe4d68858c179a
--- /dev/null
+++ b/cpu/esp8266/periph/adc.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_adc
+ * @{
+ *
+ * @file
+ * @brief       Low-level ADC driver implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG    0
+#include "debug.h"
+
+#include "cpu.h"
+#include "mutex.h"
+#include "periph/adc.h"
+#include "periph_conf.h"
+#include "board.h"
+
+#include "common.h"
+#include "sdk/sdk.h"
+
+#if defined(ADC_NUMOF) && ADC_NUMOF > 0
+
+int adc_init(adc_t line)
+{
+    CHECK_PARAM_RET (line < ADC_NUMOF, -1)
+
+    /* no special inialization needed */
+    return 0;
+}
+
+
+int adc_sample(adc_t line, adc_res_t res)
+{
+    CHECK_PARAM_RET (line < ADC_NUMOF, -1)
+    CHECK_PARAM_RET (res == ADC_RES_10BIT, -1)
+
+    #ifdef MODULE_ESP_SDK
+    return system_adc_read ();
+    #else
+    return test_tout(false);
+    #endif
+}
+
+#endif
diff --git a/cpu/esp8266/periph/cpuid.c b/cpu/esp8266/periph/cpuid.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f2d68fbf64482bd66834c6ec05304a726fdb47a
--- /dev/null
+++ b/cpu/esp8266/periph/cpuid.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_cpuid
+ * @{
+ *
+ * @file
+ * @brief       Implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+#include "periph/cpuid.h"
+#include "sdk/sdk.h"
+
+void cpuid_get(void *id)
+{
+    uint32_t chip_id = system_get_chip_id();
+    memcpy(id, &(chip_id), CPUID_LEN);
+}
diff --git a/cpu/esp8266/periph/flash.c b/cpu/esp8266/periph/flash.c
new file mode 100644
index 0000000000000000000000000000000000000000..912c3ae927e6d52cfc0a5dd25d5030f7aa9981a4
--- /dev/null
+++ b/cpu/esp8266/periph/flash.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Low-level MTD flash drive implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "board.h"
+#include "common.h"
+#include "irq_arch.h"
+#include "log.h"
+#include "mtd.h"
+
+#include "c_types.h"
+#include "esp/spiflash.h"
+#include "spi_flash.h"
+#include "sdk/rom.h"
+
+#define SDK_FLASH_FUNCTIONS
+
+/* the external pointer to the system MTD device */
+mtd_dev_t* mtd0 = 0;
+
+mtd_dev_t  _flash_dev;
+mtd_desc_t _flash_driver;
+
+/* forward declaration of mtd functions */
+static int _flash_init  (mtd_dev_t *dev);
+static int _flash_read  (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size);
+static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size);
+static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size);
+static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power);
+
+static uint32_t _flash_beg;  /* first byte addr of the flash drive in SPI flash */
+static uint32_t _flash_end;  /* first byte addr after the flash drive in SPI flash */
+static uint32_t _flash_size; /* resulting size of the flash drive in SPI flash */
+
+#define SPIFFS_FLASH_BEGIN 0x80000 /* TODO determine real possible value */
+
+void flash_drive_init (void)
+{
+    DEBUG("%s\n", __func__);
+
+    _flash_driver.init  = &_flash_init;
+    _flash_driver.read  = &_flash_read;
+    _flash_driver.write = &_flash_write;
+    _flash_driver.erase = &_flash_erase;
+    _flash_driver.power = &_flash_power;
+
+    _flash_beg  = SPIFFS_FLASH_BEGIN;
+    _flash_end  = flashchip->chip_size - 5 * flashchip->sector_size;
+    _flash_size = _flash_end - _flash_beg;
+
+    _flash_dev.driver = &_flash_driver;
+    _flash_dev.sector_count = _flash_size / flashchip->sector_size;
+
+    mtd0 = &_flash_dev;
+
+    _flash_dev.pages_per_sector = flashchip->sector_size / flashchip->page_size;
+    _flash_dev.page_size = flashchip->page_size;
+
+    DEBUG("%s flashchip chip_size=%d block_size=%d sector_size=%d page_size=%d\n", __func__,
+          flashchip->chip_size, flashchip->block_size,
+          flashchip->sector_size, flashchip->page_size);
+    DEBUG("%s flash_dev sector_count=%d pages_per_sector=%d page_size=%d\n", __func__,
+          _flash_dev.sector_count, _flash_dev.pages_per_sector, _flash_dev.page_size);
+    DEBUG("\n");
+}
+
+static int _flash_init  (mtd_dev_t *dev)
+{
+    DEBUG("%s dev=%p driver=%p\n", __func__, dev, &_flash_driver);
+
+    CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV);
+
+    #ifdef SPI_FLASH_CHIP_SIZE
+    if (SPI_FLASH_CHIP_SIZE <= SPIFFS_FLASH_BEGIN) {
+    #else
+    if (flashchip->chip_size <= SPIFFS_FLASH_BEGIN) {
+    #endif
+        LOG_ERROR("Flash size is equal or less than %d Byte, "
+                  "SPIFFS cannot be used\n", SPIFFS_FLASH_BEGIN);
+        return -ENODEV;
+    }
+
+    return 0;
+}
+
+#define SPI_FLASH_BUF_SIZE 64
+uint8_t _flash_buf[SPI_FLASH_BUF_SIZE];
+
+static int _flash_read  (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
+{
+    DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff);
+
+    CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV);
+    CHECK_PARAM_RET (buff != NULL, -ENOTSUP);
+
+    /* size must be within the flash address space */
+    CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
+
+    #ifndef SDK_FLASH_FUNCTIONS
+    bool result = spiflash_read (_flash_beg + addr, buff, size);
+    return result ? (int)size : -EIO;
+    #else
+    critical_enter();
+
+    /* it would be great if would work in that way, but would be too easy :-( */
+    /* memcpy(buff, (void*)(_flash_beg + addr + 0x40200000), size); */
+
+    int result = SPI_FLASH_RESULT_OK;
+    uint32_t len = size;
+
+    /* if addr is not 4 byte aligned, we need to read the first full word */
+    if (addr & 0x3) {
+        uint32_t word_addr = addr & ~0x3;
+        uint32_t pos_in_word = addr & 0x3;
+        uint32_t len_in_word = 4 - pos_in_word;
+        len_in_word = (len_in_word < len) ? len_in_word : len;
+
+        result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
+        memcpy(buff, _flash_buf + pos_in_word, len_in_word);
+
+        buff  = (uint8_t*)buff + len_in_word;
+        addr += len_in_word;
+        len  -= len_in_word;
+    }
+
+    /* read all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */
+    while (result == SPI_FLASH_RESULT_OK && len > 4) {
+        uint32_t len_full_words = len & ~0x3;
+
+        if (len_full_words > SPI_FLASH_BUF_SIZE) {
+            len_full_words = SPI_FLASH_BUF_SIZE;
+        }
+
+        result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words);
+        memcpy(buff, _flash_buf, len_full_words);
+
+        buff  = (uint8_t*)buff + len_full_words;
+        addr += len_full_words;
+        len  -= len_full_words;
+    }
+
+    /* if there is some remaining, we need to prepare last word */
+    if (result == SPI_FLASH_RESULT_OK && len) {
+        result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
+        memcpy(buff, _flash_buf, len);
+    }
+
+    critical_exit();
+    return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO;
+    #endif
+}
+
+static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
+{
+    DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff);
+
+    CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV);
+    CHECK_PARAM_RET (buff != NULL, -ENOTSUP);
+
+    /* size must be within the flash address space */
+    CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
+
+    #ifndef SDK_FLASH_FUNCTIONS
+
+    bool result = spiflash_write (_flash_beg + addr, (uint8_t*)buff, size);
+    return result ? (int)size : -EIO;
+
+    #else
+
+    critical_enter();
+
+    int result = SPI_FLASH_RESULT_OK;
+    uint32_t len = size;
+
+    /* if addr is not 4 byte aligned, we need to prepare first full word */
+    if (addr & 0x3) {
+        uint32_t word_addr = addr & ~0x3;
+        uint32_t pos_in_word = addr & 0x3;
+        uint32_t len_in_word = 4 - pos_in_word;
+        len_in_word = (len_in_word < len) ? len_in_word : len;
+
+        result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
+        memcpy(_flash_buf + pos_in_word, buff, len_in_word);
+        result |= spi_flash_write (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4);
+
+        buff  = (uint8_t*)buff + len_in_word;
+        addr += len_in_word;
+        len  -= len_in_word;
+    }
+
+    /* write all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */
+    while (result == SPI_FLASH_RESULT_OK && len > 4) {
+        uint32_t len_full_words = len & ~0x3;
+
+        if (len_full_words > SPI_FLASH_BUF_SIZE) {
+            len_full_words = SPI_FLASH_BUF_SIZE;
+        }
+
+        memcpy(_flash_buf, buff, len_full_words);
+        result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words);
+
+        buff  = (uint8_t*)buff + len_full_words;
+        addr += len_full_words;
+        len  -= len_full_words;
+    }
+
+    /* if there is some remaining, we need to prepare last word */
+    if (result == SPI_FLASH_RESULT_OK && len) {
+        result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
+        memcpy(_flash_buf, buff, len);
+        result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, 4);
+    }
+
+    critical_exit();
+    return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO;
+    #endif
+}
+
+static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size)
+{
+    DEBUG("%s dev=%p addr=%08x size=%u\n", __func__, dev, addr, size);
+
+    CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV);
+
+    /* size must be within the flash address space */
+    CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW);
+
+    /* size must be a multiple of sector_size && at least one sector */
+    CHECK_PARAM_RET (size >= flashchip->sector_size, -ENOTSUP);
+    CHECK_PARAM_RET (size % flashchip->sector_size == 0, -ENOTSUP)
+
+    #ifndef SDK_FLASH_FUNCTIONS
+    bool result = false;
+    uint32_t count = size / flashchip->sector_size;
+    while (count--) {
+        uint32_t sec = _flash_beg + addr + count * flashchip->sector_size;
+        if (!(result = spiflash_erase_sector (sec))) {
+            break;
+        }
+    }
+    return result ? 0 : -EIO;
+    #else
+    critical_enter();
+
+    uint32_t result = SPI_FLASH_RESULT_OK;
+    uint32_t count = size / flashchip->sector_size;
+    while (count--) {
+        uint32_t sec = (_flash_beg + addr) / flashchip->sector_size + count;
+        if ((result = spi_flash_erase_sector (sec)) != SPI_FLASH_RESULT_OK) {
+            break;
+        }
+    }
+
+    critical_exit();
+    return result;
+    #endif
+}
+
+static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power)
+{
+    DEBUG("%s\n", __func__);
+
+    return -ENOTSUP;
+}
diff --git a/cpu/esp8266/periph/gpio.c b/cpu/esp8266/periph/gpio.c
new file mode 100644
index 0000000000000000000000000000000000000000..928866b73141228390575ab41ebbfe3c817e8e29
--- /dev/null
+++ b/cpu/esp8266/periph/gpio.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_gpio
+ * @{
+ *
+ * @file
+ * @brief       Low-level GPIO driver implementation for ESP8266
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#include <stdbool.h>
+
+#include "log.h"
+#include "periph/gpio.h"    /* RIOT gpio.h */
+
+#include "c_types.h"
+#include "eagle_soc.h"
+#include "ets_sys.h"
+
+#include "sdk/ets.h"
+#include "esp/gpio_regs.h"
+#include "esp/iomux_regs.h"
+#include "esp/rtc_regs.h"
+
+#include "common.h"
+#include "gpio_common.h"
+#include "irq_arch.h"
+#include "syscalls.h"
+
+/*
+ * IOMUX to GPIO mapping
+ * source https://www.espressif.com/sites/default/files/documentation/0d-esp8266_pin_list_release_15-11-2014.xlsx
+ */
+
+const uint8_t _gpio_to_iomux[]   = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 };
+const uint8_t _iomux_to_gpio[]   = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 };
+
+_gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] =
+{
+   _GPIO,   /* gpio0 */
+
+   _UART,   /* gpio1  UART0 RxD */
+   _GPIO,   /* gpio2 */
+   _UART,   /* gpio3  UART0 TxD */
+   _GPIO,   /* gpio4 */
+   _GPIO,   /* gpio5 */
+   _SPIF,   /* gpio6  SPI flash CLK */
+   _SPIF,   /* gpio7  SPI flash MISO */
+   _SPIF,   /* gpio8  SPI flash MOSI */
+   #if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT)
+   _SPIF,   /* gpio9  SPI flash HD (qio/qout flash mode) */
+   _SPIF,   /* gpio10 SPI flash WP (qio/qout flash mode) */
+   #else
+   _GPIO,   /* gpio9  can be used as GPIO if not needed for flash */
+   _GPIO,   /* gpio10 can be used as GPIO if not needed for flash */
+   #endif
+   _SPIF,   /* gpio11 SPI flash CS */
+   _GPIO,   /* gpio12 */
+   _GPIO,   /* gpio13 */
+   _GPIO,   /* gpio14 */
+   _GPIO,   /* gpio15 */
+   _GPIO    /* gpio16 */
+};
+
+int gpio_init(gpio_t pin, gpio_mode_t mode)
+{
+    DEBUG("%s: %d %d\n", __func__, pin, mode);
+
+    CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
+
+    /* check whether pin can be used as GPIO or is used in anyway else */
+    switch (_gpio_pin_usage[pin]) {
+        case _I2C:  LOG_ERROR("GPIO%d is used as I2C signal.\n", pin); return -1;
+        case _PWM:  LOG_ERROR("GPIO%d is used as PWM output.\n", pin); return -1;
+        case _SPI:  LOG_ERROR("GPIO%d is used as SPI interface.\n", pin); return -1;
+        case _SPIF: LOG_ERROR("GPIO%d is used as SPI flash.\n", pin); return -1;
+        case _UART: LOG_ERROR("GPIO%d is used as UART interface.\n", pin); return -1;
+        default: break;
+    }
+
+    /* GPIO16 requires separate handling */
+    if (pin == GPIO16) {
+        RTC.GPIO_CFG[3] = (RTC.GPIO_CFG[3] & 0xffffffbc) | BIT(0);
+        RTC.GPIO_CONF = RTC.GPIO_CONF & ~RTC_GPIO_CONF_OUT_ENABLE;
+
+        switch (mode) {
+            case GPIO_OUT:
+                RTC.GPIO_ENABLE = RTC.GPIO_OUT | RTC_GPIO_CONF_OUT_ENABLE;
+                break;
+
+            case GPIO_OD:
+                LOG_ERROR("GPIO mode GPIO_OD is not supported for GPIO16.\n");
+                return -1;
+
+            case GPIO_OD_PU:
+                LOG_ERROR("GPIO mode GPIO_OD_PU is not supported for GPIO16.\n");
+                return -1;
+
+            case GPIO_IN:
+                RTC.GPIO_ENABLE = RTC.GPIO_OUT & ~RTC_GPIO_CONF_OUT_ENABLE;
+                RTC.GPIO_CFG[3] &= ~RTC_GPIO_CFG3_PIN_PULLUP;
+                break;
+
+            case GPIO_IN_PU:
+                LOG_ERROR("GPIO mode GPIO_IN_PU is not supported for GPIO16.\n");
+                return -1;
+
+            case GPIO_IN_PD:
+                LOG_ERROR("GPIO mode GPIO_IN_PD is not supported for GPIO16.\n");
+                return -1;
+
+            default:
+                LOG_ERROR("Invalid GPIO mode for GPIO%d.\n", pin);
+                return -1;
+        }
+        return 0;
+    }
+
+    uint8_t  iomux      = _gpio_to_iomux [pin];
+    uint32_t iomux_conf = (iomux > 11) ? IOMUX_FUNC(0) : IOMUX_FUNC(3);
+
+    switch (mode) {
+
+        case GPIO_OUT:   iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE;
+                         iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
+                         GPIO.CONF[pin] &= ~GPIO_CONF_OPEN_DRAIN;
+                         GPIO.ENABLE_OUT_SET = BIT(pin);
+                         break;
+
+        case GPIO_OD_PU: iomux_conf |= IOMUX_PIN_PULLUP;
+                         iomux_conf |= IOMUX_PIN_PULLUP_SLEEP;
+        case GPIO_OD:    iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE;
+                         iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
+                         GPIO.CONF[pin] |= GPIO_CONF_OPEN_DRAIN;
+                         GPIO.ENABLE_OUT_SET = BIT(pin);
+                         break;
+
+        case GPIO_IN_PU: iomux_conf |= IOMUX_PIN_PULLUP;
+                         iomux_conf |= IOMUX_PIN_PULLUP_SLEEP;
+        case GPIO_IN:    GPIO.ENABLE_OUT_CLEAR = BIT(pin);
+                         break;
+
+        case GPIO_IN_PD: LOG_ERROR("GPIO mode GPIO_IN_PD is not supported.\n");
+                         return -1;
+
+        default: LOG_ERROR("Invalid GPIO mode for GPIO%d.\n", pin);
+    }
+
+    IOMUX.PIN[iomux] = iomux_conf;
+
+    return 0;
+}
+
+static gpio_isr_ctx_t gpio_isr_ctx_table [GPIO_PIN_NUMOF] = { };
+static bool gpio_int_enabled_table [GPIO_PIN_NUMOF] = { };
+
+void IRAM gpio_int_handler (void* arg)
+{
+    irq_isr_enter();
+
+    for (int i = 0; i < GPIO_PIN_NUMOF; i++) {
+
+        uint32_t mask = BIT(i);
+
+        if (GPIO.STATUS & mask) {
+            GPIO.STATUS_CLEAR = mask;
+            if (gpio_int_enabled_table[i] && (GPIO.CONF[i] & GPIO_PIN_INT_TYPE_MASK)) {
+                gpio_isr_ctx_table[i].cb (gpio_isr_ctx_table[i].arg);
+            }
+        }
+        mask = mask << 1;
+    }
+
+    irq_isr_exit();
+}
+
+int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
+                  gpio_cb_t cb, void *arg)
+{
+    if (gpio_init(pin, mode)) {
+        return -1;
+    }
+
+    if (pin == GPIO16) {
+        /* GPIO16 requires separate handling */
+        LOG_ERROR("GPIO16 cannot generate interrupts.\n");
+        return -1;
+    }
+    gpio_isr_ctx_table[pin].cb  = cb;
+    gpio_isr_ctx_table[pin].arg = arg;
+
+    GPIO.CONF[pin] = SET_FIELD(GPIO.CONF[pin], GPIO_CONF_INTTYPE, flank);
+    if (flank != GPIO_NONE) {
+        gpio_int_enabled_table [pin] = (gpio_isr_ctx_table[pin].cb != NULL);
+        ets_isr_attach (ETS_GPIO_INUM, gpio_int_handler, 0);
+        ets_isr_unmask ((1 << ETS_GPIO_INUM));
+    }
+
+    return 0;
+}
+
+void gpio_irq_enable (gpio_t pin)
+{
+    CHECK_PARAM(pin < GPIO_PIN_NUMOF);
+
+    gpio_int_enabled_table [pin] = true;
+}
+
+void gpio_irq_disable (gpio_t pin)
+{
+    CHECK_PARAM(pin < GPIO_PIN_NUMOF);
+
+    gpio_int_enabled_table [pin] = false;
+}
+
+int gpio_read (gpio_t pin)
+{
+    CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
+
+    if (pin == GPIO16) {
+        /* GPIO16 requires separate handling */
+        return RTC.GPIO_IN & BIT(0);
+    }
+
+    return (GPIO.IN & BIT(pin)) ? 1 : 0;
+}
+
+void gpio_write (gpio_t pin, int value)
+{
+    DEBUG("%s: %d %d\n", __func__, pin, value);
+
+    CHECK_PARAM(pin < GPIO_PIN_NUMOF);
+
+    if (pin == GPIO16) {
+        /* GPIO16 requires separate handling */
+        RTC.GPIO_OUT = (RTC.GPIO_OUT & ~BIT(0)) | (value ? 1 : 0);
+        return;
+    }
+
+    if (value) {
+        GPIO.OUT_SET = BIT(pin) & GPIO_OUT_PIN_MASK;
+    }
+    else {
+        GPIO.OUT_CLEAR = BIT(pin) & GPIO_OUT_PIN_MASK;
+    }
+}
+
+void gpio_set (gpio_t pin)
+{
+    gpio_write (pin, 1);
+}
+
+void gpio_clear (gpio_t pin)
+{
+    gpio_write (pin, 0);
+}
+
+void gpio_toggle (gpio_t pin)
+{
+    DEBUG("%s: %d\n", __func__, pin);
+
+    CHECK_PARAM(pin < GPIO_PIN_NUMOF);
+
+    if (pin == GPIO16) {
+        /* GPIO16 requires separate handling */
+        RTC.GPIO_OUT = (RTC.GPIO_OUT & ~BIT(0)) | ((RTC.GPIO_IN & BIT(0)) ? 0 : 1);
+        return;
+    }
+
+    GPIO.OUT ^= BIT(pin);
+}
diff --git a/cpu/esp8266/periph/hwrng.c b/cpu/esp8266/periph/hwrng.c
new file mode 100644
index 0000000000000000000000000000000000000000..4696810e63a39caf3453cf0d21b9e988d6ce1f15
--- /dev/null
+++ b/cpu/esp8266/periph/hwrng.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_hwrng
+ * @{
+ *
+ * @file
+ * @brief       Low-level random number generator driver implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "periph_conf.h"
+#include "periph/hwrng.h"
+
+#include "esp/wdev_regs.h"
+
+void hwrng_init(void)
+{
+    /* no need for initialization */
+}
+
+void hwrng_read(void *buf, unsigned int num)
+{
+    unsigned int count = 0;
+    uint8_t *b = (uint8_t *)buf;
+
+    while (count < num) {
+        /* read next 4 bytes of random data */
+        uint32_t tmp = WDEV.HWRNG;
+
+        /* copy data into result vector */
+        for (int i = 0; i < 4 && count < num; i++) {
+            b[count++] = (uint8_t)tmp;
+            tmp = tmp >> 8;
+        }
+    }
+}
+
+uint32_t hwrand (void)
+{
+    uint32_t _tmp;
+    hwrng_read(&_tmp, sizeof(uint32_t));
+    return _tmp;
+}
diff --git a/cpu/esp8266/periph/i2c.c b/cpu/esp8266/periph/i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..bdcff8212446e2631df3eda8daff70ec2e9c2704
--- /dev/null
+++ b/cpu/esp8266/periph/i2c.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup drivers_periph_i2c
+ * @{
+ *
+ * @file
+ * @brief       Low-level I2C driver implementation using ESP8266 SDK
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+/*
+   PLEASE NOTE:
+
+   Some parts of the implementation bases on the bit-banging implementation as
+   described in [wikipedia](https://en.wikipedia.org/wiki/I%C2%B2C) as well as
+   its implementation in [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
+   These parts are under the copyright of their respective owners.
+*/
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include "cpu.h"
+#include "log.h"
+#include "mutex.h"
+#include "periph_conf.h"
+#include "periph/gpio.h"
+#include "periph/i2c.h"
+
+#include "common.h"
+
+#include "esp/gpio_regs.h"
+#include "sdk/ets.h"
+
+#if defined(I2C_NUMOF) && I2C_NUMOF > 0
+
+/* has to be declared as extern since it is not possible to include */
+/* user_interface.h due to conflicts with gpio_init */
+extern uint8_t system_get_cpu_freq(void);
+extern bool system_update_cpu_freq(uint8_t freq);
+
+/* max clock stretching counter */
+#define I2C_CLOCK_STRETCH 400
+
+typedef struct
+{
+    i2c_speed_t speed;
+    i2c_t dev;
+
+    bool started;
+
+    gpio_t scl;
+    gpio_t sda;
+
+    uint32_t scl_bit;   /* gpio bit mask for faster access */
+    uint32_t sda_bit;   /* gpio bit mask for faster access */
+
+    uint32_t delay;
+
+} _i2c_bus_t;
+
+static _i2c_bus_t _i2c_bus[] =
+{
+  #if defined(I2C0_SDA) && defined(I2C0_SDA)
+  {
+    .speed = I2C0_SPEED,
+    .sda = I2C0_SDA,
+    .scl = I2C0_SCL
+  },
+  #endif
+  #if defined(I2C1_SDA) && defined(I2C1_SDA)
+  {
+    .speed = I2C1_SPEED,
+    .sda = I2C1_SDA,
+    .scl = I2C1_SCL
+  },
+  #endif
+  #if defined(I2C2_SDA) && defined(I2C2_SDA)
+  {
+    .speed = I2C2_SPEED,
+    .sda = I2C2_SDA,
+    .scl = I2C2_SCL
+  },
+  #endif
+};
+
+static const uint32_t _i2c_delays[][2] =
+{
+    /* values specify one half-period and are only valid for -O2 option */
+    /* value = [period - 0.5us(160MHz) or 1.0us(80MHz)] * cycles per second / 2 */
+    /* cycles per us = ca. 20 (80 MHz) / ca. 40 (160 MHz) */
+    [I2C_SPEED_LOW]       = {1990, 990}, /*   10 kbps (period 100 us) */
+    [I2C_SPEED_NORMAL]    = { 190,  90}, /*  100 kbps (period 10 us) */
+    [I2C_SPEED_FAST]      = {  40,  17}, /*  400 kbps (period 2.5 us) */
+    [I2C_SPEED_FAST_PLUS] = {  13,   0}, /*    1 Mbps (period 1 us) */
+    [I2C_SPEED_HIGH]      = {   0,   0}  /*  3.4 Mbps (period 0.3 us) is not working */
+};
+
+static mutex_t i2c_bus_lock[I2C_NUMOF] = { MUTEX_INIT };
+
+/* forward declaration of internal functions */
+
+static inline void _i2c_delay (_i2c_bus_t* bus);
+static inline bool _i2c_read_scl (_i2c_bus_t* bus);
+static inline bool _i2c_read_sda (_i2c_bus_t* bus);
+static inline void _i2c_set_scl (_i2c_bus_t* bus);
+static inline void _i2c_clear_scl (_i2c_bus_t* bus);
+static inline void _i2c_set_sda (_i2c_bus_t* bus);
+static inline void _i2c_clear_sda (_i2c_bus_t* bus);
+static int _i2c_start_cond (_i2c_bus_t* bus);
+static int _i2c_stop_cond (_i2c_bus_t* bus);
+static int _i2c_write_bit (_i2c_bus_t* bus, bool bit);
+static int _i2c_read_bit (_i2c_bus_t* bus, bool* bit);
+static int _i2c_write_byte (_i2c_bus_t* bus, uint8_t byte);
+static int _i2c_read_byte (_i2c_bus_t* bus, uint8_t* byte, bool ack);
+static int _i2c_arbitration_lost (_i2c_bus_t* bus, const char* func);
+
+/* implementation of i2c interface */
+
+void i2c_init(i2c_t dev)
+{
+    if (I2C_NUMOF != sizeof(_i2c_bus)/sizeof(_i2c_bus_t)) {
+        LOG_INFO("I2C_NUMOF does not match number of I2C_SDA_x/I2C_SCL_x definitions\n");
+        LOG_INFO("Please check your board configuration in 'board.h'\n");
+        assert(I2C_NUMOF < sizeof(_i2c_bus)/sizeof(_i2c_bus_t));
+
+        return;
+    }
+
+    CHECK_PARAM (dev < I2C_NUMOF)
+
+    if (_i2c_bus[dev].speed == I2C_SPEED_HIGH) {
+        LOG_INFO("I2C_SPEED_HIGH is not supported\n");
+        return;
+    }
+
+    i2c_acquire (dev);
+
+    _i2c_bus[dev].dev     = dev;
+    _i2c_bus[dev].delay   =_i2c_delays[_i2c_bus[dev].speed][ets_get_cpu_frequency() == 80 ? 1 : 0];
+    _i2c_bus[dev].scl_bit = BIT(_i2c_bus[dev].scl); /* store bit mask for faster access */
+    _i2c_bus[dev].sda_bit = BIT(_i2c_bus[dev].sda); /* store bit mask for faster access */
+    _i2c_bus[dev].started = false; /* for handling of repeated start condition */
+
+    DEBUG ("%s: scl=%d sda=%d speed=%d\n", __func__,
+           _i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed);
+
+    /* configure SDA and SCL pin as GPIO in open-drain mode with enabled pull-ups */
+    gpio_init (_i2c_bus[dev].scl, GPIO_OD_PU);
+    gpio_init (_i2c_bus[dev].sda, GPIO_OD_PU);
+
+    /* set SDA and SCL to be floating and pulled-up to high */
+    _i2c_set_sda (&_i2c_bus[dev]);
+    _i2c_set_scl (&_i2c_bus[dev]);
+
+    i2c_release (dev);
+
+    return;
+}
+
+int i2c_acquire(i2c_t dev)
+{
+    CHECK_PARAM_RET (dev < I2C_NUMOF, -1)
+
+    mutex_lock(&i2c_bus_lock[dev]);
+    return 0;
+}
+
+int i2c_release(i2c_t dev)
+{
+    CHECK_PARAM_RET (dev < I2C_NUMOF, -1)
+
+    mutex_unlock(&i2c_bus_lock[dev]);
+    return 0;
+}
+
+int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags)
+{
+    DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n",
+           __func__, dev, addr, data, len, flags);
+
+    CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL);
+    CHECK_PARAM_RET (len > 0, -EINVAL);
+    CHECK_PARAM_RET (data != NULL, -EINVAL);
+
+    _i2c_bus_t* bus = &_i2c_bus[dev];
+
+    int res = 0;
+
+    /* send START condition and address if I2C_NOSTART is not set */
+    if (!(flags & I2C_NOSTART)) {
+
+        /* START condition */
+        if ((res = _i2c_start_cond (bus)) != 0) {
+            return res;
+        }
+
+        /* send 10 bit or 7 bit address */
+        if (flags & I2C_ADDR10) {
+            /* prepare 10 bit address bytes */
+            uint8_t addr1 = 0xf0 | (addr & 0x0300) >> 7 | I2C_READ;
+            uint8_t addr2 = addr & 0xff;
+            /* send address bytes wit read flag */
+            if ((res = _i2c_write_byte (bus, addr1)) != 0 ||
+                (res = _i2c_write_byte (bus, addr2)) != 0) {
+                return res;
+            }
+        }
+        else {
+            /* send address byte with read flag */
+            if ((res = _i2c_write_byte (bus, (addr << 1 | I2C_READ))) != 0) {
+                return res;
+            }
+        }
+    }
+
+    /* receive bytes if send address was successful */
+    for (unsigned int i = 0; i < len; i++) {
+        if ((res = _i2c_read_byte (bus, &(((uint8_t*)data)[i]), i < len-1)) != 0) {
+            break;
+        }
+    }
+
+    /* send STOP condition if I2C_NOSTOP flag is not set */
+    if (!(flags & I2C_NOSTOP)) {
+        _i2c_stop_cond (bus);
+    }
+
+    return res;
+}
+
+int /* IRAM */ i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint8_t flags)
+{
+    DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n",
+           __func__, dev, addr, data, len, flags);
+
+    CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL);
+    CHECK_PARAM_RET (len > 0, -EINVAL);
+    CHECK_PARAM_RET (data != NULL, -EINVAL);
+
+    _i2c_bus_t* bus = &_i2c_bus[dev];
+
+    int res = 0;
+
+    /*  if I2C_NOSTART is not set, send START condition and ADDR */
+    if (!(flags & I2C_NOSTART)) {
+
+        /* START condition */
+        if ((res = _i2c_start_cond (bus)) != 0) {
+            return res;
+        }
+
+        /* send 10 bit or 7 bit address */
+        if (flags & I2C_ADDR10) {
+            /* prepare 10 bit address bytes */
+            uint8_t addr1 = 0xf0 | (addr & 0x0300) >> 7;
+            uint8_t addr2 = addr & 0xff;
+            /* send address bytes without read flag */
+            if ((res = _i2c_write_byte (bus, addr1)) != 0 ||
+                (res = _i2c_write_byte (bus, addr2)) != 0) {
+                return res;
+            }
+        }
+        else {
+            /* send address byte without read flag */
+            if ((res = _i2c_write_byte (bus, addr << 1)) != 0) {
+                return res;
+            }
+        }
+    }
+
+    /* send bytes if send address was successful */
+    for (unsigned int i = 0; i < len; i++) {
+        if ((res = _i2c_write_byte (bus, ((uint8_t*)data)[i])) != 0) {
+            break;
+        }
+    }
+
+    /* send STOP condition if I2C_NOSTOP flag is not set */
+    if (!(flags & I2C_NOSTOP)) {
+        return _i2c_stop_cond (bus);
+    }
+
+    return res;
+}
+
+void i2c_poweron(i2c_t dev)
+{
+    /* since I2C is realized in software there is no device to power on */
+    /* just return */
+}
+
+void i2c_poweroff(i2c_t dev)
+{
+    /* since I2C is realized in software there is no device to power off */
+    /* just return */
+}
+
+/* --- internal functions --- */
+
+static inline void _i2c_delay (_i2c_bus_t* bus)
+{
+    /* produces a delay */
+    /* ca. 20 cycles = 1 us (80 MHz) or ca. 40 cycles = 1 us (160 MHz) */
+
+    uint32_t cycles = bus->delay;
+    if (cycles) {
+        __asm__ volatile ("1:  _addi.n  %0, %0, -1 \n"
+                          "    bnez     %0, 1b     \n" : "=r" (cycles) : "0" (cycles));
+    }
+}
+
+/*
+ * Please note: SDA and SDL pins are used in GPIO_OD_PU mode
+ *              (open-drain with pull-ups).
+ *
+ * Setting a pin which is in open-drain mode leaves the pin floating and
+ * the signal is pulled up to high. The signal can then be actively driven
+ * to low by a slave. A read operation returns the current signal at the pin.
+ *
+ * Clearing a pin which is in open-drain mode actively drives the signal to
+ * low.
+ */
+
+static inline bool _i2c_read_scl(_i2c_bus_t* bus)
+{
+    /* read SCL status (pin is in open-drain mode and set) */
+    return GPIO.IN & bus->scl_bit;
+}
+
+static inline bool _i2c_read_sda(_i2c_bus_t* bus)
+{
+    /* read SDA status (pin is in open-drain mode and set) */
+    return GPIO.IN & bus->sda_bit;
+}
+
+static inline void _i2c_set_scl(_i2c_bus_t* bus)
+{
+    /* set SCL signal high (pin is in open-drain mode and pulled-up) */
+    GPIO.OUT_SET = bus->scl_bit;
+}
+
+static inline void _i2c_clear_scl(_i2c_bus_t* bus)
+{
+    /* set SCL signal low (actively driven to low) */
+    GPIO.OUT_CLEAR = bus->scl_bit;
+}
+
+static inline void _i2c_set_sda(_i2c_bus_t* bus)
+{
+    /* set SDA signal high (pin is in open-drain mode and pulled-up) */
+    GPIO.OUT_SET = bus->sda_bit;
+}
+
+static inline void _i2c_clear_sda(_i2c_bus_t* bus)
+{
+    /* set SDA signal low (actively driven to low) */
+    GPIO.OUT_CLEAR = bus->sda_bit;
+}
+
+static /* IRAM */ int _i2c_arbitration_lost (_i2c_bus_t* bus, const char* func)
+{
+    DEBUG("%s: arbitration lost dev=%u\n", func, bus->dev);
+
+    /* reset SCL and SDA to passive HIGH (floating and pulled-up) */
+    _i2c_set_sda (bus);
+    _i2c_set_scl (bus);
+
+    /* reset repeated start indicator */
+    bus->started = false;
+
+    return -EAGAIN;
+}
+
+static /* IRAM */ int _i2c_start_cond(_i2c_bus_t* bus)
+{
+    /*
+     * send start condition
+     * on entry: SDA and SCL are set to be floating and pulled-up to high
+     * on exit : SDA and SCL are actively driven to low
+     */
+
+    int res = 0;
+
+    if (bus->started) {
+        /* prepare the repeated start condition */
+
+        /* SDA = passive HIGH (floating and pulled-up) */
+        _i2c_set_sda (bus);
+
+        /* t_VD;DAT not neccessary */
+        /* _i2c_delay (bus); */
+
+        /* SCL = passive HIGH (floating and pulled-up) */
+        _i2c_set_scl (bus);
+
+        /* clock stretching, wait as long as clock is driven to low by the slave */
+        uint32_t stretch = I2C_CLOCK_STRETCH;
+        while (!_i2c_read_scl (bus) && stretch--) {}
+        if (stretch == 0) {
+            DEBUG("%s: clock stretching timeout dev=%u\n", __func__, bus->dev);
+            res = -ETIMEDOUT;
+        }
+
+        /* wait t_SU;STA - set-up time for a repeated START condition */
+        /* min. in us: 4.7 (SM), 0.6 (FM), 0.26 (FPM), 0.16 (HSM); no max. */
+        _i2c_delay (bus);
+    }
+
+    /* if SDA is low, arbitration is lost and someone else is driving the bus */
+    if (!_i2c_read_sda (bus)) {
+        return _i2c_arbitration_lost (bus, __func__);
+    }
+
+    /* begin the START condition: SDA = active LOW */
+    _i2c_clear_sda (bus);
+
+    /* wait t_HD;STA - hold time (repeated) START condition, */
+    /* max none */
+    /* min 4.0 us (SM), 0.6 us (FM), 0.26 us (FPM), 0.16 us (HSM) */
+    _i2c_delay (bus);
+
+    /* complete the START condition: SCL = active LOW */
+    _i2c_clear_scl (bus);
+
+    /* needed for repeated start condition */
+    bus->started = true;
+
+    return res;
+}
+
+static /* IRAM */ int _i2c_stop_cond(_i2c_bus_t* bus)
+{
+    /*
+     * send stop condition
+     * on entry: SCL is active low and SDA can be changed
+     * on exit : SCL and SDA are set to be floating and pulled-up to high
+     */
+
+    int res = 0;
+
+    /* begin the STOP condition: SDA = active LOW */
+    _i2c_clear_sda (bus);
+
+    /* wait t_LOW - LOW period of SCL clock */
+    /* min. in us: 4.7 (SM), 1.3 (FM), 0.5 (FPM), 0.16 (HSM); no max. */
+    _i2c_delay (bus);
+
+    /* SCL = passive HIGH (floating and pulled up) while SDA = active LOW */
+    _i2c_set_scl (bus);
+
+    /* clock stretching, wait as long as clock is driven to low by the slave */
+    uint32_t stretch = I2C_CLOCK_STRETCH;
+    while (!_i2c_read_scl (bus) && stretch--) {}
+    if (stretch == 0) {
+        DEBUG("%s: clock stretching timeout dev=%u\n", __func__, bus->dev);
+        res = -ETIMEDOUT;
+    }
+
+    /* wait t_SU;STO - hold time (repeated) START condition, */
+    /* min. in us: 4.0 (SM), 0.6 (FM), 0.26 (FPM), 0.16 (HSM); no max. */
+    _i2c_delay (bus);
+
+    /* complete the STOP condition: SDA = passive HIGH (floating and pulled up) */
+    _i2c_set_sda (bus);
+
+    /* reset repeated start indicator */
+    bus->started = false;
+
+    /* wait t_BUF - bus free time between a STOP and a START condition */
+    /* min. in us: 4.7 (SM), 1.3 (FM), 0.5 (FPM), 0.16 (HSM); no max. */
+    _i2c_delay (bus);
+
+    /* if SDA is low, arbitration is lost and someone else is driving the bus */
+    if (_i2c_read_sda (bus) == 0) {
+        return _i2c_arbitration_lost (bus, __func__);
+    }
+
+    return res;
+}
+
+static /* IRAM */ int _i2c_write_bit (_i2c_bus_t* bus, bool bit)
+{
+    /*
+     * send one bit
+     * on entry: SCL is active low, SDA can be changed
+     * on exit : SCL is active low, SDA can be changed
+     */
+
+    int res = 0;
+
+    /* SDA = bit */
+    if (bit) {
+        _i2c_set_sda (bus);
+    }
+    else {
+        _i2c_clear_sda (bus);
+    }
+
+    /* wait t_VD;DAT - data valid time (time until data are valid) */
+    /* max. in us: 3.45 (SM), 0.9 (FM), 0.45 (FPM); no min */
+    _i2c_delay (bus);
+
+    /* SCL = passive HIGH (floating and pulled-up), SDA value is available */
+    _i2c_set_scl (bus);
+
+    /* wait t_HIGH - time for the slave to read SDA */
+    /* min. in us: 4 (SM), 0.6 (FM), 0.26 (FPM), 0.09 (HSM); no max. */
+    _i2c_delay (bus);
+
+    /* clock stretching, wait as long as clock is driven low by the slave */
+    uint32_t stretch = I2C_CLOCK_STRETCH;
+    while (!_i2c_read_scl (bus) && stretch--) {}
+    if (stretch == 0) {
+        DEBUG("%s: clock stretching timeout dev=%u\n", __func__, bus->dev);
+        res = -ETIMEDOUT;
+    }
+
+    /* if SCL is high, now data is valid */
+    /* if SDA is high, check that nobody else is driving SDA low */
+    if (bit && !_i2c_read_sda(bus)) {
+        return _i2c_arbitration_lost (bus, __func__);
+    }
+
+    /* SCL = active LOW to allow next SDA change */
+    _i2c_clear_scl(bus);
+
+    return res;
+}
+
+static /* IRAM */ int _i2c_read_bit (_i2c_bus_t* bus, bool* bit)
+{
+    /* read one bit
+     * on entry: SCL is active low, SDA can be changed
+     * on exit : SCL is active low, SDA can be changed
+     */
+
+    int res = 0;
+
+    /* SDA = passive HIGH (floating and pulled-up) to let the slave drive data */
+    _i2c_set_sda (bus);
+
+    /* wait t_VD;DAT - data valid time (time until data are valid) */
+    /* max. in us: 3.45 (SM), 0.9 (FM), 0.45 (FPM); no min */
+    _i2c_delay (bus);
+
+    /* SCL = passive HIGH (floating and pulled-up), SDA value is available */
+    _i2c_set_scl (bus);
+
+    /* clock stretching, wait as long as clock is driven to low by the slave */
+    uint32_t stretch = I2C_CLOCK_STRETCH;
+    while (!_i2c_read_scl (bus) && stretch--) {}
+    if (stretch == 0) {
+        DEBUG("%s: clock stretching timeout dev=%u\n", __func__, bus->dev);
+        res = -ETIMEDOUT;
+    }
+
+    /* wait t_HIGH - time for the slave to read SDA */
+    /* min. in us: 4 (SM), 0.6 (FM), 0.26 (FPM), 0.09 (HSM); no max. */
+    _i2c_delay (bus);
+
+    /* SCL is high, read out bit */
+    *bit = _i2c_read_sda (bus);
+
+    /* SCL = active LOW to allow next SDA change */
+    _i2c_clear_scl(bus);
+
+    return res;
+}
+
+static /* IRAM */ int _i2c_write_byte (_i2c_bus_t* bus, uint8_t byte)
+{
+    /* send one byte and returns 0 in case of ACK from slave */
+
+    /* send the byte from MSB to LSB */
+    for (unsigned i = 0; i < 8; i++) {
+        int res = _i2c_write_bit(bus, (byte & 0x80) != 0);
+        if (res != 0) {
+            return res;
+        }
+        byte = byte << 1;
+    }
+
+    /* read acknowledge bit (low) from slave */
+    bool bit;
+    int res = _i2c_read_bit (bus, &bit);
+    if (res != 0) {
+        return res;
+    }
+
+    return !bit ? 0 : -EIO;
+}
+
+
+static /* IRAM */ int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack)
+{
+    bool bit;
+
+    /* read the byte */
+    for (unsigned i = 0; i < 8; i++) {
+        int res = _i2c_read_bit (bus, &bit);
+        if (res != 0) {
+            return res;
+        }
+        *byte = (*byte << 1) | bit;
+    }
+
+    /* write acknowledgement flag */
+    _i2c_write_bit(bus, !ack);
+
+    return 0;
+}
+
+void i2c_print_config(void)
+{
+    for (unsigned bus = 0; bus < I2C_NUMOF; bus++) {
+        LOG_INFO("\tI2C_DEV(%d): scl=%d sda=%d\n",
+                 bus, _i2c_bus[bus].scl, _i2c_bus[bus].sda);
+    }
+}
+
+#else /* if defined(I2C_NUMOF) && I2C_NUMOF */
+
+void i2c_print_config(void)
+{
+    LOG_INFO("\tI2C: no devices\n");
+}
+
+#endif /* if defined(I2C_NUMOF) && I2C_NUMOF */
diff --git a/cpu/esp8266/periph/pm.c b/cpu/esp8266/periph/pm.c
new file mode 100644
index 0000000000000000000000000000000000000000..5546b715c0958a89ec6b5cbb6d8a9fe81e7e9eb7
--- /dev/null
+++ b/cpu/esp8266/periph/pm.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_pm
+ * @{
+ *
+ * @file
+ * @brief       Implementation of power management functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+#include <stdbool.h>
+
+#include "irq.h"
+
+#include "esp/xtensa_ops.h"
+#include "sdk/ets_task.h"
+#include "sdk/sdk.h"
+
+#include "syscalls.h"
+
+void pm_set_lowest(void)
+{
+    DEBUG ("%s\n", __func__);
+
+    /* execute all pending system tasks before going to sleep */
+    /* is it really necessary, the timer interrupt is thrown every some ms? */
+    ets_tasks_run ();
+
+    #if !defined(QEMU)
+    DEBUG ("%s enter to sleep @%u\n", __func__, phy_get_mactime());
+
+    /* passive wait for interrupt to leave lowest power mode */
+    __asm__ volatile ("waiti 0");
+
+    DEBUG ("%s exit from sleep @%u\n", __func__, phy_get_mactime());
+    #endif
+
+    /*
+     * We could execute all pending system tasks after an interrupt before
+     * continuing RIOT. However, to give RIOT tasks the highest priority,
+     * *ets_tasks_run* should be called only before going to sleep
+     */
+    ets_tasks_run ();
+}
+
+void pm_off(void)
+{
+    DEBUG ("%s\n", __func__);
+    system_deep_sleep(0);
+}
+
+void pm_reboot(void)
+{
+    DEBUG ("%s\n", __func__);
+
+    /* shut down WIFI and call system_restart_local after timer */
+    system_restart ();
+}
diff --git a/cpu/esp8266/periph/pwm.c b/cpu/esp8266/periph/pwm.c
new file mode 100644
index 0000000000000000000000000000000000000000..4f72a574f5ac8ba13e36cad438f07e4687cc0f31
--- /dev/null
+++ b/cpu/esp8266/periph/pwm.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_pwm
+ * @{
+ *
+ * @file
+ * @brief       Low-level PWM driver implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+#include "cpu.h"
+#include "log.h"
+#include "irq_arch.h"
+#include "periph/pwm.h"
+#include "periph/gpio.h"
+
+#include "common.h"
+#include "esp/iomux_regs.h"
+#include "esp/timer_regs.h"
+#include "gpio_common.h"
+#include "sdk/ets.h"
+
+#if defined(PWM_NUMOF) && PWM_NUMOF > 0
+
+#define TIMER_FRC1_CLKDIV_16    BIT(2)
+#define TIMER_FRC1_CLKDIV_256   BIT(3)
+
+#define ETS_FRC1_INT_ENABLE     ETS_FRC1_INTR_ENABLE
+#define ETS_FRC1_INT_DISABLE    ETS_FRC1_INTR_DISABLE
+#define ETS_FRC1_INT_ATTACH     ETS_FRC_TIMER1_INTR_ATTACH
+#define ETS_FRC1_NMI_ATTACH     ETS_FRC_TIMER1_NMI_INTR_ATTACH
+
+typedef struct
+{
+    uint16_t    duty;
+    uint32_t    next_on;
+    uint32_t    next_off;
+    gpio_t      gpio;
+
+} _pwm_chn_t;
+
+typedef struct
+{
+    pwm_mode_t  mode;
+    uint16_t    res;
+    uint32_t    load;
+    uint32_t    cycles;
+    uint8_t     chn_num;
+    _pwm_chn_t  chn[PWM_CHANNEL_NUM_MAX];
+
+} _pwm_dev_t;
+
+static _pwm_dev_t _pwm_dev;
+
+static const uint32_t _pwm_channel_gpios[] = PWM0_CHANNEL_GPIOS;
+
+static void _pwm_timer_handler (void* arg)
+{
+    irq_isr_enter ();
+
+    _pwm_dev.cycles++;
+
+    for (int i = 0; i < _pwm_dev.chn_num; i++) {
+        if (_pwm_dev.chn[i].duty != 0 &&
+            _pwm_dev.chn[i].next_on == _pwm_dev.cycles) {
+            gpio_set (_pwm_dev.chn[i].gpio);
+            _pwm_dev.chn[i].next_on += _pwm_dev.res;
+        }
+        else if (_pwm_dev.chn[i].duty < _pwm_dev.res &&
+                 _pwm_dev.chn[i].next_off == _pwm_dev.cycles) {
+            gpio_clear (_pwm_dev.chn[i].gpio);
+            _pwm_dev.chn[i].next_off += _pwm_dev.res;
+        }
+    }
+
+    irq_isr_exit ();
+}
+
+static void _pwm_start(void)
+{
+    /* enable the timer and the interrupt and load the counter */
+    TIMER_FRC1.CTRL = TIMER_FRC1_CLKDIV_16 | TIMER_CTRL_RELOAD | TIMER_CTRL_RUN;
+    TM1_EDGE_INT_ENABLE();
+    ETS_FRC1_INT_ENABLE();
+    TIMER_FRC1.LOAD = _pwm_dev.load;
+
+    _pwm_dev.cycles = 0;
+
+    /* set the duty for all channels to start them */
+    for (int i = 0; i < _pwm_dev.chn_num; i++) {
+        pwm_set(PWM_DEV(0), i, _pwm_dev.chn[i].duty);
+    }
+}
+
+static void _pwm_stop(void)
+{
+    /* disable the interrupt and the timer */
+    ETS_FRC1_INT_DISABLE();
+    TM1_EDGE_INT_DISABLE();
+    TIMER_FRC1.CTRL &= ~TIMER_CTRL_RUN;
+}
+
+#define PWM_MAX_CPS 100000UL  /* maximum cycles per second */
+
+uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
+{
+    DEBUG ("%s pwm=%u mode=%u freq=%u, res=%u\n", __func__, pwm, mode, freq, res);
+
+    uint8_t _pwm_channel_gpio_num = sizeof(_pwm_channel_gpios) >> 2;
+
+    CHECK_PARAM_RET (pwm < PWM_NUMOF, 0);
+    CHECK_PARAM_RET (freq > 0, 0);
+    CHECK_PARAM_RET (_pwm_channel_gpio_num <= PWM_CHANNEL_NUM_MAX, 0);
+
+    /* maximum number of cycles per second (freq*res) should not be greater than */
+    /* 100.000 (period of 10 us), reduce freq if neccessary and keep resolution */
+    if (res * freq > PWM_MAX_CPS) {
+        freq = PWM_MAX_CPS / res;
+    }
+
+    _pwm_dev.load = 5e6 / freq / res;   /* load value for FRC1 at TIMER_FRC1_CLKDIV_16 */
+    _pwm_dev.res = res;
+    _pwm_dev.chn_num = 0;
+    _pwm_dev.cycles = 0;
+    _pwm_dev.mode = mode;
+
+    for (int i = 0; i < _pwm_channel_gpio_num; i++) {
+        if (_gpio_pin_usage[_pwm_channel_gpios[i]] != _GPIO) {
+            LOG_ERROR("GPIO%d is used for something else and cannot be used as PWM output\n", i);
+            return 0;
+        }
+
+        if (gpio_init(_pwm_channel_gpios[i], GPIO_OUT) < 0) {
+            return 0;
+        }
+
+        gpio_clear (_pwm_channel_gpios[i]);
+
+        _pwm_dev.chn[_pwm_dev.chn_num].duty = 0;
+        _pwm_dev.chn[_pwm_dev.chn_num].next_on = 0;
+        _pwm_dev.chn[_pwm_dev.chn_num].next_off = 0;
+        _pwm_dev.chn[_pwm_dev.chn_num].gpio = _pwm_channel_gpios[i];
+
+        _pwm_dev.chn_num++;
+    }
+
+    TIMER_FRC1.CTRL = TIMER_FRC1_CLKDIV_16 | TIMER_CTRL_RELOAD | TIMER_CTRL_RUN;
+    ETS_FRC1_INT_ATTACH(_pwm_timer_handler,0);
+    TM1_EDGE_INT_ENABLE();
+    ETS_FRC1_INT_ENABLE();
+
+    TIMER_FRC1.LOAD = _pwm_dev.load;
+
+    return freq;
+}
+
+uint8_t pwm_channels(pwm_t pwm)
+{
+    CHECK_PARAM_RET (pwm < PWM_NUMOF, 0);
+
+    return _pwm_dev.chn_num;
+}
+
+void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
+{
+    DEBUG("%s pwm=%u channel=%u value=%u\n", __func__, pwm, channel, value);
+
+    CHECK_PARAM (pwm < PWM_NUMOF);
+    CHECK_PARAM (channel < _pwm_dev.chn_num);
+    CHECK_PARAM (value <= _pwm_dev.res);
+
+    uint32_t state = irq_disable();
+    uint32_t phase = _pwm_dev.cycles - _pwm_dev.cycles % _pwm_dev.res + _pwm_dev.res;
+
+    switch (_pwm_dev.mode) {
+        case PWM_LEFT:
+            _pwm_dev.chn[channel].next_on  = phase;
+            break;
+
+        case PWM_RIGHT:
+            _pwm_dev.chn[channel].next_on  = phase + _pwm_dev.res - value;
+            break;
+
+        case PWM_CENTER:
+            _pwm_dev.chn[channel].next_on  = phase + (_pwm_dev.res - value) / 2;
+            break;
+    }
+
+    _pwm_dev.chn[channel].next_off = _pwm_dev.chn[channel].next_on + value;
+    _pwm_dev.chn[channel].duty = value;
+
+    irq_restore(state);
+}
+
+void pwm_poweron(pwm_t pwm)
+{
+    CHECK_PARAM (pwm < PWM_NUMOF);
+
+    _pwm_start();
+}
+
+void pwm_poweroff(pwm_t pwm)
+{
+    CHECK_PARAM (pwm < PWM_NUMOF);
+
+    _pwm_stop ();
+}
+
+void pwm_print_config(void)
+{
+    LOG_INFO("\tPWM_DEV(0): channels=[ ");
+    for (unsigned i = 0; i < sizeof(_pwm_channel_gpios) >> 2; i++) {
+        LOG_INFO("%d ", _pwm_channel_gpios[i]);
+    }
+    LOG_INFO("]\n");
+}
+
+#else /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */
+
+void pwm_print_config(void)
+{
+    LOG_INFO("\tPWM: no devices\n");
+}
+
+#endif /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */
diff --git a/cpu/esp8266/periph/rtc.c b/cpu/esp8266/periph/rtc.c
new file mode 100644
index 0000000000000000000000000000000000000000..cfdabca47a7a633220da2395bc370dfcb009f91a
--- /dev/null
+++ b/cpu/esp8266/periph/rtc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_rtc
+ * @{
+ *
+ * @file
+ * @brief       Low-level RTC driver implementation using ESP8266 SDK
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#include "cpu.h"
+#include "log.h"
+#include "periph/rtc.h"
+
+#include "common.h"
+
+#include "sdk/ets.h"
+
+void rtc_init(void)
+{
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+}
+
+void rtc_poweron(void)
+{
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+}
+
+void rtc_poweroff(void)
+{
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+}
+
+int rtc_set_time(struct tm *ttime)
+{
+    (void) time;
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+    return -1;
+}
+
+int rtc_get_time(struct tm *ttime)
+{
+    (void) time;
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+    return -1;
+}
+
+int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
+{
+    (void) time;
+    (void) cb;
+    (void) arg;
+
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+    return -1;
+}
+
+int rtc_get_alarm(struct tm *time)
+{
+    (void) time;
+
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+    return -1;
+}
+
+void rtc_clear_alarm(void)
+{
+    /* TODO implement */
+    NOT_YET_IMPLEMENTED();
+}
diff --git a/cpu/esp8266/periph/spi.c b/cpu/esp8266/periph/spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d0440f7c1d5744ac16760a15f9d779425bd3a43
--- /dev/null
+++ b/cpu/esp8266/periph/spi.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_spi
+ * @{
+ *
+ * @file
+ * @brief       Low-level SPI driver implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+#include "common.h"
+#include "log.h"
+
+#if defined(MODULE_PERIPH_SPI)
+
+#include <string.h>
+
+#include "cpu.h"
+#include "mutex.h"
+#include "periph/spi.h"
+
+#include "esp/iomux_regs.h"
+#include "esp/spi_regs.h"
+
+#include "gpio_common.h"
+
+#define SPI_BUS_NUM     2
+#define SPI_BLOCK_SIZE  64         /* number of bytes per SPI transfer */
+
+static mutex_t _spi_lock[SPI_BUS_NUM] = { MUTEX_INIT };
+
+/* indicate whether SPI interface were already initilized */
+static bool _spi_initialized[SPI_BUS_NUM] = { false };
+
+/* indicate whether pins of the SPI interface were already initilized */
+static bool _spi_pins_initialized[SPI_BUS_NUM] = { false };
+
+/*
+ * GPIOs that were once initialized as SPI interface pins can not be used
+ * afterwards for anything else. Therefore, SPI interfaces are not initialized
+ * until they are used for the first time. The *spi_init* function is just a
+ * dummy for source code compatibility. The initialization of an SPI interface
+ * is performed by the *_spi_init_internal* function, which is called either by
+ * the *spi_init_cs* function or the *spi_acquire* function when the interface
+ * is used for the first time.
+ */
+void IRAM spi_init (spi_t bus)
+{
+    return;
+}
+
+void _spi_init_internal(spi_t bus)
+{
+    /* only one physical SPI(1) bus (HSPI) can be used for peripherals */
+    /* RIOT's SPI_DEV(0) is mapped to SPI(1) bus (HSPI) */
+    /* TODO SPI overlap mode SPI and HSPI */
+    CHECK_PARAM (bus == SPI_DEV(0));
+
+    /* avoid multiple initializations */
+    if (_spi_initialized[bus]) {
+        return;
+    }
+    _spi_initialized[bus] = true;
+
+    DEBUG("%s bus=%u\n", __func__, bus);
+
+    /* initialize pins */
+    spi_init_pins(bus);
+
+    /* check whether pins could be initialized, otherwise return, CS is not
+       initialized in spi_init_pins */
+    if (_gpio_pin_usage[SPI0_SCK_GPIO] != _SPI &&
+        _gpio_pin_usage[SPI0_MOSI_GPIO] != _SPI &&
+        _gpio_pin_usage[SPI0_MISO_GPIO] != _SPI) {
+        return;
+    }
+
+    /* set bus into a defined state */
+    SPI(bus).USER0  = SPI_USER0_MOSI | SPI_USER0_CLOCK_IN_EDGE | SPI_USER0_DUPLEX;
+    SPI(bus).USER0 |= SPI_USER0_CS_SETUP | SPI_USER0_CS_HOLD;
+
+    /* set byte order to little endian for read and write operations */
+    SPI(bus).USER0 &= ~(SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER);
+
+    /* set bit order to most significant first for read and write operations */
+    SPI(bus).CTRL0 = 0; /* ~(SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER); */
+
+    DEBUG("%s SPI(bus).USER0=%08x SPI(bus).CTRL0=%08x\n",
+          __func__,  SPI(bus).USER0, SPI(bus).CTRL0);
+}
+
+void spi_init_pins(spi_t bus)
+{
+    /* see spi_init */
+    CHECK_PARAM (bus == SPI_DEV(0));
+
+    /* call initialization of the SPI interface if it is not initialized yet */
+    if (!_spi_initialized[bus]) {
+        _spi_init_internal(bus);
+    }
+
+    /* avoid multiple pin initializations */
+    if (_spi_pins_initialized[bus]) {
+        return;
+    }
+    _spi_pins_initialized[bus] = true;
+
+    DEBUG("%s bus=%u\n", __func__, bus);
+
+    uint32_t iomux_func = (bus == 0) ? IOMUX_FUNC(1) : IOMUX_FUNC(2);
+
+    /*
+     * CS is handled as normal GPIO ouptut. Due to the small number of GPIOs
+     * we have, we do not initialize the default CS pin here. Either the app
+     * uses spi_init_cs to initialize the CS pin explicitly, or we initialize
+     * the default CS when spi_aquire is used first time.
+     */
+    IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] &= ~IOMUX_PIN_FUNC_MASK;
+    IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] &= ~IOMUX_PIN_FUNC_MASK;
+    IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]]  &= ~IOMUX_PIN_FUNC_MASK;
+
+    IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] |= iomux_func;
+    IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] |= iomux_func;
+    IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]]  |= iomux_func;
+
+    _gpio_pin_usage [SPI0_MISO_GPIO] = _SPI;  /* pin cannot be used for anything else */
+    _gpio_pin_usage [SPI0_MOSI_GPIO] = _SPI;  /* pin cannot be used for anything else */
+    _gpio_pin_usage [SPI0_SCK_GPIO]  = _SPI;  /* pin cannot be used for anything else */
+}
+
+int spi_init_cs(spi_t bus, spi_cs_t cs)
+{
+    DEBUG("%s bus=%u cs=%u\n", __func__, bus, cs);
+
+    /* see spi_init */
+    CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV);
+
+    /* call initialization of the SPI interface if it is not initialized yet */
+    if (!_spi_initialized[bus]) {
+        _spi_init_internal(bus);
+    }
+
+    /* return if pin is already initialized as SPI CS signal */
+    if (_gpio_pin_usage [cs] == _SPI) {
+        return SPI_OK;
+    }
+
+    if (_gpio_pin_usage [cs] != _GPIO) {
+        return SPI_NOCS;
+    }
+
+    gpio_init(cs, GPIO_OUT);
+    gpio_set (cs);
+
+    _gpio_pin_usage [cs]  = _SPI;  /* pin cannot be used for anything else */
+
+    return SPI_OK;
+}
+
+int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
+{
+    DEBUG("%s bus=%u cs=%u mode=%u clk=%u\n", __func__, bus, cs, mode, clk);
+
+    /* see spi_init */
+    CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV);
+
+    /* call initialization of the SPI interface if it is not initialized yet */
+    if (!_spi_initialized[bus]) {
+        _spi_init_internal(bus);
+    }
+
+    /* if parameter cs is GPIO_UNDEF, the default CS pin is used */
+    cs = (cs == GPIO_UNDEF) ? SPI0_CS0_GPIO : cs;
+
+    /* if the CS pin used is not yet initialized, we do it now */
+    if (_gpio_pin_usage[cs] != _SPI && spi_init_cs(bus, cs) != SPI_OK) {
+        LOG_ERROR("SPI_DEV(%d) CS signal could not be initialized\n", bus);
+        return SPI_NOCS;
+    }
+
+    /* lock the bus */
+    mutex_lock(&_spi_lock[bus]);
+
+    /* set SPI mode */
+    bool cpha = (mode == SPI_MODE_1 || mode == SPI_MODE_3);
+    bool cpol = (mode == SPI_MODE_2 || mode == SPI_MODE_3);
+
+    if (cpol) {
+        cpha = !cpha;  /* CPHA must be inverted when CPOL = 1 */
+    }
+
+    if (cpha) {
+        SPI(bus).USER0 |= SPI_USER0_CLOCK_OUT_EDGE;
+    }
+    else {
+        SPI(bus).USER0 &= ~SPI_USER0_CLOCK_OUT_EDGE;
+    }
+
+    if (cpol) {
+        SPI(bus).PIN |= SPI_PIN_IDLE_EDGE;
+    }
+    else {
+        SPI(bus).PIN &= ~SPI_PIN_IDLE_EDGE;
+    }
+
+    /* set SPI clock
+     * see ESP8266 Technical Reference Appendix 2 - SPI registers
+     * https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf
+     */
+
+    uint32_t spi_clkdiv_pre;
+    uint32_t spi_clkcnt_N;
+
+    switch (clk) {
+        case SPI_CLK_10MHZ:  spi_clkdiv_pre = 2;    /* predivides 80 MHz to 40 MHz */
+                             spi_clkcnt_N = 4;      /* 4 cycles results into 10 MHz */
+                             break;
+        case SPI_CLK_5MHZ:   spi_clkdiv_pre = 2;    /* predivides 80 MHz to 40 MHz */
+                             spi_clkcnt_N = 8;      /* 8 cycles results into 5 MHz */
+                             break;
+        case SPI_CLK_1MHZ:   spi_clkdiv_pre = 2;    /* predivides 80 MHz to 40 MHz */
+                             spi_clkcnt_N = 40;     /* 40 cycles results into 1 MHz */
+                             break;
+        case SPI_CLK_400KHZ: spi_clkdiv_pre = 20;   /* predivides 80 MHz to 4 MHz */
+                             spi_clkcnt_N = 10;     /* 10 cycles results into 400 kHz */
+                             break;
+        case SPI_CLK_100KHZ: spi_clkdiv_pre = 20;   /* predivides 80 MHz to 4 MHz */
+                             spi_clkcnt_N = 40;     /* 20 cycles results into 100 kHz */
+                             break;
+        default: spi_clkdiv_pre = 20;   /* predivides 80 MHz to 4 MHz */
+                 spi_clkcnt_N = 40;     /* 20 cycles results into 100 kHz */
+    }
+
+    /* register values are set to deviders-1 */
+    spi_clkdiv_pre--;
+    spi_clkcnt_N--;
+
+    DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n", __func__, spi_clkdiv_pre, spi_clkcnt_N);
+
+    /* SPI clock is derived from system bus frequency and should not be affected by */
+    /* CPU clock */
+
+    IOMUX.CONF &= ~(bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK
+                             : IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK);
+    SPI(bus).CLOCK  = VAL2FIELD_M (SPI_CLOCK_DIV_PRE, spi_clkdiv_pre) |
+                      VAL2FIELD_M (SPI_CLOCK_COUNT_NUM, spi_clkcnt_N) |
+                      VAL2FIELD_M (SPI_CLOCK_COUNT_HIGH, (spi_clkcnt_N+1)/2-1) |
+                      VAL2FIELD_M (SPI_CLOCK_COUNT_LOW, spi_clkcnt_N);
+
+    DEBUG("%s IOMUX.CONF=%08x SPI(bus).CLOCK=%08x\n",
+          __func__, IOMUX.CONF, SPI(bus).CLOCK);
+
+    return SPI_OK;
+}
+
+void spi_release(spi_t bus)
+{
+    /* see spi_init */
+    CHECK_PARAM (bus == SPI_DEV(0));
+
+    /* release the bus */
+    mutex_unlock(&_spi_lock[bus]);
+}
+
+/*
+ * Following functions are from the hardware SPI driver of the esp-open-rtos
+ * project.
+ *
+ * Copyright (c) Ruslan V. Uss, 2016
+ * BSD Licensed as described in the file LICENSE
+ * https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE
+ */
+
+inline static void _set_size(uint8_t bus, uint8_t bytes)
+{
+    uint32_t bits = ((uint32_t)bytes << 3) - 1;
+    SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MISO_BITLEN, bits);
+    SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MOSI_BITLEN, bits);
+}
+
+inline static void _wait(uint8_t bus)
+{
+    while (SPI(bus).CMD & SPI_CMD_USR) {}
+}
+
+inline static void _start(uint8_t bus)
+{
+    SPI(bus).CMD |= SPI_CMD_USR;
+}
+
+inline static void _store_data(uint8_t bus, const void *data, size_t len)
+{
+    uint8_t words = len / 4;
+    uint8_t tail = len % 4;
+
+    memcpy((void *)SPI(bus).W, data, len - tail);
+
+    if (!tail) {
+        return;
+    }
+
+    uint32_t last = 0;
+    uint8_t *offs = (uint8_t *)data + len - tail;
+    for (uint8_t i = 0; i < tail; i++) {
+        last = last | (offs[i] << (i * 8));
+    }
+    SPI(bus).W[words] = last;
+}
+
+static const uint8_t spi_empty_out[SPI_BLOCK_SIZE] = { 0 };
+
+static void _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len)
+{
+    DEBUG("%s bus=%u out=%p in=%p len=%u\n", __func__, bus, out, in, len);
+
+    /* transfer one block data */
+    _wait(bus);
+    _set_size(bus, len);
+    _store_data(bus, out ? out : spi_empty_out, len);
+    _start(bus);
+    _wait(bus);
+    if (in) {
+        memcpy(in, (void *)SPI(bus).W, len);
+    }
+}
+
+void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
+                        const void *out, void *in, size_t len)
+{
+    /* see spi_init */
+    CHECK_PARAM (bus == SPI_DEV(0));
+
+    DEBUG("%s bus=%u cs=%u cont=%d out=%p in=%p len=%u\n",
+          __func__, bus, cs, cont, out, in, len);
+
+    if (!len) {
+        return;
+    }
+
+    #if ENABLE_DEBUG
+    if (out) {
+        DEBUG("out = ");
+        for (size_t i = 0; i < len; i++) {
+            DEBUG("%02x ", ((const uint8_t *)out)[i]);
+        }
+        DEBUG("\n");
+    }
+    #endif
+
+    if (cs != SPI_CS_UNDEF) {
+        gpio_clear (cs);
+    }
+
+    size_t blocks = len / SPI_BLOCK_SIZE;
+    uint8_t tail = len % SPI_BLOCK_SIZE;
+
+    DEBUG("%s bus=%u cs=%u blocks=%d tail=%d\n",
+          __func__, bus, cs, blocks, tail);
+
+    for (size_t i = 0; i < blocks; i++) {
+        _spi_buf_transfer(bus,
+                          out ? (const uint8_t *)out + i * SPI_BLOCK_SIZE : NULL,
+                          in  ? (uint8_t *)in + i * SPI_BLOCK_SIZE : NULL, SPI_BLOCK_SIZE);
+    }
+
+    if (tail) {
+        _spi_buf_transfer(bus,
+                          out ? (const uint8_t *)out + blocks * SPI_BLOCK_SIZE : 0,
+                          in  ? (uint8_t *)in + blocks * SPI_BLOCK_SIZE : NULL, tail);
+    }
+
+    if (!cont && (cs != SPI_CS_UNDEF)) {
+        gpio_set (cs);
+    }
+
+    #if ENABLE_DEBUG
+    if (in) {
+        DEBUG("in = ");
+        for (size_t i = 0; i < len; i++) {
+            DEBUG("%02x ", ((const uint8_t *)in)[i]);
+        }
+        DEBUG("\n");
+    }
+    #endif
+}
+
+void spi_print_config(void)
+{
+    LOG_INFO("\tSPI_DEV(0): ");
+    LOG_INFO("sck=%d " , SPI0_SCK_GPIO);
+    LOG_INFO("miso=%d ", SPI0_MISO_GPIO);
+    LOG_INFO("mosi=%d ", SPI0_MOSI_GPIO);
+    LOG_INFO("cs=%d\n" , SPI0_CS0_GPIO);
+}
+
+#else /* MODULE_PERIPH_SPI */
+
+void spi_print_config(void)
+{
+    LOG_INFO("\tSPI: no devices\n");
+}
+
+#endif /* MODULE_PERIPH_SPI */
diff --git a/cpu/esp8266/periph/timer.c b/cpu/esp8266/periph/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d26ba8adaab489c148bac24e74fe1aa8ca76a90
--- /dev/null
+++ b/cpu/esp8266/periph/timer.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_timer
+ * @{
+ *
+ * @file
+ * @brief       Low-level timer driver implementation using ESP8266 SDK
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+/* WARNING! enable debugging will have timing side effects and can lead
+ * to timer underflows, system crashes or system dead locks in worst case. */
+#define ENABLE_DEBUG 0
+#include "debug.h"
+#include "log.h"
+
+#include "xtimer.h"
+#include "periph/timer.h"
+
+#include "common.h"
+#include "irq_arch.h"
+#include "esp/common_macros.h"
+#include "sdk/sdk.h"
+#include "xtensa/hal.h"
+
+#if !defined(MODULE_ESP_SW_TIMER)
+
+/* hardware timer used */
+
+#define HW_TIMER_NUMOF        1
+#define HW_TIMER_CHANNELS     1
+
+#define HW_TIMER_MASK         0xffffffff
+#define HW_TIMER_DELTA_MAX    0x00ffffff    /* in us */
+#define HW_TIMER_DELTA_MIN    0x00000001    /* in us */
+#define HW_TIMER_DELTA_MASK   0x00ffffff
+#define HW_TIMER_DELTA_RSHIFT 24
+#define HW_TIMER_CORRECTION   2             /* overhead in us */
+
+#define HW_TIMER_CLOCK             (APB_CLK_FREQ)
+
+#define US_TO_HW_TIMER_TICKS(t)    (t * system_get_cpu_freq())
+#define HW_TIMER_TICKS_TO_US(t)    (t / system_get_cpu_freq())
+
+struct hw_channel_t
+{
+    bool        used;         /* indicates whether the channel is used */
+    uint32_t    start_time;   /* physical time when the timer channel has been started */
+    uint32_t    delta_time;   /* timer delta value (delta = cycles * timer_max + remainder) */
+    uint32_t    cycles;       /* number of complete max timer cycles */
+    uint32_t    remainder;    /* remainder timer value */
+};
+
+struct hw_timer_t
+{
+    bool                 initialized; /* indicates whether timer is already initialized */
+    bool                 started;     /* indicates whether timer is already started */
+    timer_isr_ctx_t      isr_ctx;
+    struct hw_channel_t  channels[HW_TIMER_CHANNELS];
+};
+
+static struct hw_timer_t timers[HW_TIMER_NUMOF] = { };
+
+static void __timer_channel_start (struct hw_timer_t* timer, struct hw_channel_t* channel);
+static void __timer_channel_stop (struct hw_timer_t* timer, struct hw_channel_t* channel);
+
+static uint32_t __hw_timer_ticks_max;
+static uint32_t __hw_timer_ticks_min;
+
+void IRAM hw_timer_handler(void* arg)
+{
+    uint32_t dev = (uint32_t)arg >> 4;
+    uint32_t chn = (uint32_t)arg & 0xf;
+
+    if (dev >= HW_TIMER_NUMOF && chn >= HW_TIMER_CHANNELS) {
+        return;
+    }
+
+    irq_isr_enter();
+
+    DEBUG("%s arg=%p\n", __func__, arg);
+
+    struct hw_timer_t*   timer   = &timers[dev];
+    struct hw_channel_t* channel = &timer->channels[chn];
+
+    if (channel->cycles) {
+        channel->cycles--;
+        xthal_set_ccompare(0, __hw_timer_ticks_max + xthal_get_ccount());
+    }
+    else if (channel->remainder >= HW_TIMER_DELTA_MIN) {
+        xthal_set_ccompare (0, US_TO_HW_TIMER_TICKS(channel->remainder) + xthal_get_ccount());
+        channel->remainder = 0;
+    }
+    else {
+        channel->remainder = 0;
+        channel->used = false;
+        ets_isr_mask (BIT(ETS_CCOM_INUM));
+        xthal_set_ccompare (0, 0);
+        timer->isr_ctx.cb(timer->isr_ctx.arg, chn);
+    }
+
+    irq_isr_exit();
+}
+
+int timer_init (tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
+{
+    DEBUG("%s dev=%u freq=%lu cb=%p arg=%p\n", __func__, dev, freq, cb, arg);
+
+    CHECK_PARAM_RET (dev  <  HW_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (freq == XTIMER_HZ_BASE, -1);
+    CHECK_PARAM_RET (cb   != NULL, -1);
+
+    if (timers[dev].initialized) {
+        DEBUG("%s timer dev=%u is already initialized (used)\n", __func__, dev);
+        return -1;
+    }
+
+    timers[dev].initialized = true;
+    timers[dev].started     = false;
+    timers[dev].isr_ctx.cb  = cb;
+    timers[dev].isr_ctx.arg = arg;
+
+    ets_isr_attach (ETS_CCOM_INUM, hw_timer_handler, NULL);
+
+    for (int i = 0; i < HW_TIMER_CHANNELS; i++) {
+        timers[dev].channels[i].used = false;
+        timers[dev].channels[i].cycles = 0;
+        timers[dev].channels[i].remainder = 0;
+    }
+
+    timer_start(dev);
+
+    return 0;
+}
+
+int IRAM timer_set(tim_t dev, int chn, unsigned int delta)
+{
+    DEBUG("%s dev=%u channel=%d delta=%u\n", __func__, dev, chn, delta);
+
+    CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (chn < HW_TIMER_CHANNELS, -1);
+
+    int state = irq_disable ();
+
+    struct hw_timer_t*   timer   = &timers[dev];
+    struct hw_channel_t* channel = &timer->channels[chn];
+
+    /* set delta time and channel used flag */
+    channel->delta_time = delta > HW_TIMER_CORRECTION ? delta - HW_TIMER_CORRECTION : 0;
+    channel->used       = true;
+
+    /* start channel with new delta time */
+    __timer_channel_start (timer, channel);
+
+    irq_restore (state);
+
+    return 0;
+}
+
+int IRAM timer_set_absolute(tim_t dev, int chn, unsigned int value)
+{
+    DEBUG("%s dev=%u channel=%d value=%u\n", __func__, dev, chn, value);
+
+    return timer_set (dev, chn, value - timer_read(dev));
+}
+
+int timer_clear(tim_t dev, int chn)
+{
+    DEBUG("%s dev=%u channel=%d\n", __func__, dev, chn);
+
+    CHECK_PARAM_RET (dev < HW_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (chn < HW_TIMER_CHANNELS, -1);
+
+    int state = irq_disable ();
+
+    /* stop running timer channel */
+    __timer_channel_stop (&timers[dev], &timers[dev].channels[chn]);
+
+    irq_restore (state);
+
+    return 0;
+}
+
+unsigned int IRAM timer_read(tim_t dev)
+{
+    (void)dev;
+
+    return phy_get_mactime ();
+}
+
+void IRAM timer_start(tim_t dev)
+{
+    DEBUG("%s dev=%u @%u\n", __func__, dev, phy_get_mactime());
+
+    CHECK_PARAM (dev < HW_TIMER_NUMOF);
+    CHECK_PARAM (!timers[dev].started);
+
+    int state = irq_disable ();
+
+    __hw_timer_ticks_max = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MAX);
+    __hw_timer_ticks_min = US_TO_HW_TIMER_TICKS(HW_TIMER_DELTA_MIN);
+
+    struct hw_timer_t* timer = &timers[dev];
+
+    timer->started = true;
+
+    for (int i = 0; i < HW_TIMER_CHANNELS; i++) {
+         __timer_channel_start (timer, &timer->channels[i]);
+    }
+
+    irq_restore (state);
+}
+
+void IRAM timer_stop(tim_t dev)
+{
+    DEBUG("%s dev=%u\n", __func__, dev);
+
+    CHECK_PARAM (dev < HW_TIMER_NUMOF);
+
+    int state = irq_disable ();
+
+    struct hw_timer_t* timer = &timers[dev];
+
+    timer->started = false;
+
+    for (int i = 0; i < HW_TIMER_CHANNELS; i++) {
+        __timer_channel_stop (timer, &timer->channels[i]);
+    }
+
+    irq_restore (state);
+}
+
+
+static void IRAM __timer_channel_start (struct hw_timer_t* timer, struct hw_channel_t* channel)
+{
+    if (!timer->started || !channel->used) {
+        return;
+    }
+
+    /* save channel starting time */
+    channel->start_time = timer_read (0);
+    channel->cycles     = channel->delta_time >> HW_TIMER_DELTA_RSHIFT;
+    channel->remainder  = channel->delta_time &  HW_TIMER_DELTA_MASK;
+
+    DEBUG("%s cycles=%u remainder=%u @%u\n",
+          __func__, channel->cycles, channel->remainder, phy_get_mactime());
+
+    /* start timer either with full cycles, remaining or minimum time */
+    if (channel->cycles) {
+        channel->cycles--;
+        xthal_set_ccompare(0, __hw_timer_ticks_max + xthal_get_ccount());
+    }
+    else if (channel->remainder >= HW_TIMER_DELTA_MIN) {
+        xthal_set_ccompare (0, US_TO_HW_TIMER_TICKS(channel->remainder) + xthal_get_ccount());
+        channel->remainder = 0;
+    }
+    else {
+        channel->remainder = 0;
+        xthal_set_ccompare(0, __hw_timer_ticks_min + xthal_get_ccount());
+    }
+
+    ets_isr_unmask (BIT(ETS_CCOM_INUM));
+}
+
+static void IRAM __timer_channel_stop (struct hw_timer_t* timer, struct hw_channel_t* channel)
+{
+    if (!channel->used) {
+        return;
+    }
+
+    ets_isr_mask (BIT(ETS_CCOM_INUM));
+
+    /* compute elapsed time */
+    uint32_t elapsed_time = timer_read (0) - channel->start_time;
+
+    if (channel->delta_time > elapsed_time) {
+        /* compute new delta time if the timer has no been expired */
+        channel->delta_time -= elapsed_time;
+    }
+    else {
+        /* otherwise deactivate the channel */
+        channel->used = false;
+    }
+}
+
+void timer_print_config(void)
+{
+    for (int i = 0; i < HW_TIMER_NUMOF; i++) {
+        LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i,
+                 sizeof(timers[i].channels) / sizeof(struct hw_channel_t));
+    }
+}
+
+#else /* MODULE_ESP_SW_TIMER */
+
+#ifndef MODULE_ESP_SDK
+#error Software timers are not available in Non-SDK version, use USE_SDK=1 to enable SDK-version.
+#else
+
+/* software timer based on os_timer_arm functions */
+
+#define OS_TIMER_NUMOF        1
+#define OS_TIMER_CHANNELS     10
+
+#define OS_TIMER_MASK         0xffffffff
+#define OS_TIMER_DELTA_MAX    0x0000ffff
+#define OS_TIMER_DELTA_MIN    0x00000064
+#define OS_TIMER_DELTA_MASK   0x0000ffff
+#define OS_TIMER_DELTA_RSHIFT 16
+#define OS_TIMER_CORRECTION   4
+
+/* Since hardware timer FRC1 is needed to implement PWM, we have to map our */
+/* timer using the exsting ETS timer with 1 us clock rate */
+
+struct phy_channel_t
+{
+    bool        used;         /* indicates whether the channel is used */
+    uint32_t    start_time;   /* physical time when the timer channel has been started */
+    uint32_t    delta_time;   /* timer delta value (delta = cycles * timer_max + remainder) */
+    uint32_t    cycles;       /* number of complete max timer cycles */
+    uint32_t    remainder;    /* remainder timer value */
+    os_timer_t  os_timer;     /* used system software timer */
+};
+
+struct phy_timer_t
+{
+    bool                 initialized; /* indicates whether timer is already initialized */
+    bool                 started;     /* indicates whether timer is already started */
+    timer_isr_ctx_t      isr_ctx;
+    struct phy_channel_t channels[OS_TIMER_CHANNELS];
+};
+
+static struct phy_timer_t timers[OS_TIMER_NUMOF] = { };
+
+static void __timer_channel_start (struct phy_timer_t* timer, struct phy_channel_t* channel);
+static void __timer_channel_stop (struct phy_timer_t* timer, struct phy_channel_t* channel);
+
+/* Since we use ETS software timers, it is not really an ISR. Therefore */
+/* we don't need to run in interrupt context. */
+
+void IRAM os_timer_handler (void* arg)
+{
+    uint32_t dev = (uint32_t)arg >> 4;
+    uint32_t chn = (uint32_t)arg & 0xf;
+
+    if (dev >= OS_TIMER_NUMOF && chn >= OS_TIMER_CHANNELS) {
+        return;
+    }
+
+    irq_isr_enter ();
+
+    struct phy_timer_t*   timer   = &timers[dev];
+    struct phy_channel_t* channel = &timer->channels[chn];
+
+    if (channel->cycles) {
+        channel->cycles--;
+        os_timer_arm_us (&channel->os_timer, OS_TIMER_DELTA_MAX, false);
+    }
+    else if (channel->remainder >= OS_TIMER_DELTA_MIN) {
+        os_timer_arm_us (&channel->os_timer, channel->remainder, false);
+        channel->remainder = 0;
+    }
+    else {
+        channel->remainder = 0;
+        channel->used = false;
+        timer->isr_ctx.cb(timer->isr_ctx.arg, chn);
+    }
+
+    irq_isr_exit ();
+}
+
+int timer_init (tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
+{
+    DEBUG("%s dev=%u freq=%lu cb=%p arg=%p\n", __func__, dev, freq, cb, arg);
+
+    CHECK_PARAM_RET (dev  <  OS_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (freq == XTIMER_HZ_BASE, -1);
+    CHECK_PARAM_RET (cb   != NULL, -1);
+
+    if (timers[dev].initialized) {
+        DEBUG("%s timer dev=%u is already initialized (used)\n", __func__, dev);
+        return -1;
+    }
+
+    timers[dev].initialized = true;
+    timers[dev].started     = false;
+    timers[dev].isr_ctx.cb  = cb;
+    timers[dev].isr_ctx.arg = arg;
+
+    for (int i = 0; i < OS_TIMER_CHANNELS; i++) {
+        os_timer_setfn(&timers[dev].channels[i].os_timer,
+                       os_timer_handler, (void*)((dev << 4) | i));
+        timers[dev].channels[i].used = false;
+        timers[dev].channels[i].cycles = 0;
+        timers[dev].channels[i].remainder = 0;
+    }
+
+    timer_start(dev);
+
+    return 0;
+}
+
+int IRAM timer_set(tim_t dev, int chn, unsigned int delta)
+{
+    DEBUG("%s dev=%u channel=%d delta=%u\n", __func__, dev, chn, delta);
+
+    CHECK_PARAM_RET (dev < OS_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (chn < OS_TIMER_CHANNELS, -1);
+
+    int state = irq_disable ();
+
+    struct phy_timer_t*   timer   = &timers[dev];
+    struct phy_channel_t* channel = &timer->channels[chn];
+
+    /* set delta time and channel used flag */
+    channel->delta_time = delta > OS_TIMER_CORRECTION ? delta - OS_TIMER_CORRECTION : 0;
+    channel->used       = true;
+
+    /* start channel with new delta time */
+    __timer_channel_start (timer, channel);
+
+    irq_restore (state);
+
+    return 0;
+}
+
+int IRAM timer_set_absolute(tim_t dev, int chn, unsigned int value)
+{
+    DEBUG("%s dev=%u channel=%d value=%u\n", __func__, dev, chn, value);
+
+    return timer_set (dev, chn, value - timer_read(dev));
+}
+
+int timer_clear(tim_t dev, int chn)
+{
+    DEBUG("%s dev=%u channel=%d\n", __func__, dev, chn);
+
+    CHECK_PARAM_RET (dev < OS_TIMER_NUMOF, -1);
+    CHECK_PARAM_RET (chn < OS_TIMER_CHANNELS, -1);
+
+    int state = irq_disable ();
+
+    /* stop running timer channel */
+    __timer_channel_stop (&timers[dev], &timers[dev].channels[chn]);
+
+    irq_restore (state);
+
+    return 0;
+}
+
+unsigned int IRAM timer_read(tim_t dev)
+{
+    (void)dev;
+
+    return phy_get_mactime ();
+}
+
+void IRAM timer_start(tim_t dev)
+{
+    DEBUG("%s dev=%u\n", __func__, dev);
+
+    CHECK_PARAM (dev < OS_TIMER_NUMOF);
+    CHECK_PARAM (!timers[dev].started);
+
+    int state = irq_disable ();
+
+    struct phy_timer_t* timer = &timers[dev];
+
+    timer->started = true;
+
+    for (int i = 0; i < OS_TIMER_CHANNELS; i++) {
+         __timer_channel_start (timer, &timer->channels[i]);
+    }
+
+    irq_restore (state);
+}
+
+void IRAM timer_stop(tim_t dev)
+{
+    DEBUG("%s dev=%u\n", __func__, dev);
+
+    CHECK_PARAM (dev < OS_TIMER_NUMOF);
+
+    int state = irq_disable ();
+
+    struct phy_timer_t* timer = &timers[dev];
+
+    timer->started = false;
+
+    for (int i = 0; i < OS_TIMER_CHANNELS; i++) {
+        __timer_channel_stop (timer, &timer->channels[i]);
+    }
+
+    irq_restore (state);
+}
+
+
+static void IRAM __timer_channel_start (struct phy_timer_t* timer, struct phy_channel_t* channel)
+{
+    if (!timer->started || !channel->used) {
+        return;
+    }
+
+    /* disarm old timer if already started */
+    os_timer_disarm (&channel->os_timer);
+
+    /* save channel starting time */
+    channel->start_time = timer_read (0);
+    channel->cycles     = channel->delta_time >> OS_TIMER_DELTA_RSHIFT;
+    channel->remainder  = channel->delta_time &  OS_TIMER_DELTA_MASK;
+
+    DEBUG("%s cycles=%u remainder=%u @%u\n",
+          __func__, channel->cycles, channel->remainder, phy_get_mactime());
+
+    /* start timer either with full cycles, remainder or minimum time */
+    if (channel->cycles) {
+        channel->cycles--;
+        os_timer_arm_us (&channel->os_timer, OS_TIMER_DELTA_MAX, false);
+    }
+    else if (channel->remainder > OS_TIMER_DELTA_MIN) {
+        os_timer_arm_us (&channel->os_timer, channel->remainder, false);
+        channel->remainder = 0;
+    }
+    else {
+        channel->remainder = 0;
+        os_timer_arm_us (&channel->os_timer, OS_TIMER_DELTA_MIN, false);
+    }
+}
+
+static void IRAM __timer_channel_stop (struct phy_timer_t* timer, struct phy_channel_t* channel)
+{
+    if (!channel->used) {
+        return;
+    }
+
+    os_timer_disarm (&channel->os_timer);
+
+    /* compute elapsed time */
+    uint32_t elapsed_time = timer_read (0) - channel->start_time;
+
+    if (channel->delta_time > elapsed_time) {
+        /* compute new delta time if the timer has no been expired */
+        channel->delta_time -= elapsed_time;
+    }
+    else {
+        /* otherwise deactivate the channel */
+        channel->used = false;
+    }
+}
+
+void timer_print_config(void)
+{
+    for (int i = 0; i < OS_TIMER_NUMOF; i++) {
+        LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i,
+                 sizeof(timers[i].channels) / sizeof(struct phy_channel_t));
+    }
+}
+
+#endif /* NON_SDK */
+
+#endif /* MODULE_ESP_SW_TIMER */
diff --git a/cpu/esp8266/periph/uart.c b/cpu/esp8266/periph/uart.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4ee15d7610a495481120fb527cc489d22c77306
--- /dev/null
+++ b/cpu/esp8266/periph/uart.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @ingroup     drivers_periph_uart
+ * @{
+ *
+ * @file
+ * @brief       Low-level UART driver implementation
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+#include "common.h"
+
+#include "cpu.h"
+#include "irq_arch.h"
+#include "log.h"
+#include "sched.h"
+#include "thread.h"
+
+#include "periph/uart.h"
+
+#include "eagle_soc.h"
+#include "esp/uart_regs.h"
+#include "sdk/sdk.h"
+
+/**
+ * @brief   Allocate memory to store the callback functions.
+ */
+static uart_isr_ctx_t isr_ctx[UART_NUMOF];
+
+static uint8_t IRAM __uart_rx_one_char (uart_t uart);
+static void __uart_tx_one_char(uart_t uart, uint8_t data);
+static void __uart_intr_enable (uart_t uart);
+static void IRAM __uart_intr_handler (void *para);
+
+int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
+{
+    CHECK_PARAM_RET (uart < UART_NUMOF, -1);
+
+    DEBUG("%s uart=%d, rate=%d, rx_cb=%p, arg=%p\n", __func__, uart, baudrate, rx_cb, arg);
+
+    /* setup the baudrate */
+    uart_div_modify(uart, UART_CLK_FREQ / baudrate);
+
+    /* register interrupt context */
+    isr_ctx[uart].rx_cb = rx_cb;
+    isr_ctx[uart].arg   = arg;
+
+    if (rx_cb) {
+        ets_isr_attach (ETS_UART_INUM, __uart_intr_handler, 0);
+
+        /* since reading is done byte for byte we set the RX FIFO FULL */
+        /* interrupt level to 1 byte */
+        UART(uart).CONF1 = SET_FIELD(UART(uart).CONF1, UART_CONF1_RXFIFO_FULL_THRESHOLD, 1);
+
+        /* enable the RX FIFO FULL interrupt */
+        __uart_intr_enable (uart);
+    }
+
+    return UART_OK;
+}
+
+void uart_write(uart_t uart, const uint8_t *data, size_t len)
+{
+    CHECK_PARAM (uart < UART_NUMOF);
+
+    for (size_t i = 0; i < len; i++) {
+        __uart_tx_one_char(uart, data[i]);
+    }
+}
+
+void uart_poweron (uart_t uart)
+{
+    /* UART can't be powered on/off, just return */
+}
+
+void uart_poweroff (uart_t uart)
+{
+    /* UART can't be powered on/off, just return */
+}
+
+void IRAM __uart_intr_handler (void *arg)
+{
+    /* to satisfy the compiler */
+    (void)arg;
+
+    irq_isr_enter ();
+
+    DEBUG("%s \n", __func__);
+
+    /*
+     * UART0 and UART1 interrupts are combined togther. So we have to
+     * iterate over all UART devices and test the INT_STATUS register for
+     * interrupts
+     */
+    for (int i = 0; i < UART_NUMOF; i++) {
+        uart_t uart = UART_DEV(0); /* UartDev.buff_uart_no; */
+        if (UART(uart).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
+            /* clear interrupt flag */
+            uint8_t data = __uart_rx_one_char (uart);
+
+            /* call registered RX callback function */
+            isr_ctx[uart].rx_cb(isr_ctx[uart].arg, data);
+
+            /* clear interrupt flag */
+            UART(uart).INT_CLEAR |= UART_INT_CLEAR_RXFIFO_FULL;
+        }
+        else {
+            /* TODO handle other type of interrupts, for the moment just clear them */
+            UART(uart).INT_CLEAR = 0x1f;
+        }
+    }
+    irq_isr_exit ();
+}
+
+/* RX/TX FIFO capacity is 128 byte */
+#define UART_FIFO_MAX 127
+
+/* receive one data byte with wait */
+static uint8_t IRAM __uart_rx_one_char (uart_t uart)
+{
+    /* uint8_t fifo_len = FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS); */
+
+    /* wait until at least von byte is in RX FIFO */
+    while (!FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS)) {}
+
+    /* read the lowest byte from RX FIFO register */
+    return UART(uart).FIFO & 0xff; /* only bit 0 ... 7 */
+}
+
+/* send one data byte with wait */
+static void __uart_tx_one_char(uart_t uart, uint8_t data)
+{
+    /* wait until at least one byte is avaiable in the TX FIFO */
+    while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(uart).STATUS) >= UART_FIFO_MAX) {}
+
+    /* send the byte by placing it in the TX FIFO */
+    UART(uart).FIFO = data;
+}
+
+static void __uart_intr_enable(uart_t uart)
+{
+    UART(uart).INT_ENABLE |= UART_INT_ENABLE_RXFIFO_FULL;
+    ETS_INTR_ENABLE(ETS_UART_INUM);
+
+    DEBUG("%s %08x\n", __func__, UART(uart).INT_ENABLE);
+}
+
+void uart_print_config(void)
+{
+    LOG_INFO("\tUART_DEV(0): txd=%d rxd=%d\n", UART0_TXD, UART0_RXD);
+}
diff --git a/cpu/esp8266/periph_cpu.c b/cpu/esp8266/periph_cpu.c
new file mode 100644
index 0000000000000000000000000000000000000000..48d3ff90b5b39cc3cde8e7d353ef6ce4ce811289
--- /dev/null
+++ b/cpu/esp8266/periph_cpu.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       CPU specific definitions and functions for peripheral handling
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ */
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+#include "periph_cpu.h"
diff --git a/cpu/esp8266/sdk/Makefile b/cpu/esp8266/sdk/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..167ad0f494db6f3f86dac984767e3cbed79a47ac
--- /dev/null
+++ b/cpu/esp8266/sdk/Makefile
@@ -0,0 +1,3 @@
+MODULE=sdk
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/sdk/doc.txt b/cpu/esp8266/sdk/doc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d0edd1fa1dbaf2844c61231accf9ad8db20351e8
--- /dev/null
+++ b/cpu/esp8266/sdk/doc.txt
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk ESP8266 SDK interface
+ * @ingroup     cpu_esp8266
+ * @brief       Function declarations and mappings for compatibility with ESP8266 SDK
+ */
diff --git a/cpu/esp8266/sdk/ets.c b/cpu/esp8266/sdk/ets.c
new file mode 100644
index 0000000000000000000000000000000000000000..799d6cb0ea1a78838c3fefcaea86c8c8086c81d2
--- /dev/null
+++ b/cpu/esp8266/sdk/ets.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 ETS ROM functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+#ifndef MODULE_ESP_SDK
+
+#include "sdk/ets.h"
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/ets.h b/cpu/esp8266/sdk/ets.h
new file mode 100644
index 0000000000000000000000000000000000000000..90b79a50d1bb69b484adfd06659da9d31ef00b42
--- /dev/null
+++ b/cpu/esp8266/sdk/ets.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 ETS ROM function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+#ifndef ETS_H
+#define ETS_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "c_types.h"
+#include "ets_sys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* interrupts that are not defined in espressif/ets_sys.h */
+#define ETS_WDEV_INUM  0    /* WDEV process FIQ interrupt */
+#define ETS_RTC_INUM   3    /* RTC interrupt */
+#define ETS_CCOM_INUM  6    /* CCOMPARE0 match interrupt */
+#define ETS_SOFT_INUM  7    /* software interrupt */
+#define ETS_WDT_INUM   8    /* SDK watchdog timer */
+#define ETS_FRC2_INUM  10   /* SDK FRC2 timer interrupt */
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING
+/*
+ * The following functions are mappings or dummies for source code
+ * compatibility of SDK and NON-SDK version
+ */
+
+#include "xtensa/xtensa_api.h"
+
+#define ets_isr_mask(x)         xt_ints_off(x)
+#define ets_isr_unmask(x)       xt_ints_on(x)
+#define ets_isr_attach(i,f,a)   xt_set_interrupt_handler(i,f,a)
+
+#define _xtos_set_exception_handler(n,f)    xt_set_exception_handler(n,f)
+
+#else /* MODULE_ESP_SDK_INT_HANDLING */
+
+extern void ets_isr_mask(uint32_t);
+extern void ets_isr_unmask(uint32_t);
+
+typedef void (_xtos_handler_t)(void*);
+extern void _xtos_set_exception_handler(int n, _xtos_handler_t* f);
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
+
+#ifndef MODULE_ESP_SDK
+extern void ets_delay_us(uint16_t us);
+extern void ets_timer_arm_new(ETSTimer *ptimer, uint32_t ms_us, int repeat_flag, int is_ms);
+extern void ets_timer_disarm(ETSTimer *ptimer);
+extern void ets_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *arg);
+#endif
+
+extern void ets_timer_arm(ETSTimer *ptimer, uint32_t ms, bool repeat_flag);
+extern void ets_timer_handler_isr(void);
+
+extern void ets_install_uart_printf(void);
+extern void ets_install_putc1(void (*p)(char c));
+extern int  ets_uart_printf(const char *format, ...);
+
+extern int  ets_putc(int);
+extern int  ets_printf(const char * format, ...);
+extern int  ets_vprintf(void *function, const char *format, va_list arg);
+
+extern uint8_t ets_get_cpu_frequency(void);
+extern void    ets_update_cpu_frequency(uint8_t);
+
+extern void *ets_memcpy(void *to, const void *from, size_t size);
+
+extern void ets_wdt_disable(void);
+extern void ets_wdt_enable (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* ETS_H */
diff --git a/cpu/esp8266/sdk/ets_task.c b/cpu/esp8266/sdk/ets_task.c
new file mode 100644
index 0000000000000000000000000000000000000000..da446e1be7fbfbafd44b37a702d21ae1dc3a5022
--- /dev/null
+++ b/cpu/esp8266/sdk/ets_task.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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.
+ *
+ * PLEASE NOTE: This file is only used in SDK version
+ */
+
+#ifdef MODULE_ESP_SDK
+
+#define ENABLE_DEBUG 0
+#include <stdio.h>
+
+#include "irq_arch.h"
+#include "mutex.h"
+#include "thread.h"
+
+#include "esp/common_macros.h"
+#include "sdk/ets_task.h"
+#include "sdk/sdk.h"
+
+#define TIMER_TASK_PRIORITY 31
+
+static uint8_t min_prio = 0;
+
+uint8_t ets_highest_1_bit (uint32_t mask)
+{
+    __asm__ volatile ("nsau %0, %1;" :"=r"(mask) : "r"(mask));
+    return 32 - mask;
+}
+
+/**
+ * @brief   Perform execution of all pending ETS system tasks.
+ *
+ * This is necessary to keep the underlying ETS system used by the
+ * SDK alive.
+ */
+void IRAM ets_tasks_run (void)
+{
+    #if ENABLE_DEBUG
+    uint32_t _entry = phy_get_mactime();
+    uint32_t _exit;
+    ets_printf("ets_tasks_run @%lu\n", _entry);
+    #endif
+
+    /* reset hardware watchdog here */
+    system_soft_wdt_feed();
+
+    while (1) {
+        uint8_t  hbit;
+        int state = irq_disable();
+        hbit = ets_highest_1_bit (ets_task_exec_mask);
+        if (min_prio < hbit) {
+            ets_task_tcb_t* task  = &ets_task_tab[hbit-1];
+            ETSEvent *      event = &task->queue[task->qposr++];
+            if (task->qposr == task->qlength) {
+                task->qposr = 0;
+            }
+            if (--task->qpending == 0) {
+                ets_task_exec_mask &= ~task->maskbit;
+            }
+            ets_task_min_prio = hbit;
+            irq_restore(state);
+            task->task(event);
+            ets_task_min_prio = min_prio;
+        }
+        else {
+            irq_restore(state);
+            break;
+        }
+    }
+
+    #if ENABLE_DEBUG
+    _exit = phy_get_mactime();
+    ets_printf("ets_tasks_run @%lu for %lu us\n", _entry, _exit - _entry);
+    #endif
+
+    /* reset hardware watchdog here again */
+    system_soft_wdt_feed();
+}
+
+/**
+ * To realize event-driven SDK functions such as WiFi functions and software
+ * timers, and to keep the system alive, the SDK internally uses its own
+ * tasks (SDK tasks) and its own scheduling mechanism. For this purpose, the
+ * SDK regularly executes SDK tasks with pending events in an endless loop
+ * using the ROM function *ets_run*.
+ *
+ * Interrupt service routines do not process interrupts directly but use
+ * the *ets_post* ROM function to send an event to one of these SDK tasks,
+ * which then processes the interrupts asynchronously. A context switch is
+ * not possible in the interrupt service routines.
+ *
+ * In the RIOT port, the task management of the SDK is replaced by the task
+ * management of the RIOT. To handle SDK tasks with pending events so that
+ * the SDK functions work and the system keeps alive, the ROM functions
+ * *ets_run* and *ets_post* are overwritten. The *ets_run* function performs
+ * all SDK tasks with pending events exactly once. It is executed at the end
+ * of the *ets_post* function and thus usually at the end of an SDK interrupt
+ * service routine or before the system goes into the lowest power mode.
+ *
+ * PLEASE REMEBER: we are doing that in interrupt context
+ *
+ * -> it must not take to much time (how can we ensure that)?
+ *
+ * -> we have to indicate that we are in interrupt context see *irq_is_in*
+ *    and *irq_interrupt_nesting* (as realized by the level 1 exception handler
+ *    in non SDK task handling environment, option MODULE_ESP_SDK_INT_HANDLING=0,
+ *    the default)
+ *
+ * -> we must not execute a context switch or we have to execute the context
+ *    switch from interrupt as following (as realized by the level 1
+ *    interrupt exception handler in non SDK task handling environment, option
+ *    MODULE_ESP_SDK_INT_HANDLING=0, the default)
+ *      _frxt_int_enter();
+ *      _frxt_switch_context();
+ *      _frxt_int_exit();
+ */
+
+typedef uint32_t (*ets_post_function_t)(uint32_t prio, ETSSignal sig, ETSParam par);
+
+static ets_post_function_t ets_post_rom = (ets_post_function_t)0x40000e24;
+
+#ifdef MODULE_ESP_SDK
+#define irom_cache_enabled() (*((uint32_t*)0x60000208) & (1 << 17))
+#else
+#define irom_cache_enabled() (1)
+#endif
+
+uint32_t IRAM ets_post (uint32_t prio, ETSSignal sig, ETSParam par)
+{
+    uint32_t ret;
+
+    critical_enter();
+
+    /* test whether we are in hardware timer interrupt handling routine */
+    if (prio == TIMER_TASK_PRIORITY) {
+        /* first call ETS system post function */
+        ret = ets_post_rom (prio, sig, par);
+
+        /* handle only pending timer events */
+        if (irom_cache_enabled()) {
+            ets_timer_handler_isr();
+        }
+    }
+    else {
+        /* simply call ROM ets_post function */
+        ret = ets_post_rom (prio, sig, par);
+    }
+    /* since only timer events are handled we have to reset watch dog timer */
+    if (irom_cache_enabled()) {
+        system_soft_wdt_feed();
+    }
+
+    critical_exit();
+
+    return ret;
+}
+
+void ets_tasks_init(void)
+{
+    /* there is nothing to do at the moment */
+}
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/ets_task.h b/cpu/esp8266/sdk/ets_task.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c031a1ca3477d11089829b2cb167a24a1f408a1
--- /dev/null
+++ b/cpu/esp8266/sdk/ets_task.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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 ETS_TASK_H
+#define ETS_TASK_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MODULE_ESP_SDK
+
+#include "ets_sys.h"
+
+extern uint8_t ets_task_min_prio;
+
+/* Task control block definition as used for ETS task functions */
+
+typedef struct {
+    ETSTask   task;     /* +0   task function */
+    ETSEvent* queue;    /* +4   event queue (ring buffer) */
+    uint8_t   qlength;  /* +8   event queue length */
+    uint8_t   qposw;    /* +9   event queue position for write */
+    uint8_t   qposr;    /* +10  event queue position for read */
+    uint8_t   qpending; /* +11  pending events */
+    uint32_t  maskbit;  /* +12  task mask bit */
+} ets_task_tcb_t;
+
+/* ROM variables, defined in esp8266.riot-os.app.ld */
+/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */
+
+extern uint8_t         ets_task_min_prio;  /* 0x3fffc6fc */
+extern void*           ets_idle_cb;        /* 0x3fffdab0 */
+extern void*           ets_idle_arg;       /* 0x3fffdab4 */
+extern uint32_t        ets_task_exec_mask; /* 0x3fffdab8 */
+extern ets_task_tcb_t  ets_task_tab[32];   /* 0x3fffdac0 */
+
+extern uint32_t ets_post (uint32_t prio, ETSSignal sig, ETSParam par);
+
+void ets_tasks_run (void);
+void ets_tasks_init (void);
+
+#else /* MODULE_ESP_SDK */
+
+#define ets_tasks_run()
+#define ets_tasks_init()
+
+#endif /* MODULE_ESP_SDK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* ETS_TASK_H */
diff --git a/cpu/esp8266/sdk/main.c b/cpu/esp8266/sdk/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..8db72d07bbad4e3ac7ffe295c4640d80ebe563f3
--- /dev/null
+++ b/cpu/esp8266/sdk/main.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK libmain function
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef MODULE_ESP_SDK
+
+#include <stdio.h>
+
+#include "c_types.h"
+
+#include "common.h"
+#include "cpu_conf.h"
+#include "irq.h"
+#include "irq_arch.h"
+#include "log.h"
+
+#include "esp/rtcmem_regs.h"
+#include "spi_flash.h"
+#include "sdk/ets.h"
+#include "sdk/main.h"
+#include "sdk/rom.h"
+
+extern char* _printf_buf;
+
+int IRAM os_printf_plus (const char* format, ...)
+{
+    va_list arglist;
+    va_start(arglist, format);
+
+    int ret = vsnprintf(_printf_buf, PRINTF_BUFSIZ, format, arglist);
+
+    if (ret > 0) {
+        ets_printf (_printf_buf);
+    }
+
+    va_end(arglist);
+
+    return ret;
+}
+
+SpiFlashOpResult IRAM spi_flash_read (uint32_t faddr, uint32_t *dst, size_t size)
+{
+    /*
+     * For simplicity, we use the ROM function. Since we need to disable the
+     * IROM cache function for that purpose, we have to be IRAM.
+     * Please note, faddr, src and size have to be aligned to 4 byte.
+     */
+
+    SpiFlashOpResult ret;
+
+    CHECK_PARAM_RET (dst != NULL, SPI_FLASH_RESULT_ERR);
+    CHECK_PARAM_RET (faddr + size <= flashchip->chip_size, SPI_FLASH_RESULT_ERR);
+
+    critical_enter ();
+    Cache_Read_Disable ();
+
+    ret = SPIRead (faddr, dst, size);
+
+    Cache_Read_Enable(0, 0, 1);
+    critical_exit ();
+
+    return ret;
+}
+
+SpiFlashOpResult IRAM spi_flash_write (uint32_t faddr, uint32_t *src, size_t size)
+{
+    /*
+     * For simplicity, we use the ROM function. Since we need to disable the
+     * IROM cache function for that purpose, we have to be in IRAM.
+     * Please note, faddr, src and size have to be aligned to 4 byte
+     */
+
+    SpiFlashOpResult ret;
+
+    CHECK_PARAM_RET (src != NULL, SPI_FLASH_RESULT_ERR);
+    CHECK_PARAM_RET (faddr + size <= flashchip->chip_size, SPI_FLASH_RESULT_ERR);
+
+    critical_enter ();
+    Cache_Read_Disable ();
+
+    ret = SPIWrite (faddr, src, size);
+
+    Cache_Read_Enable(0, 0, 1);
+    critical_exit ();
+
+    return ret;
+}
+
+SpiFlashOpResult IRAM spi_flash_erase_sector(uint16_t sec)
+{
+    CHECK_PARAM_RET (sec < flashchip->chip_size / flashchip->sector_size, SPI_FLASH_RESULT_ERR);
+
+    critical_enter ();
+    Cache_Read_Disable();
+
+    SpiFlashOpResult ret = SPIEraseSector (sec);
+
+    Cache_Read_Enable(0, 0, 1);
+    critical_exit ();
+
+    return ret;
+}
+
+void system_deep_sleep(uint32_t time_in_us)
+{
+    /* TODO implement */
+    (void)time_in_us;
+    NOT_YET_IMPLEMENTED();
+}
+
+void system_restart(void)
+{
+    /* TODO it's just a hard reset at the moment */
+    __asm__ volatile (" call0 0x40000080 ");
+}
+
+/**
+ * Following code is completly or at least partially from
+ * https://github.com/pvvx/esp8266web
+ * (c) PV` 2015
+ *
+ * @{
+ */
+
+uint8_t ICACHE_FLASH_ATTR system_get_checksum(uint8_t *ptr, uint32_t len)
+{
+    uint8_t checksum = 0xEF;
+    while (len--) {
+        checksum ^= *ptr++;
+    }
+    return checksum;
+}
+
+#define RTCMEM_SIZE 0x300      /* user RTC RAM 768 bytes, 192 dword registers */
+
+static bool IRAM _system_rtc_mem_access (uint32_t src, void *dst, uint32_t size, bool write)
+{
+    /* src hast to be smaller than 192 */
+    CHECK_PARAM_RET (src <= (RTCMEM_SIZE >> 2), false);
+    /* src times 4 plus size must less than RTCMEM_SIZE */
+    CHECK_PARAM_RET (((src << 2) + size) < RTCMEM_SIZE, false);
+    /* des_addr has to be a multiple of 4 */
+    CHECK_PARAM_RET (((uint32_t)dst & 0x3) == 0, false);
+
+    /* align size to next higher multiple of 4 */
+    if (size & 0x3) {
+        size = (size + 4) & ~0x3;
+    }
+
+    for (uint32_t i = 0; i < (size >> 2); i++) {
+        if (write) {
+            RTCMEM_SYSTEM[src + i] = ((uint32_t*)dst)[i];
+        }
+        else {
+            ((uint32_t*)dst)[i] = RTCMEM_SYSTEM[src + i];
+        }
+    }
+
+    return true;
+}
+
+bool IRAM system_rtc_mem_read (uint32_t src_addr, void *des_addr, uint32_t save_size)
+{
+    return _system_rtc_mem_access (src_addr, des_addr, save_size, false);
+}
+
+bool IRAM system_rtc_mem_write (uint32_t src_addr, void *des_addr, uint32_t save_size)
+{
+    return _system_rtc_mem_access (src_addr, des_addr, save_size, true);
+}
+
+/** @} */
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/main.h b/cpu/esp8266/sdk/main.h
new file mode 100644
index 0000000000000000000000000000000000000000..e87927e527adfbcb807bf74ef9e7f36bb1c36f72
--- /dev/null
+++ b/cpu/esp8266/sdk/main.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK libmain function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "c_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MODULE_ESP_SDK
+#include "esp/dport_regs.h"
+
+/*
+ * The following functions are mappings or dummies for source code
+ * compatibility of SDK and NON-SDK version
+ */
+
+#define system_get_time       phy_get_mactime
+#define system_get_chip_id()  (((DPORT.OTP_MAC1 & 0xffff) << 8) + ((DPORT.OTP_MAC0 >> 24) & 0xff))
+#define system_get_cpu_freq   ets_get_cpu_frequency
+/* TODO #define system_update_cpu_freq  ets_update_cpu_frequency */
+
+extern int      os_printf_plus (const char* format, ...);
+
+extern void     system_deep_sleep (uint32_t time_in_us);
+extern uint8_t  system_get_checksum(uint8_t *ptr, uint32_t len);
+extern void     system_restart (void);
+
+extern bool     system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint32_t save_size);
+extern bool     system_rtc_mem_write(uint32_t src_addr, void *des_addr, uint32_t save_size);
+
+#endif /* MODULE_ESP_SDK */
+
+extern void NmiTimSetFunc(void (*func)(void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* MAIN_H */
diff --git a/cpu/esp8266/sdk/phy.c b/cpu/esp8266/sdk/phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c7d4a3ab24ac3bd56dadad371f728dfd345ae28
--- /dev/null
+++ b/cpu/esp8266/sdk/phy.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK libphy functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef MODULE_ESP_SDK
+
+#include "sdk/phy.h"
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/phy.h b/cpu/esp8266/sdk/phy.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e06abc8045d081c5fa70e9b0519903ccb50d309
--- /dev/null
+++ b/cpu/esp8266/sdk/phy.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK libphy function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef PHY_H
+#define PHY_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "c_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MODULE_ESP_SDK
+/*
+ * The following functions are mappings or dummies for source code
+ * compatibility of SDK and NON-SDK version
+ */
+
+#include "esp/dport_regs.h"
+
+extern void     phy_afterwake_set_rfoption(int op);
+extern int      phy_check_data_table(void * gdctbl, int x, int flg);
+extern int      register_chipv6_phy(uint8_t * esp_init_data);
+extern void     sleep_reset_analog_rtcreg_8266(void);
+extern uint32_t test_tout(bool);
+extern void     write_data_to_rtc(uint8_t *);
+
+#endif /* MODULE_ESP_SDK */
+
+extern uint32_t phy_get_mactime(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* PHY_H */
diff --git a/cpu/esp8266/sdk/pp.c b/cpu/esp8266/sdk/pp.c
new file mode 100644
index 0000000000000000000000000000000000000000..930de41b2b5276a8f6ec0173fc822aa71ce924de
--- /dev/null
+++ b/cpu/esp8266/sdk/pp.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 other ROM functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef MODULE_ESP_SDK
+
+#include "sdk/pp.h"
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/pp.h b/cpu/esp8266/sdk/pp.h
new file mode 100644
index 0000000000000000000000000000000000000000..4909004364606e11e52baf9d63e0cf9f3978af6b
--- /dev/null
+++ b/cpu/esp8266/sdk/pp.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK libpp function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef PP_H
+#define PP_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "c_types.h"
+
+#ifndef MODULE_ESP_SDK
+/*
+ * The following functions are mappings or dummies for source code
+ * compatibility of SDK and NON-SDK version
+ */
+
+#define system_soft_wdt_feed()
+
+#endif /* MODULE_ESP_SDK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* PP_H */
diff --git a/cpu/esp8266/sdk/rom.c b/cpu/esp8266/sdk/rom.c
new file mode 100644
index 0000000000000000000000000000000000000000..377f10c0258a4e9e99ca25b5ad3c24ad26c9831d
--- /dev/null
+++ b/cpu/esp8266/sdk/rom.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 other ROM functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef MODULE_ESP_SDK
+
+#include "sdk/rom.h"
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/sdk/rom.h b/cpu/esp8266/sdk/rom.h
new file mode 100644
index 0000000000000000000000000000000000000000..e76862b375c6631cbb8fb75fd97ff9fb34349aba
--- /dev/null
+++ b/cpu/esp8266/sdk/rom.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 other ROM function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef ROM_H
+#define ROM_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "c_types.h"
+#include "spi_flash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MODULE_ESP_SDK
+/*
+ * The following functions are mappings or dummies for source code
+ * compatibility of SDK and NON-SDK version
+ */
+
+extern uint8_t rom_i2c_readReg(uint32_t block, uint32_t host_id, uint32_t reg_add);
+extern uint8_t rom_i2c_readReg_Mask(uint32_t block, uint32_t host_id,
+                                    uint32_t reg_add,uint32_t Msb, uint32_t Lsb);
+extern void rom_i2c_writeReg (uint32_t block, uint32_t host_id,
+                              uint32_t reg_add, uint32_t data);
+extern void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id,
+                                  uint32_t reg_add, uint32_t Msb, uint32_t Lsb,
+                                  uint32_t indata);
+
+extern uint32_t rtc_get_reset_reason(void);
+
+#endif /* MODULE_ESP_SDK */
+
+/* pointer to flash chip data structure */
+extern SpiFlashChip* flashchip;
+
+extern SpiFlashOpResult spi_flash_attach(void);
+
+void Cache_Read_Disable(void);
+void Cache_Read_Enable (uint32_t odd_even, uint32_t mb_count, uint32_t no_idea);
+
+SpiFlashOpResult Wait_SPI_Idle(SpiFlashChip *chip);
+SpiFlashOpResult SPI_write_enable(SpiFlashChip *chip);
+
+SpiFlashOpResult SPIEraseArea  (uint32_t off, size_t len);
+SpiFlashOpResult SPIEraseBlock (uint32_t num);
+SpiFlashOpResult SPIEraseSector(uint32_t num);
+SpiFlashOpResult SPIEraseChip  (void);
+
+SpiFlashOpResult SPILock  (void);
+SpiFlashOpResult SPIUnlock(void);
+
+SpiFlashOpResult SPIRead  (uint32_t off, uint32_t *dst, size_t size);
+SpiFlashOpResult SPIWrite (uint32_t off, const uint32_t *src, size_t size);
+
+int SPIReadModeCnfig (uint32_t);
+
+/* set elements of flashchip, see struct SpiFlashChip; */
+SpiFlashOpResult SPIParamCfg (uint32_t deviceId,
+                              uint32_t chip_size,
+                              uint32_t block_size,
+                              uint32_t sector_size,
+                              uint32_t page_size,
+                              uint32_t status_mask);
+
+extern void uartAttach (void);
+extern void    uart_div_modify(uint8 uart_no, uint32_t DivLatchValue);
+extern void Uart_Init (uint8 uart_no);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* ROM_H */
diff --git a/cpu/esp8266/sdk/sdk.h b/cpu/esp8266/sdk/sdk.h
new file mode 100644
index 0000000000000000000000000000000000000000..c36ff451ade5e56b81a600e4196603f83edd28ad
--- /dev/null
+++ b/cpu/esp8266/sdk/sdk.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 SDK container
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef SDK_H
+#define SDK_H
+
+#include "c_types.h"
+#include "ets_sys.h"
+
+#include "sdk/ets.h"
+#include "sdk/main.h"
+#include "sdk/phy.h"
+#include "sdk/pp.h"
+#include "sdk/rom.h"
+#include "sdk/user.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MODULE_ESP_SDK
+#include "espressif/osapi.h"
+#include "espressif/user_interface.h"
+#endif /* MODULE_ESP_SDK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDK_H */
diff --git a/cpu/esp8266/sdk/user.c b/cpu/esp8266/sdk/user.c
new file mode 100644
index 0000000000000000000000000000000000000000..707077ead1d779a04350bec18c5af85236bb7fb0
--- /dev/null
+++ b/cpu/esp8266/sdk/user.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 user defined SDK functions
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#include "c_types.h"
+
+#include "common.h"
+#include "cpu_conf.h"
+
+#include "esp/uart_regs.h"
+#include "spi_flash.h"
+#include "sdk/rom.h"
+#include "sdk/user.h"
+
+uint32_t __attribute__((weak)) user_rf_cal_sector_set(void)
+{
+    uint32_t sec_num = flashchip->chip_size / flashchip->sector_size;
+    return sec_num - 5;
+}
+
+#ifndef MODULE_ESP_SDK
+
+void uart_tx_flush (uint32_t num)
+{
+    while ((UART(num).STATUS >> UART_STATUS_TXFIFO_COUNT_S) & UART_STATUS_TXFIFO_COUNT_M) {}
+}
+
+/**
+ * Following code is completly or at least partially from
+ * https://github.com/pvvx/esp8266web
+ * (c) PV` 2015
+ *
+ * @{
+ */
+
+void IRAM system_set_pll (uint8_t crystal_26m_en)
+{
+    if(rom_i2c_readReg(103,4,1) != 136) { /* 8: 40MHz, 136: 26MHz */
+        if (crystal_26m_en == 1) { /* 0: 40MHz, 1: 26MHz */
+            /* set 80MHz PLL CPU */
+            rom_i2c_writeReg(103,4,1,136);
+            rom_i2c_writeReg(103,4,2,145);
+        }
+    }
+}
+
+/** @} */
+
+#endif
diff --git a/cpu/esp8266/sdk/user.h b/cpu/esp8266/sdk/user.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac0e13e358487bf5d83450448b6c387757e3c001
--- /dev/null
+++ b/cpu/esp8266/sdk/user.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266_sdk
+ * @{
+ *
+ * @file
+ * @brief       ESP8266 user defined SDK function prototypes
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#ifndef USER_H
+#define USER_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "c_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MODULE_ESP_SDK
+
+extern uint32_t user_rf_cal_sector_set(void);
+extern void     uart_tx_flush (uint32_t);
+extern void     system_set_pll (uint8_t);
+
+#endif /* MODULE_ESP_SDK */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* USER_H */
diff --git a/cpu/esp8266/startup.c b/cpu/esp8266/startup.c
new file mode 100644
index 0000000000000000000000000000000000000000..f37ad180d5a11bccc0ff28b2b7b53924dfa9a653
--- /dev/null
+++ b/cpu/esp8266/startup.c
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the CPU initialization
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ * @}
+ */
+
+#define ENABLE_DEBUG  0
+#include "debug.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "kernel_init.h"
+#include "log.h"
+#include "periph/init.h"
+
+#include "c_types.h"
+#include "spi_flash.h"
+
+#include "board.h"
+#include "common.h"
+#include "exceptions.h"
+#include "syscalls.h"
+#include "tools.h"
+#include "thread_arch.h"
+
+#include "esp/iomux_regs.h"
+#include "esp/spi_regs.h"
+#include "esp/xtensa_ops.h"
+#include "sdk/sdk.h"
+
+#if MODULE_ESP_GDBSTUB
+#include "esp-gdbstub/gdbstub.h"
+#endif
+
+extern void board_init(void);
+extern void board_print_config(void);
+
+uint32_t hwrand (void);
+
+#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
+/* initialization as it should be called from newlibc */
+extern void _init(void);
+#endif
+
+extern uint8_t _bss_start;
+extern uint8_t _bss_end;
+extern uint8_t _sheap;
+extern uint8_t _eheap;
+
+#ifdef MODULE_ESP_SDK
+
+#include "sdk/ets_task.h"
+
+/**
+ * @brief System main loop called by the ETS
+ *
+ * This function is called by ETS after all initializations has been
+ * finished to start periodic processing of defined ETS tasks. We
+ * overwrite this ETS function to take over the control and to start RIOT.
+ */
+void ets_run(void)
+{
+    #if ENABLE_DEBUG
+    register uint32_t *sp __asm__ ("a1");
+    ets_uart_printf("_stack      %p\n", sp);
+    ets_uart_printf("_bss_start  %p\n", &_bss_start);
+    ets_uart_printf("_bss_end    %p\n", &_bss_end);
+    ets_uart_printf("_heap_start %p\n", &_sheap);
+    ets_uart_printf("_heap_end   %p\n", &_eheap);
+    ets_uart_printf("_heap_free  %lu\n", get_free_heap_size());
+    #endif
+
+    /* init min task priority */
+    ets_task_min_prio = 0;
+
+    #ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
+    _init();
+    #endif
+
+    ets_tasks_init();
+
+    /* enable interrupts used by ETS/SDK */
+    #ifndef MODULE_ESP_SDK_INT_HANDLING
+    ets_isr_unmask(BIT(ETS_FRC2_INUM));
+    ets_isr_unmask(BIT(ETS_WDEV_INUM));
+    ets_isr_unmask(BIT(ETS_WDT_INUM));
+    #endif
+
+    #ifdef MODULE_ESP_GDBSTUB
+    gdbstub_init();
+    #endif
+
+    #if ENABLE_DEBUG==0
+    /* disable SDK messages */
+    system_set_os_print(0);
+    #endif
+
+    #ifdef CONTEXT_SWITCH_BY_INT
+    extern void IRAM thread_yield_isr(void* arg);
+    ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL);
+    ets_isr_unmask(BIT(ETS_SOFT_INUM));
+    #endif
+
+    /* does not return */
+    kernel_init();
+}
+
+/**
+ * @brief Initialize the CPU, the board and the peripherals
+ *
+ * This function is called by ESP8266 SDK when all system initializations
+ * has been finished.
+ */
+void system_init(void)
+{
+    LOG_INFO("\nStarting ESP8266 CPU with ID: %08x", system_get_chip_id());
+    LOG_INFO("\nSDK Version %s\n\n", system_get_sdk_version());
+
+    /* avoid reconnection all the time */
+    wifi_station_disconnect();
+
+    /* set exception handlers */
+    init_exceptions ();
+
+    /* init random number generator */
+    srand(hwrand());
+
+    /* init flash drive */
+    extern void flash_drive_init (void);
+    flash_drive_init();
+
+    /* trigger static peripheral initialization */
+    periph_init();
+
+    /* trigger board initialization */
+    board_init();
+
+    /* print the board config */
+    board_print_config();
+}
+
+
+/**
+ * @brief   Entry point in user space after a system reset
+ *
+ * This function is called after system reset by the ESP8266 SDK. In this
+ * functions following steps are neccessary:
+ *
+ * 1. Reinit system timer as microsecond timer (precision is 500 us)
+ * 2. Set the UART parameters for serial output
+ * 3. Set the system initialization callback
+ */
+
+void IRAM user_init (void)
+{
+    syscalls_init ();
+    thread_isr_stack_init ();
+
+    /* run system in high performance mode */
+    system_update_cpu_freq(160);
+
+    /* reinit system timer as microsecond timer */
+    system_timer_reinit ();
+
+    /* setup the serial communication */
+    uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
+
+    /* once the ETS initialization is done we can start with our code as callback */
+    system_init_done_cb(system_init);
+
+    /* keep wifi interface in null mode per default */
+    wifi_set_opmode_current (0);
+}
+
+#else /* MODULE_ESP_SDK */
+
+#include "esp/dport_regs.h"
+#include "esp/phy_info.h"
+#include "esp/spiflash.h"
+
+/**
+ * @brief   Defines the structure of the file header in SPI flash
+ *
+ * @see https://github.com/espressif/esptool/wiki/Firmware-Image-Format
+ */
+typedef struct __attribute__((packed))
+{
+    uint8_t  magic;    /* always 0xe9 */
+    uint8_t  segments; /* number of segments */
+    uint8_t  mode;     /* 0 - qio, 1 - qout, 2 - dio, 3 - dout */
+    uint8_t  speed:4;  /* 0 - 40 MHz, 1 - 26 MHz, 2 - 20 MHz, 15 - 80 MHz */
+    uint8_t  size:4;   /* 0 - 512 kB, 1 - 256 kB, 2 - 1 MB, 3 - 2 MB, 4 - 4 MB */
+
+} _spi_flash_header;
+
+#define SPI_FLASH_SECTOR_SIZE 4096
+
+struct s_info {
+    uint32 ap_ip;    /* +00 */
+    uint32 ap_mask;  /* +04 */
+    uint32 ap_gw;    /* +08 */
+    uint32 st_ip;    /* +0C */
+    uint32 st_mask;  /* +10 */
+    uint32 st_gw;    /* +14 */
+    uint8 ap_mac[6]; /* +18 */
+    uint8 st_mac[6]; /* +1E */
+}  __attribute__((packed, aligned(4)));
+
+static struct s_info info;
+
+enum rst_reason {
+    REASON_DEFAULT_RST      = 0,
+    REASON_WDT_RST          = 1,
+    REASON_EXCEPTION_RST    = 2,
+    REASON_SOFT_WDT_RST     = 3,
+    REASON_SOFT_RESTART     = 4,
+    REASON_DEEP_SLEEP_AWAKE = 5,
+    REASON_EXT_SYS_RST      = 6
+};
+
+struct rst_info{
+    uint32 reason;
+    uint32 exccause;
+    uint32 epc1;
+    uint32 epc2;
+    uint32 epc3;
+    uint32 excvaddr;
+    uint32 depc;
+};
+
+/**
+ * @brief   System configuration store formats
+ *
+ * source https://github.com/pvvx/esp8266web
+ * (c) PV` 2015
+ *
+ * @{
+ */
+
+/* SDK 2.0.0 */
+#define wifi_config_size 0x494 /* 1172 bytes */
+#define g_ic_size (wifi_config_size + 532) /* 1704 bytes */
+
+struct ets_store_wifi_hdr { /* Sector flash addr flashchip->chip_size-0x1000  (0x4027F000) */
+    uint8  bank;      /* +00 = 0, 1 WiFi config flash addr: */
+                      /*       0 - flashchip->chip_size-0x3000 (0x7D000), */
+                      /*       1 - flashchip->chip_size-0x2000 */
+    uint8  unused[3]; /* +01 = 0xff, 0xff, 0xff */
+    uint32 flag;      /* +04 = 0x55aa55aa */
+    uint32 wr_cnt;    /* +08 = 0x00000001 */
+    uint32 len[2];    /* +12 = 0x00000020, 0xffffffff */
+    uint32 chk[2];    /* +20 = 0x000000ed, 0xffffffff */
+    uint32 flag2;     /* +28 = 0xaa55aa55 */
+};
+
+static const uint8_t
+ets_store_wifi_hdr_default[sizeof(struct ets_store_wifi_hdr)] =
+{
+    0x00, 0xff, 0xff, 0xff, 0xaa, 0x55, 0xaa, 0x55,
+    0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0xed, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0x55, 0xaa, 0x55, 0xaa
+};
+
+struct s_wifi_store { /* WiFi config flash addr: flashchip->chip_size - 0x3000 or -0x2000 */
+    /* SDK >= 2.0.0 */
+    uint8    boot_info[8];     /* +000   0x000         (boot_info[1]) boot_version */
+    uint8    wfmode[4];        /* +008   0x008 */
+    uint32   st_ssid_len;      /* +012   0x00c */
+    uint8    st_ssid[32];      /* +016   0x010 */
+    uint8    field_048[7];     /* +048   0x030 */
+    uint8    st_passw[64];     /* +055   0x037 */
+    uint8    field_119;        /* +119   0x077 */
+    uint8    data_120[32];     /* +120   0x078 */
+    uint8    field_152[17];    /* +152   0x098 */
+    uint8    field_169;        /* +169   0x0a9 */
+    uint8    field_170[6];     /* +170   0x0aa */
+    uint32   ap_ssid_len;      /* +176   0x0b0 */
+    uint8    ap_ssid[32];      /* +180   0x0b4 */
+    uint8    ap_passw[64];     /* +212   0x0d4 */
+    uint8    field_276[32];    /* +276   0x114 */
+    uint8    field_308;        /* +308   0x134 */
+    uint8    wfchl;            /* +309   0x135 */
+    uint8    field_310;        /* +310   0x136 */
+    uint8    field_311;        /* +311   0x137 */
+    uint8    field_312;        /* +312   0x138 */
+    uint8    field_313;        /* +313   0x139 */
+    uint8    field_314;        /* +314   0x13a */
+    uint8    field_315;        /* +315   0x13b */
+    uint16   field_316;        /* +316   0x13c */
+    uint8    field_318[2];     /* +318   0x13e */
+    uint32   st1ssid_len;      /* +320   0x140 */
+    uint8    st1ssid[32];      /* +324   0x144 */
+    uint8    st1passw[64];     /* +356   0x164 */
+    uint8    field_420[400];   /* +420   0x1a4 */
+    uint32   field_820[3];     /* +820   0x334 */
+    uint8    field_832[4];     /* +832   0x340     wifi_station_set_auto_connect */
+    uint32   phy_mode;         /* +836   0x344 */
+    uint8    field_840[36];    /* +840   0x348 */
+    uint16   beacon;           /* +876   0x36c     876+532 g_ic+1408 */
+    uint8    field_878[2];     /* +878   0x36e */
+    uint32   field_880;        /* +880   0x370 */
+    uint32   field_884;        /* +884   0x374 */
+    uint32   field_888;        /* +888   0x378 */
+    uint8    field_892[284];   /* +892   0x37c     ... 1176  0x498 */
+};
+
+struct s_g_ic {
+    uint32    boot_info;        /* +0000 g_ic+0    0x3FFF2324 boot_version? */
+    uint32    field_004;        /* +0004 g_ic+4 */
+    uint32    field_008;        /* +0008 g_ic+8 */
+    uint32    field_00C;        /* +000C g_ic+12 */
+    struct netif **netif1;      /* +0010 g_ic+16 */
+    struct netif **netif2;      /* +0014 g_ic+20 */
+    uint32    field_018;        /* +0018 g_ic+24 */
+    uint32    field_01C;        /* +001C g_ic+28 */
+    uint32    field_020;        /* +0020 g_ic+32 */
+    uint32    field_024;        /* +0024 g_ic+36 */
+    uint32    field_028;        /* +0028 g_ic+40 */
+    uint8     field_02C[84];    /* +002C g_ic+44 */
+    uint32    field_080;        /* +0080 g_ic+128 */
+    uint8     field_084[200];   /* +0084 g_ic+132 */
+    /* [0x12c] */
+    void *    field_14C;        /* +014C g_ic+332 */
+    uint32    ratetable;        /* +0150 g_ic+336 */
+    uint8     field_154[44];    /* +0154 g_ic+340 */
+    uint32    field_180;        /* +0180 g_ic+384 */
+    /* [0x170..0x180] wifi_get_user_ie */
+    void *    field_184;        /* +0184 g_ic+388 user_ie_manufacturer_recv_cb */
+    uint32    field_188;        /* +0188 g_ic+392 */
+    uint32    field_18C;        /* +018C g_ic+396 */
+    uint32    field_190;        /* +0190 g_ic+400 */
+    uint32    field_194;        /* +0194 g_ic+404 */
+    uint32    field_198;        /* +0198 g_ic+408 */
+    uint32    field_19C;        /* +019C g_ic+412 */
+    uint32    field_1A0;        /* +01A0 g_ic+416 */
+    uint32    field_1A4;        /* +01A4 g_ic+420 */
+    uint32    field_1A8;        /* +01A8 g_ic+424 */
+    uint32    field_1AC;        /* +01AC g_ic+428 */
+    uint32    field_1B0;        /* +01B0 g_ic+432 */
+    uint32    field_1B4;        /* +01B4 g_ic+436 */
+    uint32    field_1B8;        /* +01B8 g_ic+440 */
+    uint32    field_1BC;        /* +01BC g_ic+444 */
+    uint32    field_1C0;        /* +01C0 g_ic+448 */
+    uint32    field_1C4;        /* +01C4 g_ic+452 */
+    uint32    field_1C8[19];    /* +01C8 g_ic+456 ...532 */
+    struct s_wifi_store wifi_store;    /* g_ic+??? */
+};
+
+typedef union _u_g_ic{
+    struct s_g_ic g;
+    uint8  c[g_ic_size];
+    uint16 w[g_ic_size/2];
+    uint32 d[g_ic_size/4];
+} u_g_ic;
+
+static u_g_ic g_ic;
+
+/** }@ */
+
+/**
+ * Following functions are from https://github.com/pvvx/esp8266web
+ * (c) PV` 2015
+ *
+ * @{
+ */
+void read_macaddr_from_otp(uint8_t* mac)
+{
+    /* fixed prefix */
+    mac[0] = 0x18;
+    mac[1] = 0xfe;
+    mac[2] = 0x34;
+
+    if ((!(DPORT.OTP_CHIPID & (1 << 15))) ||
+        ((DPORT.OTP_MAC0 == 0) && (DPORT.OTP_MAC1 == 0))) {
+        mac[3] = 0x18;
+        mac[4] = 0xfe;
+        mac[5] = 0x34;
+    }
+    else {
+        mac[3] = (DPORT.OTP_MAC1 >> 8) & 0xff;
+        mac[4] = DPORT.OTP_MAC1 & 0xff;
+        mac[5] = (DPORT.OTP_MAC0 >> 24) & 0xff;
+    }
+}
+
+int ICACHE_FLASH_ATTR flash_data_check(uint8 *check_buf)
+{
+    uint32 cbuf[32];
+    uint32 *pcbuf = cbuf;
+    uint8 *pbuf = check_buf;
+    int i = 27;
+    while (i--) {
+        *pcbuf = pbuf[0] | (pbuf[1]<<8) | (pbuf[2]<<16) | (pbuf[3]<<24);
+        pcbuf++;
+        pbuf+=4;
+    }
+    cbuf[24] = (DPORT.OTP_MAC1 & 0xFFFFFFF) | ((DPORT.OTP_CHIPID & 0xF000) << 16);
+    cbuf[25] = (DPORT.OTP_MAC2 & 0xFFFFFFF) | (DPORT.OTP_MAC0 & 0xFF000000);
+    pcbuf = cbuf;
+    uint32 xsum = 0;
+    do {
+        xsum += *pcbuf++;
+    } while (pcbuf != &cbuf[26]);
+    xsum ^= 0xFFFFFFFF;
+    if (cbuf[26] != xsum) {
+        return 1;
+    }
+    return 0;
+}
+
+/** }@ */
+
+
+/**
+ * @brief   Startup function hook placed at 0x40100000
+ */
+void __attribute__((section(".UserEnter.text"))) NORETURN _call_user_start_hook(void)
+{
+    __asm__ volatile (
+        "   vectors_base:      .word   0x40100000  \n"  /* must contain entry point */
+        "                                          \n"
+        "   _call_user_start:                      \n"  /* system startup function */
+        "              .global _call_user_start    \n"
+        "              l32r    a2, vectors_base    \n"  /* set vector base */
+        "              wsr     a2, vecbase         \n"
+        "              call0   cpu_user_start      \n"  /* call startup function */
+        );
+    UNREACHABLE();
+}
+
+void ICACHE_FLASH_ATTR start_phase2 (void);
+
+/**
+ * @brief   Startup function
+ *
+ * This function is the entry point in the user application. It is called
+ * after a system reset to startup the system.
+ */
+void __attribute__((noreturn)) IRAM cpu_user_start (void)
+{
+    register uint32_t *sp __asm__ ("a1"); (void)sp;
+
+    /* PHASE 1: startup in SDK */
+
+    struct rst_info rst_if = { .reason = 0 };
+    system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info));
+
+    /**
+     * Setup the serial communication speed. After cold start UART_CLK_FREQ is
+     * only 26/40 (65 %). So the baud rate would be only 74880. To have 115200
+     * at the beginning of the cold start, we have to set it to 177231 baud.
+     * This is changed later in function system_set_pll.
+     */
+    system_set_pll(1); /* parameter is fix (from esp_init_data_default.bin byte 48) */
+
+    #if 0
+    if (rst_if.reason > REASON_DEFAULT_RST) {
+        /* warm start */
+        uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
+    }
+    else {
+        /* cold start */
+        uart_div_modify(0, UART_CLK_FREQ / 177231);
+    }
+    #else
+    uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
+    #endif
+
+    /* flush uart_tx_buffer */
+    ets_uart_printf("                                                     \n");
+
+    #if ENABLE_DEBUG
+    ets_uart_printf("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason());
+    ets_uart_printf("exccause=%ld excvaddr=%08lx\n", rst_if.exccause, rst_if.excvaddr);
+    ets_uart_printf("epc1=%08lx epc2=%08lx epc3=%08lx\n", rst_if.epc1, rst_if.epc2, rst_if.epc3);
+    ets_uart_printf("depc=%ld\n", rst_if.depc);
+    ets_uart_printf("_stack      %p\n", sp);
+    ets_uart_printf("_bss_start  %p\n", &_bss_start);
+    ets_uart_printf("_bss_end    %p\n", &_bss_end);
+    ets_uart_printf("_heap_start %p\n", &_sheap);
+    ets_uart_printf("_heap_end   %p\n", &_eheap);
+    ets_uart_printf("_heap_free  %lu\n", get_free_heap_size());
+    #endif
+
+    uint32_t flash_sectors;
+    uint32_t flash_size;
+
+    _spi_flash_header flash_header;
+
+    SPI(0).USER0 |= SPI_USER0_CS_SETUP;
+    SPIRead(0, (uint32_t*)&flash_header, 4);
+
+    assert (flash_header.magic == 0xe9);
+
+    /* SPI flash sectors a 4.096 byte */
+    switch (flash_header.size) {
+        case 0:  flash_sectors =  128; break; /* 512 kByte */
+        case 1:  flash_sectors =   64; break; /* 256 kByte */
+        case 2:  flash_sectors =  256; break; /*   1 MByte */
+        case 3:  flash_sectors =  512; break; /*   2 MByte */
+        case 4:  flash_sectors = 1024; break; /*   4 MByte */
+        default: flash_sectors =  128; break; /* default 512 kByte */
+    }
+
+    flash_size = flash_sectors * SPI_FLASH_SECTOR_SIZE;
+
+    flashchip->chip_size = flash_size;
+    flashchip->sector_size = SPI_FLASH_SECTOR_SIZE;
+
+    /*
+     * SPI flash speed params
+     * speed = 80MHz / clkdiv_pre / clkcnt_N
+     */
+    uint32_t clkdiv_pre = 1;      /* default 40 MHz = 80 MHz / 1 / 2 */
+    uint32_t clkcnt_N = 2;
+
+    switch (flash_header.speed) {
+        case  0: clkdiv_pre = 1;  /* 40 MHz = 80 MHz / 1 / 2 */
+                 clkcnt_N   = 2;
+                 break;
+
+        case  1: clkdiv_pre = 1;  /* 26 MHz = 80 MHz / 1 / 3 */
+                 clkcnt_N   = 3;
+                 break;
+
+        case  2: clkdiv_pre = 1;  /* 20 MHz = 80 MHz / 1 / 4 */
+                 clkcnt_N   = 4;
+                 break;
+
+        case 15: clkdiv_pre = 0;  /* clock is equal to system clock */
+                 break;
+
+        default: break;
+    }
+
+    if (clkdiv_pre) {
+        IOMUX.CONF &= ~IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
+        SPI(0).CLOCK = VAL2FIELD_M(SPI_CLOCK_DIV_PRE, clkdiv_pre - 1) |
+                       VAL2FIELD_M(SPI_CLOCK_COUNT_NUM, clkcnt_N - 1) |
+                       VAL2FIELD_M(SPI_CLOCK_COUNT_HIGH, clkcnt_N/2 - 1) |
+                       VAL2FIELD_M(SPI_CLOCK_COUNT_LOW, clkcnt_N - 1);
+    }
+    else {
+        IOMUX.CONF   |= IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK;
+        SPI(0).CLOCK |= SPI_CLOCK_EQU_SYS_CLOCK;
+    }
+
+    ets_uart_printf("Flash size: %lu byte, speed %d MHz",
+                    flash_size, clkdiv_pre ? 80 / clkdiv_pre / clkcnt_N : 80);
+
+    switch (flash_header.mode) {
+        case 0:  ets_printf(", mode QIO\n"); break;
+        case 1:  ets_printf(", mode QOUT\n"); break;
+        case 2:  ets_printf(", mode DIO\n"); break;
+        case 3:  ets_printf(", mode DOUT\n"); break;
+        default: ets_printf("\n");
+    }
+
+    ets_uart_printf("\nStarting ESP8266 CPU with ID: %08x\n\n", system_get_chip_id());
+
+    /* clear .bss to avoid startup problems because of compiler optimization options */
+    memset(&_bss_start, 0x0, &_bss_end-&_bss_start);
+
+    /**
+      * Following parts of code are partially from or inspired by the
+      * following projects:
+      *
+      * [esp8266web](https://github.com/pvvx/esp8266web)
+      * (c) PV` 2015
+      *
+      * [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
+      * Copyright (C) 2015 Superhouse Automation Pty Ltd
+      * BSD Licensed as described in the file LICENSE
+      *
+      * @{
+      */
+    struct ets_store_wifi_hdr  binfo;
+    struct s_wifi_store        wscfg;
+
+    /* load boot info (32 byte) from last sector and */
+    uint32_t binfo_addr = flash_size - SPI_FLASH_SECTOR_SIZE;
+    SPIRead (binfo_addr, (uint32_t*)&binfo, sizeof(binfo));
+
+    /* load the system config (1176 byte) from last 3 or 2 sectors */
+    uint32_t wscfg_addr = flash_size - (binfo.bank ? 2 : 3) * SPI_FLASH_SECTOR_SIZE;
+    SPIRead (wscfg_addr, (uint32_t*)&wscfg, sizeof(wscfg));
+
+    Cache_Read_Enable(0, 0, 1);
+
+    #if ENABLE_DEBUG
+    printf("boot_inf sector @0x%x\n", flash_size - SPI_FLASH_SECTOR_SIZE);
+    esp_hexdump(&binfo, sizeof(binfo), 'b', 16);
+    #endif
+
+    LOG_INFO("load boot_inf 0x%x, len %d, chk %02x\n",
+             binfo_addr, sizeof(binfo),
+             system_get_checksum((uint8_t*)&binfo, sizeof(binfo)));
+    LOG_INFO("load wifi_cfg 0x%x, len %d, chk %02x\n",
+             wscfg_addr, sizeof(wscfg),
+             system_get_checksum((uint8_t*)&wscfg, sizeof(wscfg)));
+
+    /* check whether boot_inf sector could be loaded */
+    if (binfo.bank > 0 && binfo.flag == 0xffffffff) {
+        LOG_INFO("no boot_inf sector @0x%x, write a default one to flash\n", binfo_addr);
+        memcpy (&binfo, ets_store_wifi_hdr_default, sizeof(binfo));
+        spi_flash_write (binfo_addr, (uint32_t*)&binfo, sizeof(binfo));
+
+    }
+
+    /* check the checksum */
+    if (binfo.flag == 0x55aa55aa &&
+        binfo.chk[binfo.bank] == system_get_checksum((uint8_t*)&wscfg, binfo.len[binfo.bank])) {
+        /* checksum test is ok */
+    }
+    else {
+        /* checksum error but continue */
+        LOG_INFO("flash check sum error @0x%x\n", wscfg_addr);
+
+        /* check whether there is no wifi_cfg sector */
+        uint8_t* wscfg_sec = (uint8_t*)&wscfg;
+        size_t i = 0;
+        for ( ; i < sizeof(wscfg); i++) {
+            if (wscfg_sec[i] != 0xff) {
+                break;
+            }
+        }
+
+        /* no data different from 0xff found, we assume that the flash was erased */
+        if (i == sizeof(wscfg)) {
+            /* TODO write a default wifi_cfg sector automatically into the flash in that case */
+            LOG_INFO("\nno wifi_cfg sector found, use following command:\n"
+                     "esptool.py write_flash 0x%x $(RIOT_CPU)/bin/wifi_cfg_default.bin\n\n",
+                     wscfg_addr);
+        }
+    }
+
+    memcpy(&g_ic.g.wifi_store, &wscfg, sizeof(wscfg));
+    uart_tx_flush(0);
+    uart_tx_flush(1);
+
+    init_exceptions ();
+
+    /* PHASE 2: sdk_init in SDK */
+
+    start_phase2();
+
+    /** }@ */
+
+    /* run system in high performance mode */
+    /* TODO system_update_cpu_freq(160); */
+
+    /* PHASE 3: start RIOT-OS kernel */
+
+    /* init random number generator */
+    srand(hwrand());
+
+    /* init flash drive */
+    extern void flash_drive_init (void);
+    flash_drive_init();
+
+    /* trigger static peripheral initialization */
+    periph_init();
+
+    /* initialize the board and startup the kernel */
+    board_init();
+
+    /* print the board config */
+    board_print_config();
+
+    #ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
+    _init();
+    #endif
+
+    #ifdef MODULE_ESP_GDBSTUB
+    gdbstub_init();
+    #endif
+
+    #ifdef CONTEXT_SWITCH_BY_INT
+    extern void IRAM thread_yield_isr(void* arg);
+    ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL);
+    ets_isr_unmask(BIT(ETS_SOFT_INUM));
+    #endif
+
+    /* startup the kernel */
+    kernel_init();
+
+    /* should not be reached */
+    UNREACHABLE() ;
+}
+
+
+void start_phase2 (void)
+{
+    uint32_t flash_size = flashchip->chip_size;
+    struct rst_info rst_if;
+
+    system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info));
+
+    /**
+      * Following parts of code are partially from or inspired by the
+      * following projects:
+      *
+      * [esp8266web](https://github.com/pvvx/esp8266web)
+      * (c) PV` 2015
+      *
+      * [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git).
+      * Copyright (C) 2015 Superhouse Automation Pty Ltd
+      * BSD Licensed as described in the file LICENSE
+      *
+      * @{
+      */
+
+    /* changes clock freqeuncy and should be done before system_set_pll */
+    sleep_reset_analog_rtcreg_8266();
+
+    /* set correct system clock and adopt UART frequency */
+    system_set_pll(1); /* parameter is fixed (from esp_init_data_default.bin byte 48) */
+    uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE);
+    uart_tx_flush(0);
+    uart_tx_flush(1);
+
+    syscalls_init ();
+    thread_isr_stack_init ();
+
+    read_macaddr_from_otp(info.st_mac);
+    LOG_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+             info.st_mac[0], info.st_mac[1], info.st_mac[2],
+             info.st_mac[3], info.st_mac[4], info.st_mac[5]);
+
+    /* load esp_init_data_default.bin */
+    uint8_t* pbuf = malloc(1024); (void)pbuf;
+    uint32_t phy_info_addr = flash_size - 4 * SPI_FLASH_SECTOR_SIZE;
+
+    sdk_phy_info_t* phy_info = (sdk_phy_info_t*)pbuf;
+    spi_flash_read (phy_info_addr, (uint32_t*)phy_info, sizeof(sdk_phy_info_t));
+
+    LOG_INFO("load phy_info 0x%x, len %d, chk %02x\n",
+             phy_info_addr, sizeof(sdk_phy_info_t),
+             system_get_checksum((uint8_t*)phy_info, sizeof(sdk_phy_info_t)));
+
+    /* load rf_cal_sec (default rf_cal_sec = flash_sectors - 5) */
+    uint32_t rf_cal_sec = user_rf_cal_sector_set();
+    uint32_t rf_cal_sec_addr = rf_cal_sec * SPI_FLASH_SECTOR_SIZE;
+    spi_flash_read (rf_cal_sec_addr, (uint32_t*)(pbuf + 128), 628);
+
+    LOG_INFO("rf_cal_sec=%d\n", rf_cal_sec);
+    LOG_INFO("load rf_cal 0x%x, len %d, chk %02x\n",
+             rf_cal_sec_addr, 628, system_get_checksum(pbuf + 128, 628));
+    LOG_INFO("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason());
+
+    #if ENABLE_DEBUG
+    printf("phy_info sector @0x%x\n", phy_info_addr);
+    esp_hexdump(pbuf, 128, 'b', 16);
+
+    printf("rf_cal sector @0x%x\n", rf_cal_sec_addr);
+    /* esp_hexdump(pbuf+128, 628, 'b', 16); */
+    #endif
+
+    sdk_phy_info_t default_phy_info;
+    get_default_phy_info(&default_phy_info);
+
+    if (phy_info->version != default_phy_info.version) {
+        /* check whether there is no phy_info sector */
+        uint8_t* phy_info_sec = (uint8_t*)phy_info;
+        size_t i = 0;
+        for ( ; i < sizeof(sdk_phy_info_t); i++) {
+            if (phy_info_sec[i] != 0xff) {
+                break;
+            }
+        }
+
+        /* no data different from 0xff found, we assume that the flash was erased */
+        if (i == sizeof(sdk_phy_info_t)) {
+            /* write a default default phy_info sector into the flash */
+            LOG_INFO("no phy_info sector found @0x%x, "
+                     "writing esp_init_data_default.bin into flash\n",
+                     phy_info_addr);
+            spi_flash_write (phy_info_addr,
+                             (uint32_t*)&default_phy_info, sizeof(sdk_phy_info_t));
+        }
+
+        LOG_INFO("set default esp_init_data!\n");
+        memcpy(pbuf, &default_phy_info, sizeof(sdk_phy_info_t));
+    }
+
+    extern uint8_t* phy_rx_gain_dc_table;
+    extern uint8_t  phy_rx_gain_dc_flag;
+
+    phy_rx_gain_dc_table = &pbuf[0x100];
+    phy_rx_gain_dc_flag  = 0;
+
+    int xflg = (flash_data_check(&pbuf[128]) != 0 ||
+                phy_check_data_table(phy_rx_gain_dc_table, 125, 1) != 0) ? 1 : 0;
+
+    if (rst_if.reason != REASON_DEEP_SLEEP_AWAKE) {
+        phy_afterwake_set_rfoption(1);
+        if (xflg == 0) {
+            write_data_to_rtc(pbuf+128);
+        }
+    }
+
+    g_ic.c[491] = ((phy_info->freq_correct_mode & 7 )== 3) ? 1 : 0;
+    pbuf[0xf8] = 0;
+
+    /* clear RTC memory */
+    memset(&rst_if, 0, sizeof(struct rst_info));
+    system_rtc_mem_write(0, &rst_if, sizeof(struct rst_info));
+
+    uart_tx_flush(0);
+    uart_tx_flush(1);
+
+    if (register_chipv6_phy(pbuf)) {
+        LOG_ERROR ("register_chipv6_phy failed");
+    }
+
+    free (pbuf);
+
+    /** @} */
+}
+
+#endif /* MODULE_ESP_SDK */
diff --git a/cpu/esp8266/syscalls.c b/cpu/esp8266/syscalls.c
new file mode 100644
index 0000000000000000000000000000000000000000..65273ee76ec0a5a4fda02a1efb950ee542f3c65c
--- /dev/null
+++ b/cpu/esp8266/syscalls.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of required system calls
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#define ENABLE_DEBUG    0
+#define MEMLEAK_DEBUG   0
+#include "debug.h"
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/reent.h>
+#include <sys/stat.h>
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ets_sys.h"
+#include "c_types.h"
+
+#include "common.h"
+#include "cpu_conf.h"
+#include "irq.h"
+#include "kernel_defines.h"
+#include "log.h"
+#include "mutex.h"
+#include "rmutex.h"
+#include "sched.h"
+#include "syscalls.h"
+
+#include "esp/xtensa_ops.h"
+#include "esp/common_macros.h"
+
+#include "sdk/sdk.h"
+
+int IRAM puts(const char * str)
+{
+    char c;
+    while ((c = *str) != 0) {
+        ets_putc(c);
+        ++str;
+    }
+    ets_putc('\n');
+    return true;
+}
+
+int IRAM putchar(int c)
+{
+    /* function is neccessary to avoid unproducable results */
+    ets_putc(c);
+    return true;
+}
+
+char _printf_buf[PRINTF_BUFSIZ];
+
+int /* IRAM */ printf(const char* format, ...)
+{
+    va_list arglist;
+    va_start(arglist, format);
+
+    int ret = vsnprintf(_printf_buf, PRINTF_BUFSIZ, format, arglist);
+
+    if (ret > 0) {
+        ets_printf (_printf_buf);
+    }
+
+    va_end(arglist);
+
+    return ret;
+}
+
+#ifdef SDK_HEAP_USED
+/**
+ * Map memory management functions to SDK memory management functions.
+ * This is necessary to use the same heap as the SDK internally does.
+ * Furthermore, these functions do at least avoid interrupts during the
+ * execution of memory management functions. Memory management function
+ * of ETS are not used and have not to considered therefore.
+ */
+extern void *pvPortMalloc (size_t size, const char *, unsigned);
+extern void vPortFree (void *ptr, const char *, unsigned);
+extern void *pvPortZalloc (size_t size, const char *, unsigned);
+extern void *pvPortCalloc (size_t nmemb, size_t size, const char *, unsigned);
+extern void *pvPortRealloc (void *ptr, size_t size, const char *, unsigned);
+extern unsigned int xPortGetFreeHeapSize(void);
+
+void* IRAM malloc(size_t size)
+{
+    #if MEMLEAK_DEBUG
+    static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
+    return pvPortMalloc(size, mem_debug_file, __LINE__);
+    #else
+    return pvPortMalloc(size, "", 0);
+    #endif
+}
+
+void IRAM free(void *ptr)
+{
+    #if MEMLEAK_DEBUG
+    static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
+    return vPortFree (ptr, mem_debug_file, __LINE__);
+    #else
+    return vPortFree (ptr, "", 0);
+    #endif
+}
+
+void* IRAM calloc(size_t nmemb, size_t size)
+{
+    #if MEMLEAK_DEBUG
+    static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
+    return pvPortCalloc(nmemb, size, mem_debug_file, __LINE__);
+    #else
+    return pvPortCalloc(nmemb, size, "", 0);
+    #endif
+}
+
+void* IRAM realloc(void *ptr, size_t size)
+{
+    #if MEMLEAK_DEBUG
+    static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;
+    return pvPortRealloc(ptr, size, mem_debug_file, __LINE__);
+    #else
+    return pvPortRealloc(ptr, size, "", 0);
+    #endif
+}
+
+void* IRAM _malloc_r (struct _reent *r, size_t size)
+{
+    return malloc (size);
+}
+
+void IRAM _free_r (struct _reent *r, void *ptr)
+{
+    free (ptr);
+}
+
+unsigned int get_free_heap_size (void)
+{
+    return xPortGetFreeHeapSize();
+}
+
+void IRAM syscalls_init (void) {}
+
+#else   /* SDK_HEAP_USED */
+/*
+ * To use the same heap SDK memory management functions have to be replaced by
+ * newlib memory functions. In that case the _malloc_lock/_unlock functions
+ * have to be defined. Memory management functions of ETS are not used and
+ * have not to considered here.
+ */
+
+void* IRAM pvPortMalloc (size_t size, const char *file, unsigned line)
+{
+    (void)file;
+    (void)line;
+
+    return malloc (size);
+}
+
+void IRAM vPortFree (void *ptr, const char *file, unsigned line)
+{
+    (void)file;
+    (void)line;
+
+    free (ptr);
+}
+
+void* IRAM pvPortCalloc (size_t nmemb, size_t size, const char *file, unsigned line)
+{
+    (void)file;
+    (void)line;
+
+    void *ptr = malloc (nmemb*size);
+    if (ptr) {
+        memset (ptr, 0x0, nmemb*size);
+    }
+    return ptr;
+}
+
+void* IRAM pvPortZalloc (size_t size, const char *file, unsigned line)
+{
+    (void)file;
+    (void)line;
+
+    void *ptr = malloc (size);
+    if (ptr) {
+        memset (ptr, 0x0, size);
+    }
+    return ptr;
+}
+
+void* IRAM pvPortRealloc (void *ptr, size_t size, const char *file, unsigned line)
+{
+    (void)file;
+    (void)line;
+
+    return realloc (ptr, size);
+}
+
+size_t IRAM xPortWantedSizeAlign(size_t size)
+{
+    /* allign the size to a multiple of 8 */
+    return (size & 0x7) ? (size & ~0x7) + 8 : size;
+}
+
+size_t IRAM xPortGetFreeHeapSize (void)
+{
+    return get_free_heap_size ();
+}
+
+/*
+ * Following function implement the lock mechanism in newlib. The only static
+ * mutex defined here is the __malloc_recursive_mutex to avoid that memory
+ * management functions try to lock before RIOT's threads are running.
+ */
+
+extern _lock_t __malloc_recursive_mutex;
+
+static rmutex_t _malloc_rmtx = RMUTEX_INIT;
+
+void IRAM syscalls_init (void)
+{
+    __malloc_recursive_mutex = (_lock_t)&_malloc_rmtx;
+}
+
+void IRAM _lock_init(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL);
+    CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
+
+    mutex_t* mtx = malloc (sizeof(mutex_t));
+
+    if (mtx) {
+        memset (mtx, 0, sizeof(mutex_t));
+        *lock = (_lock_t)mtx;
+    }
+}
+
+void IRAM _lock_init_recursive(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL);
+    CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
+
+    rmutex_t* rmtx = malloc (sizeof(rmutex_t));
+
+    if (rmtx) {
+        memset (rmtx, 0, sizeof(rmutex_t));
+        *lock = (_lock_t)rmtx;
+    }
+}
+
+void IRAM _lock_close(_lock_t *lock)
+{
+    CHECK_PARAM (lock != NULL);
+    CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
+
+    free ((void*)*lock);
+    *lock = 0;
+}
+
+void IRAM _lock_close_recursive(_lock_t *lock)
+{
+    CHECK_PARAM (lock != NULL);
+    CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx));
+
+    free ((void*)*lock);
+    *lock = 0;
+}
+
+void IRAM _lock_acquire(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL && *lock != 0);
+
+    mutex_lock ((mutex_t*)*lock);
+}
+
+void IRAM _lock_acquire_recursive(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL && *lock != 0);
+
+    rmutex_lock ((rmutex_t*)*lock);
+}
+
+int IRAM _lock_try_acquire(_lock_t *lock)
+{
+    CHECK_PARAM_RET (sched_active_thread != 0, 0);
+    CHECK_PARAM_RET (lock != NULL && *lock != 0, 0);
+
+    return rmutex_trylock ((rmutex_t*)*lock);
+}
+
+int IRAM _lock_try_acquire_recursive(_lock_t *lock)
+{
+    CHECK_PARAM_RET (sched_active_thread != 0, 0);
+    CHECK_PARAM_RET (lock != NULL && *lock != 0, 0);
+
+    return mutex_trylock ((mutex_t*)*lock);
+}
+
+void IRAM _lock_release(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL && *lock != 0);
+
+    mutex_unlock ((mutex_t*)*lock);
+}
+
+void IRAM _lock_release_recursive(_lock_t *lock)
+{
+    CHECK_PARAM (sched_active_thread != 0);
+    CHECK_PARAM (lock != NULL && *lock != 0);
+
+    rmutex_unlock ((rmutex_t*)*lock);
+}
+
+
+#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
+
+#define _cheap heap_top
+
+extern char *heap_top;
+extern char _eheap;     /* end of heap (defined in esp8266.riot-os.app.ld) */
+
+#else /* MODULE_NEWLIB_SYSCALLS_DEFAULT */
+
+static uint8_t* _cheap = 0; /* last allocated chunk of heap */
+extern uint8_t  _eheap;     /* end of heap (defined in esp8266.riot-os.app.ld) */
+extern uint8_t  _sheap;     /* start of heap (defined in esp8266.riot-os.app.ld) */
+
+void* IRAM _sbrk_r (struct _reent *r, ptrdiff_t incr)
+{
+    uint8_t* _cheap_old;
+
+    /* initial _cheap */
+    if (_cheap == NULL) {
+        _cheap = &_sheap;
+    }
+
+    /* save old _cheap */
+    _cheap_old = _cheap;
+
+    /* check whether _cheap + incr overflows the heap */
+    if (_cheap + incr >= &_eheap) {
+        r->_errno = ENOMEM;
+        return (caddr_t)-1;
+    }
+
+    /* set new _cheap */
+    _cheap += incr;
+
+    #if ENABLE_DEBUG
+    uint32_t remaining = &_eheap - _cheap;
+    printf ("%s %lu byte allocated in %p .. %p, remaining %u\n",
+            __func__, incr, _cheap_old, _cheap, remaining);
+    #endif
+
+    /* return allocated memory */
+    return (void*) _cheap_old;
+}
+
+
+
+#endif  /* MODULE_NEWLIB_SYSCALLS_DEFAULT */
+
+unsigned int IRAM get_free_heap_size (void)
+{
+    return (_cheap) ? &_eheap - _cheap : 0;
+}
+
+#endif /* SDK_HEAP_USED */
+
+#if !defined(MODULE_NEWLIB_SYSCALLS_DEFAULT)
+
+NORETURN void _exit(int status)
+{
+    UNREACHABLE();
+}
+
+static int _no_sys_func (struct _reent *r, const char* f)
+{
+    LOG_ERROR("system function %s does not exist\n", f);
+    r->_errno = ENOSYS;
+    return -1;
+}
+
+int _open_r(struct _reent *r, const char *path, int flag, int m)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _close_r(struct _reent *r, int fd)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _fstat_r(struct _reent *r, int fdes, struct stat *stat)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _stat_r(struct _reent *r, const char *path, struct stat *buff)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _lseek_r(struct _reent *r, int fdes, int off, int w)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _write_r(struct _reent *r, int fd, const void *buff, size_t cnt)
+{
+    return _no_sys_func (r, __func__);
+}
+
+int _read_r(struct _reent *r, int fd, void *buff, size_t cnt)
+{
+    return _no_sys_func (r, __func__);
+}
+
+#include <sys/time.h>
+
+int _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
+{
+    (void) tz;
+    if (tv) {
+        uint32_t microseconds = system_get_time();
+        tv->tv_sec = microseconds / 1000000;
+        tv->tv_usec = microseconds % 1000000;
+    }
+    return 0;
+}
+
+#endif /* MODULE_NEWLIB_SYSCALLS_DEFAULT */
+
+int _rename_r (struct _reent *r, const char* old, const char* new)
+{
+    DEBUG("%s: system function does not exist\n", __func__);
+    r->_errno = ENOSYS;
+    return -1;
+}
+
+#include <math.h>
+
+double __ieee754_remainder(double x, double y) {
+    return x - y * floor(x/y);
+}
+
+float __ieee754_remainderf(float x, float y) {
+    return x - y * floor(x/y);
+}
diff --git a/cpu/esp8266/thread_arch.c b/cpu/esp8266/thread_arch.c
new file mode 100644
index 0000000000000000000000000000000000000000..fab78e28aa2828063e9feb7ac1bfa7cca0dc8127
--- /dev/null
+++ b/cpu/esp8266/thread_arch.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of the kernel's architecture dependent thread interface
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+/*
+ * PLEASE NOTE: Some parts of the code are taken from the FreeRTOS port for
+ * Xtensa processors from Cadence Design Systems. These parts are marked
+ * accordingly. For these parts, the following license is valid:
+ *
+ * Copyright (c) 2003-2015 Cadence Design Systems, Inc.
+ *
+ * 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.
+ */
+
+#define ENABLE_DEBUG    0
+#include "debug.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "board.h"
+#include "cpu.h"
+#include "irq.h"
+#include "log.h"
+#include "thread.h"
+#include "sched.h"
+
+#include "common.h"
+#include "esp/common_macros.h"
+#include "esp/xtensa_ops.h"
+#include "sdk/ets_task.h"
+#include "sdk/rom.h"
+#include "sdk/sdk.h"
+#include "tools.h"
+#include "xtensa/xtensa_context.h"
+
+/* User exception dispatcher when exiting */
+extern void _xt_user_exit(void);
+
+/* Switch context to the highest priority ready task without context save */
+extern void _frxt_dispatch(void);
+
+/* Set an flag indicating that a task switch is required on return from interrupt */
+extern void _frxt_setup_switch(void);
+
+/* Switch context to the highest priority ready task with context save */
+extern void vPortYield(void);
+extern void vPortYieldFromInt(void);
+
+char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_start, int stack_size)
+{
+    /*
+     * Stack layout after task stack initialization
+     *
+     *                                            +------------------------+
+     *                                            |                        | TOP
+     *                                            |  thread_control_block  |
+     *        stack_start + stack_size        ==> |                        |
+     *                                            +------------------------+
+     *        top_of_stack                    ==> |                        |
+     *                                            |      XT_CP_FRAME       |
+     *                                            |       (optional)       |
+     *        top_of_stack + 1 - XT_CP_SIZE   ==> |                        |
+     *                                            +------------------------+
+     *                                            |                        |
+     *                                            |      XT_STK_FRAME      |
+     *                                            |                        | XT_STK_...
+     *                                            | a2 = arg               | XT_STK_A2
+     *                                            | a1 = sp + XT_STK_FRMSZ | XT_STK_A1
+     *                                            | a0 = sched_task_exit   | XT_STK_A0
+     *                                            | ps = PS_UM | PS_EXCM   | XT_STK_PS
+     *                                            | pc = task_func         | XT_STK_PC
+     *   sp = top_of_stack + 1 - XT_CP_SIZE   ==> | exit = _xt_user_exit   | XT_STK_EXIT
+     *                         - XT_STK_FRMSZ     +------------------------+
+     *                                            |                        |
+     *                                            | remaining stack space  |
+     *                                            |   available for data   |
+     *        stack_start (preallocated var)  ==> |                        | BOTTOM
+     *                                            +------------------------+
+     *
+     * Initialized stack frame represents the registers as set when the
+     * the task function would have been called.
+     *
+     * Registers in a called function
+     *
+     *   pc - PC at the beginning in the function
+     *   a0 - return address from the function (return address to caller)
+     *   a1 - current stack pointer at the beginning in the function
+     *   a2 - first argument of the function
+     */
+
+    /* stack is [stack_start+0 ... stack_start+stack_size-1] */
+    uint8_t *top_of_stack;
+    uint8_t *sp;
+
+    top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size-1);
+
+    /* Clear whole stack with a known value to assist debugging */
+    #if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK)
+        /* Unfortunatly, this affects thread_measure_stack_free function */
+        memset(stack_start, 0, stack_size);
+    #endif
+
+    /* BEGIN - code from FreeRTOS port for Xtensa from Cadence */
+
+    /* Create interrupt stack frame aligned to 16 byte boundary */
+    sp = (uint8_t*)(((uint32_t)(top_of_stack+1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf);
+
+    /* ensure that stack is big enough */
+    assert (sp > (uint8_t*)stack_start);
+
+    XtExcFrame* exc_frame = (XtExcFrame*)sp;
+
+    /* Explicitly initialize certain saved registers */
+    exc_frame->pc   = (uint32_t)task_func;         /* task entry point */
+    exc_frame->a0   = (uint32_t)sched_task_exit;   /* task exit point (CHANGED) */
+    exc_frame->a1   = (uint32_t)sp + XT_STK_FRMSZ; /* physical top of stack frame */
+    exc_frame->a2   = (uint32_t)arg;               /* parameters for task_func */
+    exc_frame->exit = (uint32_t)_xt_user_exit;     /* user exception exit dispatcher */
+
+    /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
+    /* Also set entry point argument parameter. */
+    #ifdef __XTENSA_CALL0_ABI__
+    /* CALL0 ABI */
+    exc_frame->ps = PS_UM | PS_EXCM;
+    #else
+    /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
+    exc_frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
+    #endif
+
+    #ifdef XT_USE_SWPRI
+    /* Set the initial virtual priority mask value to all 1's. */
+    exc_frame->vpri = 0xFFFFFFFF;
+    #endif
+
+    #if XCHAL_CP_NUM > 0
+    /*
+     * Init the coprocessor save area (see xtensa_context.h)
+     * No access to TCB here, so derive indirectly. Stack growth is top to bottom.
+     * p = (uint32_t *) xMPUSettings->coproc_area;
+     */
+    uint32_t *p;
+
+    p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE) & ~0xf);
+    p[0] = 0;
+    p[1] = 0;
+    p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
+    #endif
+
+    /* END - code from FreeRTOS port for Xtensa from Cadence */
+
+    DEBUG("%s start=%p size=%d top=%p sp=%p free=%u\n",
+          __func__, stack_start, stack_size, top_of_stack, sp, sp-(uint8_t*)stack_start);
+
+    return (char*)sp;
+}
+
+
+unsigned sched_interrupt_nesting = 0;  /* Interrupt nesting level */
+
+#ifdef CONTEXT_SWITCH_BY_INT
+/**
+ * Context switches are realized using software interrupts
+ */
+void IRAM thread_yield_isr(void* arg)
+{
+    /* set the context switch flag (indicates that context has to be switched
+       is switch on exit from interrupt in _frxt_int_exit */
+    _frxt_setup_switch();
+}
+#endif
+
+void  thread_yield_higher(void)
+{
+    /* reset hardware watchdog */
+    system_soft_wdt_feed();
+
+    /* handle pending ets tasks first to keep system alive */
+    ets_tasks_run();
+
+    /* yield next task */
+    #if defined(ENABLE_DEBUG) && defined(DEVELHELP)
+    if (sched_active_thread) {
+        DEBUG("%u old task %u %s %u\n", phy_get_mactime(),
+               sched_active_thread->pid, sched_active_thread->name,
+               sched_active_thread->sp - sched_active_thread-> stack_start);
+    }
+    #endif
+
+    if (!irq_is_in()) {
+        #ifdef CONTEXT_SWITCH_BY_INT
+        WSR(BIT(ETS_SOFT_INUM), interrupt);
+        #else
+        vPortYield();
+        #endif
+    }
+    else {
+        _frxt_setup_switch();
+    }
+
+    #if defined(ENABLE_DEBUG) && defined(DEVELHELP)
+    if (sched_active_thread) {
+        DEBUG("%u new task %u %s %u\n", phy_get_mactime(),
+               sched_active_thread->pid, sched_active_thread->name,
+               sched_active_thread->sp - sched_active_thread-> stack_start);
+    }
+    #endif
+
+    return;
+}
+
+void  thread_stack_print(void)
+{
+    /* Print the current stack to stdout. */
+
+    #if defined(DEVELHELP)
+    volatile thread_t* task = thread_get(sched_active_pid);
+    if (task) {
+
+        char* stack_top = task->stack_start + task->stack_size;
+        int   size = stack_top - task->sp;
+        printf("Printing current stack of thread %" PRIkernel_pid "\n", thread_getpid());
+        esp_hexdump((void*)(task->sp), size >> 2, 'w', 8);
+    }
+    #else
+    NOT_SUPPORTED();
+    #endif
+}
+
+void  thread_print_stack(void)
+{
+    /* Prints human readable, ps-like thread information for debugging purposes. */
+    /* because of Xtensa stack structure and call0 ABI, it is not possible to implement */
+    NOT_YET_IMPLEMENTED();
+    return;
+}
+
+#if defined(DEVELHELP)
+
+extern uint8_t port_IntStack;
+extern uint8_t port_IntStackTop;
+
+void thread_isr_stack_init(void)
+{
+    /* code from thread.c, please see the copyright notice there */
+
+    /* assign each int of the stack the value of it's address */
+    uintptr_t *stackmax = (uintptr_t *)&port_IntStackTop;
+    uintptr_t *stackp = (uintptr_t *)&port_IntStack;
+
+    while (stackp < stackmax) {
+        *stackp = (uintptr_t) stackp;
+        stackp++;
+    }
+}
+
+int thread_isr_stack_usage(void)
+{
+    return &port_IntStackTop - &port_IntStack -
+           thread_measure_stack_free((char*)&port_IntStack);
+}
+
+void *thread_isr_stack_pointer(void)
+{
+    /* Get the current ISR stack pointer. */
+    return &port_IntStackTop;
+}
+
+void *thread_isr_stack_start(void)
+{
+    /* Get the start of the ISR stack. */
+    return &port_IntStack;
+}
+
+void thread_isr_stack_print(void)
+{
+    printf("Printing current ISR\n");
+    esp_hexdump(&port_IntStack, &port_IntStackTop-&port_IntStack, 'w', 8);
+}
+
+#else /* DEVELHELP */
+
+void thread_isr_stack_init(void) {}
+
+#endif /* DEVELHELP */
+
+NORETURN void cpu_switch_context_exit(void)
+{
+    /* Switch context to the highest priority ready task without context save */
+    _frxt_dispatch();
+
+    UNREACHABLE();
+}
diff --git a/cpu/esp8266/tools.c b/cpu/esp8266/tools.c
new file mode 100644
index 0000000000000000000000000000000000000000..230621a09152949a88335251dbff16e5b3ff15d0
--- /dev/null
+++ b/cpu/esp8266/tools.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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_esp8266
+ * @{
+ *
+ * @file
+ * @brief       Implementation of some tools
+ *
+ * @author      Gunar Schorcht <gunar@schorcht.net>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "esp/common_macros.h"
+#include "tools.h"
+
+void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line)
+{
+    uint32_t count = 0;
+    uint32_t size;
+
+    uint8_t*  addr8  = (uint8_t*) addr;
+    uint16_t* addr16 = (uint16_t*)addr;
+    uint32_t* addr32 = (uint32_t*)addr;
+    uint64_t* addr64 = (uint64_t*)addr;
+
+    switch (width) {
+        case 'b': size = 1; break;
+        case 'h': size = 2; break;
+        case 'w': size = 4; break;
+        case 'g': size = 8; break;
+        default : size = 1; break;
+    }
+
+    while (count < num) {
+        if (count % per_line == 0) {
+            printf ("%08x: ", (uint32_t)((uint8_t*)addr+count*size));
+        }
+        switch (width) {
+            case 'b': printf("%02" PRIx8, addr8[count++]); break;
+            case 'h': printf("%04" PRIx16, addr16[count++]); break;
+            case 'w': printf("%08" PRIx32, addr32[count++]); break;
+            case 'g': printf("%016" PRIx64, addr64[count++]); break;
+
+            default : printf("."); count++; break;
+        }
+        if (count % per_line == 0) {
+            printf ("\n");
+        }
+    }
+    printf ("\n");
+}
diff --git a/cpu/esp8266/vendor/Makefile b/cpu/esp8266/vendor/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4465636f70ce3e05f308ebfaea97b3ad098485e6
--- /dev/null
+++ b/cpu/esp8266/vendor/Makefile
@@ -0,0 +1,9 @@
+# Add a list of subdirectories, that should also be built:
+DIRS += esp
+DIRS += xtensa
+
+ifeq ($(ENABLE_GDBSTUB), 1)
+    DIRS += esp-gdbstub
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/vendor/README.md b/cpu/esp8266/vendor/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..29084961b616cca349114fc521aa23651d5255e1
--- /dev/null
+++ b/cpu/esp8266/vendor/README.md
@@ -0,0 +1,16 @@
+The subdirectories here contain third-party software components used by the RIOT port for ESP8266.
+
+### esp
+
+The files that are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). The files in this directory are under the copyright of their respective owners. Please note the copyright notice in these files. All of these files are BSD Licensed as described in the file [LICENSE](https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE).
+
+### esp-gdbstub
+
+The files in this directory are a modified version of [esp-gdbstub](https://github.com/espressif/esp-gdbstub). The files are copyright of Espressif Systems (Shanghai) Pte., Ltd. and are licensed under the Espressif MIT license.
+
+### espressif
+
+The files in this directory are either from the [ESP8266_NONOS_SDK](https://github.com/espressif/ESP8266_NONOS_SDK.git) or from the [ESP_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK.git) for ESP8266. All of these files are copyright of Espressif Systems (Shanghai) Pte., Ltd. Please note the copyright notice in these files.
+
+### xtensa
+The files in this directory are from the [FreeRTOS port for Xtensa](https://github.com/tensilica/freertos) configurable processors and Diamond processors. All of these files are copyright of Cadence Design Systems Inc. and licensed under the MIT license.
diff --git a/cpu/esp8266/vendor/esp-gdbstub/License b/cpu/esp8266/vendor/esp-gdbstub/License
new file mode 100644
index 0000000000000000000000000000000000000000..0d8ccab252fe6e7df530bed0950e35b50ec94ebe
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/License
@@ -0,0 +1,9 @@
+ESPRESSIF MIT License
+
+Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+
+Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, it is 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.
diff --git a/cpu/esp8266/vendor/esp-gdbstub/Makefile b/cpu/esp8266/vendor/esp-gdbstub/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..30d8b91bf5140ca2c24b27380d1f719eb5970c12
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/Makefile
@@ -0,0 +1,3 @@
+MODULE=esp_gdbstub
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/vendor/esp-gdbstub/README.md b/cpu/esp8266/vendor/esp-gdbstub/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4aa84302aebee717adfdbeda68420c445f26d83d
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/README.md
@@ -0,0 +1,69 @@
+
+GDBSTUB
+=======
+
+Intro
+-----
+
+While the ESP8266 supports the standard Gnu set of C programming utilities, for now the choice of debuggers
+has been limited: there is an attempt at [OpenOCD support](https://github.com/projectgus/openocd), but at
+the time of writing, it doesn't support hardware watchpoints and breakpoints yet, and it needs a separate
+JTAG adapter connecting to the ESP8266s JTAG pins. As an alternative, [Cesanta](https://www.cesanta.com/)
+has implemented a barebones[GDB stub](https://blog.cesanta.com/esp8266-gdb) in their Smart.js solution -
+unfortunately, this only supports exception catching and needs some work before you can use it outside of
+the Smart.js platform. Moreover, it also does not work with FreeRTOS.
+
+For internal use, we at Espressif desired a GDB stub that works with FreeRTOS and is a bit more capable,
+so we designed our own implementation of it. This stub works both under FreeRTOS as well as the OS-less
+SDK and is able to catch exceptions and do backtraces on them, read and write memory, forward [os_]printf
+statements to gdb, single-step instructions and set hardware break- and watchpoints. It connects to the
+host machine (which runs gdb) using the standard serial connection that's also used for programming.
+
+In order to be useful the gdbstub has to be used in conjunction with an xtensa-lx106-elf-gdb, for example
+as generated by the [esp-open-sdk](https://github.com/pfalcon/esp-open-sdk) project.
+
+Usage
+-----
+ * Grab the gdbstub project and put the files in a directory called 'gdbstub' in your project. You can do this
+either by checking out the Git repo, or adding the Git repo as a submodule to your project if it's already
+in Git.
+ * Modify your Makefile. You'll need to include the gdbstub sources: if your Makefile is structured like the
+ones in the Espressif examples, you can add `gdbstub` to the `SUBDIRS` define and `gdbstub/libgdbstub.a` to the
+`COMPONENTS_eagle.app.v6` define. Also, you probably want to add `-ggdb` to your compiler flags (`TARGET_LDFLAGS`)
+and, if you are debugging, change any optimation flags (-Os, -O2 etc) into `-Og`. Finally, make sure your Makefile
+also compiles .S files.
+ * Configure gdbstub by editting `gdbstub-cfg.h`. There are a bunch of options you can tweak: FreeRTOS or bare SDK,
+private exception/breakpoint stack, console redirection to GDB, wait till debugger attachment etc. You can also
+configure the options by including the proper -Dwhatever gcc flags in your Makefiles.
+ * In your user_main.c, add an `#include <../gdbstub/gdbstub.h>` and call `gdbstub_init();` somewhere in user_main.
+ * Compile and flash your board.
+ * Run gdb, depending on your configuration immediately after resetting the board or after it has run into
+an exception. The easiest way to do it is to use the provided script: xtensa-lx106-elf-gdb -x gdbcmds -b 38400
+Change the '38400' into the baud rate your code uses. You may need to change the gdbcmds script to fit the
+configuration of your hardware and build environment.
+
+Notes
+-----
+ * Using software breakpoints ('br') only works on code that's in RAM. Code in flash can only have a hardware
+breakpoint ('hbr').
+ * Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available.
+ * Pressing control-C to interrupt the running program depends on gdbstub hooking the UART interrupt.
+If some code re-hooks this afterwards, gdbstub won't be able to receive characters. If gdbstub handles
+the interrupt, the user code will not receive any characters.
+ * Continuing from an exception is not (yet) supported in FreeRTOS mode.
+ * The WiFi hardware is designed to be serviced by software periodically. It has some buffers so it
+will behave OK when some data comes in while the processor is busy, but these buffers are not infinite.
+If the WiFi hardware receives lots of data while the debugger has stopped the CPU, it is bound
+to crash. This will happen mostly when working with UDP and/or ICMP; TCP-connections in general will
+not send much more data when the other side doesn't send any ACKs.
+
+License
+-------
+This gdbstub is licensed under the Espressif MIT license, as described in the License file.
+
+
+Thanks
+------
+ * Cesanta, for their initial ESP8266 exception handling only gdbstub,
+ * jcmvbkbc, for providing an incompatible but interesting gdbstub for other Xtensa CPUs,
+ * Sysprogs (makers of VisualGDB), for their suggestions and bugreports.
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbcmds b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds
new file mode 100644
index 0000000000000000000000000000000000000000..61dfdbeda79e7cdb3e8ae281b6ae0454ebf5758d
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds
@@ -0,0 +1,8 @@
+file ../ld/esp8266.riot-os.sdk.app.ld
+#set remotedebug 1
+set remotelogfile gdb_rsp_logfile.txt
+set serial baud 115200
+set remote hardware-breakpoint-limit 1
+set remote hardware-watchpoint-limit 1
+#set debug xtensa 4
+target remote /dev/ttyUSB0
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h
new file mode 100644
index 0000000000000000000000000000000000000000..849d733220d5bf56338d4ac130aacf0df7a9c477
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h
@@ -0,0 +1,71 @@
+#ifndef GDBSTUB_CFG_H
+#define GDBSTUB_CFG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL
+and do some other magic to make everything work and compile under FreeRTOS.
+*/
+#ifndef GDBSTUB_FREERTOS
+#define GDBSTUB_FREERTOS 1
+#endif
+
+/*
+Enable this to make the exception and debugging handlers switch to a private stack. This will use
+up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's
+normally disabled because not many situations need it. If for some reason the GDB communication
+stops when you run into an error in your code, try enabling this.
+*/
+#ifndef GDBSTUB_USE_OWN_STACK
+#define GDBSTUB_USE_OWN_STACK 0
+#endif
+
+/*
+If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by
+hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't
+work for your program anymore. This will fail if your program sets an UART interrupt handler after
+the gdbstub_init call.
+*/
+#ifndef GDBSTUB_CTRLC_BREAK
+#define GDBSTUB_CTRLC_BREAK 1
+#endif
+
+/*
+Enabling this will redirect console output to GDB. This basically means that printf/os_printf output
+will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if
+you use a normal terminal, you can't read the printfs anymore.
+*/
+#ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 1
+#endif
+
+/*
+Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by
+breaking in the init routine; use the gdb 'c' command (continue) to start the program.
+*/
+#ifndef GDBSTUB_BREAK_ON_INIT
+#define GDBSTUB_BREAK_ON_INIT 1
+#endif
+
+/*
+Function attributes for function types.
+Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function
+(and related) can always be in flash, because it's called in the normal code flow. The rest of the
+gdbstub functions can be in flash too, but only if there's no chance of them being called when the
+flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines
+are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most
+likely crash.
+*/
+#define ATTR_GDBINIT    ICACHE_FLASH_ATTR
+#ifndef ATTR_GDBFN
+#define ATTR_GDBFN
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GDBSTUB_CFG_H */
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S
new file mode 100644
index 0000000000000000000000000000000000000000..8ff28da66e5b7d4aa51337779a5ded8e492816c0
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S
@@ -0,0 +1,404 @@
+/******************************************************************************
+ * Copyright 2015 Espressif Systems
+ *
+ * Description: Assembly routines for the gdbstub
+ *
+ * License: ESPRESSIF MIT License
+ *******************************************************************************/
+
+
+#include "gdbstub-cfg.h"
+
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/core-isa.h>
+#include <xtensa/corebits.h>
+
+#define DEBUG_PC	(EPC + XCHAL_DEBUGLEVEL)
+#define DEBUG_EXCSAVE	(EXCSAVE + XCHAL_DEBUGLEVEL)
+#define DEBUG_PS	(EPS + XCHAL_DEBUGLEVEL)
+
+
+.global gdbstub_savedRegs
+
+#if GDBSTUB_USE_OWN_STACK
+.global gdbstub_exceptionStack
+#endif
+
+	.text
+.literal_position
+
+	.text
+	.align	4
+
+/*
+The savedRegs struct:
+	uint32_t pc;
+	uint32_t ps;
+	uint32_t sar;
+	uint32_t vpri;
+	uint32_t a0;
+	uint32_t a[14]; //a2..a15
+	uint32_t litbase;
+	uint32_t sr176;
+	uint32_t sr208;
+	uint32_t a1;
+	uint32_t reason;
+*/
+
+/*
+This is the debugging exception routine; it's called by the debugging vector
+
+We arrive here with all regs intact except for a2. The old contents of A2 are saved
+into the DEBUG_EXCSAVE special function register. EPC is the original PC.
+*/
+gdbstub_debug_exception_entry:
+/*
+	//Minimum no-op debug exception handler, for debug
+	rsr a2,DEBUG_PC
+	addi a2,a2,3
+	wsr a2,DEBUG_PC
+	xsr	a2, DEBUG_EXCSAVE
+	rfi	XCHAL_DEBUGLEVEL
+*/
+
+//Save all regs to structure
+	movi	a2, gdbstub_savedRegs
+	s32i	a0, a2, 0x10
+	s32i	a1, a2, 0x58
+	rsr		a0, DEBUG_PS
+	s32i	a0, a2, 0x04
+	rsr		a0, DEBUG_EXCSAVE //was R2
+	s32i	a0, a2, 0x14
+	s32i	a3, a2, 0x18
+	s32i	a4, a2, 0x1c
+	s32i	a5, a2, 0x20
+	s32i	a6, a2, 0x24
+	s32i	a7, a2, 0x28
+	s32i	a8, a2, 0x2c
+	s32i	a9, a2, 0x30
+	s32i	a10, a2, 0x34
+	s32i	a11, a2, 0x38
+	s32i	a12, a2, 0x3c
+	s32i	a13, a2, 0x40
+	s32i	a14, a2, 0x44
+	s32i	a15, a2, 0x48
+	rsr		a0, SAR
+	s32i	a0, a2, 0x08
+	rsr		a0, LITBASE
+	s32i	a0, a2, 0x4C
+	rsr		a0, 176
+	s32i	a0, a2, 0x50
+	rsr		a0, 208
+	s32i	a0, a2, 0x54
+	rsr		a0, DEBUGCAUSE
+	s32i	a0, a2, 0x5C
+	rsr		a4, DEBUG_PC
+	s32i	a4, a2, 0x00
+
+#if GDBSTUB_USE_OWN_STACK
+	//Move to our own stack
+	movi a1, exceptionStack+255*4
+#endif
+
+//If ICOUNT is -1, disable it by setting it to 0, otherwise we will keep triggering on the same instruction.
+	rsr		a2, ICOUNT
+	movi	a3, -1
+	bne		a2, a3, noIcountReset
+	movi	a3, 0
+	wsr		a3, ICOUNT
+noIcountReset:
+
+	rsr	a2, ps
+	addi	a2, a2, -PS_EXCM_MASK
+	wsr	a2, ps
+	rsync
+
+//Call into the C code to do the actual handling.
+	call0	gdbstub_handle_debug_exception
+
+DebugExceptionExit:
+
+	rsr	a2, ps
+	addi	a2, a2, PS_EXCM_MASK
+	wsr	a2, ps
+	rsync
+
+	//Restore registers from the gdbstub_savedRegs struct
+	movi	a2, gdbstub_savedRegs
+	l32i	a0, a2, 0x00
+	wsr		a0, DEBUG_PC
+//	l32i	a0, a2, 0x54
+//	wsr		a0, 208
+	l32i	a0, a2, 0x50
+	//wsr		a0, 176		//Some versions of gcc do not understand this...
+	.byte  0x00, 176, 0x13	//so we hand-assemble the instruction.
+	l32i	a0, a2, 0x4C
+	wsr		a0, LITBASE
+	l32i	a0, a2, 0x08
+	wsr		a0, SAR
+	l32i	a15, a2, 0x48
+	l32i	a14, a2, 0x44
+	l32i	a13, a2, 0x40
+	l32i	a12, a2, 0x3c
+	l32i	a11, a2, 0x38
+	l32i	a10, a2, 0x34
+	l32i	a9, a2, 0x30
+	l32i	a8, a2, 0x2c
+	l32i	a7, a2, 0x28
+	l32i	a6, a2, 0x24
+	l32i	a5, a2, 0x20
+	l32i	a4, a2, 0x1c
+	l32i	a3, a2, 0x18
+	l32i	a0, a2, 0x14
+	wsr		a0, DEBUG_EXCSAVE //was R2
+	l32i	a0, a2, 0x04
+	wsr		a0, DEBUG_PS
+	l32i	a1, a2, 0x58
+	l32i	a0, a2, 0x10
+
+	//Read back vector-saved a2 value, put back address of this routine.
+	movi	a2, gdbstub_debug_exception_entry
+	xsr	a2, DEBUG_EXCSAVE
+
+	//All done. Return to where we came from.
+	rfi	XCHAL_DEBUGLEVEL
+
+
+
+#if GDBSTUB_FREERTOS
+/*
+FreeRTOS exception handling code. For some reason or another, we can't just hook the main exception vector: it
+seems FreeRTOS uses that for something else too (interrupts). FreeRTOS has its own fatal exception handler, and we
+hook that. Unfortunately, that one is called from a few different places (eg directly in the DoubleExceptionVector)
+so the precise location of the original register values are somewhat of a mystery when we arrive here...
+
+As a 'solution', we'll just decode the most common case of the user_fatal_exception_handler being called from
+the user exception handler vector:
+- excsave1 - orig a0
+- a1: stack frame:
+	sf+16: orig a1
+	sf+8: ps
+	sf+4: epc
+	sf+12: orig a0
+	sf: magic no?
+*/
+	.global gdbstub_handle_user_exception
+	.global gdbstub_user_exception_entry
+	.align	4
+gdbstub_user_exception_entry:
+//Save all regs to structure
+	movi	a0, gdbstub_savedRegs
+	s32i	a1, a0, 0x14 //was a2
+	s32i	a3, a0, 0x18
+	s32i	a4, a0, 0x1c
+	s32i	a5, a0, 0x20
+	s32i	a6, a0, 0x24
+	s32i	a7, a0, 0x28
+	s32i	a8, a0, 0x2c
+	s32i	a9, a0, 0x30
+	s32i	a10, a0, 0x34
+	s32i	a11, a0, 0x38
+	s32i	a12, a0, 0x3c
+	s32i	a13, a0, 0x40
+	s32i	a14, a0, 0x44
+	s32i	a15, a0, 0x48
+	rsr		a2, SAR
+	s32i	a2, a0, 0x08
+	rsr		a2, LITBASE
+	s32i	a2, a0, 0x4C
+	rsr		a2, 176
+	s32i	a2, a0, 0x50
+	rsr		a2, 208
+	s32i	a2, a0, 0x54
+	rsr		a2, EXCCAUSE
+	s32i	a2, a0, 0x5C
+
+//Get the rest of the regs from the stack struct
+	l32i	a3, a1, 12
+	s32i	a3, a0, 0x10
+	l32i	a3, a1, 16
+	s32i	a3, a0, 0x58
+	l32i	a3, a1, 8
+	s32i	a3, a0, 0x04
+	l32i	a3, a1, 4
+	s32i	a3, a0, 0x00
+
+#if GDBSTUB_USE_OWN_STACK
+	movi a1, exceptionStack+255*4
+#endif
+
+	rsr	a2, ps
+	addi	a2, a2, -PS_EXCM_MASK
+	wsr	a2, ps
+	rsync
+
+	call0	gdbstub_handle_user_exception
+
+UserExceptionExit:
+
+/*
+Okay, from here on, it Does Not Work. There's not really any continuing from an exception in the
+FreeRTOS case; there isn't any effort put in reversing the mess the exception code made yet. Maybe this
+is still something we need to implement later, if there's any demand for it, or maybe we should modify
+FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.)
+*/
+	j UserExceptionExit
+
+
+	.global gdbstub_handle_uart_int
+	.global gdbstub_uart_entry
+	.align	4
+gdbstub_uart_entry:
+	//On entry, the stack frame is at SP+16.
+	//This is a small stub to present that as the first arg to the gdbstub_handle_uart function.
+	movi	a2, 16
+	add		a2, a2, a1
+	movi	a3, gdbstub_handle_uart_int
+	jx		a3
+
+#endif
+
+
+
+	.global gdbstub_save_extra_sfrs_for_exception
+	.align 4
+//The Xtensa OS HAL does not save all the special function register things. This bit of assembly
+//fills the gdbstub_savedRegs struct with them.
+gdbstub_save_extra_sfrs_for_exception:
+	movi	a2, gdbstub_savedRegs
+	rsr		a3, LITBASE
+	s32i	a3, a2, 0x4C
+	rsr		a3, 176
+	s32i	a3, a2, 0x50
+	rsr		a3, 208
+	s32i	a3, a2, 0x54
+	rsr		a3, EXCCAUSE
+	s32i	a3, a2, 0x5C
+	ret
+
+	.global gdbstub_init_debug_entry
+	.global _DebugExceptionVector
+	.align	4
+gdbstub_init_debug_entry:
+//This puts the following 2 instructions into the debug exception vector:
+//	xsr	a2, DEBUG_EXCSAVE
+//	jx	a2
+	movi	a2, _DebugExceptionVector
+	movi	a3, 0xa061d220
+	s32i	a3, a2, 0
+	movi	a3, 0x00000002
+	s32i	a3, a2, 4
+
+//Tell the just-installed debug vector where to go.
+	movi	a2, gdbstub_debug_exception_entry
+	wsr		a2, DEBUG_EXCSAVE
+
+	ret
+
+
+//Set up ICOUNT register to step one single instruction
+	.global gdbstub_icount_ena_single_step
+	.align 4
+gdbstub_icount_ena_single_step:
+	movi	a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode
+	movi	a2, -2
+	wsr		a3, ICOUNTLEVEL
+	wsr		a2, ICOUNT
+	isync
+	ret
+
+
+//These routines all assume only one breakpoint and watchpoint is available, which
+//is the case for the ESP8266 Xtensa core.
+
+
+	.global gdbstub_set_hw_breakpoint
+gdbstub_set_hw_breakpoint:
+	//a2 - addr, a3 - len (unused here)
+	rsr		a4, IBREAKENABLE
+	bbsi	a4, 0, return_w_error
+	wsr		a2, IBREAKA
+	movi	a2, 1
+	wsr		a2, IBREAKENABLE
+	isync
+	movi 	a2, 1
+	ret
+
+	.global gdbstub_del_hw_breakpoint
+gdbstub_del_hw_breakpoint:
+	//a2 - addr
+	rsr		a5, IBREAKENABLE
+	bbci	a5, 0, return_w_error
+	rsr		a3, IBREAKA
+	bne		a3, a2, return_w_error
+	movi	a2,0
+	wsr		a2, IBREAKENABLE
+	isync
+	movi	a2, 1
+	ret
+
+	.global gdbstub_set_hw_watchpoint
+	//a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access)
+gdbstub_set_hw_watchpoint:
+	//Check if any of the masked address bits are set. If so, that is an error.
+	movi	a5,0x0000003F
+	xor		a5, a5, a3
+	bany	a2, a5, return_w_error
+	//Check if watchpoint already is set
+	rsr		a5, DBREAKC
+	movi	a6, 0xC0000000
+	bany	a6, a5, return_w_error
+	//Set watchpoint
+	wsr		a2, DBREAKA
+
+	//Combine type and mask
+	movi	a6, 0x3F
+	and		a3, a3, a6
+	slli	a4, a4, 30
+	or		a3, a3, a4
+	wsr		a3, DBREAKC
+
+//	movi	a2, 1
+	mov		a2, a3
+	isync
+	ret
+
+
+	.global gdbstub_del_hw_watchpoint
+	//a2 - addr
+gdbstub_del_hw_watchpoint:
+	//See if the address matches
+	rsr		a3, DBREAKA
+	bne		a3, a2, return_w_error
+	//See if the bp actually is set
+	rsr		a3, DBREAKC
+	movi	a2, 0xC0000000
+	bnone	a3, a2, return_w_error
+	//Disable bp
+	movi	a2,0
+	wsr		a2,DBREAKC
+	movi	a2,1
+	isync
+	ret
+
+return_w_error:
+	movi	a2, 0
+	ret
+
+
+//Breakpoint, with an attempt at a functional function prologue and epilogue...
+	.global gdbstub_do_break_breakpoint_addr
+	.global gdbstub_do_break
+	.align	4
+gdbstub_do_break:
+	addi	a1, a1, -16
+	s32i	a15, a1, 12
+	mov		a15, a1
+
+gdbstub_do_break_breakpoint_addr:
+	break 0,0
+
+	mov		a1, a15
+	l32i	a15, a1, 12
+	addi	a1, a1, 16
+	ret
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h
new file mode 100644
index 0000000000000000000000000000000000000000..cecee2ad8e9fea1484baafd52c3d04808237effc
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h
@@ -0,0 +1,25 @@
+#ifndef GDBSTUB_ENTRY_H
+#define GDBSTUB_ENTRY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gdbstub_init_debug_entry(void);
+void gdbstub_do_break(void);
+void gdbstub_icount_ena_single_step(void);
+void gdbstub_save_extra_sfrs_for_exception(void);
+void gdbstub_uart_entry(void);
+
+int gdbstub_set_hw_breakpoint(int addr, int len);
+int gdbstub_set_hw_watchpoint(int addr, int len, int type);
+int gdbstub_del_hw_breakpoint(int addr);
+int gdbstub_del_hw_watchpoint(int addr);
+
+extern void* gdbstub_do_break_breakpoint_addr;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GDBSTUB_ENTRY_H */
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c80cdfdb1162adddaf616255c96483d8e75ab6a
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c
@@ -0,0 +1,766 @@
+/******************************************************************************
+ * Copyright 2015 Espressif Systems
+ *
+ * Description: A stub to make the ESP8266 debuggable by GDB over the serial
+ * port.
+ *
+ * License: ESPRESSIF MIT License
+ *******************************************************************************/
+
+#include <string.h>
+
+#include "gdbstub.h"
+#include "ets_sys.h"
+#include "eagle_soc.h"
+#include "c_types.h"
+#include "gpio.h"
+#include "xtensa/corebits.h"
+
+#include "gdbstub.h"
+#include "gdbstub-entry.h"
+#include "gdbstub-cfg.h"
+
+// From xtruntime-frames.h
+struct XTensa_exception_frame_s {
+    uint32_t pc;
+    uint32_t ps;
+    uint32_t sar;
+    uint32_t vpri;
+    uint32_t a0;
+    uint32_t a[14]; //a2..a15
+    // These are added manually by the exception code; the HAL doesn't
+    // set these on an exception.
+    uint32_t litbase;
+    uint32_t sr176;
+    uint32_t sr208;
+    uint32_t a1;
+    // 'reason' is abused for both the debug and the exception vector: if bit 7 is set,
+    // this contains an exception reason, otherwise it contains a debug vector bitmap.
+    uint32_t reason;
+};
+
+
+struct XTensa_rtos_int_frame_s {
+    uint32_t exitPtr;
+    uint32_t pc;
+    uint32_t ps;
+    uint32_t a[16];
+    uint32_t sar;
+};
+
+// OS-less SDK defines. Defines some headers for things that aren't in the
+// include files, plus the xthal stack frame struct.
+#include "sdk/sdk.h"
+
+#define EXCEPTION_GDB_SP_OFFSET 0x100
+
+//We need some UART register defines.
+#define ETS_UART_INUM       5
+#define REG_UART_BASE( i )  (0x60000000+(i)*0xf00)
+#define UART_STATUS( i )    (REG_UART_BASE( i ) + 0x1C)
+#define UART_RXFIFO_CNT     0x000000FF
+#define UART_RXFIFO_CNT_S   0
+#define UART_TXFIFO_CNT     0x000000FF
+#define UART_TXFIFO_CNT_S   16
+#define UART_FIFO( i )      (REG_UART_BASE( i ) + 0x0)
+#define UART_INT_ENA(i)     (REG_UART_BASE(i) + 0xC)
+#define UART_INT_CLR(i)     (REG_UART_BASE(i) + 0x10)
+#define UART_RXFIFO_TOUT_INT_ENA    (BIT(8))
+#define UART_RXFIFO_FULL_INT_ENA    (BIT(0))
+#define UART_RXFIFO_TOUT_INT_CLR    (BIT(8))
+#define UART_RXFIFO_FULL_INT_CLR    (BIT(0))
+
+// Length of buffer used to reserve GDB commands. Has to be at least able to
+// fit the G command, which implies a minimum size of about 190 bytes.
+#define PBUFLEN 256
+// Length of gdb stdout buffer, for console redirection
+#define OBUFLEN 32
+
+// The asm stub saves the Xtensa registers here when a debugging exception
+// happens.
+struct XTensa_exception_frame_s gdbstub_savedRegs;
+#if GDBSTUB_USE_OWN_STACK
+// This is the debugging exception stack.
+int exceptionStack[256];
+#endif
+
+static unsigned char cmd[PBUFLEN];   // GDB command input buffer
+static char chsum;                   // Running checksum of the output packet
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+static unsigned char obuf[OBUFLEN];  // GDB stdout buffer
+static int obufpos=0;                // Current position in the buffer
+#endif
+static int32_t singleStepPs = -1;    // Stores ps when single-stepping
+                                     // instruction. -1 when not in use.
+
+// Small function to feed the hardware watchdog. Needed to stop the ESP from
+// resetting due to a watchdog timeout while reading a command.
+static void ATTR_GDBFN keepWDTalive(void)
+{
+    uint64_t *wdtval = (uint64_t*)0x3ff21048;
+    uint64_t *wdtovf = (uint64_t*)0x3ff210cc;
+    int *wdtctl = (int*)0x3ff210c8;
+    *wdtovf = *wdtval+1600000;
+    *wdtctl |= (1 << 31);
+}
+
+// Receive a char from the uart. Uses polling and feeds the watchdog.
+static int ATTR_GDBFN gdbRecvChar(void)
+{
+    int i;
+    while (((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0)
+        keepWDTalive();
+    i = READ_PERI_REG(UART_FIFO(0));
+    return i;
+}
+
+// Send a char to the uart.
+static void ATTR_GDBFN gdbSendChar(char c)
+{
+    while (((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126)
+        ;
+    WRITE_PERI_REG(UART_FIFO(0), c);
+}
+
+// Send the start of a packet; reset checksum calculation.
+static void ATTR_GDBFN gdbPacketStart(void)
+{
+    chsum=0;
+    gdbSendChar('$');
+}
+
+// Send a char as part of a packet
+static void ATTR_GDBFN gdbPacketChar(char c)
+{
+    if (c == '#' || c == '$' || c == '}' || c == '*')
+    {
+        gdbSendChar('}');
+        gdbSendChar(c ^ 0x20);
+        chsum += (c ^ 0x20) +'}';
+    }
+    else
+    {
+        gdbSendChar(c);
+        chsum += c;
+    }
+}
+
+// Send a string as part of a packet
+static void ATTR_GDBFN gdbPacketStr(char *c)
+{
+    while (*c != 0)
+    {
+        gdbPacketChar(*c);
+        c++;
+    }
+}
+
+// Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
+static void ATTR_GDBFN gdbPacketHex(int val, int bits)
+{
+    char hexChars[]="0123456789abcdef";
+    int i;
+    for (i = bits; i > 0; i -= 4)
+        gdbPacketChar(hexChars[(val >> (i-4)) & 0xf]);
+}
+
+// Finish sending a packet.
+static void ATTR_GDBFN gdbPacketEnd(void)
+{
+    gdbSendChar('#');
+    gdbPacketHex(chsum, 8);
+}
+
+// Error states used by the routines that grab stuff from the incoming gdb packet
+#define ST_ENDPACKET -1
+#define ST_ERR -2
+#define ST_OK -3
+#define ST_CONT -4
+
+// Grab a hex value from the gdb packet. Ptr will get positioned on the end
+// of the hex string, as far as the routine has read into it. Bits/4 indicates
+// the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much
+// hex chars as possible.
+static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) {
+    int i;
+    int no;
+    unsigned int v=0;
+    no=bits/4;
+    if (bits==-1) no=64;
+    for (i=0; i<no; i++) {
+        char c;
+        c=**ptr;
+        (*ptr)++;
+        if (c>='0' && c<='9') {
+            v <<= 4;
+            v|=(c-'0');
+        } else if (c>='A' && c<='F') {
+            v <<= 4;
+            v|=(c-'A')+10;
+        } else if (c>='a' && c<='f') {
+            v <<= 4;
+            v|=(c-'a')+10;
+        } else if (c=='#') {
+            if (bits==-1) {
+                (*ptr)--;
+                return v;
+            }
+            return ST_ENDPACKET;
+        } else {
+            if (bits==-1) {
+                (*ptr)--;
+                return v;
+            }
+            return ST_ERR;
+        }
+    }
+    return v;
+}
+
+// Swap an int into the form gdb wants it
+static int ATTR_GDBFN iswap(int i)
+{
+    int r;
+    r  = ((i >> 24) & 0xff);
+    r |= ((i >> 16) & 0xff) << 8;
+    r |= ((i >> 8) & 0xff) << 16;
+    r |= ((i >> 0) & 0xff) << 24;
+    return r;
+}
+
+// Read a byte from the ESP8266 memory.
+static unsigned char ATTR_GDBFN readbyte(unsigned int p)
+{
+    int *i = (int*)(p & (~3));
+    if (p < 0x20000000 || p >= 0x60000000)
+        return -1;
+    return *i >> ((p & 3) * 8);
+}
+
+// Write a byte to the ESP8266 memory.
+static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d)
+{
+    int *i = (int*)(p & (~3));
+    if (p < 0x20000000 || p >= 0x60000000) return;
+    if ((p & 3) == 0) *i = (*i & 0xffffff00) | (d << 0);
+    if ((p & 3) == 1) *i = (*i & 0xffff00ff) | (d << 8);
+    if ((p & 3) == 2) *i = (*i & 0xff00ffff) | (d << 16);
+    if ((p & 3) == 3) *i = (*i & 0x00ffffff) | (d << 24);
+}
+
+// Returns 1 if it makes sense to write to addr p
+static int ATTR_GDBFN validWrAddr(int p)
+{
+    if (p >= 0x3ff00000 && p < 0x40000000) return 1;
+    if (p >= 0x40100000 && p < 0x40140000) return 1;
+    if (p >= 0x60000000 && p < 0x60002000) return 1;
+    return 0;
+}
+
+/*
+Register file in the format lx106 gdb port expects it.
+Inspired by gdb/regformats/reg-xtensa.dat from
+https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
+As decoded by Cesanta.
+*/
+struct regfile
+{
+    uint32_t a[16];
+    uint32_t pc;
+    uint32_t sar;
+    uint32_t litbase;
+    uint32_t sr176;
+    uint32_t sr208;
+    uint32_t ps;
+};
+
+
+//Send the reason execution is stopped to GDB.
+static void ATTR_GDBFN sendReason(void)
+{
+    #if 0
+    char *reason=""; //default
+    #endif
+    gdbPacketStart();
+    gdbPacketChar('T');
+    if (gdbstub_savedRegs.reason == 0xff)
+    {
+        gdbPacketHex(2, 8); //sigint
+    }
+    else if (gdbstub_savedRegs.reason & 0x80)
+    {
+        // exception-to-signal mapping
+        char exceptionSignal[] = { 4, 31, 11, 11, 2, 6 , 8, 0, 6, 7, 0, 0, 7, 7, 7, 7};
+        unsigned int i=0;
+        // We stopped because of an exception.
+        // Convert exception code to a signal number and send it.
+        i = gdbstub_savedRegs.reason & 0x7f;
+        if (i < sizeof(exceptionSignal))
+            gdbPacketHex(exceptionSignal[i], 8);
+        else
+            gdbPacketHex(11, 8);
+    }
+    else
+    {
+        // We stopped because of a debugging exception.
+        gdbPacketHex(5, 8); //sigtrap
+        // Current Xtensa GDB versions don't seem to request this, so let's
+        // leave it off.
+        #if 0
+        if (gdbstub_savedRegs.reason&(1 << 0)) reason="break";
+        if (gdbstub_savedRegs.reason&(1 << 1)) reason="hwbreak";
+        if (gdbstub_savedRegs.reason&(1 << 2)) reason="watch";
+        if (gdbstub_savedRegs.reason&(1 << 3)) reason="swbreak";
+        if (gdbstub_savedRegs.reason&(1 << 4)) reason="swbreak";
+
+        gdbPacketStr(reason);
+        gdbPacketChar(':');
+        //ToDo: watch: send address
+        #endif
+    }
+    gdbPacketEnd();
+}
+
+// Handle a command as received from GDB.
+static int ATTR_GDBFN gdbHandleCommand(unsigned char *cmd, int len)
+{
+    // Handle a command
+    int i, j, k;
+    unsigned char *data=cmd+1;
+    if (cmd[0] == 'g')
+    {   // send all registers to gdb
+        gdbPacketStart();
+        gdbPacketHex(iswap(gdbstub_savedRegs.a0), 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.a1), 32);
+        for (i = 2; i < 16; i++)
+            gdbPacketHex(iswap(gdbstub_savedRegs.a[i-2]), 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.pc), 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.sar), 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.litbase), 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.sr176), 32);
+        gdbPacketHex(0, 32);
+        gdbPacketHex(iswap(gdbstub_savedRegs.ps), 32);
+        gdbPacketEnd();
+    }
+    else if (cmd[0]=='G')
+    {   //receive content for all registers from gdb
+        gdbstub_savedRegs.a0 = iswap(gdbGetHexVal(&data, 32));
+        gdbstub_savedRegs.a1 = iswap(gdbGetHexVal(&data, 32));
+        for (i = 2; i < 16; i++)
+            gdbstub_savedRegs.a[i-2]=iswap(gdbGetHexVal(&data, 32));
+        gdbstub_savedRegs.pc = iswap(gdbGetHexVal(&data, 32));
+        gdbstub_savedRegs.sar = iswap(gdbGetHexVal(&data, 32));
+        gdbstub_savedRegs.litbase = iswap(gdbGetHexVal(&data, 32));
+        gdbstub_savedRegs.sr176 = iswap(gdbGetHexVal(&data, 32));
+        gdbGetHexVal(&data, 32);
+        gdbstub_savedRegs.ps = iswap(gdbGetHexVal(&data, 32));
+        gdbPacketStart();
+        gdbPacketStr("OK");
+        gdbPacketEnd();
+    }
+    else if (cmd[0]=='m') {    //read memory to gdb
+        i=gdbGetHexVal(&data, -1);
+        data++;
+        j=gdbGetHexVal(&data, -1);
+        gdbPacketStart();
+        for (k=0; k<j; k++) {
+            gdbPacketHex(readbyte(i++), 8);
+        }
+        gdbPacketEnd();
+    } else if (cmd[0]=='M') {    //write memory from gdb
+        i=gdbGetHexVal(&data, -1); //addr
+        data++; //skip ,
+        j=gdbGetHexVal(&data, -1); //length
+        data++; //skip :
+        if (validWrAddr(i) && validWrAddr(i+j)) {
+            for (k=0; k<j; k++) {
+                writeByte(i, gdbGetHexVal(&data, 8));
+                i++;
+            }
+            //Make sure caches are up-to-date. Procedure according to Xtensa ISA document, ISYNC inst desc.
+            __asm__ volatile("ISYNC\nISYNC\n");
+            gdbPacketStart();
+            gdbPacketStr("OK");
+            gdbPacketEnd();
+        } else {
+            //Trying to do a software breakpoint on a flash proc, perhaps?
+            gdbPacketStart();
+            gdbPacketStr("E01");
+            gdbPacketEnd();
+        }
+    } else if (cmd[0]=='?') {    //Reply with stop reason
+        sendReason();
+//    } else if (strncmp(cmd, "vCont?", 6)==0) {
+//        gdbPacketStart();
+//        gdbPacketStr("vCont;c;s");
+//        gdbPacketEnd();
+    } else if (strncmp((char*)cmd, "vCont;c", 7)==0 || cmd[0]=='c') {    //continue execution
+        return ST_CONT;
+    } else if (strncmp((char*)cmd, "vCont;s", 7)==0 || cmd[0]=='s') {    //single-step instruction
+        //Single-stepping can go wrong if an interrupt is pending, especially when it is e.g. a task switch:
+        //the ICOUNT register will overflow in the task switch code. That is why we disable interupts when
+        //doing single-instruction stepping.
+        singleStepPs=gdbstub_savedRegs.ps;
+        gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps & ~0xf)|(XCHAL_DEBUGLEVEL-1);
+        gdbstub_icount_ena_single_step();
+        return ST_CONT;
+    } else if (cmd[0]=='q') {    //Extended query
+        if (strncmp((char*)&cmd[1], "Supported", 9)==0) { //Capabilities query
+            gdbPacketStart();
+            gdbPacketStr("swbreak+;hwbreak+;PacketSize=255");
+            gdbPacketEnd();
+        } else {
+            //We don't support other queries.
+            gdbPacketStart();
+            gdbPacketEnd();
+            return ST_ERR;
+        }
+    } else if (cmd[0]=='Z') {    //Set hardware break/watchpoint.
+        data+=2; //skip 'x,'
+        i=gdbGetHexVal(&data, -1);
+        data++; //skip ','
+        j=gdbGetHexVal(&data, -1);
+        gdbPacketStart();
+        if (cmd[1]=='1') {    //Set breakpoint
+            if (gdbstub_set_hw_breakpoint(i, j)) {
+                gdbPacketStr("OK");
+            } else {
+                gdbPacketStr("E01");
+            }
+        } else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //Set watchpoint
+            int access=0;
+            int mask=0;
+            if (cmd[1]=='2') access=2; //write
+            if (cmd[1]=='3') access=1; //read
+            if (cmd[1]=='4') access=3; //access
+            if (j==1) mask=0x3F;
+            if (j==2) mask=0x3E;
+            if (j==4) mask=0x3C;
+            if (j==8) mask=0x38;
+            if (j==16) mask=0x30;
+            if (j==32) mask=0x20;
+            if (j==64) mask=0x00;
+            if (mask!=0 && gdbstub_set_hw_watchpoint(i,mask, access)) {
+                gdbPacketStr("OK");
+            } else {
+                gdbPacketStr("E01");
+            }
+        }
+        gdbPacketEnd();
+    } else if (cmd[0]=='z') {    //Clear hardware break/watchpoint
+        data+=2; //skip 'x,'
+        i=gdbGetHexVal(&data, -1);
+        data++; //skip ','
+        j=gdbGetHexVal(&data, -1);
+        gdbPacketStart();
+        if (cmd[1]=='1') {    //hardware breakpoint
+            if (gdbstub_del_hw_breakpoint(i)) {
+                gdbPacketStr("OK");
+            } else {
+                gdbPacketStr("E01");
+            }
+        } else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //hardware watchpoint
+            if (gdbstub_del_hw_watchpoint(i)) {
+                gdbPacketStr("OK");
+            } else {
+                gdbPacketStr("E01");
+            }
+        }
+        gdbPacketEnd();
+    } else {
+        //We don't recognize or support whatever GDB just sent us.
+        gdbPacketStart();
+        gdbPacketEnd();
+        return ST_ERR;
+    }
+    return ST_OK;
+}
+
+
+//Lower layer: grab a command packet and check the checksum
+//Calls gdbHandleCommand on the packet if the checksum is OK
+//Returns ST_OK on success, ST_ERR when checksum fails, a
+//character if it is received instead of the GDB packet
+//start char.
+static int ATTR_GDBFN gdbReadCommand(void) {
+    unsigned char c;
+    unsigned char chsum=0, rchsum;
+    unsigned char sentchs[2];
+    int p=0;
+    unsigned char *ptr;
+    c=gdbRecvChar();
+    if (c!='$') return c;
+    while(1) {
+        c=gdbRecvChar();
+        if (c=='#') {    //end of packet, checksum follows
+            cmd[p]=0;
+            break;
+        }
+        chsum+=c;
+        if (c=='$') {
+            //Wut, restart packet?
+            chsum=0;
+            p=0;
+            continue;
+        }
+        if (c=='}') {        //escape the next char
+            c=gdbRecvChar();
+            chsum+=c;
+            c^=0x20;
+        }
+        cmd[p++]=c;
+        if (p>=PBUFLEN) return ST_ERR;
+    }
+    //A # has been received. Get and check the received chsum.
+    sentchs[0]=gdbRecvChar();
+    sentchs[1]=gdbRecvChar();
+    ptr=&sentchs[0];
+    rchsum=gdbGetHexVal(&ptr, 8);
+//    ets_printf("c %x r %x\n", chsum, rchsum);
+    if (rchsum!=chsum) {
+        gdbSendChar('-');
+        return ST_ERR;
+    } else {
+        gdbSendChar('+');
+        return gdbHandleCommand(cmd, p);
+    }
+}
+
+//Get the value of one of the A registers
+static unsigned int ATTR_GDBFN getaregval(int reg) {
+    if (reg==0) return gdbstub_savedRegs.a0;
+    if (reg==1) return gdbstub_savedRegs.a1;
+    return gdbstub_savedRegs.a[reg-2];
+}
+
+//Set the value of one of the A registers
+static void ATTR_GDBFN setaregval(int reg, unsigned int val) {
+    ets_printf("%x -> %x\n", val, reg);
+    if (reg==0) gdbstub_savedRegs.a0=val;
+    if (reg==1) gdbstub_savedRegs.a1=val;
+    gdbstub_savedRegs.a[reg-2]=val;
+}
+
+//Emulate the l32i/s32i instruction we're stopped at.
+static void ATTR_GDBFN emulLdSt(void) {
+    unsigned char i0=readbyte(gdbstub_savedRegs.pc);
+    unsigned char i1=readbyte(gdbstub_savedRegs.pc+1);
+    unsigned char i2=readbyte(gdbstub_savedRegs.pc+2);
+    int *p;
+    if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x20) {
+        //l32i
+        p=(int*)getaregval(i1 & 0xf)+(i2*4);
+        setaregval(i0 >> 4, *p);
+        gdbstub_savedRegs.pc+=3;
+    } else if ((i0 & 0xf)==0x8) {
+        //l32i.n
+        p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4);
+        setaregval(i0 >> 4, *p);
+        gdbstub_savedRegs.pc+=2;
+    } else if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x60) {
+        //s32i
+        p=(int*)getaregval(i1 & 0xf)+(i2*4);
+        *p=getaregval(i0 >> 4);
+        gdbstub_savedRegs.pc+=3;
+    } else if ((i0 & 0xf)==0x9) {
+        //s32i.n
+        p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4);
+        *p=getaregval(i0 >> 4);
+        gdbstub_savedRegs.pc+=2;
+    } else {
+        ets_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0);
+    }
+}
+
+// We just caught a debug exception and need to handle it. This is called
+// from an assembly routine in gdbstub-entry.S
+void ATTR_GDBFN gdbstub_handle_debug_exception(void)
+{
+    ets_wdt_disable();
+
+    if (singleStepPs != -1)
+    {
+        // We come here after single-stepping an instruction. Interrupts are
+        // disabled for the single step. Re-enable them here.
+        gdbstub_savedRegs.ps = (gdbstub_savedRegs.ps & ~0xf) | (singleStepPs & 0xf);
+        singleStepPs = -1;
+    }
+
+    sendReason();
+    while (gdbReadCommand()!=ST_CONT)
+        ;
+
+    if ((gdbstub_savedRegs.reason & 0x84) == 0x4)
+    {
+        //We stopped due to a watchpoint. We can't re-execute the current instruction
+        //because it will happily re-trigger the same watchpoint, so we emulate it
+        //while we're still in debugger space.
+        emulLdSt();
+    } else if ((gdbstub_savedRegs.reason & 0x88)==0x8) {
+        //We stopped due to a BREAK instruction. Skip over it.
+        //Check the instruction first; gdb may have replaced it with the original instruction
+        //if it's one of the breakpoints it set.
+        if (readbyte(gdbstub_savedRegs.pc+2)==0 &&
+                    (readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0x40 &&
+                    (readbyte(gdbstub_savedRegs.pc) & 0x0f)==0x00) {
+            gdbstub_savedRegs.pc+=3;
+        }
+    } else if ((gdbstub_savedRegs.reason & 0x90)==0x10) {
+        //We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction
+        //actually is a BREAK.N
+        if ((readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0xf0 &&
+                    readbyte(gdbstub_savedRegs.pc)==0x2d) {
+            gdbstub_savedRegs.pc+=3;
+        }
+    }
+    ets_wdt_enable();
+}
+
+
+#ifdef MODULE_ESP_SDK_INT_HANDLING
+
+// Non-OS exception handler. Gets called by the Xtensa HAL.
+static void ATTR_GDBFN gdb_exception_handler (void* arg)
+{
+    struct XTensa_exception_frame_s* frame = (struct XTensa_exception_frame_s*)arg;
+
+    // Save the extra registers the Xtensa HAL doesn't save
+    gdbstub_save_extra_sfrs_for_exception();
+
+    // Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+    ets_memcpy(&gdbstub_savedRegs, frame, 19*4);
+
+    // Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it
+    // has a fixed offset from the address of the passed frame, we can recover it.
+    gdbstub_savedRegs.a1 = (uint32_t)frame + EXCEPTION_GDB_SP_OFFSET;
+
+    gdbstub_savedRegs.reason |= 0x80; //mark as an exception reason
+
+    ets_wdt_disable();
+    sendReason();
+    while (gdbReadCommand() != ST_CONT)
+        ;
+    ets_wdt_enable();
+
+    // Copy any changed registers back to the frame the Xtensa HAL uses.
+    ets_memcpy(frame, &gdbstub_savedRegs, 19*4);
+}
+
+#else
+/* TODO
+static void ATTR_GDBFN gdb_exception_handler (XtExcFrame *frame)
+{
+    ets_printf("GDB EXCEPTION\n");
+    while (1) ;
+}
+*/
+#endif // MODULE_ESP_SDK_INT_HANDLING
+
+
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+// Replacement putchar1 routine. Instead of spitting out the character
+// directly, it will buffer up to OBUFLEN characters (or up to a \n,
+// whichever comes earlier) and send it out as a gdb stdout packet.
+static void ATTR_GDBFN gdb_semihost_putchar1(char c)
+{
+    obuf[obufpos++]=c;
+    if (c=='\n' || obufpos==OBUFLEN)
+    {
+        int i;
+        gdbPacketStart();
+        gdbPacketChar('O');
+        for (i=0; i<obufpos; i++)
+            gdbPacketHex(obuf[i], 8);
+        gdbPacketEnd();
+        obufpos=0;
+    }
+}
+#endif
+
+// The OS-less SDK uses the Xtensa HAL to handle exceptions. We can use those
+// functions to catch any fatal exceptions and invoke the debugger when this
+// happens.
+static void ATTR_GDBINIT install_exceptions(void)
+{
+#ifdef MODULE_ESP_SDK_INT_HANDLING
+    unsigned int i;
+    unsigned int exno[]=
+             {
+                 EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL,
+                 EXCCAUSE_INSTR_ERROR, EXCCAUSE_LOAD_STORE_ERROR,
+                 EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED,
+                 EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR,
+                 EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR,
+                 EXCCAUSE_INSTR_PROHIBITED,    EXCCAUSE_LOAD_PROHIBITED,
+                 EXCCAUSE_STORE_PROHIBITED
+             };
+    for (i = 0; i < (sizeof(exno)/sizeof(exno[0])); i++)
+        _xtos_set_exception_handler(exno[i], gdb_exception_handler);
+#endif
+}
+
+#if GDBSTUB_CTRLC_BREAK
+
+static void ATTR_GDBFN uart_hdlr(void *arg, void *frame)
+{
+    int doDebug=0;
+    int fifolen=0;
+    //Save the extra registers the Xtensa HAL doesn't save
+    gdbstub_save_extra_sfrs_for_exception();
+
+    fifolen=(READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+    while (fifolen!=0)
+    {
+        //Check if any of the chars is control-C. Throw away rest.
+        if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3)
+            doDebug=1;
+        fifolen--;
+    }
+    WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+
+    if (doDebug)
+    {
+        // Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+        ets_memcpy(&gdbstub_savedRegs, frame, 19*4);
+        gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+        //mark as user break reason
+        gdbstub_savedRegs.reason=0xff;
+
+        ets_wdt_disable();
+        sendReason();
+        while(gdbReadCommand()!=ST_CONT);
+        ets_wdt_enable();
+        // Copy any changed registers back to the frame the Xtensa HAL uses.
+        ets_memcpy(frame, &gdbstub_savedRegs, 19*4);
+    }
+}
+
+static void ATTR_GDBINIT install_uart_hdlr(void)
+{
+    ets_isr_attach(ETS_UART_INUM, (ets_isr_t)uart_hdlr, NULL);
+    SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+    // enable uart interrupt
+    ets_isr_unmask((1 << ETS_UART_INUM));
+}
+
+#endif // GDBSTUB_CTRLC_BREAK
+
+// gdbstub initialization routine.
+void ATTR_GDBINIT gdbstub_init(void)
+{
+    #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+    ets_install_putc1(gdb_semihost_putchar1);
+    #endif
+
+    #if GDBSTUB_CTRLC_BREAK
+    install_uart_hdlr();
+    #endif
+
+    install_exceptions();
+    gdbstub_init_debug_entry();
+
+    #if GDBSTUB_BREAK_ON_INIT
+    gdbstub_do_break();
+    #endif
+}
diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9e8b4a094ffe487ac8fa0280fdc0ff317d4e12b
--- /dev/null
+++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h
@@ -0,0 +1,14 @@
+#ifndef GDBSTUB_H
+#define GDBSTUB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gdbstub_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GDBSTUB_H */
diff --git a/cpu/esp8266/vendor/esp/FreeRTOS.h b/cpu/esp8266/vendor/esp/FreeRTOS.h
new file mode 100644
index 0000000000000000000000000000000000000000..64c2b8225d2cec261d5e2811f2ebbbb3b6cc4f5a
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/FreeRTOS.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 Gunar Schorcht
+ *
+ * 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.
+ *
+ * FreeRTOS to RIOT-OS adaption module
+ */
+
+#ifndef FREERTOS_H
+#define FREERTOS_H
+
+#ifndef DOXYGEN
+
+#include "stdlib.h"
+
+#include "mutex.h"
+#include "irq.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SemaphoreHandle_t mutex_t*
+
+static inline SemaphoreHandle_t xSemaphoreCreateMutex(void)
+{
+    mutex_t* _tmp = malloc (sizeof(mutex_t));
+    mutex_init(_tmp);
+    return _tmp;
+}
+
+#define xSemaphoreTake(s,to)   mutex_lock(s)
+#define xSemaphoreGive(s)      mutex_unlock(s)
+
+#define vPortEnterCritical()   int _irq_state = irq_disable ()
+#define vPortExitCritical()    irq_restore(_irq_state)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* FREERTOS_H */
diff --git a/cpu/esp8266/vendor/esp/LICENSE b/cpu/esp8266/vendor/esp/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..08d96c4a598744b4424545e586bc646ad5ab9cdf
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/LICENSE
@@ -0,0 +1,12 @@
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
diff --git a/cpu/esp8266/vendor/esp/Makefile b/cpu/esp8266/vendor/esp/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5db2d2121ce972a88a386483be3e7583494ccce0
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/Makefile
@@ -0,0 +1,3 @@
+MODULE=esp
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/vendor/esp/README.md b/cpu/esp8266/vendor/esp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..bf5deb40d3d2bdef367e6aced1193e88c3f6f9f1
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/README.md
@@ -0,0 +1,3 @@
+All files in this directory are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). They are under the copyright of their respective owners. Please note the copyright notice in these files.
+
+All of these files are BSD Licensed as described in the file [LICENSE](https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE).
diff --git a/cpu/esp8266/vendor/esp/common_macros.h b/cpu/esp8266/vendor/esp/common_macros.h
new file mode 100644
index 0000000000000000000000000000000000000000..d14c34639c2bfdea9fe32e7e285b52d8b16eedfa
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/common_macros.h
@@ -0,0 +1,145 @@
+/* Some common compiler macros
+ *
+ * Not esp8266-specific.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Superhouse Automation Pty Ltd
+ * BSD Licensed as described in the file LICENSE
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef COMMON_MACROS_H
+#define COMMON_MACROS_H
+
+#include <sys/cdefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNUSED __attributed((unused))
+
+#ifndef BIT
+#define BIT(X) (1<<(X))
+#endif
+
+/* These macros convert values to/from bitfields specified by *_M and *_S (mask
+ * and shift) constants.  Used primarily with ESP8266 register access.
+ */
+
+#define VAL2FIELD(fieldname, value) ((value) << fieldname##_S)
+#define FIELD2VAL(fieldname, regbits) (((regbits) >> fieldname##_S) & fieldname##_M)
+
+#define FIELD_MASK(fieldname) (fieldname##_M << fieldname##_S)
+#define SET_FIELD(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD(fieldname, value))
+
+/* VAL2FIELD/SET_FIELD do not normally check to make sure that the passed value
+ * will fit in the specified field (without clobbering other bits).  This makes
+ * them faster and is usually fine.  If you do need to make sure that the value
+ * will not overflow the field, use VAL2FIELD_M or SET_FIELD_M (which will
+ * first mask the supplied value to only the allowed number of bits) instead.
+ */
+#define VAL2FIELD_M(fieldname, value) (((value) & fieldname##_M) << fieldname##_S)
+#define SET_FIELD_M(regbits, fieldname, value) (((regbits) & ~FIELD_MASK(fieldname)) | VAL2FIELD_M(fieldname, value))
+
+/* Set bits in reg with specified mask.
+ */
+#define SET_MASK_BITS(reg, mask) (reg) |= (mask)
+
+/* Clear bits in reg with specified mask
+ */
+#define CLEAR_MASK_BITS(reg, mask) (reg) &= ~(mask)
+
+/* Use the IRAM macro to place functions into Instruction RAM (IRAM)
+   instead of flash (aka irom).
+
+   (This is the opposite to the Espressif SDK, where functions default
+   to being placed in IRAM but the ICACHE_FLASH_ATTR attribute will
+   place them in flash.)
+
+   Use the IRAM attribute for functions which are called when the
+   flash may not be available (for example during NMI exceptions), or
+   for functions which are called very frequently and need high
+   performance.
+
+   Usage example:
+
+   void IRAM high_performance_function(void)
+   {
+       // do important thing here
+   }
+
+   Bear in mind IRAM is limited (32KB), compared to up to 1MB of flash.
+*/
+#define IRAM __attribute__((section(".iram1.text")))
+
+/* Use the RAM macro to place constant data (rodata) into RAM (data
+   RAM) instead of the default placement in flash. This is useful for
+   constant data which needs high performance access.
+
+   Usage example:
+
+   const RAM uint8_t constants[] = { 1, 2, 3, 7 };
+
+   When placing string literals in RAM, they need to be declared with
+   the type "const char[]" not "const char *"
+
+   Usage example:
+
+   const RAM char hello_world[] = "Hello World";
+*/
+#define RAM __attribute__((section(".data")))
+
+/* Use the IRAM_DATA macro to place data into Instruction RAM (IRAM)
+   instead of the default of flash (for constant data) or data RAM
+   (for non-constant data).
+
+   This may be useful to free up data RAM. However all data read from
+   any instruction space (either IRAM or Flash) must be 32-bit aligned
+   word reads. Reading unaligned data stored with IRAM_DATA will be
+   slower than reading data stored in RAM. You can't perform unaligned
+   writes to IRAM.
+*/
+#define IRAM_DATA __attribute__((section(".iram1.data")))
+
+/* Use the IROM macro to store constant values in IROM flash. In
+  esp-open-rtos this is already the default location for most constant
+  data (rodata), so you don't need this attribute in 99% of cases.
+
+  The exceptions are to mark data in the core & freertos libraries,
+  where the default for constant data storage is RAM.
+
+  (Unlike the Espressif SDK you don't need to use an attribute like
+  ICACHE_FLASH_ATTR for functions, they go into flash by default.)
+
+  Important to note: IROM flash is accessed via 32-bit word aligned
+  reads. esp-open-rtos does some magic to "fix" unaligned reads, but
+  performance is reduced.
+*/
+#ifdef    __cplusplus
+    #define IROM __attribute__((section(".irom0.text")))
+    #define IROM_LIT __attribute__((section(".irom0.literal")))
+#else
+    #define IROM __attribute__((section(".irom0.text")))
+    #define IROM_LIT __attribute__((section(".irom0.literal"))) const
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMMON_MACROS_H */
diff --git a/cpu/esp8266/vendor/esp/dport_regs.h b/cpu/esp8266/vendor/esp/dport_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..79769b61b91b79a6dd8cf33233e848d3b55394ef
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/dport_regs.h
@@ -0,0 +1,155 @@
+/* esp/dport_regs.h
+ *
+ * ESP8266 DPORT0 register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef DPORT_REGS_H
+#define DPORT_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DPORT_BASE 0x3ff00000
+#define DPORT (*(struct DPORT_REGS *)(DPORT_BASE))
+
+/* DPORT registers
+
+   Control various aspects of core/peripheral interaction... Not well
+   documented or understood.
+*/
+
+struct DPORT_REGS {
+    uint32_t volatile DPORT0;              // 0x00  FIXME: need a better name for this
+    uint32_t volatile INT_ENABLE;          // 0x04
+    uint32_t volatile _unknown08;          // 0x08
+    uint32_t volatile SPI_READY;           // 0x0c
+    uint32_t volatile _unknown10;          // 0x10
+    uint32_t volatile CPU_CLOCK;           // 0x14
+    uint32_t volatile CLOCKGATE_WATCHDOG;  // 0x18
+    uint32_t volatile _unknown1c;          // 0x1c
+    uint32_t volatile SPI_INT_STATUS;      // 0x20
+    uint32_t volatile SPI_CACHE_RAM;       // 0x24
+    uint32_t volatile PERI_IO;             // 0x28
+    uint32_t volatile SLC_TX_DESC_DEBUG;   // 0x2c
+    uint32_t volatile _unknown30;          // 0x30
+    uint32_t volatile _unknown34;          // 0x34
+    uint32_t volatile _unknown38;          // 0x38
+    uint32_t volatile _unknown3c;          // 0x3c
+    uint32_t volatile _unknown40;          // 0x40
+    uint32_t volatile _unknown44;          // 0x44
+    uint32_t volatile _unknown48;          // 0x48
+    uint32_t volatile _unknown4c;          // 0x4c
+    uint32_t volatile OTP_MAC0;            // 0x50
+    uint32_t volatile OTP_MAC1;            // 0x54
+    uint32_t volatile OTP_CHIPID;          // 0x58
+    uint32_t volatile OTP_MAC2;            // 0x5c
+};
+
+_Static_assert(sizeof(struct DPORT_REGS) == 0x60, "DPORT_REGS is the wrong size");
+
+/* Details for DPORT0 register */
+
+/* Currently very little known about this register.  The following is based on analysis of the startup code in the Espressif SDK: */
+
+#define DPORT_DPORT0_FIELD0_M  0x0000001f
+#define DPORT_DPORT0_FIELD0_S  0
+
+/* Details for INT_ENABLE register */
+
+/* Set flags to enable CPU interrupts from some peripherals. Read/write.
+
+   bit 0 - INT_ENABLE_WDT (unclear exactly how this works.  Set by RTOS SDK startup code)
+   bit 1 - INT_ENABLE_TIMER0 allows TIMER 0 (FRC1) to trigger interrupt INUM_TIMER_FRC1.
+   bit 2 - INT_ENABLE_TIMER1 allows TIMER 1 (FRC2) to trigger interrupt INUM_TIMER_FRC2.
+
+   Espressif calls this register "EDGE_INT_ENABLE_REG". The "edge" in
+   question is (I think) the interrupt line from the peripheral, as
+   the interrupt status bit is set. There may be a similar register
+   for enabling "level" interrupts instead of edge triggering
+   - this is unknown.
+*/
+
+#define DPORT_INT_ENABLE_WDT     BIT(0)
+#define DPORT_INT_ENABLE_TIMER0  BIT(1)
+#define DPORT_INT_ENABLE_TIMER1  BIT(2)
+
+/* Aliases for the Espressif way of referring to TIMER0 (FRC1) and TIMER1
+ * (FRC2).. */
+#define DPORT_INT_ENABLE_FRC1  DPORT_INT_ENABLE_TIMER0
+#define DPORT_INT_ENABLE_FRC2  DPORT_INT_ENABLE_TIMER1
+
+/* Details for SPI_READY register */
+
+#define DPORT_SPI_READY_IDLE     BIT(9)
+
+/* Details for CPU_CLOCK register */
+
+#define DPORT_CPU_CLOCK_X2       BIT(0)
+
+/* Details for CLOCKGATE_WATCHDOG register */
+
+// Set and then cleared during sdk_system_restart_in_nmi().
+// Not sure what this does.  May be related to ESPSAR.UNKNOWN_48
+#define DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8  BIT(8)
+
+/* Comment found in pvvx/mp3_decode headers: "use clockgate_watchdog(flg) { if(flg) 0x3FF00018 &= 0x77; else 0x3FF00018 |= 8; }".  Not sure what this means or does. */
+
+#define DPORT_CLOCKGATE_WATCHDOG_DISABLE  BIT(3)
+
+/* Details for SPI_INT_STATUS register */
+
+#define DPORT_SPI_INT_STATUS_SPI0  BIT(4)
+#define DPORT_SPI_INT_STATUS_SPI1  BIT(7)
+#define DPORT_SPI_INT_STATUS_I2S   BIT(9)
+
+/* Details for SPI_CACHE_RAM register */
+
+#define DPORT_SPI_CACHE_RAM_BANK1  BIT(3)
+#define DPORT_SPI_CACHE_RAM_BANK0  BIT(4)
+
+/* Details for PERI_IO register */
+
+#define DPORT_PERI_IO_SWAP_UARTS       BIT(0)
+#define DPORT_PERI_IO_SWAP_SPIS        BIT(1)
+#define DPORT_PERI_IO_SWAP_UART0_PINS  BIT(2)
+#define DPORT_PERI_IO_SWAP_UART1_PINS  BIT(3)
+#define DPORT_PERI_IO_SPI1_PRIORITY    BIT(5)
+#define DPORT_PERI_IO_SPI1_SHARED      BIT(6)
+#define DPORT_PERI_IO_SPI0_SHARED      BIT(7)
+
+/* Details for SLC_TX_DESC_DEBUG register */
+
+#define SLC_TX_DESC_DEBUG_VALUE_M      0x0000ffff
+#define SLC_TX_DESC_DEBUG_VALUE_S      0
+
+#define SLC_TX_DESC_DEBUG_VALUE_MAGIC  0xcccc
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* DPORT_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/flashchip.h b/cpu/esp8266/vendor/esp/flashchip.h
new file mode 100644
index 0000000000000000000000000000000000000000..4aad689d199e5bb6eabae2d441170e0ce7a04b5c
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/flashchip.h
@@ -0,0 +1,67 @@
+/* flashchip.h
+ *
+ * sdk_flashchip_t structure used by the SDK and some bootrom routines
+ *
+ * This is in a separate include file because it's referenced by several other
+ * headers which are otherwise independent of each other.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Alex Stewart and Angus Gratton
+ * BSD Licensed as described in the file LICENSE
+ */
+
+/*
+Copyright (C) 2015 Alex Stewart and Angus Gratton
+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.
+*/
+
+#ifndef FLASHCHIP_H
+#define FLASHCHIP_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SDK/bootrom uses this structure internally to account for flash size.
+
+   chip_size field is initialised during startup from the flash size
+   saved in the image header (on the first 8 bytes of SPI flash).
+
+   Other field are initialised to hardcoded values by the SDK.
+
+   ** NOTE: This structure is passed to some bootrom routines and is therefore
+   fixed.  Be very careful if you want to change it that you do not break
+   things. **
+
+   Based on RE work by @foogod at
+   http://esp8266-re.foogod.com/wiki/Flashchip_%28IoT_RTOS_SDK_0.9.9%29
+*/
+typedef struct {
+    uint32_t device_id;
+    uint32_t chip_size;   /* in bytes */
+    uint32_t block_size;  /* in bytes */
+    uint32_t sector_size; /* in bytes */
+    uint32_t page_size;   /* in bytes */
+    uint32_t status_mask;
+} sdk_flashchip_t;
+
+extern sdk_flashchip_t sdk_flashchip;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* FLASHCHIP_H */
diff --git a/cpu/esp8266/vendor/esp/gpio_regs.h b/cpu/esp8266/vendor/esp/gpio_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..f545e2965c750e214c684b87b723bd2bedb95217
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/gpio_regs.h
@@ -0,0 +1,192 @@
+/* esp/gpio_regs.h
+ *
+ * ESP8266 GPIO register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef GPIO_REGS_H
+#define GPIO_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GPIO_BASE 0x60000300
+#define GPIO (*(struct GPIO_REGS *)(GPIO_BASE))
+
+/** GPIO output registers GPIO.OUT, GPIO.OUT_SET, GPIO.OUT_CLEAR:
+ *
+ * _SET and _CLEAR write-only registers set and clear bits in the main register,
+ * respectively.
+ *
+ * i.e.
+ *   GPIO.OUT_SET = BIT(3);
+ * and
+ *   GPIO.OUT |= BIT(3);
+ *
+ * ... are equivalent, but the former uses fewer CPU cycles.
+ *
+ * ENABLE_OUT / ENABLE_OUT_SET / ENABLE_OUT_CLEAR:
+ *
+ * Determine whether the corresponding GPIO has its output enabled or not.
+ * When clear, GPIO can function as an input.  When set, GPIO will drive its
+ * output (and IN register will simply reflect the output state).
+ *
+ * (_SET/_CLEAR function similarly to OUT registers)
+ *
+ * STATUS / STATUS_SET / STATUS_CLEAR:
+ *
+ * Indicates which GPIOs have triggered an interrupt.  Interrupt status should
+ * be reset by writing to STATUS or STATUS_CLEAR.
+ *
+ * (_SET/_CLEAR function similarly to OUT registers)
+ *
+ * IN:
+ *
+ * Low 16 bits represent GPIO0-15 state (see also above).
+ *
+ * High 16 bits represent "strapping pins" values captured at reset time:
+ * bit 31 - GPIO10 (SD_DATA3)
+ * bit 30 - GPIO9 (SD_DATA2)
+ * bit 29 - GPIO7 (SD_DATA0)
+ * bit 18 - GPIO15 (MTDO)
+ * bit 17 - GPIO0
+ * bit 16 - GPIO2
+ * (In other words, highest 3 and lowest 3 bits of 16-bit half-word are used).
+ * BootROM uses strapping pin values to determine boot mode.
+ *
+ * Source and more information: 0D-ESP8266__Pin_List*.xlsx document
+ */
+
+struct GPIO_REGS {
+    uint32_t volatile OUT;              // 0x00
+    uint32_t volatile OUT_SET;          // 0x04
+    uint32_t volatile OUT_CLEAR;        // 0x08
+    uint32_t volatile ENABLE_OUT;       // 0x0c
+    uint32_t volatile ENABLE_OUT_SET;   // 0x10
+    uint32_t volatile ENABLE_OUT_CLEAR; // 0x14
+    uint32_t volatile IN;               // 0x18
+    uint32_t volatile STATUS;           // 0x1c
+    uint32_t volatile STATUS_SET;       // 0x20
+    uint32_t volatile STATUS_CLEAR;     // 0x24
+    uint32_t volatile CONF[16];         // 0x28 - 0x64
+    uint32_t volatile PWM;              // 0x68
+    uint32_t volatile RTC_CALIB;        // 0x6c
+    uint32_t volatile RTC_CALIB_RESULT; // 0x70
+};
+
+_Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
+
+/* Details for additional OUT register fields */
+
+/* Bottom 16 bits of GPIO.OUT are for GPIOs 0-15, but upper 16 bits
+   are used to configure the input signalling pins for Bluetooth
+   Coexistence config (see esp/phy.h for a wrapper function).
+*/
+#define GPIO_OUT_PIN_MASK 0x0000FFFF
+#define GPIO_OUT_BT_COEXIST_MASK 0x03FF0000
+#define GPIO_OUT_BT_ACTIVE_ENABLE BIT(24)
+#define GPIO_OUT_BT_PRIORITY_ENABLE BIT(25)
+#define GPIO_OUT_BT_ACTIVE_PIN_M 0x0F
+#define GPIO_OUT_BT_ACTIVE_PIN_S 16
+#define GPIO_OUT_BT_PRIORITY_PIN_M 0x0F
+#define GPIO_OUT_BT_PRIORITY_PIN_S 20
+
+/* Details for CONF[i] registers */
+
+/* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output.
+ *
+ * GPIO_CONF_CONFIG (multi-value)
+ *     FIXME: Unclear what these do.  Need to find a better name.
+ *
+ * GPIO_CONF_WAKEUP_ENABLE (boolean)
+ *     Can an interrupt contion on this pin wake the processor from a sleep
+ *     state?
+ *
+ * GPIO_CONF_INTTYPE (multi-value)
+ *     Under what conditions this GPIO input should generate an interrupt.
+ *     (see gpio_inttype_t enum below for values)
+ *
+ * GPIO_CONF_OPEN_DRAIN (boolean)
+ *     If this bit is set, the pin is in "open drain" mode - a high output state
+ *     will leave the pin floating but not source any current. If bit is cleared,
+ *     the pin is in push/pull mode so a high output state will drive the pin up
+ *     to +Vcc (3.3V).  In either case, a low output state will pull the pin down
+ *     to ground.
+ *
+ *     GPIO_CONF_OPEN_DRAIN does not appear to work on all pins.
+ *
+ *
+ * GPIO_CONF_SOURCE_PWM (boolean)
+ *     When set, GPIO pin output will be connected to the sigma-delta PWM
+ *     generator (controlled by the GPIO.PWM register).  When cleared, pin
+ *     output will function as a normal GPIO output (controlled by the
+ *     GPIO.OUT* registers).
+ */
+
+#define GPIO_CONF_CONFIG_M       0x00000003
+#define GPIO_CONF_CONFIG_S       11
+#define GPIO_CONF_WAKEUP_ENABLE  BIT(10)
+#define GPIO_CONF_INTTYPE_M      0x00000007
+#define GPIO_CONF_INTTYPE_S      7
+#define GPIO_CONF_OPEN_DRAIN     BIT(2)
+#define GPIO_CONF_SOURCE_PWM     BIT(0)
+
+/* Valid values for the GPIO_CONF_INTTYPE field */
+typedef enum {
+    GPIO_INTTYPE_NONE       = 0,
+    GPIO_INTTYPE_EDGE_POS   = 1,
+    GPIO_INTTYPE_EDGE_NEG   = 2,
+    GPIO_INTTYPE_EDGE_ANY   = 3,
+    GPIO_INTTYPE_LEVEL_LOW  = 4,
+    GPIO_INTTYPE_LEVEL_HIGH = 5,
+} gpio_inttype_t;
+
+/* Details for PWM register */
+
+#define GPIO_PWM_ENABLE          BIT(16)
+#define GPIO_PWM_PRESCALER_M     0x000000ff
+#define GPIO_PWM_PRESCALER_S     8
+#define GPIO_PWM_TARGET_M        0x000000ff
+#define GPIO_PWM_TARGET_S        0
+
+/* Details for RTC_CALIB register */
+
+#define GPIO_RTC_CALIB_START     BIT(31)
+#define GPIO_RTC_CALIB_PERIOD_M  0x000003ff
+#define GPIO_RTC_CALIB_PERIOD_S  0
+
+/* Details for RTC_CALIB_RESULT register */
+
+#define GPIO_RTC_CALIB_RESULT_READY       BIT(31)
+#define GPIO_RTC_CALIB_RESULT_READY_REAL  BIT(30)
+#define GPIO_RTC_CALIB_RESULT_VALUE_M     0x000fffff
+#define GPIO_RTC_CALIB_RESULT_VALUE_S     0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* GPIO_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/iomux_regs.h b/cpu/esp8266/vendor/esp/iomux_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..42f2064a08c344601b6224df7b09b6f4d9229387
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/iomux_regs.h
@@ -0,0 +1,172 @@
+/* esp/iomux_regs.h
+ *
+ * ESP8266 IOMUX register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ *
+ * Note that IOMUX register order is _not_ the same as GPIO order. See
+ * esp/iomux.h for programmer-friendly IOMUX configuration options.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef IOMUX_REGS_H
+#define IOMUX_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOMUX_BASE 0x60000800
+#define IOMUX (*(struct IOMUX_REGS *)(IOMUX_BASE))
+
+struct IOMUX_REGS {
+    uint32_t volatile CONF;    // 0x00
+    uint32_t volatile PIN[16]; // 0x04 - 0x40
+};
+
+_Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size");
+
+/* Details for CONF register */
+
+#define IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK  BIT(8)
+#define IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK  BIT(9)
+
+/* Details for PIN registers */
+
+#define IOMUX_PIN_OUTPUT_ENABLE        BIT(0)
+#define IOMUX_PIN_OUTPUT_ENABLE_SLEEP  BIT(1)
+#define IOMUX_PIN_PULLDOWN_SLEEP       BIT(2)
+#define IOMUX_PIN_PULLUP_SLEEP         BIT(3)
+#define IOMUX_PIN_FUNC_LOW_M           0x00000003
+#define IOMUX_PIN_FUNC_LOW_S           4
+#define IOMUX_PIN_PULLDOWN             BIT(6)
+#define IOMUX_PIN_PULLUP               BIT(7)
+#define IOMUX_PIN_FUNC_HIGH_M          0x00000004
+#define IOMUX_PIN_FUNC_HIGH_S          6
+
+#define IOMUX_PIN_FUNC_MASK            0x00000130
+
+/* WARNING: Macro evaluates argument twice */
+#define IOMUX_FUNC(val) (VAL2FIELD_M(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD_M(IOMUX_PIN_FUNC_HIGH, val))
+
+#define IOMUX_GPIO0   IOMUX.PIN[12]
+#define IOMUX_GPIO1   IOMUX.PIN[5]
+#define IOMUX_GPIO2   IOMUX.PIN[13]
+#define IOMUX_GPIO3   IOMUX.PIN[4]
+#define IOMUX_GPIO4   IOMUX.PIN[14]
+#define IOMUX_GPIO5   IOMUX.PIN[15]
+#define IOMUX_GPIO6   IOMUX.PIN[6]
+#define IOMUX_GPIO7   IOMUX.PIN[7]
+#define IOMUX_GPIO8   IOMUX.PIN[8]
+#define IOMUX_GPIO9   IOMUX.PIN[9]
+#define IOMUX_GPIO10  IOMUX.PIN[10]
+#define IOMUX_GPIO11  IOMUX.PIN[11]
+#define IOMUX_GPIO12  IOMUX.PIN[0]
+#define IOMUX_GPIO13  IOMUX.PIN[1]
+#define IOMUX_GPIO14  IOMUX.PIN[2]
+#define IOMUX_GPIO15  IOMUX.PIN[3]
+
+#define IOMUX_GPIO0_FUNC_GPIO              IOMUX_FUNC(0)
+#define IOMUX_GPIO0_FUNC_SPI0_CS2          IOMUX_FUNC(1)
+#define IOMUX_GPIO0_FUNC_CLOCK_OUT         IOMUX_FUNC(4)
+
+#define IOMUX_GPIO1_FUNC_UART0_TXD         IOMUX_FUNC(0)
+#define IOMUX_GPIO1_FUNC_SPI0_CS1          IOMUX_FUNC(1)
+#define IOMUX_GPIO1_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO1_FUNC_CLOCK_RTC_BLINK   IOMUX_FUNC(4)
+
+#define IOMUX_GPIO2_FUNC_GPIO              IOMUX_FUNC(0)
+#define IOMUX_GPIO2_FUNC_I2SO_WS           IOMUX_FUNC(1)
+#define IOMUX_GPIO2_FUNC_UART1_TXD         IOMUX_FUNC(2)
+#define IOMUX_GPIO2_FUNC_UART0_TXD         IOMUX_FUNC(4)
+
+#define IOMUX_GPIO3_FUNC_UART0_RXD         IOMUX_FUNC(0)
+#define IOMUX_GPIO3_FUNC_I2SO_DATA         IOMUX_FUNC(1)
+#define IOMUX_GPIO3_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO3_FUNC_CLOCK_XTAL_BLINK  IOMUX_FUNC(4)
+
+#define IOMUX_GPIO4_FUNC_GPIO              IOMUX_FUNC(0)
+#define IOMUX_GPIO4_FUNC_CLOCK_XTAL        IOMUX_FUNC(1)
+
+#define IOMUX_GPIO5_FUNC_GPIO              IOMUX_FUNC(0)
+#define IOMUX_GPIO5_FUNC_CLOCK_RTC         IOMUX_FUNC(1)
+
+#define IOMUX_GPIO6_FUNC_SD_CLK            IOMUX_FUNC(0)
+#define IOMUX_GPIO6_FUNC_SPI0_CLK          IOMUX_FUNC(1)
+#define IOMUX_GPIO6_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO6_FUNC_UART1_CTS         IOMUX_FUNC(4)
+
+#define IOMUX_GPIO7_FUNC_SD_DATA0          IOMUX_FUNC(0)
+#define IOMUX_GPIO7_FUNC_SPI0_Q_MISO       IOMUX_FUNC(1)
+#define IOMUX_GPIO7_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO7_FUNC_UART1_TXD         IOMUX_FUNC(4)
+
+#define IOMUX_GPIO8_FUNC_SD_DATA1          IOMUX_FUNC(0)
+#define IOMUX_GPIO8_FUNC_SPI0_D_MOSI       IOMUX_FUNC(1)
+#define IOMUX_GPIO8_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO8_FUNC_UART1_RXD         IOMUX_FUNC(4)
+
+#define IOMUX_GPIO9_FUNC_SD_DATA2          IOMUX_FUNC(0)
+#define IOMUX_GPIO9_FUNC_SPI0_HD           IOMUX_FUNC(1)
+#define IOMUX_GPIO9_FUNC_GPIO              IOMUX_FUNC(3)
+#define IOMUX_GPIO9_FUNC_SPI1_HD           IOMUX_FUNC(4)
+
+#define IOMUX_GPIO10_FUNC_SD_DATA3         IOMUX_FUNC(0)
+#define IOMUX_GPIO10_FUNC_SPI0_WP          IOMUX_FUNC(1)
+#define IOMUX_GPIO10_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO10_FUNC_SPI1_WP          IOMUX_FUNC(4)
+
+#define IOMUX_GPIO11_FUNC_SD_CMD           IOMUX_FUNC(0)
+#define IOMUX_GPIO11_FUNC_SPI0_CS0         IOMUX_FUNC(1)
+#define IOMUX_GPIO11_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO11_FUNC_UART1_RTS        IOMUX_FUNC(4)
+
+#define IOMUX_GPIO12_FUNC_MTDI             IOMUX_FUNC(0)
+#define IOMUX_GPIO12_FUNC_I2SI_DATA        IOMUX_FUNC(1)
+#define IOMUX_GPIO12_FUNC_SPI1_Q_MISO      IOMUX_FUNC(2)
+#define IOMUX_GPIO12_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO12_FUNC_UART0_DTR        IOMUX_FUNC(4)
+
+#define IOMUX_GPIO13_FUNC_MTCK             IOMUX_FUNC(0)
+#define IOMUX_GPIO13_FUNC_I2SI_BCK         IOMUX_FUNC(1)
+#define IOMUX_GPIO13_FUNC_SPI1_D_MOSI      IOMUX_FUNC(2)
+#define IOMUX_GPIO13_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO13_FUNC_UART0_CTS        IOMUX_FUNC(4)
+
+#define IOMUX_GPIO14_FUNC_MTMS             IOMUX_FUNC(0)
+#define IOMUX_GPIO14_FUNC_I2SI_WS          IOMUX_FUNC(1)
+#define IOMUX_GPIO14_FUNC_SPI1_CLK         IOMUX_FUNC(2)
+#define IOMUX_GPIO14_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO14_FUNC_UART0_DSR        IOMUX_FUNC(4)
+
+#define IOMUX_GPIO15_FUNC_MTDO             IOMUX_FUNC(0)
+#define IOMUX_GPIO15_FUNC_I2SO_BCK         IOMUX_FUNC(1)
+#define IOMUX_GPIO15_FUNC_SPI1_CS0         IOMUX_FUNC(2)
+#define IOMUX_GPIO15_FUNC_GPIO             IOMUX_FUNC(3)
+#define IOMUX_GPIO15_FUNC_UART0_RTS        IOMUX_FUNC(4)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* IOMUX_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/phy_info.c b/cpu/esp8266/vendor/esp/phy_info.c
new file mode 100644
index 0000000000000000000000000000000000000000..d474b2b8e1c8adb5c74ef8b065d91859a8588b6a
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/phy_info.c
@@ -0,0 +1,200 @@
+/* Routines to allow custom access to the Internal Espressif
+   SDK PHY datastructures.
+
+   Matches espressif/phy_internal.h
+
+   Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton,
+   BSD Licensed as described in the file LICENSE.
+ */
+
+/*
+Copyright (C) 2016 Angus Gratton
+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.
+*/
+
+#ifndef MODULE_ESP_SDK
+#ifdef RIOT_VERSION
+#include <stdio.h>
+#include "c_types.h"
+#include "esp/common_macros.h"
+#include "esp/flashchip.h"
+#include "esp/phy_info.h"
+#include "spi_flash.h"
+#include "sdk/rom.h"
+
+#define sdk_spi_flash_read   spi_flash_read
+#define sdk_spi_flash_write  spi_flash_write
+
+#else
+#include <espressif/phy_info.h>
+#include <espressif/esp_common.h>
+#include <common_macros.h>
+#endif
+#include <string.h>
+
+static const sdk_phy_info_t IROM default_phy_info = {
+    ._reserved00 = { 0x05, 0x00, 0x04, 0x02, 0x05 },
+    .version = 5,
+    ._reserved06 = { 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04,
+                     0x05, 0x05, 0x04,-0x02,-0x03,-0x01,-0x10,-0x10,
+                     -0x10,-0x20,-0x20, -0x20},
+    .spur_freq_primary = 225,
+    .spur_freq_divisor = 10,
+    .spur_freq_en_h = 0xFF,
+    .spur_freq_en_l = 0xFF,
+
+    ._reserved1e = { 0xf8, 0, 0xf8, 0xf8 },
+
+    .target_power = { 82, 78, 74, 68, 64, 56 },
+    .target_power_index_mcs = { 0, 0, 1, 1, 2, 3, 4, 5 },
+
+    .crystal_freq = CRYSTAL_FREQ_26M,
+
+    .sdio_config = SDIO_CONFIG_AUTO,
+
+    .bt_coexist_config = BT_COEXIST_CONFIG_NONE,
+    .bt_coexist_protocol = BT_COEXIST_PROTOCOL_WIFI_ONLY,
+
+    .dual_ant_config = DUAL_ANT_CONFIG_NONE,
+
+    ._reserved34 = 0x02,
+
+    .crystal_sleep = CRYSTAL_SLEEP_OFF,
+
+    .spur_freq_2_primary = 225,
+    .spur_freq_2_divisor = 10,
+    .spur_freq_2_en_h = 0x00,
+    .spur_freq_2_en_l = 0x00,
+    .spur_freq_cfg_msb = 0x00,
+    .spur_freq_2_cfg_msb = 0x00,
+    .spur_freq_3_cfg = 0x0000,
+    .spur_freq_4_cfg = 0x0000,
+
+    ._reserved4a = { 0x01, 0x93, 0x43, 0x00 },
+
+    .low_power_en = false,
+    .lp_atten_stage01 = LP_ATTEN_STAGE01_23DB,
+    .lp_atten_bb = 0,
+
+    .pwr_ind_11b_en = false,
+    .pwr_ind_11b_0 = 0,
+    .pwr_ind_11b_1 = 0,
+
+    /* Nominal 3.3V VCC. NOTE: This value is 0 in the
+       esp-open-rtos SDK default config sector, and may be unused
+       by that version of the SDK?
+    */
+    .pa_vdd = 33,
+
+    /* Note: untested with the esp-open-rtos SDK default config sector, may be unused? */
+    .freq_correct_mode = FREQ_CORRECT_DISABLE,
+    .force_freq_offset = 0,
+
+    /* Note: is zero with the esp-open-rtos SDK default config sector, may be unused? */
+    .rf_cal_mode = RF_CAL_MODE_SAVED,
+};
+
+sdk_phy_info_t* default_phy_info_ref = (sdk_phy_info_t*)&default_phy_info;
+sdk_phy_info_t* get_default_phy_info_ref(void)
+{
+    return (sdk_phy_info_t*)&default_phy_info;
+}
+
+void get_default_phy_info(sdk_phy_info_t *info) __attribute__((weak, alias("get_sdk_default_phy_info")));
+
+void get_sdk_default_phy_info(sdk_phy_info_t *info)
+{
+    memcpy(info, &default_phy_info, sizeof(sdk_phy_info_t));
+}
+
+void read_saved_phy_info(sdk_phy_info_t *info)
+{
+    sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t));
+}
+
+void write_saved_phy_info(const sdk_phy_info_t *info)
+{
+    sdk_spi_flash_write(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t));
+}
+
+void dump_phy_info(const sdk_phy_info_t *info, bool raw)
+{
+    printf("version=%d\n", info->version);
+    printf("spur_freq = %.3f (%d/%d)\n",
+           (float)info->spur_freq_primary / info->spur_freq_divisor,
+           info->spur_freq_primary,
+           info->spur_freq_divisor);
+    printf("spur_freq_en = 0x%02x 0x%02x\n", info->spur_freq_en_h,
+           info->spur_freq_en_l);
+    printf("target_power\n");
+    for(int i = 0; i < 6; i++) {
+        printf("  %d: %.2fdB (raw 0x%02x)\n", i,
+               info->target_power[i]/4.0,
+               info->target_power[i]);
+    }
+    printf("target_power_index_mcs:");
+    for(int i = 0; i < 8; i++) {
+        printf(" %d%c", info->target_power_index_mcs[i],
+               i == 7 ? '\n' : ',');
+    }
+
+    printf("crystal_freq: %s (raw %d)\n",
+           (info->crystal_freq == CRYSTAL_FREQ_40M ? "40MHz" :
+            (info->crystal_freq == CRYSTAL_FREQ_26M ? "26MHz" :
+             (info->crystal_freq == CRYSTAL_FREQ_24M ? "24MHz" : "???"))),
+           info->crystal_freq);
+
+    printf("sdio_config: %d\n", info->sdio_config);
+    printf("bt_coexist config: %d protocol: 0x%02x\n",
+           info->bt_coexist_config, info->bt_coexist_protocol);
+    printf("dual_ant_config: %d\n", info->dual_ant_config);
+
+    printf("crystal_sleep: %d\n", info->crystal_sleep);
+
+    printf("spur_freq_2 = %.3f (%d/%d)\n",
+           (float)info->spur_freq_2_primary / info->spur_freq_2_divisor,
+           info->spur_freq_2_primary,
+           info->spur_freq_2_divisor);
+    printf("spur_freq_2_en = 0x%02x 0x%02x\n", info->spur_freq_2_en_h,
+           info->spur_freq_2_en_l);
+
+    printf("spur_freq_cfg_msb = 0x%02x\n", info->spur_freq_cfg_msb);
+    printf("spur_freq_2_)cfg_msb = 0x%02x\n", info->spur_freq_2_cfg_msb);
+    printf("spur_freq_3_cfg = 0x%04x\n", info->spur_freq_3_cfg);
+    printf("spur_freq_4_cfg = 0x%04x\n", info->spur_freq_4_cfg);
+
+    printf("low_power_en = %d\n", info->low_power_en);
+    printf("lp_atten_stage01 = 0x%02x\n", info->lp_atten_stage01);
+    printf("lp_atten_bb = %.2f (raw 0x%02x)\n", info->lp_atten_bb / 4.0,
+           info->lp_atten_bb);
+
+    printf("pa_vdd = %d\n", info->pa_vdd);
+
+    printf("freq_correct_mode = 0x%02x\n", info->freq_correct_mode);
+    printf("force_freq_offset = %d\n", info->force_freq_offset);
+    printf("rf_cal_mode = 0x%02x\n", info->rf_cal_mode);
+
+    if(raw) {
+        printf("Raw values:");
+        uint8_t *p = (uint8_t *)info;
+        for(unsigned int i = 0; i < sizeof(sdk_phy_info_t); i ++) {
+            if(i % 8 == 0) {
+                printf("\n0x%02x:", i);
+            }
+            printf(" %02x", p[i]);
+        }
+        printf("\n\n");
+    }
+}
+
+#endif
diff --git a/cpu/esp8266/vendor/esp/phy_info.h b/cpu/esp8266/vendor/esp/phy_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..d069befd06753afac53281339bbec4a1df69d157
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/phy_info.h
@@ -0,0 +1,509 @@
+/** Internal Espressif SDK "PHY info" data structure
+
+   The data structure (sdk_phy_info_t) is used to configure the
+   ESP8266 PHY layer via the SDK. The fields here are not written
+   directly to hardware, the SDK code (mostly in libphy) parses this
+   structure and configures the hardware.
+
+   The structure loaded at reset time from a flash configuration
+   sector (see read_saved_phy_info()) (Espressif's SDK sources this
+   from a file "esp_init_data_default.bin"). If no valid structure is
+   found in the flash config sector then the SDK loads default values
+   (see get_default_phy_info()). It is possible to implement a custom
+   get_default_phy_info() to change the PHY default settings (see the
+   'version' field below).
+
+   @note It is possible that the SDK will quietly write a new
+   configuration sector to flash itself following internal
+   calibration, etc. However this does not seem to happen, you need to
+   flash it explicitly if you want it stored there.
+
+   @note Most of what is below is unconfirmed, except where a @note
+   says that it has been confirmed to work as expected. Please
+   consider submitting notes if you find behaviour here that works or
+   doesn't work as expected.
+
+   Information on the meaning/offset of fields comes from Espressif's
+   flash download tool, which uses an Excel spreadsheet (in the
+   init_data directory of the ZIP file) to configure and a Python
+   script to convert an esp_init_data_custom.bin file to flash:
+   http://bbs.espressif.com/viewtopic.php?f=5&t=433
+
+   Many fields remain undocumented (& disassembly of libphy suggests
+   that some documented fields supported undocumented values.)
+
+   A few additional notes about the phy_info fields can be found
+   in the ESP Arduino ESP8266 phy_init_data structure (however most of
+   that content is verbatim from Espressif's spreadsheet):
+   https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_phy.c#L29
+
+   Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton,
+   BSD Licensed as described in the file LICENSE.
+ */
+
+/*
+Copyright (C) 2016 Angus Gratton
+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.
+*/
+
+#ifndef PHY_INFO_H
+#define PHY_INFO_H
+
+#ifndef DOXYGEN
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CRYSTAL_FREQ_xx values as used by sdk_phy_info_t.crystal_freq */
+#define CRYSTAL_FREQ_40M 0
+#define CRYSTAL_FREQ_26M 1
+#define CRYSTAL_FREQ_24M 2
+
+/* SDIO_CONFIG_xx values as used by sdk_phy_info_t.sdio_config */
+#define SDIO_CONFIG_AUTO 0   /* Uses pin strapping to determine */
+#define SDIO_CONFIG_SDIOV1_1 /* Data output on negative edge */
+#define SDIO_CONFIG_SDIOV2_0 /* data output on positive edge */
+
+/* BT_COEXIST_CONFIG_xx values as used by sdk_phy_info_t.bt_coexist */
+/* No bluetooth */
+#define BT_COEXIST_CONFIG_NONE 0
+/* Coexistence configuration A:
+   GPIO 0  - WLAN_ACTIVE
+   GPIO 14 - BT_ACTIVE
+   GPIO 13 - BT_PRIORITY
+   GPIO 3  - ANT_SEL_BT
+*/
+#define BT_COEXIST_CONFIG_A 1
+/* No coexistence, but Bluetooth enabled?
+   Unsure how this works?
+ */
+#define BT_COEXIST_CONFIG_PRESENT 2
+/* Coexistence configuration B:
+   GPIO 0 - WLAN_ACTIVE
+   GPIO 14 - BT_PRIORITY
+   GPIO 13 - BT_ACTIVE
+   GPIO 3  - ANT_SEL_BT
+*/
+#define BT_COEXIST_CONFIG_B 3
+
+/* BT_COEXIST_PROTOCOL_xx values for coexistence protocol,
+   field sdk_phy_info_t.bt_coexist_protocol
+ */
+#define BT_COEXIST_PROTOCOL_WIFI_ONLY 0
+#define BT_COEXIST_PROTOCOL_BT_ONLY 1
+
+/* Coexistence is enabled, Bluetooth has its own antenna */
+#define BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT 2
+/* Coexistence is enabled, Bluetooth shares WiFi antenna */
+#define BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT 4
+
+/* Coexistence is enabled, use only BT_ACTIVE signal */
+#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY 0
+/* Coexistence is enabled, use both BT_ACTIVE and BT_PRIORITY signals */
+#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_PRIORITY 1
+
+/* DUAL_ANT_CONFIG_xx values for dual antenna config,
+   field sdk_phy_info_t.dual_ant_config
+
+   (Not really clear how this feature works, if at all.)
+*/
+#define DUAL_ANT_CONFIG_NONE 0
+/* antenna diversity for WiFi, use GPIO0 + U0RXD (?) */
+#define DUAL_ANT_CONFIG_DUAL 1
+/* TX/RX switch for external PA & LNA: GPIO 0 high, GPIO 3 low during TX */
+#define DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW
+/* TX/RX switch for external PA & LNA: GPIO 0 low, GPIO 3 high during TX */
+#define DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH
+
+
+/* CRYSTAL_SLEEP_xx values used for sdk_phy_info_t.crystal_sleep
+ */
+#define CRYSTAL_SLEEP_OFF 0
+#define CRYSTAL_SLEEP_ON 1
+#define CRYSTAL_SLEEP_GPIO16 2
+#define CRYSTAL_SLEEP_GPIO2 3
+
+/* RF Stage 0 & 1 attenuation constants. Use for sdk_phy_info_t.lp_atten_stage01
+
+   @note These values have been tested and are confirmed to work as
+   expected by measuring RSSI w/ rt73 USB adapter in monitor mode
+   (some values also checked on spectrum analyzer) - provided
+   low_power_en is set then the signal is attenuated as per this
+   setting.
+
+   (It may look like LP_ATTEN_STAGE01_11_5DB is out of order, but
+   according to monitor mode captures this is the correct ordering of
+   these constants.)
+
+   Setting the numeric values in between these constants appears to
+   also attenuate the signal, but not necessarily by the amount you'd
+   expect.
+*/
+#define LP_ATTEN_STAGE01_0DB    0x0f /*     0dB */
+#define LP_ATTEN_STAGE01_2_5DB  0x0e /*  -2.5dB */
+#define LP_ATTEN_STAGE01_6DB    0x0d /*    -6dB */
+#define LP_ATTEN_STAGE01_8_5DB  0x09 /*  -8.5dB */
+#define LP_ATTEN_STAGE01_11_5DB 0x0c /* -11.5dB */
+#define LP_ATTEN_STAGE01_14DB   0x08 /*   -14dB */
+#define LP_ATTEN_STAGE01_17_5DB 0x04 /* -17.5dB */
+#define LP_ATTEN_STAGE01_23DB   0x00 /*   -23dB */
+
+/* Constant for sdk_phy_info_t.pa_vdd */
+#define PA_VDD_MEASURE_VCC 0xFF
+
+/* Bitmask flags for sdk_phy_info_t.freq_correct_mode */
+
+/* Set this flag to disable frequency offset correction */
+#define FREQ_CORRECT_DISABLE 0
+
+/* Set this flag to enable frequency offset correction */
+#define FREQ_CORRECT_ENABLE BIT(0)
+
+/* Set = Baseband PLL frequency is 160MHz (can only apply +ve offset)
+ * Unset = Baseband PLL frequency is 168MHz (can apply +ve/-ve offset */
+#define FREQ_CORRECT_BB_160M BIT(1)
+
+/* Set = use force_freq_offset field to correct, Unset = automatically
+   measure & correct offset
+*/
+#define FREQ_CORRECT_FORCE BIT(2)
+
+
+/* RF_CAL_MODE_xx fields used for sdk_phy_info_t.rf_cal_mode
+ */
+/* Use saved RF CAL data from flash, only. RF init takes 2ms. */
+#define RF_CAL_MODE_SAVED 0
+/* Calibrate TX power control only, use saved RF CAL data for others.
+   RF init takes 20ms. */
+#define RF_CAL_MODE_TXPOWER_ONLY 1
+/* Unclear if/how this mode is different to 2? */
+#define RF_CAL_MODE_SAVED_2 2
+/* Run full RF CAL routine. RF init takes approx 200ms. */
+#define RF_CAL_MODE_FULL 3
+
+/* Data structure that maps to the phy_info configuration block */
+typedef struct __attribute__((packed)) {
+    uint8_t _reserved00[0x05]; /* 0x00 - 0x04 */
+
+    /* This "version" field was set to 5 in the SDK phy_info,
+       and the original SDK startup code checks it is 5 and then loads
+       default PHY configuration otherwise.
+
+       esp-open-rtos will load phy_info from get_default_phy_info() if
+       the value stored in flash has a different value to the value
+       returned in get_default_phy_info(). This means you can
+       increment the version return by get_default_phy_info() (to any
+       value but 0xFF), and know that the new defaults will replace
+       any older stored values.
+
+       @notes It's not clear whether this is actually a version field
+       (the other 24 bytes here have equally arbitrary numbers in
+       them.) Changing the "version" to other values does not seem to
+       effect WiFi performance at all, neither does zeroing out the
+       first 5 reserved bytes in _reserved00. However zeroing bytes in
+       the _reserved06 region will break WiFi entirely.
+    */
+    uint8_t version;          /* 0x05 */
+    int8_t _reserved06[0x14]; /* 0x06 - 0x19 */
+
+    /* spur_freq = spur_freq_primary / spur_freq_divisor */
+    uint8_t spur_freq_primary; /* 0x1a */
+    uint8_t spur_freq_divisor; /* 0x1b */
+
+    /* Bitmask to enable spur_freq for each channel
+       Appears to be a big endian short word?
+     */
+    uint8_t spur_freq_en_h;      /* 0x1c */
+    uint8_t spur_freq_en_l;      /* 0x1d */
+
+    uint8_t _reserved1e[4];   /* 0x1e - 0x21 */
+
+    /* Each value is a target power level.
+       Units are 1/4 dBm ie value 64 = 16dBm.
+
+       SDK defaults to using these transmit powers:
+       20.5dBm, 19.5dBm, 18.5dBm, 17dBm, 16dBm, 14dBm
+
+       @note Adjusting these values is confirmed to reduce
+       transmit power accordingly.
+    */
+    uint8_t target_power[6]; /* 0x22 - 0x27 */
+
+    /* Maps 8 MCS (modulation & coding schemes) types for 802.11b, g &
+     * n to a target_power level index (0-5), set above.
+
+     This mapping of MCS slot to MCS type is derived from the
+     spreadsheet and also a table sent by Espressif, but is untested
+     and may be SDK version dependendent (especially any 802.11n
+     rates). However the general relationship is confirmed to hold
+     (higher MCS index = higher bit rate).
+
+     MCS 0: 1Mbps/2Mbps/5.5Mbps/11Mbps (802.11b) / 6Mbps/9Mbps (802.11g)
+         default target_power 0 (default 20.5dBm)
+         (see also pwr_ind_11b_en)
+
+     MCS 1: 12Mbps (802.11g)
+         default target_power 0 (default 20.5dBm)
+
+     MCS 2: 18Mbps (802.11g)
+         default target_power 1 (19.5dBm)
+
+     MCS 3: 24Mbps (802.11g)
+         default target_power 1 (19.5dBm)
+
+     MCS 4: 36Mbps (802.11g)
+         default target_power 2 (18.5dBm)
+
+     MCS 5: 48Mbps (802.11g)
+         default target_power 3 (17dBm)
+
+     MCS 6: 54Mbps (802.11g)
+         default target_power 4 (16dBm)
+
+     MCS 7: 65Mbps (802.11n) - unclear if ever used?
+         default target_power 5 (14dBm)
+    */
+    uint8_t target_power_index_mcs[8]; /* 0x28 - 0x2f */
+
+    /* One of CRYSTAL_FREQ_40M / CRYSTAL_FREQ_26M / CRYSTAL_FREQ_24M
+
+       The crystal configured here is the input to the PLL setting
+       calculations which are used to derive the CPU & APB peripheral
+       clock frequency, and probably the WiFi PLLs (unconfirmed.)
+     */
+    uint8_t crystal_freq; /* 0x30 */
+
+    uint8_t _unused31; /* 0x31: Possibly high byte of crystal freq? */
+
+    /* One of SDIO_CONFIG_AUTO, SDIO_CONFIG_SDIOV1_1, SDIO_CONFIG_SDIOV2_0 */
+    uint8_t sdio_config; /* 0x32 */
+
+    /* BT coexistence pin configuration.
+
+       One of BT_COEXIST_CONFIG_NONE, BT_COEXIST_CONFIG_A,
+       BT_COEXIST_CONFIG_PRESENT, BT_COEXIST_CONFIG_B
+    */
+    uint8_t bt_coexist_config; /* 0x33 */
+
+    /* BT coexistence pin protocol.
+
+       If no coexistence:
+       Either BT_COEXIST_PROTOCOL_WIFI_ONLY, or
+       BT_COEXIST_PROTOCOL_BT_ONLY.
+
+       If coexistence:
+       Combine one of
+       BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT or
+       BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT
+       with one of
+       BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY or
+       BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_BT_PRIORITY
+    */
+    uint8_t bt_coexist_protocol; /* 0x34 */
+
+    /* Dual antenna configuration
+
+       One of DUAL_ANT_CONFIG_NONE, DUAL_ANT_CONFIG_DUAL,
+       DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW,
+       DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH
+    */
+    uint8_t dual_ant_config; /* 0x35 */
+
+    uint8_t _reserved34; /* 0x36 */
+
+    /* For sharing crystal clock with other devices:
+       one of CRYSTAL_SLEEP_OFF, CRYSTAL_SLEEP_ON,
+       CRYSTAL_SLEEP_GPIO16, CRYSTAL_SLEEP_GPIO2
+    */
+    uint8_t crystal_sleep; /* 0x37 */
+
+    uint8_t _unused38[8];
+
+    /* spur_freq_2 = spur_freq_2_primary / spur_freq_2_divisor */
+    uint8_t spur_freq_2_primary; /* 0x40 */
+    uint8_t spur_freq_2_divisor; /* 0x41 */
+
+    /* Bitmask to enable spur_freq_2 for each channel?
+       Appears to be a big endian short word?
+    */
+    uint8_t spur_freq_2_en_h; /* 0x42 */
+    uint8_t spur_freq_2_en_l; /* 0x43 */
+
+    /* Not really clear what these do */
+    uint8_t spur_freq_cfg_msb; /* 0x44 */
+    uint8_t spur_freq_2_cfg_msb; /* 0x45 */
+    uint16_t spur_freq_3_cfg; /* 0x46 - 0x47 */
+    uint16_t spur_freq_4_cfg; /* 0x48 - 0x49 */
+
+    uint8_t _reserved4a[4]; /* 0x4a - 0x4d */
+
+    uint8_t _unused78[15]; /* 0x4e - 0x5c */
+
+    /* Flag to enable low power mode */
+    uint8_t low_power_en; /* 0x5d */
+
+    /* Low Power attenuation of RF gain stages 0 & 1
+
+       Attenuates transmit power if/when low_power_en is set.
+
+       Use one of the constants LP_ATTEN_STAGE01_0DB,
+       LP_ATTEN_STAGE01_2_5DB, LP_ATTEN_STAGE01_6DB,
+       LP_ATTEN_STAGE01_8_5DB, LP_ATTEN_STAGE01_11_5DB,
+       LP_ATTEN_STAGE01_14DB, LP_ATTEN_STAGE01_17_5DB,
+       LP_ATTEN_STAGE01_23DB.
+     */
+    uint8_t lp_atten_stage01; /* 0x5e */
+
+    /* Low Power(?) attenuation of baseband gain
+
+       Units are minus 1/4 dB, ie value 4 == -1dB.
+
+       Maximum value is 24 (0x18) == -6dB
+     */
+    uint8_t lp_atten_bb; /* 0x5f */
+
+    /* I believe this means, when pwr_ind_11b_en == 0 then the 802.11g
+       MCS 0 level from target_power_index_mcs are used to
+       determine 802.11b transmit power level.
+
+       However, when pwr_ind_11b_en == 1 then the index values in
+       pwr_ind_11b_0 & pwr_ind_11b_1 are used for 802.11b instead.
+
+       This is all unconfirmed, if you can confirm then please update
+       this comment.
+     */
+    uint8_t pwr_ind_11b_en; /* 0x60 */
+
+    /* 802.11b low data rate power index (0~5).
+       Sets the power level index for operation at 1 & 2Mbps
+    */
+    uint8_t pwr_ind_11b_0; /* 0x61 */
+
+    /* 802.11b high data rate power index (0~5)
+       Sets the power level index for operation at 5.5 & 11Mbps
+    */
+    uint8_t pwr_ind_11b_1; /* 0x62 */
+
+    uint8_t _unused63[8]; /* 0x63 - 0x6a */
+
+    /* Set the voltage of PA_VDD, which appears to be an internal analog
+       reference voltage(?)
+
+       This field is called vdd33_const in the Arduino phy fields,
+       and relates to usage of the TOUT pin (ADC pin).
+
+       Set to PA_VDD_MEASURE_VCC (0xFF) and leave TOUT (ADC) pin
+       floating in order to use the ADC to measure the 3.3V input
+       voltage.
+
+       Set to value in the range 18-36 (1.8V to 3.6V) to set a
+       reference voltage(?) when using TOUT pin as an ADC input. I
+       think this is the reference voltage used to scale the 0-1V
+       which is allowed on the pin, in order to get an accurate
+       reading. So it should be set to a value that matches system
+       VCC... I think!
+    */
+    uint8_t pa_vdd; /* 0x6b */
+
+    /* Disable RF calibration cycle for this many times */
+    uint8_t disable_rfcal_count; /* 0x6c */
+
+    uint8_t _unused6d[3];
+
+    /* Flags for frequency correction
+
+       A bitmask combination of any of: FREQ_CORRECT_DISABLE,
+       FREQ_CORRECT_ENABLE, FREQ_CORRECT_BB_160M, FREQ_CORRECT_FORCE
+     */
+    uint8_t freq_correct_mode; /* 0x70 */
+
+    /* Force frequency offset adjustment (instead of auto measuring)
+       units are 1 = 8kHz, full range +/- 1016kHz.
+
+       Only used if FREQ_CORRECT_ENABLE and FREQ_CORRECT_FORCE are
+       set in freq_correct_mode.
+
+       Unclear whether setting FREQ_CORRECT_BB_160M (which allows only positive offsets) changes the usable range.
+    */
+    int8_t force_freq_offset; /* 0x71 */
+
+    /* Use stored data in flash for RF calibration.
+
+       This field was previously called rf_cal_use_flash.
+
+       Acceptable values one of RF_CAL_MODE_SAVED, RF_CAL_MODE_TXPOWER_ONLY, RF_CAL_MODE_SAVED_2, RF_CAL_MODE_FULL.
+     */
+    uint8_t rf_cal_mode; /* 0x72 */
+
+    uint8_t _unused73[13];
+} sdk_phy_info_t;
+
+/* Some sanity check static assertions. These can probably be
+   removed after this structure has been better tested.
+*/
+_Static_assert(sizeof(sdk_phy_info_t) == 128, "sdk_phy_info_t is wrong size!");
+_Static_assert(offsetof(sdk_phy_info_t, version) == 5, "version at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, target_power) == 34, "target_power_qdb at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, bt_coexist_protocol) == 52, "bt_coexist_protocol at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, spur_freq_2_primary) == 64, "spur_freq_2_primary at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, lp_atten_stage01) == 94, "lp_atten_stage01 at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, pa_vdd) == 107, "pa_vdd aka vdd33_const at wrong offset");
+_Static_assert(offsetof(sdk_phy_info_t, rf_cal_mode) == 114, "rf_cal_use_flash at wrong offset!");
+
+/* Read the default PHY info into the supplied structure.
+
+   This function is weak-aliased to get_sdk_default_phy_info() so you
+   can replace it with your own if you want to vary the default values
+   - suggested way to do this is to call get_sdk_default_phy_info()
+   and then only update the fields you care about.
+
+   The default PHY info is used at startup whenever the version field
+   in the default sdk_phy_info_t does not match the version field
+   stored in flash. So you can increment the version field to force a
+   reset to defaults, regardless of what values are in flash.
+*/
+void get_default_phy_info(sdk_phy_info_t *info);
+
+/* Read the "SDK default" PHY info as used by the Espressif SDK */
+void get_sdk_default_phy_info(sdk_phy_info_t *info);
+
+/* Read the PHY info currently stored in the SPI flash SDK configuration sector.
+
+   This PHY info is updated by the SDK following RF calibration, etc.
+
+   Note that the saved data may be corrupt - read the 'version' field to verify.
+*/
+void read_saved_phy_info(sdk_phy_info_t *info);
+
+/* Update the saved PHY info in the SPI flash. A reset is necessary to use these values.
+
+   Note that the SDK may clobber these values, so it's recommended you reset ASAP after updating them.
+*/
+void write_saved_phy_info(const sdk_phy_info_t *info);
+
+/* Dump known fields in the phy info structure to stdout,
+   if 'raw' flag is set then the raw hex values are also dumped.
+*/
+void dump_phy_info(const sdk_phy_info_t *info, bool raw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* PHY_INFO_H */
diff --git a/cpu/esp8266/vendor/esp/rom.h b/cpu/esp8266/vendor/esp/rom.h
new file mode 100644
index 0000000000000000000000000000000000000000..71721c55a5ff0b8d7a310fa33f3d58d452192c3b
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/rom.h
@@ -0,0 +1,57 @@
+/* "Boot ROM" function signatures
+
+   Note that a lot of the ROM functions used in the IoT SDK aren't
+   referenced from the Espressif RTOS SDK, and are probably incompatible.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef ROM_H
+#define ROM_H
+
+#include "esp/types.h"
+#include "flashchip.h"
+
+#ifdef    __cplusplus
+extern "C" {
+#endif
+
+void Cache_Read_Disable(void);
+
+/* http://esp8266-re.foogod.com/wiki/Cache_Read_Enable
+
+   Note: when compiling non-OTA we use the ROM version of this
+   function, but for OTA we use the version in extras/rboot-ota that
+   maps the correct flash page for OTA support.
+ */
+void Cache_Read_Enable(uint32_t odd_even, uint32_t mb_count, uint32_t no_idea);
+
+/* Low-level SPI flash read/write routines */
+int Enable_QMode(sdk_flashchip_t *chip);
+int Disable_QMode(sdk_flashchip_t *chip);
+int SPI_page_program(sdk_flashchip_t *chip, uint32_t dest_addr, uint32_t *src_addr, uint32_t size);
+int SPI_read_data(sdk_flashchip_t *chip, uint32_t src_addr, uint32_t *dest_addr, uint32_t size);
+int SPI_write_enable(sdk_flashchip_t *chip);
+int SPI_sector_erase(sdk_flashchip_t *chip, uint32_t addr);
+int SPI_read_status(sdk_flashchip_t *chip, uint32_t *status);
+int SPI_write_status(sdk_flashchip_t *chip, uint32_t status);
+int Wait_SPI_Idle(sdk_flashchip_t *chip);
+
+#ifdef    __cplusplus
+}
+#endif
+
+#endif /* ROM_H */
diff --git a/cpu/esp8266/vendor/esp/rtc_regs.h b/cpu/esp8266/vendor/esp/rtc_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ad130d37d425f1b74cc86587e1b7d8c471cad50
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/rtc_regs.h
@@ -0,0 +1,130 @@
+/* esp/rtc_regs.h
+ *
+ * ESP8266 RTC register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ *
+ * RTC peripheral remains powered during deep sleep, and RTC clock
+ * is used to wake from deep sleep when RTC.COUNTER == RTC.COUNTER_ALARM.
+ *
+ * "GPIO16" is a special GPIO pin connected to the RTC subsystem,
+ * GPIO16 must be connected to reset to allow wake from deep sleep.
+ *
+ * The contents of scratch registers RTC.SCRATCH[] are preserved
+ * across reset, including wake from sleep (unconfirmed). Contents of
+ * RTCMEM are also preserved.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef RTC_REGS_H
+#define RTC_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTC_BASE 0x60000700
+#define RTC (*(struct RTC_REGS *)(RTC_BASE))
+
+//FIXME: need to understand/clarify distinction between GPIO_CONF and GPIO_CFG[]
+// Note: GPIO_CFG[3] is also known as PAD_XPD_DCDC_CONF in eagle_soc.h
+
+struct RTC_REGS {
+    uint32_t volatile CTRL0;        // 0x00
+    uint32_t volatile COUNTER_ALARM;    // 0x04
+    uint32_t volatile RESET_REASON0;    // 0x08       //FIXME: need better name
+    uint32_t volatile _unknownc;        // 0x0c
+    uint32_t volatile _unknown10;       // 0x10
+    uint32_t volatile RESET_REASON1;    // 0x14       //FIXME: need better name
+    uint32_t volatile RESET_REASON2;    // 0x18       //FIXME: need better name
+    uint32_t volatile COUNTER;          // 0x1c
+    uint32_t volatile INT_SET;          // 0x20
+    uint32_t volatile INT_CLEAR;        // 0x24
+    uint32_t volatile INT_ENABLE;       // 0x28
+    uint32_t volatile _unknown2c;       // 0x2c
+    uint32_t volatile SCRATCH[4];       // 0x30 - 3c
+    uint32_t volatile _unknown40;       // 0x40
+    uint32_t volatile _unknown44;       // 0x44
+    uint32_t volatile _unknown48;       // 0x48
+    uint32_t volatile _unknown4c[7];    // 0x4c - 0x64
+    uint32_t volatile GPIO_OUT;         // 0x68
+    uint32_t volatile _unknown6c[2];    // 0x6c - 0x70
+    uint32_t volatile GPIO_ENABLE;      // 0x74
+    uint32_t volatile _unknown80[5];    // 0x78 - 0x88
+    uint32_t volatile GPIO_IN;          // 0x8c
+    uint32_t volatile GPIO_CONF;        // 0x90
+    uint32_t volatile GPIO_CFG[6];      // 0x94 - 0xa8
+};
+
+_Static_assert(sizeof(struct RTC_REGS) == 0xac, "RTC_REGS is the wrong size");
+
+/* Details for CTRL0 register */
+
+/* Writing this bit causes a software reset but
+   the device then fails in ets_main.c (needs other parameters set?) */
+#define RTC_CTRL0_BIT31 BIT(31)
+
+/* Details for RESET_REASONx registers */
+
+/* The following are used in sdk_rtc_get_reset_reason().  Details are still a
+ * bit sketchy regarding exactly what they mean/do.. */
+
+#define RTC_RESET_REASON1_CODE_M  0x0000000f
+#define RTC_RESET_REASON1_CODE_S  0
+
+#define RTC_RESET_REASON2_CODE_M  0x0000003f
+#define RTC_RESET_REASON2_CODE_S  8
+
+/* Writing this bit causes the ESP to go into some kind of unrecoverable boot loop */
+#define RTC_RESET_REASON0_BIT20 BIT(20)
+
+/* Both bits 20 & 21 can be set & cleared from software,
+   BIT21 appears to be checked inside sdk_rtc_get_reset_reason() */
+#define RTC_RESET_REASON0_BIT21 BIT(21)
+#define RTC_RESET_REASON0_BIT22 BIT(22)
+
+/* Details for GPIO_CONF register */
+
+#define RTC_GPIO_CONF_OUT_ENABLE BIT(0)
+
+/* Details for GPIO_CFG[3] register controlling GPIO16 (possibly others?) */
+
+#define RTC_GPIO_CFG3_PIN_PULLUP          BIT(2)
+#define RTC_GPIO_CFG3_PIN_PULLDOWN        BIT(3)
+#define RTC_GPIO_CFG3_PIN_PULLUP_SLEEP    BIT(4)
+#define RTC_GPIO_CFG3_PIN_PULLDOWN_SLEEP  BIT(5)
+
+/* The PIN_FUNC values here are probably similar to the
+   values used to set the iomux registers...? */
+#define RTC_GPIO_CFG3_PIN_FUNC_M 0x00000043
+#define RTC_GPIO_CFG3_PIN_FUNC_S 0
+
+/* This should be the function value needed to have GPIO16 be the alarm
+   output from the RTC. FIXME: Needs to be validated. */
+#define RTC_GPIO_CFG3_PIN_FUNC_RTC_GPIO0  BIT(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* RTC_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/rtcmem_regs.h b/cpu/esp8266/vendor/esp/rtcmem_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca7d0bdd153cf7a2cbc11087deb70c582c2f4061
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/rtcmem_regs.h
@@ -0,0 +1,67 @@
+/* esp/rtcmem_regs.h
+ *
+ * ESP8266 RTC semi-persistent memory register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef RTCMEM_REGS_H
+#define RTCMEM_REGS_H
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The RTC memory is a range of 256 words (1 KB) of general-purpose memory
+ * within the Real Time Clock peripheral.  Because it's part of the RTC, it
+ * continues to be powered (and retains its contents) even when the ESP8266 is
+ * in its deepest sleep mode (and other RAM is lost).  It can therefore be
+ * useful for keeping data which must be persisted through sleep or a reset.
+ *
+ * Note, however, that it is not "battery backed", or flash memory, and thus
+ * will not keep its contents if power is removed entirely.
+ */
+
+// We could just define these as 'volatile uint32_t *', but doing things this
+// way means that the RTCMEM* defines will include array size information, so
+// the C compiler can do bounds-checking for static arguments.
+
+typedef volatile uint32_t rtcmem_array64_t[64];
+typedef volatile uint32_t rtcmem_array128_t[128];
+typedef volatile uint32_t rtcmem_array256_t[256];
+
+#define RTCMEM_BASE 0x60001000
+
+/* RTCMEM is an array covering the entire semi-persistent memory range */
+#define RTCMEM (*(rtcmem_array256_t *)(RTCMEM_BASE))
+
+/* RTCMEM_BACKUP / RTCMEM_SYSTEM / RTCMEM_USER are the same range, divided up
+ * into chunks by application/use, as defined by Espressif */
+
+#define RTCMEM_BACKUP (*(rtcmem_array64_t *)(RTCMEM_BASE))
+#define RTCMEM_SYSTEM (*(rtcmem_array64_t *)(RTCMEM_BASE + 0x100))
+#define RTCMEM_USER (*(rtcmem_array128_t *)(RTCMEM_BASE + 0x200))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTCMEM_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/spi_regs.h b/cpu/esp8266/vendor/esp/spi_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..58000fda88e8f3ef4167edb10d448a524169bdda
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/spi_regs.h
@@ -0,0 +1,271 @@
+/** esp/spi.h
+ *
+ * Configuration of SPI registers.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Superhouse Automation Pty Ltd
+ * BSD Licensed as described in the file LICENSE
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef SPI_REGS_H
+#define SPI_REGS_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+/* Register definitions for the SPI peripherals on the ESP8266.
+ *
+ * There are twp SPI devices built into the ESP8266:
+ *   SPI(0) is at 0x60000200
+ *   SPI(1) is at 0x60000100
+ * (note that the device number order is reversed in memory)
+ *
+ * Each device is allocated a block of 64 32-bit registers (256 bytes of
+ * address space) to communicate with application code.
+ */
+
+#define SPI_BASE 0x60000200
+#define SPI(i) (*(struct SPI_REGS *)(0x60000200 - (i)*0x100))
+
+#define SPI0_BASE SPI_BASE
+#define SPI1_BASE (SPI_BASE - 0x100)
+
+struct SPI_REGS {
+    uint32_t volatile CMD;          // 0x00
+    uint32_t volatile ADDR;         // 0x04
+    uint32_t volatile CTRL0;        // 0x08
+    uint32_t volatile CTRL1;        // 0x0c
+    uint32_t volatile RSTATUS;      // 0x10
+    uint32_t volatile CTRL2;        // 0x14
+    uint32_t volatile CLOCK;        // 0x18
+    uint32_t volatile USER0;        // 0x1c
+    uint32_t volatile USER1;        // 0x20
+    uint32_t volatile USER2;        // 0x24
+    uint32_t volatile WSTATUS;      // 0x28
+    uint32_t volatile PIN;          // 0x2c
+    uint32_t volatile SLAVE0;       // 0x30
+    uint32_t volatile SLAVE1;       // 0x34
+    uint32_t volatile SLAVE2;       // 0x38
+    uint32_t volatile SLAVE3;       // 0x3c
+    uint32_t volatile W[16];        // 0x40 - 0x7c
+    uint32_t volatile _unused[28];  // 0x80 - 0xec
+    uint32_t volatile EXT0;         // 0xf0
+    uint32_t volatile EXT1;         // 0xf4
+    uint32_t volatile EXT2;         // 0xf8
+    uint32_t volatile EXT3;         // 0xfc
+};
+
+_Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
+
+/* Details for CMD register */
+
+#define SPI_CMD_READ                       BIT(31)
+#define SPI_CMD_WRITE_ENABLE               BIT(30)
+#define SPI_CMD_WRITE_DISABLE              BIT(29)
+#define SPI_CMD_READ_ID                    BIT(28)
+#define SPI_CMD_READ_SR                    BIT(27)
+#define SPI_CMD_WRITE_SR                   BIT(26)
+#define SPI_CMD_PP                         BIT(25)
+#define SPI_CMD_SE                         BIT(24)
+#define SPI_CMD_BE                         BIT(23)
+#define SPI_CMD_CE                         BIT(22)
+#define SPI_CMD_DP                         BIT(21)
+#define SPI_CMD_RES                        BIT(20)
+#define SPI_CMD_HPM                        BIT(19)
+#define SPI_CMD_USR                        BIT(18)
+
+/* Details for CTRL0 register */
+
+#define SPI_CTRL0_WR_BIT_ORDER             BIT(26)
+#define SPI_CTRL0_RD_BIT_ORDER             BIT(25)
+#define SPI_CTRL0_QIO_MODE                 BIT(24)
+#define SPI_CTRL0_DIO_MODE                 BIT(23)
+#define SPI_CTRL0_QOUT_MODE                BIT(20)
+#define SPI_CTRL0_DOUT_MODE                BIT(14)
+#define SPI_CTRL0_FASTRD_MODE              BIT(13)
+#define SPI_CTRL0_CLOCK_EQU_SYS_CLOCK      BIT(12)
+#define SPI_CTRL0_CLOCK_NUM_M              0x0000000F
+#define SPI_CTRL0_CLOCK_NUM_S              8
+#define SPI_CTRL0_CLOCK_HIGH_M             0x0000000F
+#define SPI_CTRL0_CLOCK_HIGH_S             4
+#define SPI_CTRL0_CLOCK_LOW_M              0x0000000F
+#define SPI_CTRL0_CLOCK_LOW_S              0
+
+/* Mask for the CLOCK_NUM/CLOCK_HIGH/CLOCK_LOW combined, in case one wants
+ * to set them all as a single value.
+ */
+#define SPI_CTRL0_CLOCK_M                  0x00000FFF
+#define SPI_CTRL0_CLOCK_S                  0
+
+/* Details for CTRL2 register */
+
+#define SPI_CTRL2_CS_DELAY_NUM_M           0x0000000F
+#define SPI_CTRL2_CS_DELAY_NUM_S           28
+#define SPI_CTRL2_CS_DELAY_MODE_M          0x00000003
+#define SPI_CTRL2_CS_DELAY_MODE_S          26
+#define SPI_CTRL2_MOSI_DELAY_NUM_M         0x00000007
+#define SPI_CTRL2_MOSI_DELAY_NUM_S         23
+#define SPI_CTRL2_MOSI_DELAY_MODE_M        0x00000003
+#define SPI_CTRL2_MOSI_DELAY_MODE_S        21
+#define SPI_CTRL2_MISO_DELAY_NUM_M         0x00000007
+#define SPI_CTRL2_MISO_DELAY_NUM_S         18
+#define SPI_CTRL2_MISO_DELAY_MODE_M        0x00000003
+#define SPI_CTRL2_MISO_DELAY_MODE_S        16
+
+/* Details for CLOCK register */
+
+#define SPI_CLOCK_EQU_SYS_CLOCK            BIT(31)
+#define SPI_CLOCK_DIV_PRE_M                0x00001FFF
+#define SPI_CLOCK_DIV_PRE_S                18
+#define SPI_CLOCK_COUNT_NUM_M              0x0000003F
+#define SPI_CLOCK_COUNT_NUM_S              12
+#define SPI_CLOCK_COUNT_HIGH_M             0x0000003F
+#define SPI_CLOCK_COUNT_HIGH_S             6
+#define SPI_CLOCK_COUNT_LOW_M              0x0000003F
+#define SPI_CLOCK_COUNT_LOW_S              0
+
+/* Mask for the COUNT_NUM/COUNT_HIGH/COUNT_LOW combined, in case one wants
+ * to set them all as a single value.
+ */
+#define SPI_CTRL0_COUNT_M                  0x0003FFFF
+#define SPI_CTRL0_COUNT_S                  0
+
+/* Details for USER0 register */
+
+#define SPI_USER0_COMMAND                  BIT(31)
+#define SPI_USER0_ADDR                     BIT(30)
+#define SPI_USER0_DUMMY                    BIT(29)
+#define SPI_USER0_MISO                     BIT(28)
+#define SPI_USER0_MOSI                     BIT(27)
+#define SPI_USER0_MOSI_HIGHPART            BIT(25)
+#define SPI_USER0_MISO_HIGHPART            BIT(24)
+#define SPI_USER0_SIO                      BIT(16)
+#define SPI_USER0_FWRITE_QIO               BIT(15)
+#define SPI_USER0_FWRITE_DIO               BIT(14)
+#define SPI_USER0_FWRITE_QUAD              BIT(13)
+#define SPI_USER0_FWRITE_DUAL              BIT(12)
+#define SPI_USER0_WR_BYTE_ORDER            BIT(11)
+#define SPI_USER0_RD_BYTE_ORDER            BIT(10)
+#define SPI_USER0_CLOCK_OUT_EDGE           BIT(7)
+#define SPI_USER0_CLOCK_IN_EDGE            BIT(6)
+#define SPI_USER0_CS_SETUP                 BIT(5)
+#define SPI_USER0_CS_HOLD                  BIT(4)
+#define SPI_USER0_FLASH_MODE               BIT(2)
+#define SPI_USER0_DUPLEX                   BIT(0)
+
+/* Details for USER1 register */
+
+#define SPI_USER1_ADDR_BITLEN_M            0x0000003F
+#define SPI_USER1_ADDR_BITLEN_S            26
+#define SPI_USER1_MOSI_BITLEN_M            0x000001FF
+#define SPI_USER1_MOSI_BITLEN_S            17
+#define SPI_USER1_MISO_BITLEN_M            0x000001FF
+#define SPI_USER1_MISO_BITLEN_S            8
+#define SPI_USER1_DUMMY_CYCLELEN_M         0x000000FF
+#define SPI_USER1_DUMMY_CYCLELEN_S         0
+
+/* Details for USER2 register */
+
+#define SPI_USER2_COMMAND_BITLEN_M         0x0000000F
+#define SPI_USER2_COMMAND_BITLEN_S         28
+#define SPI_USER2_COMMAND_VALUE_M          0x0000FFFF
+#define SPI_USER2_COMMAND_VALUE_S          0
+
+/* Details for PIN register */
+
+#define SPI_PIN_IDLE_EDGE                  BIT(29)  ///< CPOL
+#define SPI_PIN_CS2_DISABLE                BIT(2)
+#define SPI_PIN_CS1_DISABLE                BIT(1)
+#define SPI_PIN_CS0_DISABLE                BIT(0)
+
+/* Details for SLAVE0 register */
+
+#define SPI_SLAVE0_SYNC_RESET              BIT(31)
+#define SPI_SLAVE0_MODE                    BIT(30)
+#define SPI_SLAVE0_WR_RD_BUF_EN            BIT(29)
+#define SPI_SLAVE0_WR_RD_STA_EN            BIT(28)
+#define SPI_SLAVE0_CMD_DEFINE              BIT(27)
+#define SPI_SLAVE0_TRANS_COUNT_M           0x0000000F
+#define SPI_SLAVE0_TRANS_COUNT_S           23
+#define SPI_SLAVE0_TRANS_DONE_EN           BIT(9)
+#define SPI_SLAVE0_WR_STA_DONE_EN          BIT(8)
+#define SPI_SLAVE0_RD_STA_DONE_EN          BIT(7)
+#define SPI_SLAVE0_WR_BUF_DONE_EN          BIT(6)
+#define SPI_SLAVE0_RD_BUF_DONE_EN          BIT(5)
+#define SPI_SLAVE0_INT_EN_M                0x0000001f
+#define SPI_SLAVE0_INT_EN_S                5
+#define SPI_SLAVE0_TRANS_DONE              BIT(4)
+#define SPI_SLAVE0_WR_STA_DONE             BIT(3)
+#define SPI_SLAVE0_RD_STA_DONE             BIT(2)
+#define SPI_SLAVE0_WR_BUF_DONE             BIT(1)
+#define SPI_SLAVE0_RD_BUF_DONE             BIT(0)
+
+/* Details for SLAVE1 register */
+
+#define SPI_SLAVE1_STATUS_BITLEN_M         0x0000001F
+#define SPI_SLAVE1_STATUS_BITLEN_S         27
+#define SPI_SLAVE1_BUF_BITLEN_M            0x000001FF
+#define SPI_SLAVE1_BUF_BITLEN_S            16
+#define SPI_SLAVE1_RD_ADDR_BITLEN_M        0x0000003F
+#define SPI_SLAVE1_RD_ADDR_BITLEN_S        10
+#define SPI_SLAVE1_WR_ADDR_BITLEN_M        0x0000003F
+#define SPI_SLAVE1_WR_ADDR_BITLEN_S        4
+#define SPI_SLAVE1_WRSTA_DUMMY_ENABLE      BIT(3)
+#define SPI_SLAVE1_RDSTA_DUMMY_ENABLE      BIT(2)
+#define SPI_SLAVE1_WRBUF_DUMMY_ENABLE      BIT(1)
+#define SPI_SLAVE1_RDBUF_DUMMY_ENABLE      BIT(0)
+
+/* Details for SLAVE2 register */
+
+#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_M  0x000000FF
+#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_S  24
+#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_M  0x000000FF
+#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_S  16
+#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_M  0x000000FF
+#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_S  8
+#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_M  0x000000FF
+#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_S  0
+
+/* Details for SLAVE3 register */
+
+#define SPI_SLAVE3_WRSTA_CMD_VALUE_M       0x000000FF
+#define SPI_SLAVE3_WRSTA_CMD_VALUE_S       24
+#define SPI_SLAVE3_RDSTA_CMD_VALUE_M       0x000000FF
+#define SPI_SLAVE3_RDSTA_CMD_VALUE_S       16
+#define SPI_SLAVE3_WRBUF_CMD_VALUE_M       0x000000FF
+#define SPI_SLAVE3_WRBUF_CMD_VALUE_S       8
+#define SPI_SLAVE3_RDBUF_CMD_VALUE_M       0x000000FF
+#define SPI_SLAVE3_RDBUF_CMD_VALUE_S       0
+
+/* Details for EXT3 register */
+
+#define SPI_EXT3_INT_HOLD_ENABLE_M         0x00000003
+#define SPI_EXT3_INT_HOLD_ENABLE_S         0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* SPI_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/spiflash.c b/cpu/esp8266/vendor/esp/spiflash.c
new file mode 100644
index 0000000000000000000000000000000000000000..20b7d1b87dedff28d77b89f33eef1c9a9af72170
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/spiflash.c
@@ -0,0 +1,267 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 sheinz (https://github.com/sheinz)
+ *
+ * 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.
+ */
+
+#ifdef RIOT_VERSION
+#include "esp/spiflash.h"
+#include "esp/flashchip.h"
+#include "esp/rom.h"
+#include "esp/spi_regs.h"
+#include "esp/FreeRTOS.h"
+#else
+#include "include/spiflash.h"
+#include "include/flashchip.h"
+#include "include/esp/rom.h"
+#include "include/esp/spi_regs.h"
+#include <FreeRTOS.h>
+#endif
+
+#include <string.h>
+
+/**
+ * Note about Wait_SPI_Idle.
+ *
+ * Each write/erase flash operation sets BUSY bit in flash status register.
+ * If attempt to access flash while BUSY bit is set operation will fail.
+ * Function Wait_SPI_Idle loops until this bit is not cleared.
+ *
+ * The approach in the following code is that each write function that is
+ * accessible from the outside should leave flash in Idle state.
+ * The read operations doesn't set BUSY bit in a flash. So they do not wait.
+ * They relay that previous operation is completely finished.
+ *
+ * This approach is different from ESP8266 bootrom where Wait_SPI_Idle is
+ * called where it needed and not.
+ */
+
+#define SPI_WRITE_MAX_SIZE  64
+
+// 64 bytes read causes hang
+// http://bbs.espressif.com/viewtopic.php?f=6&t=2439
+#define SPI_READ_MAX_SIZE   60
+
+
+/**
+ * Low level SPI flash write. Write block of data up to 64 bytes.
+ */
+static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
+        uint8_t *buf, uint32_t size)
+{
+    uint32_t words = size >> 2;
+    if (size & 0b11) {
+        words++;
+    }
+
+    Wait_SPI_Idle(chip);  // wait for previous write to finish
+
+    SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
+
+    memcpy((void*)SPI(0).W, buf, words<<2);
+
+    __asm__ volatile("memw");
+
+    SPI_write_enable(chip);
+
+    SPI(0).CMD = SPI_CMD_PP;
+    while (SPI(0).CMD) {}
+}
+
+/**
+ * Write a page of flash. Data block should not cross page boundary.
+ */
+static bool IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr,
+    uint8_t *buf, uint32_t size)
+{
+    // check if block to write doesn't cross page boundary
+    if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) {
+        return false;
+    }
+
+    if (size < 1) {
+        return true;
+    }
+
+    while (size >= SPI_WRITE_MAX_SIZE) {
+        spi_write_data(flashchip, dest_addr, buf, SPI_WRITE_MAX_SIZE);
+
+        size -= SPI_WRITE_MAX_SIZE;
+        dest_addr += SPI_WRITE_MAX_SIZE;
+        buf += SPI_WRITE_MAX_SIZE;
+
+        if (size < 1) {
+            return true;
+        }
+    }
+
+    spi_write_data(flashchip, dest_addr, buf, size);
+
+    return true;
+}
+
+/**
+ * Split block of data into pages and write pages.
+ */
+static bool IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
+{
+    if (sdk_flashchip.chip_size < (addr + size)) {
+        return false;
+    }
+
+    uint32_t write_bytes_to_page = sdk_flashchip.page_size -
+        (addr % sdk_flashchip.page_size);  // TODO: place for optimization
+
+    if (size < write_bytes_to_page) {
+        if (!spi_write_page(&sdk_flashchip, addr, dst, size)) {
+            return false;
+        }
+    } else {
+        if (!spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
+            return false;
+        }
+
+        uint32_t offset = write_bytes_to_page;
+        uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
+        for (uint32_t i = 0; i < pages_to_write; i++) {
+            if (!spi_write_page(&sdk_flashchip, addr + offset,
+                        dst + offset, sdk_flashchip.page_size)) {
+                return false;
+            }
+            offset += sdk_flashchip.page_size;
+        }
+
+        if (!spi_write_page(&sdk_flashchip, addr + offset,
+                    dst + offset, size - offset)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size)
+{
+    bool result = false;
+
+    if (buf) {
+        vPortEnterCritical();
+        Cache_Read_Disable();
+
+        result = spi_write(addr, buf, size);
+
+        // make sure all write operations is finished before exiting
+        Wait_SPI_Idle(&sdk_flashchip);
+
+        Cache_Read_Enable(0, 0, 1);
+        vPortExitCritical();
+    }
+
+    return result;
+}
+
+/**
+ * Read SPI flash up to 64 bytes.
+ */
+static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr,
+        uint8_t *buf, uint32_t size)
+{
+    SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
+    SPI(0).CMD = SPI_CMD_READ;
+
+    while (SPI(0).CMD) {};
+
+    __asm__ volatile("memw");
+
+    memcpy(buf, (const void*)SPI(0).W, size);
+}
+
+/**
+ * Read SPI flash data. Data region doesn't need to be page aligned.
+ */
+static inline bool IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
+        uint8_t *dst, uint32_t size)
+{
+    if (size < 1) {
+        return true;
+    }
+
+    if ((addr + size) > flashchip->chip_size) {
+        return false;
+    }
+
+    while (size >= SPI_READ_MAX_SIZE) {
+        read_block(flashchip, addr, dst, SPI_READ_MAX_SIZE);
+        dst += SPI_READ_MAX_SIZE;
+        size -= SPI_READ_MAX_SIZE;
+        addr += SPI_READ_MAX_SIZE;
+    }
+
+    if (size > 0) {
+        read_block(flashchip, addr, dst, size);
+    }
+
+    return true;
+}
+
+bool IRAM spiflash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size)
+{
+    bool result = false;
+
+    if (buf) {
+        vPortEnterCritical();
+        Cache_Read_Disable();
+
+        result = read_data(&sdk_flashchip, dest_addr, buf, size);
+
+        Cache_Read_Enable(0, 0, 1);
+        vPortExitCritical();
+    }
+
+    return result;
+}
+
+bool IRAM spiflash_erase_sector(uint32_t addr)
+{
+    if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) {
+        return false;
+    }
+
+    if (addr & 0xFFF) {
+        return false;
+    }
+
+    vPortEnterCritical();
+    Cache_Read_Disable();
+
+    SPI_write_enable(&sdk_flashchip);
+
+    SPI(0).ADDR = addr & 0x00FFFFFF;
+    SPI(0).CMD = SPI_CMD_SE;
+    while (SPI(0).CMD) {};
+
+    Wait_SPI_Idle(&sdk_flashchip);
+
+    Cache_Read_Enable(0, 0, 1);
+    vPortExitCritical();
+
+    return true;
+}
diff --git a/cpu/esp8266/vendor/esp/spiflash.h b/cpu/esp8266/vendor/esp/spiflash.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf93f629ddeb17717152e246dc6cc92d47f2ebda
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/spiflash.h
@@ -0,0 +1,72 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 sheinz (https://github.com/sheinz)
+ *
+ * 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.
+ */
+#ifndef SPIFLASH_H
+#define SPIFLASH_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPI_FLASH_SECTOR_SIZE      4096
+
+/**
+ * Read data from SPI flash.
+ *
+ * @param addr Address to read from. Can be not aligned.
+ * @param buf Buffer to read to. Doesn't have to be aligned.
+ * @param size Size of data to read. Buffer size must be >= than data size.
+ *
+ * @return true if success, otherwise false
+ */
+bool IRAM spiflash_read(uint32_t addr, uint8_t *buf, uint32_t size);
+
+/**
+ * Write data to SPI flash.
+ *
+ * @param addr Address to write to. Can be not aligned.
+ * @param buf Buffer of data to write to flash. Doesn't have to be aligned.
+ * @param size Size of data to write. Buffer size must be >= than data size.
+ *
+ * @return true if success, otherwise false
+ */
+bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size);
+
+/**
+ * Erase a sector.
+ *
+ * @param addr Address of sector to erase. Must be sector aligned.
+ *
+ * @return true if success, otherwise false
+ */
+bool IRAM spiflash_erase_sector(uint32_t addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPIFLASH_H */
diff --git a/cpu/esp8266/vendor/esp/timer_regs.h b/cpu/esp8266/vendor/esp/timer_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b299684c8a0fc9b1c4e2631ca10abce15fe4fb6
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/timer_regs.h
@@ -0,0 +1,151 @@
+/* esp/timer_regs.h
+ *
+ * ESP8266 Timer register definitions
+ *
+ * Not compatible with ESP SDK register access code.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef TIMER_REGS_H
+#define TIMER_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TIMER_BASE 0x60000600
+#define TIMER(i) (*(struct TIMER_REGS *)(TIMER_BASE + (i)*0x20))
+#define TIMER_FRC1 TIMER(0)
+#define TIMER_FRC2 TIMER(1)
+
+/* TIMER registers
+ *
+ * ESP8266 has two hardware timer counters, FRC1 and FRC2.
+ *
+ * FRC1 is a 24-bit countdown timer, triggers interrupt when reaches zero.
+ * FRC2 is a 32-bit countup timer, can set a variable match value to trigger an interrupt.
+ *
+ * FreeRTOS tick timer appears to come from XTensa core tick timer0,
+ * not either of these.  FRC2 is used in the FreeRTOS SDK however. It
+ * is set to free-run, interrupting periodically via updates to the
+ * ALARM register. sdk_ets_timer_init configures FRC2 and assigns FRC2
+ * interrupt handler at sdk_vApplicationTickHook+0x68
+ */
+
+struct TIMER_REGS {            // FRC1  FRC2
+    uint32_t volatile LOAD;    // 0x00  0x20
+    uint32_t volatile COUNT;   // 0x04  0x24
+    uint32_t volatile CTRL;    // 0x08  0x28
+    uint32_t volatile STATUS;  // 0x0c  0x2c
+    uint32_t volatile ALARM;   //       0x30
+};
+
+_Static_assert(sizeof(struct TIMER_REGS) == 0x14, "TIMER_REGS is the wrong size");
+
+#define TIMER_FRC1_MAX_LOAD 0x7fffff
+
+/* Details for LOAD registers */
+
+/* Behavior for FRC1:
+ *
+ * When TIMER_CTRL_RELOAD is cleared in TIMER(0).CTRL, FRC1 will
+ * reload to its max value once underflowed (unless the load
+ * value is rewritten in the interrupt handler.)
+ *
+ * When TIMER_CTRL_RELOAD is set in TIMER(0).CTRL, FRC1 will reload
+ * from the load register value once underflowed.
+ *
+ * Behavior for FRC2:
+ *
+ * If TIMER_CTRL_RELOAD is cleared in TIMER(1).CTRL, writing to
+ * this register will update the FRC2 COUNT value.
+ *
+ * If TIMER_CTRL_RELOAD is set in TIMER(1).CTRL, the behaviour
+ * appears to be the same except that writing 0 to the load register
+ * both sets the COUNT register to 0 and disables the timer, even if
+ * the TIMER_CTRL_RUN bit is set.
+ *
+ * Offsets 0x34, 0x38, 0x3c all seem to read back the LOAD_REG value
+ * also (but have no known function.)
+ */
+
+/* Details for CTRL registers */
+
+/* Observed behaviour is like this:
+ *
+ *  * When TIMER_CTRL_INT_HOLD is set, the interrupt status bit
+ *    TIMER_CTRL_INT_STATUS remains set when the timer interrupt
+ *    triggers, unless manually cleared by writing 0 to
+ *    TIMER(x).STATUS.  While the interrupt status bit stays set
+ *    the timer will continue to run normally, but the interrupt
+ *    (INUM_TIMER_FRC1 or INUM_TIMER_FRC2) won't trigger again.
+ *
+ *  * When TIMER_CTRL_INT_HOLD is cleared (default), there's no need to
+ *    manually write to TIMER(x).STATUS. The interrupt status bit
+ *    TIMER_CTRL_INT_STATUS automatically clears after the interrupt
+ *    triggers, and the interrupt handler will run again
+ *    automatically.
+ */
+
+/* The values for TIMER_CTRL_CLKDIV control how many CPU clock cycles amount to
+ * one timer clock cycle.  For valid values, see the timer_clkdiv_t enum below.
+ */
+
+/* TIMER_CTRL_INT_STATUS gets set when interrupt fires, and cleared on a write
+ * to TIMER(x).STATUS (or cleared automatically if TIMER_CTRL_INT_HOLD is not
+ * set).
+ */
+
+#define TIMER_CTRL_INT_HOLD    BIT(0)
+#define TIMER_CTRL_CLKDIV_M    0x00000003
+#define TIMER_CTRL_CLKDIV_S    2
+#define TIMER_CTRL_RELOAD      BIT(6)
+#define TIMER_CTRL_RUN         BIT(7)
+#define TIMER_CTRL_INT_STATUS  BIT(8)
+
+typedef enum {
+    TIMER_CLKDIV_1 = 0,
+    TIMER_CLKDIV_16 = 1,
+    TIMER_CLKDIV_256 = 2,
+} timer_clkdiv_t;
+
+/* Details for STATUS registers */
+
+/* Reading this register always returns the value in
+ * TIMER(x).LOAD
+ *
+ * Writing zero to this register clears the FRC1
+ * interrupt status.
+ */
+
+/* Details for FRC2.ALARM register */
+
+/* Interrupt match value for FRC2. When COUNT == ALARM,
+   the interrupt fires.
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* TIMER_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/types.h b/cpu/esp8266/vendor/esp/types.h
new file mode 100644
index 0000000000000000000000000000000000000000..a83a796d511d0f15b529c5d489b4db29398394f0
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/types.h
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef volatile uint32_t *esp_reg_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TYPES_H */
diff --git a/cpu/esp8266/vendor/esp/uart_regs.h b/cpu/esp8266/vendor/esp/uart_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..86df49297133a3d6bdbf2901c8eb2c77336c52cd
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/uart_regs.h
@@ -0,0 +1,211 @@
+/** esp/uart.h
+ *
+ * Configuration of UART registers.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Superhouse Automation Pty Ltd
+ * BSD Licensed as described in the file LICENSE
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+#ifndef UART_REGS_H
+#define UART_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Register definitions for the UART peripherals on the ESP8266.
+ *
+ * There are twp UART devices built into the ESP8266:
+ *   UART(0) is at 0x60000000
+ *   UART(1) is at 0x60000F00
+ *
+ * Each device is allocated a block of 64 32-bit registers (256 bytes of
+ * address space) to communicate with application code.
+ */
+
+#define UART_BASE 0x60000000
+#define UART(i) (*(struct UART_REGS *)(UART_BASE + (i)*0xf00))
+
+#define UART0_BASE UART_BASE
+#define UART1_BASE (UART_BASE + 0xf00)
+
+struct UART_REGS {
+    uint32_t volatile FIFO;           // 0x00
+    uint32_t volatile INT_RAW;        // 0x04
+    uint32_t volatile INT_STATUS;     // 0x08
+    uint32_t volatile INT_ENABLE;     // 0x0c
+    uint32_t volatile INT_CLEAR;      // 0x10
+    uint32_t volatile CLOCK_DIVIDER;  // 0x14
+    uint32_t volatile AUTOBAUD;       // 0x18
+    uint32_t volatile STATUS;         // 0x1c
+    uint32_t volatile CONF0;          // 0x20
+    uint32_t volatile CONF1;          // 0x24
+    uint32_t volatile LOW_PULSE;      // 0x28
+    uint32_t volatile HIGH_PULSE;     // 0x2c
+    uint32_t volatile PULSE_COUNT;    // 0x30
+    uint32_t volatile _unused[17];    // 0x34 - 0x74
+    uint32_t volatile DATE;           // 0x78
+    uint32_t volatile ID;             // 0x7c
+};
+
+_Static_assert(sizeof(struct UART_REGS) == 0x80, "UART_REGS is the wrong size");
+
+/* Details for FIFO register */
+
+#define UART_FIFO_DATA_M  0x000000ff
+#define UART_FIFO_DATA_S  0
+
+/* Details for INT_RAW register */
+
+#define UART_INT_RAW_RXFIFO_TIMEOUT          BIT(8)
+#define UART_INT_RAW_BREAK_DETECTED          BIT(7)
+#define UART_INT_RAW_CTS_CHANGED             BIT(6)
+#define UART_INT_RAW_DSR_CHANGED             BIT(5)
+#define UART_INT_RAW_RXFIFO_OVERFLOW         BIT(4)
+#define UART_INT_RAW_FRAMING_ERR             BIT(3)
+#define UART_INT_RAW_PARITY_ERR              BIT(2)
+#define UART_INT_RAW_TXFIFO_EMPTY            BIT(1)
+#define UART_INT_RAW_RXFIFO_FULL             BIT(0)
+
+/* Details for INT_STATUS register */
+
+#define UART_INT_STATUS_RXFIFO_TIMEOUT       BIT(8)
+#define UART_INT_STATUS_BREAK_DETECTED       BIT(7)
+#define UART_INT_STATUS_CTS_CHANGED          BIT(6)
+#define UART_INT_STATUS_DSR_CHANGED          BIT(5)
+#define UART_INT_STATUS_RXFIFO_OVERFLOW      BIT(4)
+#define UART_INT_STATUS_FRAMING_ERR          BIT(3)
+#define UART_INT_STATUS_PARITY_ERR           BIT(2)
+#define UART_INT_STATUS_TXFIFO_EMPTY         BIT(1)
+#define UART_INT_STATUS_RXFIFO_FULL          BIT(0)
+
+/* Details for INT_ENABLE register */
+
+#define UART_INT_ENABLE_RXFIFO_TIMEOUT       BIT(8)
+#define UART_INT_ENABLE_BREAK_DETECTED       BIT(7)
+#define UART_INT_ENABLE_CTS_CHANGED          BIT(6)
+#define UART_INT_ENABLE_DSR_CHANGED          BIT(5)
+#define UART_INT_ENABLE_RXFIFO_OVERFLOW      BIT(4)
+#define UART_INT_ENABLE_FRAMING_ERR          BIT(3)
+#define UART_INT_ENABLE_PARITY_ERR           BIT(2)
+#define UART_INT_ENABLE_TXFIFO_EMPTY         BIT(1)
+#define UART_INT_ENABLE_RXFIFO_FULL          BIT(0)
+
+/* Details for INT_CLEAR register */
+
+#define UART_INT_CLEAR_RXFIFO_TIMEOUT        BIT(8)
+#define UART_INT_CLEAR_BREAK_DETECTED        BIT(7)
+#define UART_INT_CLEAR_CTS_CHANGED           BIT(6)
+#define UART_INT_CLEAR_DSR_CHANGED           BIT(5)
+#define UART_INT_CLEAR_RXFIFO_OVERFLOW       BIT(4)
+#define UART_INT_CLEAR_FRAMING_ERR           BIT(3)
+#define UART_INT_CLEAR_PARITY_ERR            BIT(2)
+#define UART_INT_CLEAR_TXFIFO_EMPTY          BIT(1)
+#define UART_INT_CLEAR_RXFIFO_FULL           BIT(0)
+
+/* Details for CLOCK_DIVIDER register */
+
+#define UART_CLOCK_DIVIDER_VALUE_M           0x000fffff
+#define UART_CLOCK_DIVIDER_VALUE_S           0
+
+/* Details for AUTOBAUD register */
+
+#define UART_AUTOBAUD_GLITCH_FILTER_M        0x000000FF
+#define UART_AUTOBAUD_GLITCH_FILTER_S        8
+#define UART_AUTOBAUD_ENABLE                 BIT(0)
+
+/* Details for STATUS register */
+
+#define UART_STATUS_TXD                      BIT(31)
+#define UART_STATUS_RTS                      BIT(30)
+#define UART_STATUS_DTR                      BIT(29)
+#define UART_STATUS_TXFIFO_COUNT_M           0x000000ff
+#define UART_STATUS_TXFIFO_COUNT_S           16
+#define UART_STATUS_RXD                      BIT(15)
+#define UART_STATUS_CTS                      BIT(14)
+#define UART_STATUS_DSR                      BIT(13)
+#define UART_STATUS_RXFIFO_COUNT_M           0x000000ff
+#define UART_STATUS_RXFIFO_COUNT_S           0
+
+/* Details for CONF0 register */
+
+#define UART_CONF0_DTR_INVERTED              BIT(24)
+#define UART_CONF0_RTS_INVERTED              BIT(23)
+#define UART_CONF0_TXD_INVERTED              BIT(22)
+#define UART_CONF0_DSR_INVERTED              BIT(21)
+#define UART_CONF0_CTS_INVERTED              BIT(20)
+#define UART_CONF0_RXD_INVERTED              BIT(19)
+#define UART_CONF0_TXFIFO_RESET              BIT(18)
+#define UART_CONF0_RXFIFO_RESET              BIT(17)
+#define UART_CONF0_IRDA_ENABLE               BIT(16)
+#define UART_CONF0_TX_FLOW_ENABLE            BIT(15)
+#define UART_CONF0_LOOPBACK                  BIT(14)
+#define UART_CONF0_IRDA_RX_INVERTED          BIT(13)
+#define UART_CONF0_IRDA_TX_INVERTED          BIT(12)
+#define UART_CONF0_IRDA_WCTL                 BIT(11)
+#define UART_CONF0_IRDA_TX_ENABLE            BIT(10)
+#define UART_CONF0_IRDA_DUPLEX               BIT(9)
+#define UART_CONF0_TXD_BREAK                 BIT(8)
+#define UART_CONF0_SW_DTR                    BIT(7)
+#define UART_CONF0_SW_RTS                    BIT(6)
+#define UART_CONF0_STOP_BITS_M               0x00000003
+#define UART_CONF0_STOP_BITS_S               4
+#define UART_CONF0_BYTE_LEN_M                0x00000003
+#define UART_CONF0_BYTE_LEN_S                2
+#define UART_CONF0_PARITY_ENABLE             BIT(1)
+#define UART_CONF0_PARITY                    BIT(0) //FIXME: does this indicate odd or even?
+
+/* Details for CONF1 register */
+
+#define UART_CONF1_RX_TIMEOUT_ENABLE         BIT(31)
+#define UART_CONF1_RX_TIMEOUT_THRESHOLD_M    0x0000007f
+#define UART_CONF1_RX_TIMEOUT_THRESHOLD_S    24
+#define UART_CONF1_RX_FLOWCTRL_ENABLE        BIT(23)
+#define UART_CONF1_RX_FLOWCTRL_THRESHOLD_M   0x0000007f
+#define UART_CONF1_RX_FLOWCTRL_THRESHOLD_S   16
+#define UART_CONF1_TXFIFO_EMPTY_THRESHOLD_M  0x0000007f
+#define UART_CONF1_TXFIFO_EMPTY_THRESHOLD_S  8
+#define UART_CONF1_RXFIFO_FULL_THRESHOLD_M   0x0000007f
+#define UART_CONF1_RXFIFO_FULL_THRESHOLD_S   0
+
+/* Details for LOW_PULSE register */
+
+#define UART_LOW_PULSE_MIN_M                 0x000fffff
+#define UART_LOW_PULSE_MIN_S                 0
+
+/* Details for HIGH_PULSE register */
+
+#define UART_HIGH_PULSE_MIN_M                0x000fffff
+#define UART_HIGH_PULSE_MIN_S                0
+
+/* Details for PULSE_COUNT register */
+
+#define UART_PULSE_COUNT_VALUE_M             0x000003ff
+#define UART_PULSE_COUNT_VALUE_S             0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* UART_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/wdev_regs.h b/cpu/esp8266/vendor/esp/wdev_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..e832b5e887d8ddd9af92abf990b221a344403c82
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/wdev_regs.h
@@ -0,0 +1,67 @@
+/* esp/wdev_regs.h
+ *
+ * ESP8266 register definitions for the "wdev" region (0x3FF2xxx)
+ *
+ * In the DPORT memory space, alongside DPORT regs. However mostly
+ * concerned with the WiFi hardware interface.
+ *
+ * Not compatible with ESP SDK register access code.
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef WDEV_REGS_H
+#define WDEV_REGS_H
+
+#ifndef DOXYGEN
+
+#include "esp/types.h"
+#include "common_macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WDEV_BASE 0x3FF20000
+#define WDEV (*(struct WDEV_REGS *)(WDEV_BASE))
+
+/* Note: This memory region is not currently well understood.  Pretty much all
+ * of the definitions here are from reverse-engineering the Espressif SDK code,
+ * many are just educated guesses, and almost certainly some are misleading or
+ * wrong.  If you can improve on any of this, please contribute!
+ */
+
+struct WDEV_REGS {
+    uint32_t volatile _unknown0[768];  // 0x0000 - 0x0bfc
+    uint32_t volatile SYS_TIME;        // 0x0c00
+    uint32_t volatile _unknown1[144];  // 0x0c04 - 0x0e40
+    uint32_t volatile HWRNG;           // 0xe44 HW RNG, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
+} __attribute__ (( packed ));
+
+_Static_assert(sizeof(struct WDEV_REGS) == 0xe48, "WDEV_REGS is the wrong size");
+
+/* Extra paranoid check about the HWRNG address, as if this becomes
+   wrong there will be no obvious symptoms apart from a lack of
+   entropy.
+*/
+_Static_assert(&WDEV.HWRNG == (void*)0x3FF20E44, "HWRNG register is at wrong address");
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* WDEV_REGS_H */
diff --git a/cpu/esp8266/vendor/esp/xtensa_ops.h b/cpu/esp8266/vendor/esp/xtensa_ops.h
new file mode 100644
index 0000000000000000000000000000000000000000..12006843aab3a3df2977aa7e9f5c8090e28d5b33
--- /dev/null
+++ b/cpu/esp8266/vendor/esp/xtensa_ops.h
@@ -0,0 +1,65 @@
+/** xtensa_ops.h
+ *
+ * Special macros/etc which deal with Xtensa-specific architecture/CPU
+ * considerations.
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2015 Superhouse Automation Pty Ltd
+ * BSD Licensed as described in the file LICENSE
+ */
+
+/*
+Copyright (c) 2015, SuperHouse Automation Pty Ltd
+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.
+*/
+
+#ifndef XTENSA_OPS_H
+#define XTENSA_OPS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Read stack pointer to variable.
+ *
+ * Note that the compiler will push a stack frame (minimum 16 bytes)
+ * in the prelude of a C function that calls any other functions.
+ */
+#define SP(var) __asm__ volatile ("mov %0, a1" : "=r" (var))
+
+/* Read the function return address to a variable.
+ *
+ * Depends on the containing function being simple enough that a0 is
+ * being used as a working register.
+ */
+#define RETADDR(var) __asm__ volatile ("mov %0, a0" : "=r" (var))
+
+// GCC macros for reading, writing, and exchanging Xtensa processor special
+// registers:
+
+#define RSR(var, reg) __asm__ volatile ("rsr %0, " #reg : "=r" (var));
+#define WSR(var, reg) __asm__ volatile ("wsr %0, " #reg : : "r" (var));
+#define XSR(var, reg) __asm__ volatile ("xsr %0, " #reg : "+r" (var));
+
+// GCC macros for performing associated "*sync" opcodes
+
+#define ISYNC() __asm__ volatile ( "isync" )
+#define RSYNC() __asm__ volatile ( "rsync" )
+#define ESYNC() __asm__ volatile ( "esync" )
+#define DSYNC() __asm__ volatile ( "dsync" )
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XTENSA_OPS_H */
diff --git a/cpu/esp8266/vendor/espressif/README.md b/cpu/esp8266/vendor/espressif/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4507ffe49026d537b2ffc43abdcc5f491fa4f194
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/README.md
@@ -0,0 +1 @@
+The files in this directory are either from the [ESP8266_NONOS_SDK](https://github.com/espressif/ESP8266_NONOS_SDK.git) or from the [ESP_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK.git) for ESP8266. All of these files are copyright of Espressif Systems (Shanghai) Pte., Ltd. Please note the copyright notice in these files.
diff --git a/cpu/esp8266/vendor/espressif/c_types.h b/cpu/esp8266/vendor/espressif/c_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..c712044bb7b2341f8cc057ba1646347e2dd0c7eb
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/c_types.h
@@ -0,0 +1,137 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+
+#ifndef C_TYPES_H
+#define C_TYPES_H
+
+/* Following header guards are necessary to avoid conflicts with original */
+/* header in SDK where _C_TYPES_H_ is used */
+#ifndef _C_TYPES_H_
+#define _C_TYPES_H_
+
+#ifndef DOXYGEN
+#ifndef _DTLS_GLOBAL_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef signed char         sint8_t;
+typedef signed short        sint16_t;
+typedef signed long         sint32_t;
+typedef signed long long    sint64_t;
+typedef unsigned long long  u_int64_t;
+typedef float               real32_t;
+typedef double              real64_t;
+
+typedef unsigned char       uint8;
+typedef unsigned char       u8;
+typedef signed char         sint8;
+typedef signed char         int8;
+typedef signed char         s8;
+typedef unsigned short      uint16;
+typedef unsigned short      u16;
+typedef signed short        sint16;
+typedef signed short        s16;
+typedef unsigned int        uint32;
+typedef unsigned int        u_int;
+typedef unsigned int        u32;
+typedef signed int          sint32;
+typedef signed int          s32;
+typedef int                 int32;
+typedef signed long long    sint64;
+typedef unsigned long long  uint64;
+typedef unsigned long long  u64;
+typedef float               real32;
+typedef double              real64;
+
+#define __le16      u16
+
+typedef unsigned int        size_t;
+
+/* #define __packed        __attribute__((packed)) */
+
+#define LOCAL       static
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+/* probably should not put STATUS here */
+typedef enum {
+    OK = 0,
+    FAIL,
+    PENDING,
+    BUSY,
+    CANCEL,
+} STATUS;
+
+#ifndef BIT
+#define BIT(nr)                 (1UL << (nr))
+#endif
+
+#define REG_SET_BIT(_r, _b)  (*(volatile uint32_t*)(_r) |= (_b))
+#define REG_CLR_BIT(_r, _b)  (*(volatile uint32_t*)(_r) &= ~(_b))
+
+#define DMEM_ATTR __attribute__((section(".bss")))
+#define SHMEM_ATTR
+
+#ifdef ICACHE_FLASH
+#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
+#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
+#else
+#define ICACHE_FLASH_ATTR
+#define ICACHE_RODATA_ATTR
+#endif /* ICACHE_FLASH */
+
+#define STORE_ATTR __attribute__((aligned(4)))
+
+#ifndef __cplusplus
+#define BOOL            bool
+#ifndef true
+#define true            (1)
+#endif
+#ifndef false
+#define false           (0)
+#endif
+#ifndef TRUE
+#define TRUE            true
+#endif
+#ifndef FALSE
+#define FALSE           false
+#endif
+
+#endif /* !__cplusplus */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DTLS_GLOBAL_H_ */
+#endif /* DOXYGEN */
+#endif /* _C_TYPES_H_ */
+#endif /* C_TYPES_H */
diff --git a/cpu/esp8266/vendor/espressif/eagle_soc.h b/cpu/esp8266/vendor/espressif/eagle_soc.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdfe61a07ed17e895d52219f752ed72c96b7a4c4
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/eagle_soc.h
@@ -0,0 +1,289 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+#ifndef EAGLE_SOC_H
+#define EAGLE_SOC_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//Register Bits{{
+#define BIT31   0x80000000
+#define BIT30   0x40000000
+#define BIT29   0x20000000
+#define BIT28   0x10000000
+#define BIT27   0x08000000
+#define BIT26   0x04000000
+#define BIT25   0x02000000
+#define BIT24   0x01000000
+#define BIT23   0x00800000
+#define BIT22   0x00400000
+#define BIT21   0x00200000
+#define BIT20   0x00100000
+#define BIT19   0x00080000
+#define BIT18   0x00040000
+#define BIT17   0x00020000
+#define BIT16   0x00010000
+#define BIT15   0x00008000
+#define BIT14   0x00004000
+#define BIT13   0x00002000
+#define BIT12   0x00001000
+#define BIT11   0x00000800
+#define BIT10   0x00000400
+#define BIT9     0x00000200
+#define BIT8     0x00000100
+#define BIT7     0x00000080
+#define BIT6     0x00000040
+#define BIT5     0x00000020
+#define BIT4     0x00000010
+#define BIT3     0x00000008
+#define BIT2     0x00000004
+#define BIT1     0x00000002
+#define BIT0     0x00000001
+//}}
+
+//Registers Operation {{
+#define ETS_UNCACHED_ADDR(addr) (addr)
+#define ETS_CACHED_ADDR(addr) (addr)
+
+
+#define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr)))
+#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val)
+#define CLEAR_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask))))
+#define SET_PERI_REG_MASK(reg, mask)   WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask)))
+#define GET_PERI_REG_BITS(reg, hipos,lowpos)      ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1))
+#define SET_PERI_REG_BITS(reg,bit_map,value,shift) (WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|((value)<<(shift)) ))
+//}}
+
+//Periheral Clock {{
+#define  APB_CLK_FREQ                                80*1000000       //unit: Hz
+#define  UART_CLK_FREQ                               APB_CLK_FREQ
+#define  TIMER_CLK_FREQ                              (APB_CLK_FREQ>>8) //divided by 256
+//}}
+
+//Peripheral device base address define{{
+#define PERIPHS_DPORT_BASEADDR              0x3ff00000
+#define PERIPHS_GPIO_BASEADDR               0x60000300
+#define PERIPHS_TIMER_BASEDDR               0x60000600
+#define PERIPHS_RTC_BASEADDR                0x60000700
+#define PERIPHS_IO_MUX                        0x60000800
+//}}
+
+//Interrupt remap control registers define{{
+#define EDGE_INT_ENABLE_REG                 (PERIPHS_DPORT_BASEADDR+0x04)
+#define TM1_EDGE_INT_ENABLE()             SET_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1)
+#define TM1_EDGE_INT_DISABLE()            CLEAR_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1)
+//}}
+
+//GPIO reg {{
+#define GPIO_REG_READ(reg)                         READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg)
+#define GPIO_REG_WRITE(reg, val)                 WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val)
+#define GPIO_OUT_ADDRESS                         0x00
+#define GPIO_OUT_W1TS_ADDRESS             0x04
+#define GPIO_OUT_W1TC_ADDRESS             0x08
+
+#define GPIO_ENABLE_ADDRESS                  0x0c
+#define GPIO_ENABLE_W1TS_ADDRESS      0x10
+#define GPIO_ENABLE_W1TC_ADDRESS      0x14
+#define GPIO_OUT_W1TC_DATA_MASK      0x0000ffff
+
+#define GPIO_IN_ADDRESS                            0x18
+
+#define GPIO_STATUS_ADDRESS                  0x1c
+#define GPIO_STATUS_W1TS_ADDRESS       0x20
+#define GPIO_STATUS_W1TC_ADDRESS      0x24
+#define GPIO_STATUS_INTERRUPT_MASK 0x0000ffff
+
+#define GPIO_RTC_CALIB_SYNC                  PERIPHS_GPIO_BASEADDR+0x6c
+#define RTC_CALIB_START                           BIT31  //first write to zero, then to one to start
+#define RTC_PERIOD_NUM_MASK              0x3ff   //max 8ms
+#define GPIO_RTC_CALIB_VALUE               PERIPHS_GPIO_BASEADDR+0x70
+#define RTC_CALIB_RDY_S                           31  //after measure, flag to one, when start from zero to one, turn to zero
+#define RTC_CALIB_VALUE_MASK             0xfffff
+
+#define GPIO_PIN0_ADDRESS                        0x28
+
+#define GPIO_ID_PIN0                                     0
+#define GPIO_ID_PIN(n)                                   (GPIO_ID_PIN0+(n))
+#define GPIO_LAST_REGISTER_ID                GPIO_ID_PIN(15)
+#define GPIO_ID_NONE                                  0xffffffff
+
+#define GPIO_PIN_COUNT                              16
+
+#define GPIO_PIN_CONFIG_MSB                    12
+#define GPIO_PIN_CONFIG_LSB                     11
+#define GPIO_PIN_CONFIG_MASK                 0x00001800
+#define GPIO_PIN_CONFIG_GET(x)                 (((x) & GPIO_PIN_CONFIG_MASK) >> GPIO_PIN_CONFIG_LSB)
+#define GPIO_PIN_CONFIG_SET(x)                  (((x) << GPIO_PIN_CONFIG_LSB) & GPIO_PIN_CONFIG_MASK)
+
+#define GPIO_WAKEUP_ENABLE                               1
+#define GPIO_WAKEUP_DISABLE                              (~GPIO_WAKEUP_ENABLE)
+#define GPIO_PIN_WAKEUP_ENABLE_MSB             10
+#define GPIO_PIN_WAKEUP_ENABLE_LSB              10
+#define GPIO_PIN_WAKEUP_ENABLE_MASK          0x00000400
+#define GPIO_PIN_WAKEUP_ENABLE_GET(x)          (((x) & GPIO_PIN_WAKEUP_ENABLE_MASK) >> GPIO_PIN_WAKEUP_ENABLE_LSB)
+#define GPIO_PIN_WAKEUP_ENABLE_SET(x)           (((x) << GPIO_PIN_WAKEUP_ENABLE_LSB) & GPIO_PIN_WAKEUP_ENABLE_MASK)
+
+#define GPIO_PIN_INT_TYPE_MASK             0x380
+#define GPIO_PIN_INT_TYPE_MSB                9
+#define GPIO_PIN_INT_TYPE_LSB                 7
+#define GPIO_PIN_INT_TYPE_GET(x)             (((x) & GPIO_PIN_INT_TYPE_MASK) >> GPIO_PIN_INT_TYPE_LSB)
+#define GPIO_PIN_INT_TYPE_SET(x)             (((x) << GPIO_PIN_INT_TYPE_LSB) & GPIO_PIN_INT_TYPE_MASK)
+
+#define GPIO_PAD_DRIVER_ENABLE             1
+#define GPIO_PAD_DRIVER_DISABLE            (~GPIO_PAD_DRIVER_ENABLE)
+#define GPIO_PIN_PAD_DRIVER_MSB            2
+#define GPIO_PIN_PAD_DRIVER_LSB             2
+#define GPIO_PIN_PAD_DRIVER_MASK         0x00000004
+#define GPIO_PIN_PAD_DRIVER_GET(x)         (((x) & GPIO_PIN_PAD_DRIVER_MASK) >> GPIO_PIN_PAD_DRIVER_LSB)
+#define GPIO_PIN_PAD_DRIVER_SET(x)          (((x) << GPIO_PIN_PAD_DRIVER_LSB) & GPIO_PIN_PAD_DRIVER_MASK)
+
+#define GPIO_AS_PIN_SOURCE                        0
+#define SIGMA_AS_PIN_SOURCE                     (~GPIO_AS_PIN_SOURCE)
+#define GPIO_PIN_SOURCE_MSB                     0
+#define GPIO_PIN_SOURCE_LSB                      0
+#define GPIO_PIN_SOURCE_MASK                  0x00000001
+#define GPIO_PIN_SOURCE_GET(x)                 (((x) & GPIO_PIN_SOURCE_MASK) >> GPIO_PIN_SOURCE_LSB)
+#define GPIO_PIN_SOURCE_SET(x)                  (((x) << GPIO_PIN_SOURCE_LSB) & GPIO_PIN_SOURCE_MASK)
+// }}
+
+// TIMER reg {{
+#define RTC_REG_READ(addr)                        READ_PERI_REG(PERIPHS_TIMER_BASEDDR + addr)
+#define RTC_REG_WRITE(addr, val)                WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + addr, val)
+#define RTC_CLR_REG_MASK(reg, mask)      CLEAR_PERI_REG_MASK(PERIPHS_TIMER_BASEDDR +reg, mask)
+/* Returns the current time according to the timer timer. */
+#define NOW()                                                 RTC_REG_READ(FRC2_COUNT_ADDRESS)
+
+//load initial_value to timer1
+#define FRC1_LOAD_ADDRESS                    0x00
+
+//timer1's counter value(count from initial_value to 0)
+#define FRC1_COUNT_ADDRESS                 0x04
+
+#define FRC1_CTRL_ADDRESS                    0x08
+
+//clear timer1's interrupt when write this address
+#define FRC1_INT_ADDRESS                      0x0c
+#define FRC1_INT_CLR_MASK                   0x00000001
+
+//timer2's counter value(count from initial_value to 0)
+#define FRC2_COUNT_ADDRESS                0x24
+// }}
+
+//RTC reg {{
+#define REG_RTC_BASE  PERIPHS_RTC_BASEADDR
+
+#define RTC_STORE0                              (REG_RTC_BASE + 0x030)
+#define RTC_STORE1                              (REG_RTC_BASE + 0x034)
+#define RTC_STORE2                              (REG_RTC_BASE + 0x038)
+#define RTC_STORE3                              (REG_RTC_BASE + 0x03C)
+
+#define RTC_GPIO_OUT                            (REG_RTC_BASE + 0x068)
+#define RTC_GPIO_ENABLE                         (REG_RTC_BASE + 0x074)
+#define RTC_GPIO_IN_DATA                        (REG_RTC_BASE + 0x08C)
+#define RTC_GPIO_CONF                           (REG_RTC_BASE + 0x090)
+#define PAD_XPD_DCDC_CONF                       (REG_RTC_BASE + 0x0A0)
+//}}
+
+//PIN Mux reg {{
+#define PERIPHS_IO_MUX_FUNC             0x13
+#define PERIPHS_IO_MUX_FUNC_S           4
+#define PERIPHS_IO_MUX_PULLUP           BIT7
+#define PERIPHS_IO_MUX_PULLUP2          BIT6
+#define PERIPHS_IO_MUX_SLEEP_PULLUP     BIT3
+#define PERIPHS_IO_MUX_SLEEP_PULLUP2    BIT2
+#define PERIPHS_IO_MUX_SLEEP_OE         BIT1
+#define PERIPHS_IO_MUX_OE               BIT0
+
+#define PERIPHS_IO_MUX_CONF_U           (PERIPHS_IO_MUX + 0x00)
+#define SPI0_CLK_EQU_SYS_CLK            BIT8
+#define SPI1_CLK_EQU_SYS_CLK            BIT9
+#define PERIPHS_IO_MUX_MTDI_U           (PERIPHS_IO_MUX + 0x04)
+#define FUNC_GPIO12                     3
+#define PERIPHS_IO_MUX_MTCK_U           (PERIPHS_IO_MUX + 0x08)
+#define FUNC_GPIO13                     3
+#define PERIPHS_IO_MUX_MTMS_U           (PERIPHS_IO_MUX + 0x0C)
+#define FUNC_GPIO14                     3
+#define PERIPHS_IO_MUX_MTDO_U           (PERIPHS_IO_MUX + 0x10)
+#define FUNC_GPIO15                     3
+#define FUNC_U0RTS                      4
+#define PERIPHS_IO_MUX_U0RXD_U          (PERIPHS_IO_MUX + 0x14)
+#define FUNC_GPIO3                      3
+#define PERIPHS_IO_MUX_U0TXD_U          (PERIPHS_IO_MUX + 0x18)
+#define FUNC_U0TXD                      0
+#define FUNC_GPIO1                      3
+#define PERIPHS_IO_MUX_SD_CLK_U         (PERIPHS_IO_MUX + 0x1c)
+#define FUNC_SDCLK                      0
+#define FUNC_SPICLK                     1
+#define PERIPHS_IO_MUX_SD_DATA0_U       (PERIPHS_IO_MUX + 0x20)
+#define FUNC_SDDATA0                    0
+#define FUNC_SPIQ                       1
+#define FUNC_U1TXD                      4
+#define PERIPHS_IO_MUX_SD_DATA1_U       (PERIPHS_IO_MUX + 0x24)
+#define FUNC_SDDATA1                    0
+#define FUNC_SPID                       1
+#define FUNC_U1RXD                      4
+#define FUNC_SDDATA1_U1RXD              7
+#define PERIPHS_IO_MUX_SD_DATA2_U       (PERIPHS_IO_MUX + 0x28)
+#define FUNC_SDDATA2                    0
+#define FUNC_SPIHD                      1
+#define FUNC_GPIO9                      3
+#define PERIPHS_IO_MUX_SD_DATA3_U       (PERIPHS_IO_MUX + 0x2c)
+#define FUNC_SDDATA3                    0
+#define FUNC_SPIWP                      1
+#define FUNC_GPIO10                     3
+#define PERIPHS_IO_MUX_SD_CMD_U         (PERIPHS_IO_MUX + 0x30)
+#define FUNC_SDCMD                      0
+#define FUNC_SPICS0                     1
+#define PERIPHS_IO_MUX_GPIO0_U          (PERIPHS_IO_MUX + 0x34)
+#define FUNC_GPIO0                      0
+#define PERIPHS_IO_MUX_GPIO2_U          (PERIPHS_IO_MUX + 0x38)
+#define FUNC_GPIO2                      0
+#define FUNC_U1TXD_BK                   2
+#define FUNC_U0TXD_BK                   4
+#define PERIPHS_IO_MUX_GPIO4_U          (PERIPHS_IO_MUX + 0x3C)
+#define FUNC_GPIO4                      0
+#define PERIPHS_IO_MUX_GPIO5_U          (PERIPHS_IO_MUX + 0x40)
+#define FUNC_GPIO5                      0
+
+#define PIN_PULLUP_DIS(PIN_NAME)                 CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP)
+#define PIN_PULLUP_EN(PIN_NAME)                  SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP)
+
+#define PIN_FUNC_SELECT(PIN_NAME, FUNC)  do { \
+    WRITE_PERI_REG(PIN_NAME,   \
+                                (READ_PERI_REG(PIN_NAME) \
+                                     &  (~(PERIPHS_IO_MUX_FUNC<<PERIPHS_IO_MUX_FUNC_S)))  \
+                                     |( (((FUNC&BIT2)<<2)|(FUNC&0x3))<<PERIPHS_IO_MUX_FUNC_S) );  \
+    } while (0)
+
+//}}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* EAGLE_SOC_H */
diff --git a/cpu/esp8266/vendor/espressif/ets_sys.h b/cpu/esp8266/vendor/espressif/ets_sys.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc4b503cf4880f63ac0a7bc1628b8eefe15aa987
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/ets_sys.h
@@ -0,0 +1,148 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+
+#ifndef ETS_SYS_H
+#define ETS_SYS_H
+
+/* Following header guards are necessary to avoid conflicts with original */
+/* header in SDK where _ETS_SYS_H is used */
+#ifndef _ETS_SYS_H
+#define _ETS_SYS_H
+
+#ifndef DOXYGEN
+
+#include "c_types.h"
+#include "eagle_soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint32_t ETSSignal;
+typedef uint32_t ETSParam;
+
+typedef struct ETSEventTag ETSEvent;
+
+struct ETSEventTag {
+    ETSSignal sig;
+    ETSParam  par;
+};
+
+typedef void (*ETSTask)(ETSEvent *e);
+
+/* timer related */
+typedef uint32_t ETSHandle;
+typedef void ETSTimerFunc(void *timer_arg);
+
+typedef struct _ETSTIMER_ {
+    struct _ETSTIMER_    *timer_next;
+    uint32_t              timer_expire;
+    uint32_t              timer_period;
+    ETSTimerFunc         *timer_func;
+    void                 *timer_arg;
+} ETSTimer;
+
+/* interrupt related */
+#define ETS_SDIO_INUM       1
+#define ETS_SPI_INUM        2
+#define ETS_GPIO_INUM       4
+#define ETS_UART_INUM       5
+#define ETS_UART1_INUM      5
+#define ETS_FRC_TIMER1_INUM 9  /* use edge*/
+
+typedef void (* ets_isr_t)(void *);
+
+void ets_intr_lock(void);
+void ets_intr_unlock(void);
+void ets_isr_attach(int i, ets_isr_t func, void *arg);
+
+void NmiTimSetFunc(void (*func)(void));
+
+#define ETS_INTR_LOCK() \
+    ets_intr_lock()
+
+#define ETS_INTR_UNLOCK() \
+    ets_intr_unlock()
+
+#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \
+    ets_isr_attach(ETS_FRC_TIMER1_INUM, (func), (void *)(arg))
+
+#define ETS_FRC_TIMER1_NMI_INTR_ATTACH(func) \
+    NmiTimSetFunc(func)
+
+#define ETS_SDIO_INTR_ATTACH(func, arg)\
+    ets_isr_attach(ETS_SDIO_INUM, (func), (void *)(arg))
+
+#define ETS_GPIO_INTR_ATTACH(func, arg) \
+    ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg))
+
+#define ETS_UART_INTR_ATTACH(func, arg) \
+    ets_isr_attach(ETS_UART_INUM, (func), (void *)(arg))
+
+#define ETS_SPI_INTR_ATTACH(func, arg) \
+    ets_isr_attach(ETS_SPI_INUM, (func), (void *)(arg))
+
+#define ETS_INTR_ENABLE(inum) \
+    ets_isr_unmask((1<<inum))
+
+#define ETS_INTR_DISABLE(inum) \
+    ets_isr_mask((1<<inum))
+
+#define ETS_UART_INTR_ENABLE() \
+    ETS_INTR_ENABLE(ETS_UART_INUM)
+
+#define ETS_UART_INTR_DISABLE() \
+    ETS_INTR_DISABLE(ETS_UART_INUM)
+
+#define ETS_FRC1_INTR_ENABLE() \
+    ETS_INTR_ENABLE(ETS_FRC_TIMER1_INUM)
+
+#define ETS_FRC1_INTR_DISABLE() \
+    ETS_INTR_DISABLE(ETS_FRC_TIMER1_INUM)
+
+#define ETS_GPIO_INTR_ENABLE() \
+    ETS_INTR_ENABLE(ETS_GPIO_INUM)
+
+#define ETS_GPIO_INTR_DISABLE() \
+    ETS_INTR_DISABLE(ETS_GPIO_INUM)
+
+#define ETS_SPI_INTR_ENABLE() \
+    ETS_INTR_ENABLE(ETS_SPI_INUM)
+
+#define ETS_SPI_INTR_DISABLE() \
+    ETS_INTR_DISABLE(ETS_SPI_INUM)
+
+#define ETS_SDIO_INTR_ENABLE() \
+    ETS_INTR_ENABLE(ETS_SDIO_INUM)
+
+#define ETS_SDIO_INTR_DISABLE() \
+    ETS_INTR_DISABLE(ETS_SDIO_INUM)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* _ETS_SYS_H */
+#endif /* ETS_SYS_H */
diff --git a/cpu/esp8266/vendor/espressif/gpio.h b/cpu/esp8266/vendor/espressif/gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..54c4c36c3687ebc9bf1476beefb2368bf569ac1c
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/gpio.h
@@ -0,0 +1,129 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+#ifndef GPIO_H
+#define GPIO_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4)
+
+#define GPIO_ID_IS_PIN_REGISTER(reg_id) \
+    ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1)))
+
+#define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0)
+
+typedef enum {
+    GPIO_PIN_INTR_DISABLE = 0,
+    GPIO_PIN_INTR_POSEDGE = 1,
+    GPIO_PIN_INTR_NEGEDGE = 2,
+    GPIO_PIN_INTR_ANYEDGE = 3,
+    GPIO_PIN_INTR_LOLEVEL = 4,
+    GPIO_PIN_INTR_HILEVEL = 5
+} GPIO_INT_TYPE;
+
+#define GPIO_OUTPUT_SET(gpio_no, bit_value) \
+    gpio_output_set((bit_value)<<gpio_no, ((~(bit_value))&0x01)<<gpio_no, 1<<gpio_no,0)
+#define GPIO_DIS_OUTPUT(gpio_no)     gpio_output_set(0,0,0, 1<<gpio_no)
+#define GPIO_INPUT_GET(gpio_no)     ((gpio_input_get()>>gpio_no)&BIT0)
+
+/* GPIO interrupt handler, registered through gpio_intr_handler_register */
+typedef void (* gpio_intr_handler_fn_t)(uint32 intr_mask, void *arg);
+
+
+/*
+ * Initialize GPIO.  This includes reading the GPIO Configuration DataSet
+ * to initialize "output enables" and pin configurations for each gpio pin.
+ * Must be called once during startup.
+ */
+// conflicts with RIOT's gpio.h // void gpio_init(void);
+
+/*
+ * Change GPIO pin output by setting, clearing, or disabling pins.
+ * In general, it is expected that a bit will be set in at most one
+ * of these masks.  If a bit is clear in all masks, the output state
+ * remains unchanged.
+ *
+ * There is no particular ordering guaranteed; so if the order of
+ * writes is significant, calling code should divide a single call
+ * into multiple calls.
+ */
+void gpio_output_set(uint32 set_mask,
+                     uint32 clear_mask,
+                     uint32 enable_mask,
+                     uint32 disable_mask);
+
+/*
+ * Sample the value of GPIO input pins and returns a bitmask.
+ */
+uint32 gpio_input_get(void);
+
+/*
+ * Set the specified GPIO register to the specified value.
+ * This is a very general and powerful interface that is not
+ * expected to be used during normal operation.  It is intended
+ * mainly for debug, or for unusual requirements.
+ */
+void gpio_register_set(uint32 reg_id, uint32 value);
+
+/* Get the current value of the specified GPIO register. */
+uint32 gpio_register_get(uint32 reg_id);
+
+/*
+ * Register an application-specific interrupt handler for GPIO pin
+ * interrupts.  Once the interrupt handler is called, it will not
+ * be called again until after a call to gpio_intr_ack.  Any GPIO
+ * interrupts that occur during the interim are masked.
+ *
+ * The application-specific handler is called with a mask of
+ * pending GPIO interrupts.  After processing pin interrupts, the
+ * application-specific handler may wish to use gpio_intr_pending
+ * to check for any additional pending interrupts before it returns.
+ */
+void gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg);
+
+/* Determine which GPIO interrupts are pending. */
+uint32 gpio_intr_pending(void);
+
+/*
+ * Acknowledge GPIO interrupts.
+ * Intended to be called from the gpio_intr_handler_fn.
+ */
+void gpio_intr_ack(uint32 ack_mask);
+
+void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state);
+
+void gpio_pin_wakeup_disable(void);
+
+void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* GPIO_H */
diff --git a/cpu/esp8266/vendor/espressif/osapi.h b/cpu/esp8266/vendor/espressif/osapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..5700e547546004373aff38e8fe376887b30e7615
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/osapi.h
@@ -0,0 +1,103 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+#ifndef OSAPI_H
+#define OSAPI_H
+
+#ifndef DOXYGEN
+
+#include <string.h>
+#include "os_type.h"
+#include "user_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ets_bzero(void *s, size_t n);
+void ets_delay_us(uint16_t us);
+void ets_install_putc1(void (*p)(char c));
+
+#define os_bzero ets_bzero
+#define os_delay_us ets_delay_us
+#define os_install_putc1 ets_install_putc1
+
+int ets_memcmp(const void *str1, const void *str2, unsigned int nbyte);
+void *ets_memcpy(void *dest, const void *src, unsigned int nbyte);
+void *ets_memmove(void *dest, const void *src, unsigned int nbyte);
+void *ets_memset(void *dest, int val, unsigned int nbyte);
+
+int ets_strcmp(const char *s1, const char *s2);
+char *ets_strcpy(char *s1, const char *s2);
+int ets_strlen(const char *s);
+int ets_strncmp(const char *s1, const char *s2, unsigned int n);
+char *ets_strncpy(char *s1, const char *s2, unsigned int n);
+char *ets_strstr(const char *s1, const char *s2);
+
+#define os_memcmp ets_memcmp
+#define os_memcpy ets_memcpy
+#define os_memmove ets_memmove
+#define os_memset ets_memset
+#define os_strcat strcat
+#define os_strchr strchr
+#define os_strcmp ets_strcmp
+#define os_strcpy ets_strcpy
+#define os_strlen ets_strlen
+#define os_strncmp ets_strncmp
+#define os_strncpy ets_strncpy
+#define os_strstr ets_strstr
+
+void ets_timer_arm_new(os_timer_t *ptimer, uint32_t time, bool repeat_flag, bool ms_flag);
+void ets_timer_disarm(os_timer_t *ptimer);
+void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg);
+
+#ifdef USE_US_TIMER
+#define os_timer_arm_us(a, b, c) ets_timer_arm_new(a, b, c, 0)
+#endif
+#define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1)
+#define os_timer_disarm ets_timer_disarm
+#define os_timer_setfn ets_timer_setfn
+
+int ets_sprintf(char *str, const char *format, ...)  __attribute__ ((format (printf, 2, 3)));
+int os_printf_plus(const char *format, ...)  __attribute__ ((format (printf, 1, 2)));
+
+#define os_sprintf  ets_sprintf
+
+#ifdef USE_OPTIMIZE_PRINTF
+#define os_printf(fmt, ...) do {    \
+    static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt;    \
+    os_printf_plus(flash_str, ##__VA_ARGS__);    \
+    } while(0)
+#else
+#define os_printf    os_printf_plus
+#endif
+
+unsigned long os_random(void);
+int os_get_random(unsigned char *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* OSAPI_H */
diff --git a/cpu/esp8266/vendor/espressif/spi_flash.h b/cpu/esp8266/vendor/espressif/spi_flash.h
new file mode 100644
index 0000000000000000000000000000000000000000..215afd07b303d0c757a29ec312b87412ec50bafb
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/spi_flash.h
@@ -0,0 +1,71 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+#ifndef SPI_FLASH_H
+#define SPI_FLASH_H
+
+#ifndef DOXYGEN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    SPI_FLASH_RESULT_OK,
+    SPI_FLASH_RESULT_ERR,
+    SPI_FLASH_RESULT_TIMEOUT
+} SpiFlashOpResult;
+
+typedef struct{
+    uint32    deviceId;
+    uint32    chip_size;    // chip size in byte
+    uint32    block_size;
+    uint32  sector_size;
+    uint32  page_size;
+    uint32  status_mask;
+} SpiFlashChip;
+
+#define SPI_FLASH_SEC_SIZE      4096
+
+uint32 spi_flash_get_id(void);
+SpiFlashOpResult spi_flash_erase_sector(uint16 sec);
+SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);
+SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);
+
+typedef SpiFlashOpResult (* user_spi_flash_read)(
+        SpiFlashChip *spi,
+        uint32 src_addr,
+        uint32 *des_addr,
+        uint32 size);
+
+void spi_flash_set_read_func(user_spi_flash_read read);
+
+bool spi_flash_erase_protect_enable(void);
+bool spi_flash_erase_protect_disable(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* SPI_FLASH_H */
diff --git a/cpu/esp8266/vendor/espressif/user_interface.h b/cpu/esp8266/vendor/espressif/user_interface.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0cf3e53abc02430f5799992145cbbca617ffeaa
--- /dev/null
+++ b/cpu/esp8266/vendor/espressif/user_interface.h
@@ -0,0 +1,658 @@
+/*
+ * ESPRESSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+#ifndef USER_INTERFACE_H
+#define USER_INTERFACE_H
+
+#ifndef DOXYGEN
+
+#include "os_type.h"
+#ifdef LWIP_OPEN_SRC
+#include "lwip/ip_addr.h"
+#else
+#include "ip_addr.h"
+#endif
+
+#include "queue.h"
+#include "user_config.h"
+#include "spi_flash.h"
+#include "gpio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MAC2STR
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+
+enum rst_reason {
+    REASON_DEFAULT_RST        = 0,
+    REASON_WDT_RST            = 1,
+    REASON_EXCEPTION_RST    = 2,
+    REASON_SOFT_WDT_RST       = 3,
+    REASON_SOFT_RESTART     = 4,
+    REASON_DEEP_SLEEP_AWAKE    = 5,
+    REASON_EXT_SYS_RST      = 6
+};
+
+struct rst_info{
+    uint32 reason;
+    uint32 exccause;
+    uint32 epc1;
+    uint32 epc2;
+    uint32 epc3;
+    uint32 excvaddr;
+    uint32 depc;
+};
+
+struct rst_info* system_get_rst_info(void);
+
+#define UPGRADE_FW_BIN1         0x00
+#define UPGRADE_FW_BIN2         0x01
+
+void system_restore(void);
+void system_restart(void);
+
+bool system_deep_sleep_set_option(uint8 option);
+bool system_deep_sleep(uint64 time_in_us);
+bool system_deep_sleep_instant(uint64 time_in_us);
+
+uint8 system_upgrade_userbin_check(void);
+void system_upgrade_reboot(void);
+uint8 system_upgrade_flag_check(void);
+void system_upgrade_flag_set(uint8 flag);
+
+void system_timer_reinit(void);
+uint32 system_get_time(void);
+
+/* user task's prio must be 0/1/2 !!!*/
+enum {
+    USER_TASK_PRIO_0 = 0,
+    USER_TASK_PRIO_1,
+    USER_TASK_PRIO_2,
+    USER_TASK_PRIO_MAX
+};
+
+bool system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen);
+bool system_os_post(uint8 prio, os_signal_t sig, os_param_t par);
+
+void system_print_meminfo(void);
+uint32 system_get_free_heap_size(void);
+
+void system_set_os_print(uint8 onoff);
+uint8 system_get_os_print(void);
+
+uint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec);
+
+uint32 system_get_chip_id(void);
+
+typedef void (* init_done_cb_t)(void);
+
+void system_init_done_cb(init_done_cb_t cb);
+
+uint32 system_rtc_clock_cali_proc(void);
+uint32 system_get_rtc_time(void);
+
+bool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size);
+bool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size);
+
+void system_uart_swap(void);
+void system_uart_de_swap(void);
+
+uint16 system_adc_read(void);
+void system_adc_read_fast(uint16 *adc_addr, uint16 adc_num, uint8 adc_clk_div);
+uint16 system_get_vdd33(void);
+
+const char *system_get_sdk_version(void);
+
+#define SYS_BOOT_ENHANCE_MODE    0
+#define SYS_BOOT_NORMAL_MODE    1
+
+#define SYS_BOOT_NORMAL_BIN        0
+#define SYS_BOOT_TEST_BIN        1
+
+uint8 system_get_boot_version(void);
+uint32 system_get_userbin_addr(void);
+uint8 system_get_boot_mode(void);
+bool system_restart_enhance(uint8 bin_type, uint32 bin_addr);
+
+#define SYS_CPU_80MHZ    80
+#define SYS_CPU_160MHZ    160
+
+bool system_update_cpu_freq(uint8 freq);
+uint8 system_get_cpu_freq(void);
+
+enum flash_size_map {
+    FLASH_SIZE_4M_MAP_256_256 = 0,  /**<  Flash size : 4Mbits. Map : 256KBytes + 256KBytes */
+    FLASH_SIZE_2M,                  /**<  Flash size : 2Mbits. Map : 256KBytes */
+    FLASH_SIZE_8M_MAP_512_512,      /**<  Flash size : 8Mbits. Map : 512KBytes + 512KBytes */
+    FLASH_SIZE_16M_MAP_512_512,     /**<  Flash size : 16Mbits. Map : 512KBytes + 512KBytes */
+    FLASH_SIZE_32M_MAP_512_512,     /**<  Flash size : 32Mbits. Map : 512KBytes + 512KBytes */
+    FLASH_SIZE_16M_MAP_1024_1024,   /**<  Flash size : 16Mbits. Map : 1024KBytes + 1024KBytes */
+    FLASH_SIZE_32M_MAP_1024_1024,    /**<  Flash size : 32Mbits. Map : 1024KBytes + 1024KBytes */
+    FLASH_SIZE_32M_MAP_2048_2048,    /**<  attention: don't support now ,just compatible for nodemcu;
+                                           Flash size : 32Mbits. Map : 2048KBytes + 2048KBytes */
+    FLASH_SIZE_64M_MAP_1024_1024,     /**<  Flash size : 64Mbits. Map : 1024KBytes + 1024KBytes */
+    FLASH_SIZE_128M_MAP_1024_1024     /**<  Flash size : 128Mbits. Map : 1024KBytes + 1024KBytes */
+};
+
+enum flash_size_map system_get_flash_size_map(void);
+
+void system_phy_set_max_tpw(uint8 max_tpw);
+void system_phy_set_tpw_via_vdd33(uint16 vdd33);
+void system_phy_set_rfoption(uint8 option);
+void system_phy_set_powerup_option(uint8 option);
+void system_phy_freq_trace_enable(bool enable);
+
+bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len);
+bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len);
+
+void system_soft_wdt_stop(void);
+void system_soft_wdt_restart(void);
+void system_soft_wdt_feed(void);
+
+void system_show_malloc(void);
+
+#define NULL_MODE       0x00
+#define STATION_MODE    0x01
+#define SOFTAP_MODE     0x02
+#define STATIONAP_MODE  0x03
+
+typedef enum _auth_mode {
+    AUTH_OPEN           = 0,
+    AUTH_WEP,
+    AUTH_WPA_PSK,
+    AUTH_WPA2_PSK,
+    AUTH_WPA_WPA2_PSK,
+    AUTH_MAX
+} AUTH_MODE;
+
+uint8 wifi_get_opmode(void);
+uint8 wifi_get_opmode_default(void);
+bool wifi_set_opmode(uint8 opmode);
+bool wifi_set_opmode_current(uint8 opmode);
+uint8 wifi_get_broadcast_if(void);
+bool wifi_set_broadcast_if(uint8 interface);
+
+struct bss_info {
+    STAILQ_ENTRY(bss_info)     next;
+
+    uint8 bssid[6];
+    uint8 ssid[32];
+    uint8 ssid_len;
+    uint8 channel;
+    sint8 rssi;
+    AUTH_MODE authmode;
+    uint8 is_hidden;
+    sint16 freq_offset;
+    sint16 freqcal_val;
+    uint8 *esp_mesh_ie;
+    uint8 simple_pair;
+};
+
+typedef struct _scaninfo {
+    STAILQ_HEAD(, bss_info) *pbss;
+    struct espconn *pespconn;
+    uint8 totalpage;
+    uint8 pagenum;
+    uint8 page_sn;
+    uint8 data_cnt;
+} scaninfo;
+
+typedef void (* scan_done_cb_t)(void *arg, STATUS status);
+
+struct station_config {
+    uint8 ssid[32];
+    uint8 password[64];
+    uint8 bssid_set;    // Note: If bssid_set is 1, station will just connect to the router
+                        // with both ssid[] and bssid[] matched. Please check about this.
+    uint8 bssid[6];
+};
+
+bool wifi_station_get_config(struct station_config *config);
+bool wifi_station_get_config_default(struct station_config *config);
+bool wifi_station_set_config(struct station_config *config);
+bool wifi_station_set_config_current(struct station_config *config);
+
+bool wifi_station_connect(void);
+bool wifi_station_disconnect(void);
+
+sint8 wifi_station_get_rssi(void);
+
+struct scan_config {
+    uint8 *ssid;    // Note: ssid == NULL, don't filter ssid.
+    uint8 *bssid;    // Note: bssid == NULL, don't filter bssid.
+    uint8 channel;    // Note: channel == 0, scan all channels, otherwise scan set channel.
+    uint8 show_hidden;    // Note: show_hidden == 1, can get hidden ssid routers' info.
+};
+
+bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb);
+
+uint8 wifi_station_get_auto_connect(void);
+bool wifi_station_set_auto_connect(uint8 set);
+
+bool wifi_station_set_reconnect_policy(bool set);
+
+enum {
+    STATION_IDLE = 0,
+    STATION_CONNECTING,
+    STATION_WRONG_PASSWORD,
+    STATION_NO_AP_FOUND,
+    STATION_CONNECT_FAIL,
+    STATION_GOT_IP
+};
+
+enum dhcp_status {
+    DHCP_STOPPED,
+    DHCP_STARTED
+};
+
+uint8 wifi_station_get_connect_status(void);
+
+uint8 wifi_station_get_current_ap_id(void);
+bool wifi_station_ap_change(uint8 current_ap_id);
+bool wifi_station_ap_number_set(uint8 ap_number);
+uint8 wifi_station_get_ap_info(struct station_config config[]);
+
+bool wifi_station_dhcpc_start(void);
+bool wifi_station_dhcpc_stop(void);
+enum dhcp_status wifi_station_dhcpc_status(void);
+bool wifi_station_dhcpc_set_maxtry(uint8 num);
+
+char* wifi_station_get_hostname(void);
+bool wifi_station_set_hostname(char *name);
+
+int wifi_station_set_cert_key(uint8 *client_cert, int client_cert_len,
+    uint8 *private_key, int private_key_len,
+    uint8 *private_key_passwd, int private_key_passwd_len);
+void wifi_station_clear_cert_key(void);
+int wifi_station_set_username(uint8 *username, int len);
+void wifi_station_clear_username(void);
+
+struct softap_config {
+    uint8 ssid[32];
+    uint8 password[64];
+    uint8 ssid_len;    // Note: Recommend to set it according to your ssid
+    uint8 channel;    // Note: support 1 ~ 13
+    AUTH_MODE authmode;    // Note: Don't support AUTH_WEP in softAP mode.
+    uint8 ssid_hidden;    // Note: default 0
+    uint8 max_connection;    // Note: default 4, max 4
+    uint16 beacon_interval;    // Note: support 100 ~ 60000 ms, default 100
+};
+
+bool wifi_softap_get_config(struct softap_config *config);
+bool wifi_softap_get_config_default(struct softap_config *config);
+bool wifi_softap_set_config(struct softap_config *config);
+bool wifi_softap_set_config_current(struct softap_config *config);
+
+struct station_info {
+    STAILQ_ENTRY(station_info)    next;
+
+    uint8 bssid[6];
+    struct ip_addr ip;
+};
+
+struct dhcps_lease {
+    bool enable;
+    struct ip_addr start_ip;
+    struct ip_addr end_ip;
+};
+
+enum dhcps_offer_option{
+    OFFER_START = 0x00,
+    OFFER_ROUTER = 0x01,
+    OFFER_END
+};
+
+uint8 wifi_softap_get_station_num(void);
+struct station_info * wifi_softap_get_station_info(void);
+void wifi_softap_free_station_info(void);
+
+bool wifi_softap_dhcps_start(void);
+bool wifi_softap_dhcps_stop(void);
+
+bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
+bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please);
+uint32 wifi_softap_get_dhcps_lease_time(void);
+bool wifi_softap_set_dhcps_lease_time(uint32 minute);
+bool wifi_softap_reset_dhcps_lease_time(void);
+
+enum dhcp_status wifi_softap_dhcps_status(void);
+bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg);
+
+#define STATION_IF      0x00
+#define SOFTAP_IF       0x01
+
+bool wifi_get_ip_info(uint8 if_index, struct ip_info *info);
+bool wifi_set_ip_info(uint8 if_index, struct ip_info *info);
+bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr);
+bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr);
+
+uint8 wifi_get_channel(void);
+bool wifi_set_channel(uint8 channel);
+
+void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func);
+void wifi_status_led_uninstall(void);
+
+/** Get the absolute difference between 2 u32_t values (correcting overflows)
+ * 'a' is expected to be 'higher' (without overflow) than 'b'. */
+#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
+
+void wifi_promiscuous_enable(uint8 promiscuous);
+
+typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);
+
+void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
+
+void wifi_promiscuous_set_mac(const uint8_t *address);
+
+enum phy_mode {
+    PHY_MODE_11B    = 1,
+    PHY_MODE_11G    = 2,
+    PHY_MODE_11N    = 3
+};
+
+enum phy_mode wifi_get_phy_mode(void);
+bool wifi_set_phy_mode(enum phy_mode mode);
+
+enum sleep_type {
+    NONE_SLEEP_T    = 0,
+    LIGHT_SLEEP_T,
+    MODEM_SLEEP_T
+};
+
+bool wifi_set_sleep_type(enum sleep_type type);
+enum sleep_type wifi_get_sleep_type(void);
+
+void wifi_fpm_open(void);
+void wifi_fpm_close(void);
+void wifi_fpm_do_wakeup(void);
+sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us);
+void wifi_fpm_set_sleep_type(enum sleep_type type);
+enum sleep_type wifi_fpm_get_sleep_type(void);
+
+typedef void (*fpm_wakeup_cb)(void);
+void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb);
+
+void wifi_fpm_auto_sleep_set_in_null_mode(uint8 req);
+
+enum {
+    EVENT_STAMODE_CONNECTED = 0,
+    EVENT_STAMODE_DISCONNECTED,
+    EVENT_STAMODE_AUTHMODE_CHANGE,
+    EVENT_STAMODE_GOT_IP,
+    EVENT_STAMODE_DHCP_TIMEOUT,
+    EVENT_SOFTAPMODE_STACONNECTED,
+    EVENT_SOFTAPMODE_STADISCONNECTED,
+    EVENT_SOFTAPMODE_PROBEREQRECVED,
+    EVENT_OPMODE_CHANGED,
+    EVENT_MAX
+};
+
+enum {
+    REASON_UNSPECIFIED              = 1,
+    REASON_AUTH_EXPIRE              = 2,
+    REASON_AUTH_LEAVE               = 3,
+    REASON_ASSOC_EXPIRE             = 4,
+    REASON_ASSOC_TOOMANY            = 5,
+    REASON_NOT_AUTHED               = 6,
+    REASON_NOT_ASSOCED              = 7,
+    REASON_ASSOC_LEAVE              = 8,
+    REASON_ASSOC_NOT_AUTHED         = 9,
+    REASON_DISASSOC_PWRCAP_BAD      = 10,  /* 11h */
+    REASON_DISASSOC_SUPCHAN_BAD     = 11,  /* 11h */
+    REASON_IE_INVALID               = 13,  /* 11i */
+    REASON_MIC_FAILURE              = 14,  /* 11i */
+    REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,  /* 11i */
+    REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,  /* 11i */
+    REASON_IE_IN_4WAY_DIFFERS       = 17,  /* 11i */
+    REASON_GROUP_CIPHER_INVALID     = 18,  /* 11i */
+    REASON_PAIRWISE_CIPHER_INVALID  = 19,  /* 11i */
+    REASON_AKMP_INVALID             = 20,  /* 11i */
+    REASON_UNSUPP_RSN_IE_VERSION    = 21,  /* 11i */
+    REASON_INVALID_RSN_IE_CAP       = 22,  /* 11i */
+    REASON_802_1X_AUTH_FAILED       = 23,  /* 11i */
+    REASON_CIPHER_SUITE_REJECTED    = 24,  /* 11i */
+
+    REASON_BEACON_TIMEOUT           = 200,
+    REASON_NO_AP_FOUND              = 201,
+    REASON_AUTH_FAIL                = 202,
+    REASON_ASSOC_FAIL                = 203,
+    REASON_HANDSHAKE_TIMEOUT        = 204,
+};
+
+typedef struct {
+    uint8 ssid[32];
+    uint8 ssid_len;
+    uint8 bssid[6];
+    uint8 channel;
+} Event_StaMode_Connected_t;
+
+typedef struct {
+    uint8 ssid[32];
+    uint8 ssid_len;
+    uint8 bssid[6];
+    uint8 reason;
+} Event_StaMode_Disconnected_t;
+
+typedef struct {
+    uint8 old_mode;
+    uint8 new_mode;
+} Event_StaMode_AuthMode_Change_t;
+
+typedef struct {
+    struct ip_addr ip;
+    struct ip_addr mask;
+    struct ip_addr gw;
+} Event_StaMode_Got_IP_t;
+
+typedef struct {
+    uint8 mac[6];
+    uint8 aid;
+} Event_SoftAPMode_StaConnected_t;
+
+typedef struct {
+    uint8 mac[6];
+    uint8 aid;
+} Event_SoftAPMode_StaDisconnected_t;
+
+typedef struct {
+    int rssi;
+    uint8 mac[6];
+} Event_SoftAPMode_ProbeReqRecved_t;
+
+typedef struct {
+    uint8 old_opmode;
+    uint8 new_opmode;
+} Event_OpMode_Change_t;
+
+typedef union {
+    Event_StaMode_Connected_t            connected;
+    Event_StaMode_Disconnected_t        disconnected;
+    Event_StaMode_AuthMode_Change_t        auth_change;
+    Event_StaMode_Got_IP_t                got_ip;
+    Event_SoftAPMode_StaConnected_t        sta_connected;
+    Event_SoftAPMode_StaDisconnected_t    sta_disconnected;
+    Event_SoftAPMode_ProbeReqRecved_t   ap_probereqrecved;
+    Event_OpMode_Change_t               opmode_changed;
+} Event_Info_u;
+
+typedef struct _esp_event {
+    uint32 event;
+    Event_Info_u event_info;
+} System_Event_t;
+
+typedef void (* wifi_event_handler_cb_t)(System_Event_t *event);
+
+void wifi_set_event_handler_cb(wifi_event_handler_cb_t cb);
+
+typedef enum wps_type {
+    WPS_TYPE_DISABLE = 0,
+    WPS_TYPE_PBC,
+    WPS_TYPE_PIN,
+    WPS_TYPE_DISPLAY,
+    WPS_TYPE_MAX,
+} WPS_TYPE_t;
+
+enum wps_cb_status {
+    WPS_CB_ST_SUCCESS = 0,
+    WPS_CB_ST_FAILED,
+    WPS_CB_ST_TIMEOUT,
+    WPS_CB_ST_WEP,
+};
+
+bool wifi_wps_enable(WPS_TYPE_t wps_type);
+bool wifi_wps_disable(void);
+bool wifi_wps_start(void);
+
+typedef void (*wps_st_cb_t)(int status);
+bool wifi_set_wps_cb(wps_st_cb_t cb);
+
+typedef void (*freedom_outside_cb_t)(uint8 status);
+int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb);
+void wifi_unregister_send_pkt_freedom_cb(void);
+int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq);
+
+int wifi_rfid_locp_recv_open(void);
+void wifi_rfid_locp_recv_close(void);
+
+typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi);
+int wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb);
+void wifi_unregister_rfid_locp_recv_cb(void);
+
+enum FIXED_RATE {
+        PHY_RATE_48       = 0x8,
+        PHY_RATE_24       = 0x9,
+        PHY_RATE_12       = 0xA,
+        PHY_RATE_6        = 0xB,
+        PHY_RATE_54       = 0xC,
+        PHY_RATE_36       = 0xD,
+        PHY_RATE_18       = 0xE,
+        PHY_RATE_9        = 0xF,
+};
+
+#define FIXED_RATE_MASK_NONE    0x00
+#define FIXED_RATE_MASK_STA        0x01
+#define FIXED_RATE_MASK_AP        0x02
+#define FIXED_RATE_MASK_ALL        0x03
+
+int wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate);
+int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate);
+
+enum support_rate {
+    RATE_11B5M    = 0,
+    RATE_11B11M    = 1,
+    RATE_11B1M    = 2,
+    RATE_11B2M    = 3,
+    RATE_11G6M    = 4,
+    RATE_11G12M    = 5,
+    RATE_11G24M    = 6,
+    RATE_11G48M    = 7,
+    RATE_11G54M    = 8,
+    RATE_11G9M    = 9,
+    RATE_11G18M    = 10,
+    RATE_11G36M    = 11,
+};
+
+int wifi_set_user_sup_rate(uint8 min, uint8 max);
+
+enum RATE_11B_ID {
+    RATE_11B_B11M    = 0,
+    RATE_11B_B5M    = 1,
+    RATE_11B_B2M    = 2,
+    RATE_11B_B1M    = 3,
+};
+
+enum RATE_11G_ID {
+    RATE_11G_G54M    = 0,
+    RATE_11G_G48M    = 1,
+    RATE_11G_G36M    = 2,
+    RATE_11G_G24M    = 3,
+    RATE_11G_G18M    = 4,
+    RATE_11G_G12M    = 5,
+    RATE_11G_G9M    = 6,
+    RATE_11G_G6M    = 7,
+    RATE_11G_B5M    = 8,
+    RATE_11G_B2M    = 9,
+    RATE_11G_B1M    = 10
+};
+
+enum RATE_11N_ID {
+    RATE_11N_MCS7S    = 0,
+    RATE_11N_MCS7    = 1,
+    RATE_11N_MCS6    = 2,
+    RATE_11N_MCS5    = 3,
+    RATE_11N_MCS4    = 4,
+    RATE_11N_MCS3    = 5,
+    RATE_11N_MCS2    = 6,
+    RATE_11N_MCS1    = 7,
+    RATE_11N_MCS0    = 8,
+    RATE_11N_B5M    = 9,
+    RATE_11N_B2M    = 10,
+    RATE_11N_B1M    = 11
+};
+
+#define RC_LIMIT_11B        0
+#define RC_LIMIT_11G        1
+#define RC_LIMIT_11N        2
+#define RC_LIMIT_P2P_11G    3
+#define RC_LIMIT_P2P_11N    4
+#define RC_LIMIT_NUM        5
+
+#define LIMIT_RATE_MASK_NONE    0x00
+#define LIMIT_RATE_MASK_STA        0x01
+#define LIMIT_RATE_MASK_AP        0x02
+#define LIMIT_RATE_MASK_ALL        0x03
+
+bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min);
+uint8 wifi_get_user_limit_rate_mask(void);
+bool wifi_set_user_limit_rate_mask(uint8 enable_mask);
+
+enum {
+    USER_IE_BEACON = 0,
+    USER_IE_PROBE_REQ,
+    USER_IE_PROBE_RESP,
+    USER_IE_ASSOC_REQ,
+    USER_IE_ASSOC_RESP,
+    USER_IE_MAX
+};
+
+typedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi);
+
+bool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len);
+int wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb);
+void wifi_unregister_user_ie_manufacturer_recv_cb(void);
+
+void wifi_enable_gpio_wakeup(uint32 i, GPIO_INT_TYPE intr_status);
+void wifi_disable_gpio_wakeup(void);
+
+void uart_div_modify(uint8 uart_no, uint32 DivLatchValue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DOXYGEN
+#endif /* USER_INTERFACE_H */
diff --git a/cpu/esp8266/vendor/xtensa/Makefile b/cpu/esp8266/vendor/xtensa/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..350d5aaf0c8331a6c82895952ec58bcb30c79cd3
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/Makefile
@@ -0,0 +1,3 @@
+MODULE=xtensa
+
+include $(RIOTBASE)/Makefile.base
diff --git a/cpu/esp8266/vendor/xtensa/README.md b/cpu/esp8266/vendor/xtensa/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6cce4e5f16ffba534b9362b19aa5e5deccc11ee1
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/README.md
@@ -0,0 +1,30 @@
+All files in this directory are from the [FreeRTOS port for Xtensa](https://github.com/tensilica/freertos) configurable processors and Diamond processors. All of these files are copyright of Cadence Design Systems Inc., see below.
+
+Some of the files are slightly modified for the RIOT OS port.
+
+Please note the following copyright notices for all these files:
+
+```
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+******************************************************************************/
+```
diff --git a/cpu/esp8266/vendor/xtensa/portasm.S b/cpu/esp8266/vendor/xtensa/portasm.S
new file mode 100644
index 0000000000000000000000000000000000000000..32391dc016602107d4969a78a317398c91c61bad
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/portasm.S
@@ -0,0 +1,620 @@
+/*
+//-----------------------------------------------------------------------------
+// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
+//
+// 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.
+//-----------------------------------------------------------------------------
+*/
+
+#ifdef RIOT_VERSION
+#include "xtensa_conf.h"
+
+#define pxCurrentTCB            sched_active_thread
+#define port_xSchedulerRunning  sched_num_threads
+#define port_switch_flag        sched_context_switch_request
+#define port_interruptNesting   irq_interrupt_nesting
+#define vTaskSwitchContext      sched_run
+#define configISR_STACK_SIZE    ISR_STACKSIZE
+
+.extern sched_active_thread
+.extern sched_num_threads
+.extern sched_context_switch_request
+.extern irq_interrupt_nesting
+#endif
+
+#include "xtensa_context.h"
+
+#define TOPOFSTACK_OFFS                 0x00    /* StackType_t *pxTopOfStack */
+#define CP_TOPOFSTACK_OFFS              0x04    /* xMPU_SETTINGS.coproc_area */
+
+/*
+*******************************************************************************
+* Interrupt stack. The size of the interrupt stack is determined by the config
+* parameter "configISR_STACK_SIZE" in FreeRTOSConfig.h
+*******************************************************************************
+*/
+    .data
+    .align      16
+    .global     port_IntStack
+port_IntStack:
+    .space      configISR_STACK_SIZE
+    .global     port_IntStackTop
+port_IntStackTop:
+    .word       0
+
+#ifndef RIOT_VERSION
+port_switch_flag:
+    .word       0
+#endif
+
+    .text
+    .literal_position
+
+/*
+*******************************************************************************
+* _frxt_setup_switch
+* void _frxt_setup_switch(void);
+*
+* Sets an internal flag indicating that a task switch is required on return
+* from interrupt handling.
+*
+*******************************************************************************
+*/
+    .global     _frxt_setup_switch
+    .type       _frxt_setup_switch,@function
+    .align      4
+_frxt_setup_switch:
+
+    ENTRY(16)
+
+    movi    a2, port_switch_flag
+    movi    a3, 1
+    s32i    a3, a2, 0
+
+    RET(16)
+
+/*
+*******************************************************************************
+*                                            _frxt_int_enter
+*                                       void _frxt_int_enter(void)
+*
+* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_ENTER function for
+* freeRTOS. Saves the rest of the interrupt context (not already saved).
+* May only be called from assembly code by the 'call0' instruction, with
+* interrupts disabled.
+* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
+*
+*******************************************************************************
+*/
+    .globl  _frxt_int_enter
+    .type   _frxt_int_enter,@function
+    .align  4
+_frxt_int_enter:
+
+    /* Save a12-13 in the stack frame as required by _xt_context_save. */
+    s32i    a12, a1, XT_STK_A12
+    s32i    a13, a1, XT_STK_A13
+
+    /* Save return address in a safe place (free a0). */
+    mov     a12, a0
+
+    /* Save the rest of the interrupted context (preserves A12-13). */
+    call0   _xt_context_save
+
+    /*
+    Save interrupted task's SP in TCB only if not nesting.
+    Manage nesting directly rather than call the generic IntEnter()
+    (in windowed ABI we can't call a C function here anyway because PS.EXCM is still set).
+    */
+
+    movi    a2,  port_xSchedulerRunning
+    movi    a3,  port_interruptNesting
+    l32i    a2,  a2, 0                  /* a2 = port_xSchedulerRunning     */
+    beqz    a2,  1f                     /* scheduler not running, no tasks */
+    l32i    a2,  a3, 0                  /* a2 = port_interruptNesting      */
+    addi    a2,  a2, 1                  /* increment nesting count         */
+    s32i    a2,  a3, 0                  /* save nesting count              */
+    bnei    a2,  1, .Lnested            /* !=0 before incr, so nested      */
+
+    movi    a2,  pxCurrentTCB
+    l32i    a2,  a2, 0                  /* a2 = current TCB                */
+    beqz    a2,  1f
+    s32i    a1,  a2, TOPOFSTACK_OFFS    /* pxCurrentTCB->pxTopOfStack = SP */
+    movi    a1,  port_IntStackTop       /* a1 = top of intr stack          */
+
+.Lnested:
+1:
+    mov     a0,  a12                    /* restore return addr and return  */
+    ret
+
+/*
+*******************************************************************************
+*                                            _frxt_int_exit
+*                                       void _frxt_int_exit(void)
+*
+* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_EXIT function for
+* FreeRTOS. If required, calls vPortYieldFromInt() to perform task context
+* switching, restore the (possibly) new task's context, and return to the
+* exit dispatcher saved in the task's stack frame at XT_STK_EXIT.
+* May only be called from assembly code by the 'call0' instruction. Does not
+* return to caller.
+* See the description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
+*
+*******************************************************************************
+*/
+    .globl  _frxt_int_exit
+    .type   _frxt_int_exit,@function
+    .align  4
+_frxt_int_exit:
+
+    movi    a2,  port_xSchedulerRunning
+    movi    a3,  port_interruptNesting
+    rsil    a0,  XCHAL_EXCM_LEVEL       /* lock out interrupts             */
+    l32i    a2,  a2, 0                  /* a2 = port_xSchedulerRunning     */
+    beqz    a2,  .Lnoswitch             /* scheduler not running, no tasks */
+    l32i    a2,  a3, 0                  /* a2 = port_interruptNesting      */
+    addi    a2,  a2, -1                 /* decrement nesting count         */
+    s32i    a2,  a3, 0                  /* save nesting count              */
+    bnez    a2,  .Lnesting              /* !=0 after decr so still nested  */
+
+    movi    a2,  pxCurrentTCB
+    l32i    a2,  a2, 0                  /* a2 = current TCB                */
+    beqz    a2,  1f                     /* no task ? go to dispatcher      */
+    l32i    a1,  a2, TOPOFSTACK_OFFS    /* SP = pxCurrentTCB->pxTopOfStack */
+
+    movi    a2,  port_switch_flag       /* address of switch flag          */
+    l32i    a3,  a2, 0                  /* a3 = port_switch_flag           */
+    beqz    a3,  .Lnoswitch             /* flag = 0 means no switch reqd   */
+    movi    a3,  0
+    s32i    a3,  a2, 0                  /* zero out the flag for next time */
+
+1:
+    /*
+    Call0 ABI callee-saved regs a12-15 need to be saved before possible preemption.
+    However a12-13 were already saved by _frxt_int_enter().
+    */
+    #ifdef __XTENSA_CALL0_ABI__
+    s32i    a14, a1, XT_STK_A14
+    s32i    a15, a1, XT_STK_A15
+    #endif
+
+    #ifdef __XTENSA_CALL0_ABI__
+    call0   vPortYieldFromInt       /* call dispatch inside the function; never returns */
+    #else
+    call4   vPortYieldFromInt       /* this one returns */
+    call0   _frxt_dispatch          /* tail-call dispatcher */
+    /* Never returns here. */
+    #endif
+
+.Lnoswitch:
+    /*
+    If we came here then about to resume the interrupted task.
+    */
+
+.Lnesting:
+    /*
+    We come here only if there was no context switch, that is if this
+    is a nested interrupt, or the interrupted task was not preempted.
+    In either case there's no need to load the SP.
+    */
+
+    /* Restore full context from interrupt stack frame */
+    call0   _xt_context_restore
+
+    /*
+    Must return via the exit dispatcher corresponding to the entrypoint from which
+    this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
+    stack frame is deallocated in the exit dispatcher.
+    */
+    l32i    a0,  a1, XT_STK_EXIT
+    ret
+
+/*
+**********************************************************************************************************
+*                                           _frxt_timer_int
+*                                      void _frxt_timer_int(void)
+*
+* Implements the Xtensa RTOS porting layer's XT_RTOS_TIMER_INT function for FreeRTOS.
+* Called every timer interrupt.
+* Manages the tick timer and calls xPortSysTickHandler() every tick.
+* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
+*
+* Callable from C (obeys ABI conventions). Implemented in assmebly code for performance.
+*
+**********************************************************************************************************
+*/
+    .globl  _frxt_timer_int
+    .type   _frxt_timer_int,@function
+    .align  4
+_frxt_timer_int:
+
+    /*
+    Xtensa timers work by comparing a cycle counter with a preset value.  Once the match occurs
+    an interrupt is generated, and the handler has to set a new cycle count into the comparator.
+    To avoid clock drift due to interrupt latency, the new cycle count is computed from the old,
+    not the time the interrupt was serviced. However if a timer interrupt is ever serviced more
+    than one tick late, it is necessary to process multiple ticks until the new cycle count is
+    in the future, otherwise the next timer interrupt would not occur until after the cycle
+    counter had wrapped (2^32 cycles later).
+
+    do {
+        ticks++;
+        old_ccompare = read_ccompare_i();
+        write_ccompare_i( old_ccompare + divisor );
+        service one tick;
+        diff = read_ccount() - old_ccompare;
+    } while ( diff > divisor );
+    */
+
+    ENTRY(16)
+    /* In RIOT-OS the timer is used in a different way and is realized in C functions. */
+    #if 0
+
+.L_xt_timer_int_catchup:
+
+    /* Update the timer comparator for the next tick. */
+    #ifdef XT_CLOCK_FREQ
+    movi    a2, XT_TICK_DIVISOR         /* a2 = comparator increment          */
+    #else
+    movi    a3, _xt_tick_divisor
+    l32i    a2, a3, 0                   /* a2 = comparator increment          */
+    #endif
+    rsr     a3, XT_CCOMPARE             /* a3 = old comparator value          */
+    add     a4, a3, a2                  /* a4 = new comparator value          */
+    wsr     a4, XT_CCOMPARE             /* update comp. and clear interrupt   */
+    esync
+
+    #ifdef __XTENSA_CALL0_ABI__
+    /* Preserve a2 and a3 across C calls. */
+    s32i    a2, sp, 4
+    s32i    a3, sp, 8
+    #endif
+
+    /* Call the FreeRTOS tick handler (see port.c). */
+    #ifdef __XTENSA_CALL0_ABI__
+    call0   xPortSysTickHandler
+    #else
+    call4   xPortSysTickHandler
+    #endif
+
+    #ifdef __XTENSA_CALL0_ABI__
+    /* Restore a2 and a3. */
+    l32i    a2, sp, 4
+    l32i    a3, sp, 8
+    #endif
+
+    /* Check if we need to process more ticks to catch up. */
+    esync                               /* ensure comparator update complete  */
+    rsr     a4, CCOUNT                  /* a4 = cycle count                   */
+    sub     a4, a4, a3                  /* diff = ccount - old comparator     */
+    blt     a2, a4, .L_xt_timer_int_catchup  /* repeat while diff > divisor */
+
+    #endif
+    RET(16)
+
+    /*
+**********************************************************************************************************
+*                                           _frxt_tick_timer_init
+*                                      void _frxt_tick_timer_init(void)
+*
+* Initialize timer and timer interrrupt handler (_xt_tick_divisor_init() has already been been called).
+* Callable from C (obeys ABI conventions on entry).
+*
+**********************************************************************************************************
+*/
+#if 0
+    .globl  _frxt_tick_timer_init
+    .type   _frxt_tick_timer_init,@function
+    .align  4
+_frxt_tick_timer_init:
+
+    ENTRY(16)
+
+    /* Set up the periodic tick timer (assume enough time to complete init). */
+    #ifdef XT_CLOCK_FREQ
+    movi    a3, XT_TICK_DIVISOR
+    #else
+    movi    a2, _xt_tick_divisor
+    l32i    a3, a2, 0
+    #endif
+    rsr     a2, CCOUNT              /* current cycle count */
+    add     a2, a2, a3              /* time of first timer interrupt */
+    wsr     a2, XT_CCOMPARE         /* set the comparator */
+
+    /*
+    Enable the timer interrupt at the device level. Don't write directly
+    to the INTENABLE register because it may be virtualized.
+    */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a2, XT_TIMER_INTEN
+    call0   xt_ints_on
+    #else
+    movi    a6, XT_TIMER_INTEN
+    call4   xt_ints_on
+    #endif
+
+    RET(16)
+#endif
+
+/*
+**********************************************************************************************************
+*                                    DISPATCH THE HIGH READY TASK
+*                                     void _frxt_dispatch(void)
+*
+* Switch context to the highest priority ready task, restore its state and dispatch control to it.
+*
+* This is a common dispatcher that acts as a shared exit path for all the context switch functions
+* including vPortYield() and vPortYieldFromInt(), all of which tail-call this dispatcher
+* (for windowed ABI vPortYieldFromInt() calls it indirectly via _frxt_int_exit() ).
+*
+* The Xtensa port uses different stack frames for solicited and unsolicited task suspension (see
+* comments on stack frames in xtensa_context.h). This function restores the state accordingly.
+* If restoring a task that solicited entry, restores the minimal state and leaves CPENABLE clear.
+* If restoring a task that was preempted, restores all state including the task's CPENABLE.
+*
+* Entry:
+*   pxCurrentTCB  points to the TCB of the task to suspend,
+*   Because it is tail-called without a true function entrypoint, it needs no 'entry' instruction.
+*
+* Exit:
+*   If incoming task called vPortYield() (solicited), this function returns as if from vPortYield().
+*   If incoming task was preempted by an interrupt, this function jumps to exit dispatcher.
+*
+**********************************************************************************************************
+*/
+    .globl  _frxt_dispatch
+    .type   _frxt_dispatch,@function
+    .align  4
+_frxt_dispatch:
+
+    #ifdef __XTENSA_CALL0_ABI__
+    call0   vTaskSwitchContext  // Get next TCB to resume
+    movi    a2, pxCurrentTCB
+    #else
+    movi    a2, pxCurrentTCB
+    call4   vTaskSwitchContext  // Get next TCB to resume
+    #endif
+    l32i    a3,  a2, 0
+    l32i    sp,  a3, TOPOFSTACK_OFFS     /* SP = next_TCB->pxTopOfStack;  */
+    s32i    a3,  a2, 0
+
+    /* Determine the type of stack frame. */
+    l32i    a2,  sp, XT_STK_EXIT        /* exit dispatcher or solicited flag */
+    bnez    a2,  .L_frxt_dispatch_stk
+
+.L_frxt_dispatch_sol:
+
+    /* Solicited stack frame. Restore minimal context and return from vPortYield(). */
+    l32i    a3,  sp, XT_SOL_PS
+    #ifdef __XTENSA_CALL0_ABI__
+    l32i    a12, sp, XT_SOL_A12
+    l32i    a13, sp, XT_SOL_A13
+    l32i    a14, sp, XT_SOL_A14
+    l32i    a15, sp, XT_SOL_A15
+    #endif
+    l32i    a0,  sp, XT_SOL_PC
+    #if XCHAL_CP_NUM > 0
+    /* Ensure wsr.CPENABLE is complete (should be, it was cleared on entry). */
+    rsync
+    #endif
+    /* As soons as PS is restored, interrupts can happen. No need to sync PS. */
+    wsr     a3,  PS
+    #ifdef __XTENSA_CALL0_ABI__
+    addi    sp,  sp, XT_SOL_FRMSZ
+    ret
+    #else
+    retw
+    #endif
+
+.L_frxt_dispatch_stk:
+
+    #if XCHAL_CP_NUM > 0
+    /* Restore CPENABLE from task's co-processor save area. */
+    movi    a3, pxCurrentTCB            /* cp_state =                       */
+    l32i    a3, a3, 0
+    l32i    a2, a3, CP_TOPOFSTACK_OFFS     /* StackType_t                       *pxStack; */
+    l16ui    a3, a2, XT_CPENABLE         /* CPENABLE = cp_state->cpenable;   */
+    wsr     a3, CPENABLE
+    #endif
+
+    /* Interrupt stack frame. Restore full context and return to exit dispatcher. */
+    call0   _xt_context_restore
+
+    /* In Call0 ABI, restore callee-saved regs (A12, A13 already restored). */
+    #ifdef __XTENSA_CALL0_ABI__
+    l32i    a14, sp, XT_STK_A14
+    l32i    a15, sp, XT_STK_A15
+    #endif
+
+    #if XCHAL_CP_NUM > 0
+    /* Ensure wsr.CPENABLE has completed. */
+    rsync
+    #endif
+
+    /*
+    Must return via the exit dispatcher corresponding to the entrypoint from which
+    this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt
+    stack frame is deallocated in the exit dispatcher.
+    */
+    l32i    a0, sp, XT_STK_EXIT
+    ret
+
+
+/*
+**********************************************************************************************************
+*                            PERFORM A SOLICTED CONTEXT SWITCH (from a task)
+*                                        void vPortYield(void)
+*
+* This function saves the minimal state needed for a solicited task suspension, clears CPENABLE,
+* then tail-calls the dispatcher _frxt_dispatch() to perform the actual context switch
+*
+* At Entry:
+*   pxCurrentTCB  points to the TCB of the task to suspend
+*   Callable from C (obeys ABI conventions on entry).
+*
+* Does not return to caller.
+*
+**********************************************************************************************************
+*/
+    .globl  vPortYield
+    .type   vPortYield,@function
+    .align  4
+vPortYield:
+
+    #ifdef __XTENSA_CALL0_ABI__
+    addi    sp,  sp, -XT_SOL_FRMSZ
+    #else
+    entry   sp,  XT_SOL_FRMSZ
+    #endif
+
+    rsr     a2,  PS
+    s32i    a0,  sp, XT_SOL_PC
+    s32i    a2,  sp, XT_SOL_PS
+    #ifdef __XTENSA_CALL0_ABI__
+    s32i    a12, sp, XT_SOL_A12         /* save callee-saved registers      */
+    s32i    a13, sp, XT_SOL_A13
+    s32i    a14, sp, XT_SOL_A14
+    s32i    a15, sp, XT_SOL_A15
+    #else
+    /* Spill register windows. Calling xthal_window_spill() causes extra    */
+    /* spills and reloads, so we will set things up to call the _nw version */
+    /* instead to save cycles.                                              */
+    movi    a6,  ~(PS_WOE_MASK|PS_INTLEVEL_MASK)  /* spills a4-a7 if needed */
+    and     a2,  a2, a6                           /* clear WOE, INTLEVEL    */
+    addi    a2,  a2, XCHAL_EXCM_LEVEL             /* set INTLEVEL           */
+    wsr     a2,  PS
+    rsync
+    call0   xthal_window_spill_nw
+    l32i    a2,  sp, XT_SOL_PS                    /* restore PS             */
+    wsr     a2,  PS
+    #endif
+
+    rsil    a2,  XCHAL_EXCM_LEVEL       /* disable low/med interrupts       */
+
+    #if XCHAL_CP_NUM > 0
+    /* Save coprocessor callee-saved state (if any). At this point CPENABLE */
+    /* should still reflect which CPs were in use (enabled).                */
+    call0   _xt_coproc_savecs
+    #endif
+
+    movi    a2,  pxCurrentTCB
+    movi    a3,  0
+    l32i    a2,  a2, 0                  /* a2 = pxCurrentTCB                */
+    s32i    a3,  sp, XT_SOL_EXIT        /* 0 to flag as solicited frame     */
+    s32i    sp,  a2, TOPOFSTACK_OFFS    /* pxCurrentTCB->pxTopOfStack = SP  */
+
+    #if XCHAL_CP_NUM > 0
+    /* Clear CPENABLE, also in task's co-processor state save area. */
+    l32i    a2,  a2, CP_TOPOFSTACK_OFFS /* a2 = pxCurrentTCB->cp_state      */
+    movi    a3,  0
+    wsr     a3,  CPENABLE
+    beqz    a2,  1f
+    s16i     a3,  a2, XT_CPENABLE        /* clear saved cpenable             */
+1:
+    #endif
+
+    /* Tail-call dispatcher. */
+    call0   _frxt_dispatch
+    /* Never reaches here. */
+
+
+/*
+**********************************************************************************************************
+*                         PERFORM AN UNSOLICITED CONTEXT SWITCH (from an interrupt)
+*                                        void vPortYieldFromInt(void)
+*
+* This calls the context switch hook (removed), saves and clears CPENABLE, then tail-calls the dispatcher
+* _frxt_dispatch() to perform the actual context switch.
+*
+* At Entry:
+*   Interrupted task context has been saved in an interrupt stack frame at pxCurrentTCB->pxTopOfStack.
+*   pxCurrentTCB  points to the TCB of the task to suspend,
+*   Callable from C (obeys ABI conventions on entry).
+*
+* At Exit:
+*   Windowed ABI defers the actual context switch until the stack is unwound to interrupt entry.
+*   Call0 ABI tail-calls the dispatcher directly (no need to unwind) so does not return to caller.
+*
+**********************************************************************************************************
+*/
+    .globl  vPortYieldFromInt
+    .type   vPortYieldFromInt,@function
+    .align  4
+vPortYieldFromInt:
+
+    ENTRY(16)
+
+    #if XCHAL_CP_NUM > 0
+    /* Save CPENABLE in task's co-processor save area, and clear CPENABLE.  */
+    movi    a3, pxCurrentTCB            /* cp_state =                       */
+    l32i    a3, a3, 0
+    l32i    a2, a3, CP_TOPOFSTACK_OFFS
+
+    rsr     a3, CPENABLE
+    s16i     a3, a2, XT_CPENABLE         /* cp_state->cpenable = CPENABLE;   */
+    movi    a3, 0
+    wsr     a3, CPENABLE                /* disable all co-processors        */
+    #endif
+
+    #ifdef __XTENSA_CALL0_ABI__
+    /* Tail-call dispatcher. */
+    call0   _frxt_dispatch
+    /* Never reaches here. */
+    #else
+    RET(16)
+    #endif
+
+/*
+**********************************************************************************************************
+*                                        _frxt_task_coproc_state
+*                                   void _frxt_task_coproc_state(void)
+*
+* Implements the Xtensa RTOS porting layer's XT_RTOS_CP_STATE function for FreeRTOS.
+*
+* May only be called when a task is running, not within an interrupt handler (returns 0 in that case).
+* May only be called from assembly code by the 'call0' instruction. Does NOT obey ABI conventions.
+* Returns in A15 a pointer to the base of the co-processor state save area for the current task.
+* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h.
+*
+**********************************************************************************************************
+*/
+#if XCHAL_CP_NUM > 0
+
+    .globl  _frxt_task_coproc_state
+    .type   _frxt_task_coproc_state,@function
+    .align  4
+_frxt_task_coproc_state:
+
+    movi    a15, port_xSchedulerRunning /* if (port_xSchedulerRunning              */
+    l32i    a15, a15, 0
+    beqz    a15, 1f
+    movi    a15, port_interruptNesting  /* && port_interruptNesting == 0           */
+    l32i    a15, a15, 0
+    bnez    a15, 1f
+    movi    a15, pxCurrentTCB
+    l32i    a15, a15, 0                 /* && pxCurrentTCB != 0) {                 */
+    beqz    a15, 2f
+    l32i    a15, a15, CP_TOPOFSTACK_OFFS
+    ret
+
+1:  movi    a15, 0
+2:  ret
+
+#endif /* XCHAL_CP_NUM > 0 */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_api.h b/cpu/esp8266/vendor/xtensa/xtensa_api.h
new file mode 100644
index 0000000000000000000000000000000000000000..025b3d1676ce0f29066291ac9da5cf3dd032b7ab
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_api.h
@@ -0,0 +1,127 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+******************************************************************************/
+
+/******************************************************************************
+  Xtensa-specific API for RTOS ports.
+******************************************************************************/
+
+#ifndef XTENSA_API_H
+#define XTENSA_API_H
+
+#include <xtensa/hal.h>
+
+#include "xtensa_context.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Typedef for C-callable interrupt handler function */
+typedef void (*xt_handler)(void *);
+
+/* Typedef for C-callable exception handler function */
+typedef void (*xt_exc_handler)(XtExcFrame *);
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to set a handler for the specified exception.
+
+    n        - Exception number (type)
+    f        - Handler function address, NULL to uninstall handler.
+
+  The handler will be passed a pointer to the exception frame, which is created
+  on the stack of the thread that caused the exception.
+
+  If the handler returns, the thread context will be restored and the faulting
+  instruction will be retried. Any values in the exception frame that are
+  modified by the handler will be restored as part of the context. For details
+  of the exception frame structure see xtensa_context.h.
+-------------------------------------------------------------------------------
+*/
+extern xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f);
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to set a handler for the specified interrupt.
+
+    n        - Interrupt number.
+    f        - Handler function address, NULL to uninstall handler.
+    arg      - Argument to be passed to handler.
+-------------------------------------------------------------------------------
+*/
+extern xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg);
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to enable the specified interrupts.
+
+    mask     - Bit mask of interrupts to be enabled.
+
+  Returns the previous state of the interrupt enables.
+-------------------------------------------------------------------------------
+*/
+extern unsigned int xt_ints_on(unsigned int mask);
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to disable the specified interrupts.
+
+    mask     - Bit mask of interrupts to be disabled.
+
+  Returns the previous state of the interrupt enables.
+-------------------------------------------------------------------------------
+*/
+extern unsigned int xt_ints_off(unsigned int mask);
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to set the specified (s/w) interrupt.
+-------------------------------------------------------------------------------
+*/
+static inline void xt_set_intset(unsigned int arg)
+{
+    xthal_set_intset(arg);
+}
+
+
+/*
+-------------------------------------------------------------------------------
+  Call this function to clear the specified (s/w or edge-triggered)
+  interrupt.
+-------------------------------------------------------------------------------
+*/
+static inline void xt_set_intclear(unsigned int arg)
+{
+    xthal_set_intclear(arg);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XTENSA_API_H */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_context.S b/cpu/esp8266/vendor/xtensa/xtensa_context.S
new file mode 100644
index 0000000000000000000000000000000000000000..c67d86a7fa715db2a59f0bf3b8e06f44b264f9b7
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_context.S
@@ -0,0 +1,623 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+--------------------------------------------------------------------------------
+
+        XTENSA CONTEXT SAVE AND RESTORE ROUTINES
+
+Low-level Call0 functions for handling generic context save and restore of
+registers not specifically addressed by the interrupt vectors and handlers.
+Those registers (not handled by these functions) are PC, PS, A0, A1 (SP).
+Except for the calls to RTOS functions, this code is generic to Xtensa.
+
+Note that in Call0 ABI, interrupt handlers are expected to preserve the callee-
+save regs (A12-A15), which is always the case if the handlers are coded in C.
+However A12, A13 are made available as scratch registers for interrupt dispatch
+code, so are presumed saved anyway, and are always restored even in Call0 ABI.
+Only A14, A15 are truly handled as callee-save regs.
+
+Because Xtensa is a configurable architecture, this port supports all user
+generated configurations (except restrictions stated in the release notes).
+This is accomplished by conditional compilation using macros and functions
+defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
+Only the processor state included in your configuration is saved and restored,
+including any processor state added by user configuration options or TIE.
+
+*******************************************************************************/
+
+/*  Warn nicely if this file gets named with a lowercase .s instead of .S:  */
+#define NOERROR #
+NOERROR: .error "C preprocessor needed for this file: make sure its filename\
+ ends in uppercase .S, or use xt-xcc's -x assembler-with-cpp option."
+
+//#include "xtensa_rtos.h"
+#include "xtensa_context.h"
+
+#ifdef XT_USE_OVLY
+#include <xtensa/overlay_os_asm.h>
+#endif
+
+    .text
+
+/*******************************************************************************
+
+_xt_context_save
+
+    !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
+
+Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the
+interrupt stack frame defined in xtensa_rtos.h.
+Its counterpart is _xt_context_restore (which also restores A12, A13).
+
+Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame.
+This function preserves A12 & A13 in order to provide the caller with 2 scratch
+regs that need not be saved over the call to this function. The choice of which
+2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw,
+to avoid moving data more than necessary. Caller can assign regs accordingly.
+
+Entry Conditions:
+    A0  = Return address in caller.
+    A1  = Stack pointer of interrupted thread or handler ("interruptee").
+    Original A12, A13 have already been saved in the interrupt stack frame.
+    Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the
+    point of interruption.
+    If windowed ABI, PS.EXCM = 1 (exceptions disabled).
+
+Exit conditions:
+    A0  = Return address in caller.
+    A1  = Stack pointer of interrupted thread or handler ("interruptee").
+    A12, A13 as at entry (preserved).
+    If windowed ABI, PS.EXCM = 1 (exceptions disabled).
+
+*******************************************************************************/
+
+    .global _xt_context_save
+    .type   _xt_context_save,@function
+    .align  4
+_xt_context_save:
+
+    s32i    a2,  sp, XT_STK_A2
+    s32i    a3,  sp, XT_STK_A3
+    s32i    a4,  sp, XT_STK_A4
+    s32i    a5,  sp, XT_STK_A5
+    s32i    a6,  sp, XT_STK_A6
+    s32i    a7,  sp, XT_STK_A7
+    s32i    a8,  sp, XT_STK_A8
+    s32i    a9,  sp, XT_STK_A9
+    s32i    a10, sp, XT_STK_A10
+    s32i    a11, sp, XT_STK_A11
+
+    /*
+    Call0 ABI callee-saved regs a12-15 do not need to be saved here.
+    a12-13 are the caller's responsibility so it can use them as scratch.
+    So only need to save a14-a15 here for Windowed ABI (not Call0).
+    */
+    #ifndef __XTENSA_CALL0_ABI__
+    s32i    a14, sp, XT_STK_A14
+    s32i    a15, sp, XT_STK_A15
+    #endif
+
+    rsr     a3,  SAR
+    s32i    a3,  sp, XT_STK_SAR
+
+    #if XCHAL_HAVE_LOOPS
+    rsr     a3,  LBEG
+    s32i    a3,  sp, XT_STK_LBEG
+    rsr     a3,  LEND
+    s32i    a3,  sp, XT_STK_LEND
+    rsr     a3,  LCOUNT
+    s32i    a3,  sp, XT_STK_LCOUNT
+    #endif
+
+    #if XT_USE_SWPRI
+    /* Save virtual priority mask */
+    movi    a3,  _xt_vpri_mask
+    l32i    a3,  a3, 0
+    s32i    a3,  sp, XT_STK_VPRI
+    #endif
+
+    #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
+    mov     a9,  a0                     /* preserve ret addr */
+    #endif
+
+    #ifndef __XTENSA_CALL0_ABI__
+    /*
+    To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
+    Need to save a9,12,13 temporarily (in frame temps) and recover originals.
+    Interrupts need to be disabled below XCHAL_EXCM_LEVEL and window overflow
+    and underflow exceptions disabled (assured by PS.EXCM == 1).
+    */
+    s32i    a12, sp, XT_STK_TMP0        /* temp. save stuff in stack frame */
+    s32i    a13, sp, XT_STK_TMP1
+    s32i    a9,  sp, XT_STK_TMP2
+
+    /*
+    Save the overlay state if we are supporting overlays. Since we just saved
+    three registers, we can conveniently use them here. Note that as of now,
+    overlays only work for windowed calling ABI.
+    */
+    #ifdef XT_USE_OVLY
+    l32i    a9,  sp, XT_STK_PC          /* recover saved PC */
+    _xt_overlay_get_state    a9, a12, a13
+    s32i    a9,  sp, XT_STK_OVLY        /* save overlay state */
+    #endif
+
+    l32i    a12, sp, XT_STK_A12         /* recover original a9,12,13 */
+    l32i    a13, sp, XT_STK_A13
+    l32i    a9,  sp, XT_STK_A9
+    addi    sp,  sp, XT_STK_FRMSZ       /* restore the interruptee's SP */
+    call0   xthal_window_spill_nw       /* preserves only a4,5,8,9,12,13 */
+    addi    sp,  sp, -XT_STK_FRMSZ
+    l32i    a12, sp, XT_STK_TMP0        /* recover stuff from stack frame */
+    l32i    a13, sp, XT_STK_TMP1
+    l32i    a9,  sp, XT_STK_TMP2
+    #endif
+
+    #if XCHAL_EXTRA_SA_SIZE > 0
+    /*
+    NOTE: Normally the xthal_save_extra_nw macro only affects address
+    registers a2-a5. It is theoretically possible for Xtensa processor
+    designers to write TIE that causes more address registers to be
+    affected, but it is generally unlikely. If that ever happens,
+    more registers need to be saved/restored around this macro invocation.
+    Here we assume a9,12,13 are preserved.
+    Future Xtensa tools releases might limit the regs that can be affected.
+    */
+    addi    a2,  sp, XT_STK_EXTRA       /* where to save it */
+    # if XCHAL_EXTRA_SA_ALIGN > 16
+    movi    a3, -XCHAL_EXTRA_SA_ALIGN
+    and     a2, a2, a3                  /* align dynamically >16 bytes */
+    # endif
+    call0   xthal_save_extra_nw         /* destroys a0,2,3,4,5 */
+    #endif
+
+    #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
+    mov     a0, a9                      /* retrieve ret addr */
+    #endif
+
+    ret
+
+/*******************************************************************************
+
+_xt_context_restore
+
+    !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
+
+Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0
+ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt
+stack frame defined in xtensa_rtos.h .
+Its counterpart is _xt_context_save (whose caller saved A12, A13).
+
+Caller is responsible to restore PC, PS, A0, A1 (SP).
+
+Entry Conditions:
+    A0  = Return address in caller.
+    A1  = Stack pointer of interrupted thread or handler ("interruptee").
+
+Exit conditions:
+    A0  = Return address in caller.
+    A1  = Stack pointer of interrupted thread or handler ("interruptee").
+    Other processor state except PC, PS, A0, A1 (SP), is as at the point
+    of interruption.
+
+*******************************************************************************/
+
+    .global _xt_context_restore
+    .type   _xt_context_restore,@function
+    .align  4
+_xt_context_restore:
+
+    #if XCHAL_EXTRA_SA_SIZE > 0
+    /*
+    NOTE: Normally the xthal_restore_extra_nw macro only affects address
+    registers a2-a5. It is theoretically possible for Xtensa processor
+    designers to write TIE that causes more address registers to be
+    affected, but it is generally unlikely. If that ever happens,
+    more registers need to be saved/restored around this macro invocation.
+    Here we only assume a13 is preserved.
+    Future Xtensa tools releases might limit the regs that can be affected.
+    */
+    mov     a13, a0                     /* preserve ret addr */
+    addi    a2,  sp, XT_STK_EXTRA       /* where to find it */
+    # if XCHAL_EXTRA_SA_ALIGN > 16
+    movi    a3, -XCHAL_EXTRA_SA_ALIGN
+    and     a2, a2, a3                  /* align dynamically >16 bytes */
+    # endif
+    call0   xthal_restore_extra_nw      /* destroys a0,2,3,4,5 */
+    mov     a0,  a13                    /* retrieve ret addr */
+    #endif
+
+    #if XCHAL_HAVE_LOOPS
+    l32i    a2,  sp, XT_STK_LBEG
+    l32i    a3,  sp, XT_STK_LEND
+    wsr     a2,  LBEG
+    l32i    a2,  sp, XT_STK_LCOUNT
+    wsr     a3,  LEND
+    wsr     a2,  LCOUNT
+    #endif
+
+    #ifdef XT_USE_OVLY
+    /*
+    If we are using overlays, this is a good spot to check if we need
+    to restore an overlay for the incoming task. Here we have a bunch
+    of registers to spare. Note that this step is going to use a few
+    bytes of storage below SP (SP-20 to SP-32) if an overlay is going
+    to be restored.
+    */
+    l32i    a2,  sp, XT_STK_PC          /* retrieve PC */
+    l32i    a3,  sp, XT_STK_PS          /* retrieve PS */
+    l32i    a4,  sp, XT_STK_OVLY        /* retrieve overlay state */
+    l32i    a5,  sp, XT_STK_A1          /* retrieve stack ptr */
+    _xt_overlay_check_map    a2, a3, a4, a5, a6
+    s32i    a2,  sp, XT_STK_PC          /* save updated PC */
+    s32i    a3,  sp, XT_STK_PS          /* save updated PS */
+    #endif
+
+    #ifdef XT_USE_SWPRI
+    /* Restore virtual interrupt priority and interrupt enable */
+    movi    a3,  _xt_intdata
+    l32i    a4,  a3, 0                  /* a4 = _xt_intenable */
+    l32i    a5,  sp, XT_STK_VPRI        /* a5 = saved _xt_vpri_mask */
+    and     a4,  a4, a5
+    wsr     a4,  INTENABLE              /* update INTENABLE */
+    s32i    a5,  a3, 4                  /* restore _xt_vpri_mask */
+    #endif
+
+    l32i    a3,  sp, XT_STK_SAR
+    l32i    a2,  sp, XT_STK_A2
+    wsr     a3,  SAR
+    l32i    a3,  sp, XT_STK_A3
+    l32i    a4,  sp, XT_STK_A4
+    l32i    a5,  sp, XT_STK_A5
+    l32i    a6,  sp, XT_STK_A6
+    l32i    a7,  sp, XT_STK_A7
+    l32i    a8,  sp, XT_STK_A8
+    l32i    a9,  sp, XT_STK_A9
+    l32i    a10, sp, XT_STK_A10
+    l32i    a11, sp, XT_STK_A11
+
+    /*
+    Call0 ABI callee-saved regs a12-15 do not need to be restored here.
+    However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(),
+    so need to be restored anyway, despite being callee-saved in Call0.
+    */
+    l32i    a12, sp, XT_STK_A12
+    l32i    a13, sp, XT_STK_A13
+    #ifndef __XTENSA_CALL0_ABI__
+    l32i    a14, sp, XT_STK_A14
+    l32i    a15, sp, XT_STK_A15
+    #endif
+
+    ret
+
+
+/*******************************************************************************
+
+_xt_coproc_init
+
+Initializes global co-processor management data, setting all co-processors
+to "unowned". Leaves CPENABLE as it found it (does NOT clear it).
+
+Called during initialization of the RTOS, before any threads run.
+
+This may be called from normal Xtensa single-threaded application code which
+might use co-processors. The Xtensa run-time initialization enables all
+co-processors. They must remain enabled here, else a co-processor exception
+might occur outside of a thread, which the exception handler doesn't expect.
+
+Entry Conditions:
+    Xtensa single-threaded run-time environment is in effect.
+    No thread is yet running.
+
+Exit conditions:
+    None.
+
+Obeys ABI conventions per prototype:
+    void _xt_coproc_init(void)
+
+*******************************************************************************/
+
+#if XCHAL_CP_NUM > 0
+
+    .global _xt_coproc_init
+    .type   _xt_coproc_init,@function
+    .align  4
+_xt_coproc_init:
+    ENTRY0
+
+    /* Initialize thread co-processor ownerships to 0 (unowned). */
+    movi    a2, _xt_coproc_owner_sa         /* a2 = base of owner array */
+    addi    a3, a2, XCHAL_CP_MAX << 2       /* a3 = top+1 of owner array */
+    movi    a4, 0                           /* a4 = 0 (unowned) */
+1:  s32i    a4, a2, 0
+    addi    a2, a2, 4
+    bltu    a2, a3, 1b
+
+    RET0
+
+#endif
+
+
+/*******************************************************************************
+
+_xt_coproc_release
+
+Releases any and all co-processors owned by a given thread. The thread is
+identified by it's co-processor state save area defined in xtensa_context.h .
+
+Must be called before a thread's co-proc save area is deleted to avoid
+memory corruption when the exception handler tries to save the state.
+May be called when a thread terminates or completes but does not delete
+the co-proc save area, to avoid the exception handler having to save the
+thread's co-proc state before another thread can use it (optimization).
+
+Entry Conditions:
+    A2  = Pointer to base of co-processor state save area.
+
+Exit conditions:
+    None.
+
+Obeys ABI conventions per prototype:
+    void _xt_coproc_release(void * coproc_sa_base)
+
+*******************************************************************************/
+
+#if XCHAL_CP_NUM > 0
+
+    .global _xt_coproc_release
+    .type   _xt_coproc_release,@function
+    .align  4
+_xt_coproc_release:
+    ENTRY0                                  /* a2 = base of save area */
+
+    movi    a3, _xt_coproc_owner_sa         /* a3 = base of owner array */
+    addi    a4, a3, XCHAL_CP_MAX << 2       /* a4 = top+1 of owner array */
+    movi    a5, 0                           /* a5 = 0 (unowned) */
+
+    rsil    a6, XCHAL_EXCM_LEVEL            /* lock interrupts */
+
+1:  l32i    a7, a3, 0                       /* a7 = owner at a3 */
+    bne     a2, a7, 2f                      /* if (coproc_sa_base == owner) */
+    s32i    a5, a3, 0                       /*   owner = unowned */
+2:  addi    a3, a3, 1<<2                    /* a3 = next entry in owner array */
+    bltu    a3, a4, 1b                      /* repeat until end of array */
+
+3:  wsr     a6, PS                          /* restore interrupts */
+
+    RET0
+
+#endif
+
+
+/*******************************************************************************
+_xt_coproc_savecs
+
+If there is a current thread and it has a coprocessor state save area, then
+save all callee-saved state into this area. This function is called from the
+solicited context switch handler. It calls a system-specific function to get
+the coprocessor save area base address.
+
+Entry conditions:
+    - The thread being switched out is still the current thread.
+    - CPENABLE state reflects which coprocessors are active.
+    - Registers have been saved/spilled already.
+
+Exit conditions:
+    - All necessary CP callee-saved state has been saved.
+    - Registers a2-a7, a13-a15 have been trashed.
+
+Must be called from assembly code only, using CALL0.
+*******************************************************************************/
+#if XCHAL_CP_NUM > 0
+
+    .extern     _xt_coproc_sa_offset   /* external reference */
+
+    .global     _xt_coproc_savecs
+    .type       _xt_coproc_savecs,@function
+    .align      4
+_xt_coproc_savecs:
+
+    /* At entry, CPENABLE should be showing which CPs are enabled. */
+
+    rsr     a2, CPENABLE                /* a2 = which CPs are enabled      */
+    beqz    a2, .Ldone                  /* quick exit if none              */
+    mov     a14, a0                     /* save return address             */
+    call0   XT_RTOS_CP_STATE            /* get address of CP save area     */
+    mov     a0, a14                     /* restore return address          */
+    beqz    a15, .Ldone                 /* if none then nothing to do      */
+    s16i    a2, a15, XT_CP_CS_ST        /* save mask of CPs being stored   */
+    movi    a13, _xt_coproc_sa_offset   /* array of CP save offsets        */
+    l32i    a15, a15, XT_CP_ASA         /* a15 = base of aligned save area */
+
+#if XCHAL_CP0_SA_SIZE
+    bbci.l  a2, 0, 2f                   /* CP 0 not enabled                */
+    l32i    a14, a13, 0                 /* a14 = _xt_coproc_sa_offset[0]   */
+    add     a3, a14, a15                /* a3 = save area for CP 0         */
+    xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP1_SA_SIZE
+    bbci.l  a2, 1, 2f                   /* CP 1 not enabled                */
+    l32i    a14, a13, 4                 /* a14 = _xt_coproc_sa_offset[1]   */
+    add     a3, a14, a15                /* a3 = save area for CP 1         */
+    xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP2_SA_SIZE
+    bbci.l  a2, 2, 2f
+    l32i    a14, a13, 8
+    add     a3, a14, a15
+    xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP3_SA_SIZE
+    bbci.l  a2, 3, 2f
+    l32i    a14, a13, 12
+    add     a3, a14, a15
+    xchal_cp3_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP4_SA_SIZE
+    bbci.l  a2, 4, 2f
+    l32i    a14, a13, 16
+    add     a3, a14, a15
+    xchal_cp4_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP5_SA_SIZE
+    bbci.l  a2, 5, 2f
+    l32i    a14, a13, 20
+    add     a3, a14, a15
+    xchal_cp5_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP6_SA_SIZE
+    bbci.l  a2, 6, 2f
+    l32i    a14, a13, 24
+    add     a3, a14, a15
+    xchal_cp6_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP7_SA_SIZE
+    bbci.l  a2, 7, 2f
+    l32i    a14, a13, 28
+    add     a3, a14, a15
+    xchal_cp7_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+.Ldone:
+    ret
+#endif
+
+
+/*******************************************************************************
+_xt_coproc_restorecs
+
+Restore any callee-saved coprocessor state for the incoming thread.
+This function is called from coprocessor exception handling, when giving
+ownership to a thread that solicited a context switch earlier. It calls a
+system-specific function to get the coprocessor save area base address.
+
+Entry conditions:
+    - The incoming thread is set as the current thread.
+    - CPENABLE is set up correctly for all required coprocessors.
+    - a2 = mask of coprocessors to be restored.
+
+Exit conditions:
+    - All necessary CP callee-saved state has been restored.
+    - CPENABLE - unchanged.
+    - Registers a2-a7, a13-a15 have been trashed.
+
+Must be called from assembly code only, using CALL0.
+*******************************************************************************/
+#if XCHAL_CP_NUM > 0
+
+    .global     _xt_coproc_restorecs
+    .type       _xt_coproc_restorecs,@function
+    .align      4
+_xt_coproc_restorecs:
+
+    mov     a14, a0                     /* save return address             */
+    call0   XT_RTOS_CP_STATE            /* get address of CP save area     */
+    mov     a0, a14                     /* restore return address          */
+    beqz    a15, .Ldone2                /* if none then nothing to do      */
+    l16ui   a3, a15, XT_CP_CS_ST        /* a3 = which CPs have been saved  */
+    xor     a3, a3, a2                  /* clear the ones being restored   */
+    s32i    a3, a15, XT_CP_CS_ST        /* update saved CP mask            */
+    movi    a13, _xt_coproc_sa_offset   /* array of CP save offsets        */
+    l32i    a15, a15, XT_CP_ASA         /* a15 = base of aligned save area */
+
+#if XCHAL_CP0_SA_SIZE
+    bbci.l  a2, 0, 2f                   /* CP 0 not enabled                */
+    l32i    a14, a13, 0                 /* a14 = _xt_coproc_sa_offset[0]   */
+    add     a3, a14, a15                /* a3 = save area for CP 0         */
+    xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP1_SA_SIZE
+    bbci.l  a2, 1, 2f                   /* CP 1 not enabled                */
+    l32i    a14, a13, 4                 /* a14 = _xt_coproc_sa_offset[1]   */
+    add     a3, a14, a15                /* a3 = save area for CP 1         */
+    xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP2_SA_SIZE
+    bbci.l  a2, 2, 2f
+    l32i    a14, a13, 8
+    add     a3, a14, a15
+    xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP3_SA_SIZE
+    bbci.l  a2, 3, 2f
+    l32i    a14, a13, 12
+    add     a3, a14, a15
+    xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP4_SA_SIZE
+    bbci.l  a2, 4, 2f
+    l32i    a14, a13, 16
+    add     a3, a14, a15
+    xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP5_SA_SIZE
+    bbci.l  a2, 5, 2f
+    l32i    a14, a13, 20
+    add     a3, a14, a15
+    xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP6_SA_SIZE
+    bbci.l  a2, 6, 2f
+    l32i    a14, a13, 24
+    add     a3, a14, a15
+    xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+#if XCHAL_CP7_SA_SIZE
+    bbci.l  a2, 7, 2f
+    l32i    a14, a13, 28
+    add     a3, a14, a15
+    xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
+2:
+#endif
+
+.Ldone2:
+    ret
+
+#endif
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_context.h b/cpu/esp8266/vendor/xtensa/xtensa_context.h
new file mode 100644
index 0000000000000000000000000000000000000000..e331d62482845c554b4df5063b23c064c5ee9233
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_context.h
@@ -0,0 +1,355 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+--------------------------------------------------------------------------------
+
+        XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES
+
+This header contains definitions and macros for use primarily by Xtensa
+RTOS assembly coded source files. It includes and uses the Xtensa hardware
+abstraction layer (HAL) to deal with config specifics. It may also be
+included in C source files.
+
+!! Supports only Xtensa Exception Architecture 2 (XEA2). XEA1 not supported. !!
+
+NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes.
+
+*******************************************************************************/
+
+#ifndef XTENSA_CONTEXT_H
+#define XTENSA_CONTEXT_H
+
+#ifdef __ASSEMBLER__
+#include    <xtensa/coreasm.h>
+#endif
+
+#include    <xtensa/config/tie.h>
+#include    <xtensa/corebits.h>
+#include    <xtensa/config/system.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
+#define ALIGNUP(n, val) (((val) + (n)-1) & -(n))
+
+
+/*
+-------------------------------------------------------------------------------
+  Macros that help define structures for both C and assembler.
+-------------------------------------------------------------------------------
+*/
+#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
+
+#define STRUCT_BEGIN            .pushsection .text; .struct 0
+#define STRUCT_FIELD(ctype,size,asname,name)    asname: .space  size
+#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space  (size)*(n)
+#define STRUCT_END(sname)       sname##Size:; .popsection
+
+#else
+
+#define STRUCT_BEGIN            typedef struct {
+#define STRUCT_FIELD(ctype,size,asname,name)    ctype   name;
+#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype   name[n];
+#define STRUCT_END(sname)       } sname;
+
+#endif //_ASMLANGUAGE || __ASSEMBLER__
+
+
+/*
+-------------------------------------------------------------------------------
+  INTERRUPT/EXCEPTION STACK FRAME FOR A THREAD OR NESTED INTERRUPT
+
+  A stack frame of this structure is allocated for any interrupt or exception.
+  It goes on the current stack. If the RTOS has a system stack for handling
+  interrupts, every thread stack must allow space for just one interrupt stack
+  frame, then nested interrupt stack frames go on the system stack.
+
+  The frame includes basic registers (explicit) and "extra" registers introduced
+  by user TIE or the use of the MAC16 option in the user's Xtensa config.
+  The frame size is minimized by omitting regs not applicable to user's config.
+
+  For Windowed ABI, this stack frame includes the interruptee's base save area,
+  another base save area to manage gcc nested functions, and a little temporary
+  space to help manage the spilling of the register windows.
+-------------------------------------------------------------------------------
+*/
+
+STRUCT_BEGIN
+STRUCT_FIELD (long, 4, XT_STK_EXIT,     exit) /* exit point for dispatch */
+STRUCT_FIELD (long, 4, XT_STK_PC,       pc)   /* return PC */
+STRUCT_FIELD (long, 4, XT_STK_PS,       ps)   /* return PS */
+STRUCT_FIELD (long, 4, XT_STK_A0,       a0)
+STRUCT_FIELD (long, 4, XT_STK_A1,       a1)   /* stack pointer before interrupt */
+STRUCT_FIELD (long, 4, XT_STK_A2,       a2)
+STRUCT_FIELD (long, 4, XT_STK_A3,       a3)
+STRUCT_FIELD (long, 4, XT_STK_A4,       a4)
+STRUCT_FIELD (long, 4, XT_STK_A5,       a5)
+STRUCT_FIELD (long, 4, XT_STK_A6,       a6)
+STRUCT_FIELD (long, 4, XT_STK_A7,       a7)
+STRUCT_FIELD (long, 4, XT_STK_A8,       a8)
+STRUCT_FIELD (long, 4, XT_STK_A9,       a9)
+STRUCT_FIELD (long, 4, XT_STK_A10,      a10)
+STRUCT_FIELD (long, 4, XT_STK_A11,      a11)
+STRUCT_FIELD (long, 4, XT_STK_A12,      a12)
+STRUCT_FIELD (long, 4, XT_STK_A13,      a13)
+STRUCT_FIELD (long, 4, XT_STK_A14,      a14)
+STRUCT_FIELD (long, 4, XT_STK_A15,      a15)
+STRUCT_FIELD (long, 4, XT_STK_SAR,      sar)
+STRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause)
+STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
+#if XCHAL_HAVE_LOOPS
+STRUCT_FIELD (long, 4, XT_STK_LBEG,   lbeg)
+STRUCT_FIELD (long, 4, XT_STK_LEND,   lend)
+STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
+#endif
+#ifndef __XTENSA_CALL0_ABI__
+/* Temporary space for saving stuff during window spill */
+STRUCT_FIELD (long, 4, XT_STK_TMP0,   tmp0)
+STRUCT_FIELD (long, 4, XT_STK_TMP1,   tmp1)
+STRUCT_FIELD (long, 4, XT_STK_TMP2,   tmp2)
+#endif
+#ifdef XT_USE_SWPRI
+/* Storage for virtual priority mask */
+STRUCT_FIELD (long, 4, XT_STK_VPRI,   vpri)
+#endif
+#ifdef XT_USE_OVLY
+/* Storage for overlay state */
+STRUCT_FIELD (long, 4, XT_STK_OVLY,   ovly)
+#endif
+STRUCT_END(XtExcFrame)
+
+#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
+#define XT_STK_NEXT1      XtExcFrameSize
+#else
+#define XT_STK_NEXT1      sizeof(XtExcFrame)
+#endif
+
+/* Allocate extra storage if needed */
+#if XCHAL_EXTRA_SA_SIZE != 0
+
+#if XCHAL_EXTRA_SA_ALIGN <= 16
+#define XT_STK_EXTRA            ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1)
+#else
+/* If need more alignment than stack, add space for dynamic alignment */
+#define XT_STK_EXTRA            (ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + XCHAL_EXTRA_SA_ALIGN)
+#endif
+#define XT_STK_NEXT2            (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE)
+
+#else
+
+#define XT_STK_NEXT2            XT_STK_NEXT1
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+  This is the frame size. Add space for 4 registers (interruptee's base save
+  area) and some space for gcc nested functions if any.
+-------------------------------------------------------------------------------
+*/
+#define XT_STK_FRMSZ            (ALIGNUP(0x10, XT_STK_NEXT2) + 0x20)
+
+
+/*
+-------------------------------------------------------------------------------
+  SOLICITED STACK FRAME FOR A THREAD
+
+  A stack frame of this structure is allocated whenever a thread enters the
+  RTOS kernel intentionally (and synchronously) to submit to thread scheduling.
+  It goes on the current thread's stack.
+
+  The solicited frame only includes registers that are required to be preserved
+  by the callee according to the compiler's ABI conventions, some space to save
+  the return address for returning to the caller, and the caller's PS register.
+
+  For Windowed ABI, this stack frame includes the caller's base save area.
+
+  Note on XT_SOL_EXIT field:
+      It is necessary to distinguish a solicited from an interrupt stack frame.
+      This field corresponds to XT_STK_EXIT in the interrupt stack frame and is
+      always at the same offset (0). It can be written with a code (usually 0)
+      to distinguish a solicted frame from an interrupt frame. An RTOS port may
+      opt to ignore this field if it has another way of distinguishing frames.
+-------------------------------------------------------------------------------
+*/
+
+STRUCT_BEGIN
+#ifdef __XTENSA_CALL0_ABI__
+STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
+STRUCT_FIELD (long, 4, XT_SOL_PC,   pc)
+STRUCT_FIELD (long, 4, XT_SOL_PS,   ps)
+STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
+STRUCT_FIELD (long, 4, XT_SOL_A12,  a12)    /* should be on 16-byte alignment */
+STRUCT_FIELD (long, 4, XT_SOL_A13,  a13)
+STRUCT_FIELD (long, 4, XT_SOL_A14,  a14)
+STRUCT_FIELD (long, 4, XT_SOL_A15,  a15)
+#else
+STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
+STRUCT_FIELD (long, 4, XT_SOL_PC,   pc)
+STRUCT_FIELD (long, 4, XT_SOL_PS,   ps)
+STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
+STRUCT_FIELD (long, 4, XT_SOL_A0,   a0)    /* should be on 16-byte alignment */
+STRUCT_FIELD (long, 4, XT_SOL_A1,   a1)
+STRUCT_FIELD (long, 4, XT_SOL_A2,   a2)
+STRUCT_FIELD (long, 4, XT_SOL_A3,   a3)
+#endif
+STRUCT_END(XtSolFrame)
+
+/* Size of solicited stack frame */
+#define XT_SOL_FRMSZ            ALIGNUP(0x10, XtSolFrameSize)
+
+
+/*
+-------------------------------------------------------------------------------
+  CO-PROCESSOR STATE SAVE AREA FOR A THREAD
+
+  The RTOS must provide an area per thread to save the state of co-processors
+  when that thread does not have control. Co-processors are context-switched
+  lazily (on demand) only when a new thread uses a co-processor instruction,
+  otherwise a thread retains ownership of the co-processor even when it loses
+  control of the processor. An Xtensa co-processor exception is triggered when
+  any co-processor instruction is executed by a thread that is not the owner,
+  and the context switch of that co-processor is then peformed by the handler.
+  Ownership represents which thread's state is currently in the co-processor.
+
+  Co-processors may not be used by interrupt or exception handlers. If an
+  co-processor instruction is executed by an interrupt or exception handler,
+  the co-processor exception handler will trigger a kernel panic and freeze.
+  This restriction is introduced to reduce the overhead of saving and restoring
+  co-processor state (which can be quite large) and in particular remove that
+  overhead from interrupt handlers.
+
+  The co-processor state save area may be in any convenient per-thread location
+  such as in the thread control block or above the thread stack area. It need
+  not be in the interrupt stack frame since interrupts don't use co-processors.
+
+  Along with the save area for each co-processor, two bitmasks with flags per
+  co-processor (laid out as in the CPENABLE reg) help manage context-switching
+  co-processors as efficiently as possible:
+
+  XT_CPENABLE
+    The contents of a non-running thread's CPENABLE register.
+    It represents the co-processors owned (and whose state is still needed)
+    by the thread. When a thread is preempted, its CPENABLE is saved here.
+    When a thread solicits a context-swtich, its CPENABLE is cleared - the
+    compiler has saved the (caller-saved) co-proc state if it needs to.
+    When a non-running thread loses ownership of a CP, its bit is cleared.
+    When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg.
+    Avoids co-processor exceptions when no change of ownership is needed.
+
+  XT_CPSTORED
+    A bitmask with the same layout as CPENABLE, a bit per co-processor.
+    Indicates whether the state of each co-processor is saved in the state
+    save area. When a thread enters the kernel, only the state of co-procs
+    still enabled in CPENABLE is saved. When the co-processor exception
+    handler assigns ownership of a co-processor to a thread, it restores
+    the saved state only if this bit is set, and clears this bit.
+
+  XT_CP_CS_ST
+    A bitmask with the same layout as CPENABLE, a bit per co-processor.
+    Indicates whether callee-saved state is saved in the state save area.
+    Callee-saved state is saved by itself on a solicited context switch,
+    and restored when needed by the coprocessor exception handler.
+    Unsolicited switches will cause the entire coprocessor to be saved
+    when necessary.
+
+  XT_CP_ASA
+    Pointer to the aligned save area.  Allows it to be aligned more than
+    the overall save area (which might only be stack-aligned or TCB-aligned).
+    Especially relevant for Xtensa cores configured with a very large data
+    path that requires alignment greater than 16 bytes (ABI stack alignment).
+-------------------------------------------------------------------------------
+*/
+
+#if XCHAL_CP_NUM > 0
+
+/*  Offsets of each coprocessor save area within the 'aligned save area':  */
+#define XT_CP0_SA   0
+#define XT_CP1_SA   ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE)
+#define XT_CP2_SA   ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE)
+#define XT_CP3_SA   ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE)
+#define XT_CP4_SA   ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE)
+#define XT_CP5_SA   ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE)
+#define XT_CP6_SA   ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE)
+#define XT_CP7_SA   ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE)
+#define XT_CP_SA_SIZE   ALIGNUP(16, XT_CP7_SA + XCHAL_CP7_SA_SIZE)
+
+/*  Offsets within the overall save area:  */
+#define XT_CPENABLE 0   /* (2 bytes) coprocessors active for this thread */
+#define XT_CPSTORED 2   /* (2 bytes) coprocessors saved for this thread */
+#define XT_CP_CS_ST 4   /* (2 bytes) coprocessor callee-saved regs stored for this thread */
+#define XT_CP_ASA   8   /* (4 bytes) ptr to aligned save area */
+/*  Overall size allows for dynamic alignment:  */
+#define XT_CP_SIZE  (12 + XT_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN)
+#else
+#define XT_CP_SIZE  0
+#endif
+
+
+/*
+-------------------------------------------------------------------------------
+  MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN
+
+  Convenient where the frame size requirements are the same for both ABIs.
+    ENTRY(sz), RET(sz) are for framed functions (have locals or make calls).
+    ENTRY0,    RET0    are for frameless functions (no locals, no calls).
+
+  where size = size of stack frame in bytes (must be >0 and aligned to 16).
+  For framed functions the frame is created and the return address saved at
+  base of frame (Call0 ABI) or as determined by hardware (Windowed ABI).
+  For frameless functions, there is no frame and return address remains in a0.
+  Note: Because CPP macros expand to a single line, macros requiring multi-line
+  expansions are implemented as assembler macros.
+-------------------------------------------------------------------------------
+*/
+
+#ifdef __ASSEMBLER__
+#ifdef __XTENSA_CALL0_ABI__
+  /* Call0 */
+  #define ENTRY(sz)     entry1  sz
+    .macro  entry1 size=0x10
+    addi    sp, sp, -\size
+    s32i    a0, sp, 0
+    .endm
+  #define ENTRY0
+  #define RET(sz)       ret1    sz
+    .macro  ret1 size=0x10
+    l32i    a0, sp, 0
+    addi    sp, sp, \size
+    ret
+    .endm
+  #define RET0          ret
+#else
+  /* Windowed */
+  #define ENTRY(sz)     entry   sp, sz
+  #define ENTRY0        entry   sp, 0x10
+  #define RET(sz)       retw
+  #define RET0          retw
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XTENSA_CONTEXT_H */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_intr.c b/cpu/esp8266/vendor/xtensa/xtensa_intr.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ec600acda03d6f95db0413feef31a7dab305a96
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_intr.c
@@ -0,0 +1,141 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+******************************************************************************/
+
+/******************************************************************************
+  Xtensa-specific interrupt and exception functions for RTOS ports.
+  Also see xtensa_intr_asm.S.
+******************************************************************************/
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING /* not needed in SDK task handling version of RIOT */
+
+#include <stdlib.h>
+
+#include <xtensa/config/core.h>
+
+#include "xtensa_api.h"
+
+
+#if XCHAL_HAVE_EXCEPTIONS
+
+/* Handler table is in xtensa_intr_asm.S */
+
+extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM];
+
+
+/*
+  Default handler for unhandled exceptions.
+*/
+void xt_unhandled_exception(XtExcFrame *frame)
+{
+    exit(-1);
+}
+
+
+/*
+  This function registers a handler for the specified exception.
+  The function returns the address of the previous handler.
+  On error, it returns 0.
+*/
+xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f)
+{
+    xt_exc_handler old;
+
+    if( n < 0 || n >= XCHAL_EXCCAUSE_NUM )
+        return 0;       /* invalid exception number */
+
+    old = _xt_exception_table[n];
+
+    if (f) {
+        _xt_exception_table[n] = f;
+    }
+    else {
+        _xt_exception_table[n] = &xt_unhandled_exception;
+    }
+
+    return ((old == &xt_unhandled_exception) ? 0 : old);
+}
+
+#endif
+
+#if XCHAL_HAVE_INTERRUPTS
+
+/* Handler table is in xtensa_intr_asm.S */
+
+typedef struct xt_handler_table_entry {
+    void * handler;
+    void * arg;
+} xt_handler_table_entry;
+
+extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS];
+
+
+/*
+  Default handler for unhandled interrupts.
+*/
+void xt_unhandled_interrupt(void * arg)
+{
+    exit(-1);
+}
+
+
+/*
+  This function registers a handler for the specified interrupt. The "arg"
+  parameter specifies the argument to be passed to the handler when it is
+  invoked. The function returns the address of the previous handler.
+  On error, it returns 0.
+*/
+xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg)
+{
+    xt_handler_table_entry * entry;
+    xt_handler               old;
+
+    if( n < 0 || n >= XCHAL_NUM_INTERRUPTS )
+        return 0;       /* invalid interrupt number */
+    if( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL )
+        return 0;       /* priority level too high to safely handle in C */
+
+    #ifdef MODULE_ESP_SDK
+    /* for compatibility reasons with SDK, we use _xtos_interrupt_table */
+    /* in reverse order */
+    entry = _xt_interrupt_table + (XCHAL_NUM_INTERRUPTS - n);
+    #else
+    entry = _xt_interrupt_table + n;
+    #endif
+    old   = entry->handler;
+
+    if (f) {
+        entry->handler = f;
+        entry->arg     = arg;
+    }
+    else {
+        entry->handler = &xt_unhandled_interrupt;
+        entry->arg     = (void*)n;
+    }
+
+    return ((old == &xt_unhandled_interrupt) ? 0 : old);
+}
+
+
+#endif /* XCHAL_HAVE_INTERRUPTS */
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_intr_asm.S b/cpu/esp8266/vendor/xtensa/xtensa_intr_asm.S
new file mode 100644
index 0000000000000000000000000000000000000000..ccae8f741a8668723a032df4aa40cb7cf04f501b
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_intr_asm.S
@@ -0,0 +1,187 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+******************************************************************************/
+
+/******************************************************************************
+  Xtensa interrupt handling data and assembly routines.
+  Also see xtensa_intr.c and xtensa_vectors.S.
+******************************************************************************/
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING /* not needed in SDK version of RIOT */
+
+#include <xtensa/hal.h>
+#include <xtensa/config/core.h>
+
+#include "xtensa_context.h"
+
+#if XCHAL_HAVE_INTERRUPTS
+
+    .literal_position
+
+/*
+-------------------------------------------------------------------------------
+  INTENABLE virtualization information.
+-------------------------------------------------------------------------------
+*/
+    .data
+    .global _xt_intdata
+    .align  8
+_xt_intdata:
+    .global _xt_intenable
+    .type   _xt_intenable,@object
+    .size   _xt_intenable,4
+    .global _xt_vpri_mask
+    .type   _xt_vpri_mask,@object
+    .size   _xt_vpri_mask,4
+
+_xt_intenable:     .word   0             /* Virtual INTENABLE     */
+_xt_vpri_mask:     .word   0xFFFFFFFF    /* Virtual priority mask */
+
+
+/*
+-------------------------------------------------------------------------------
+  Table of C-callable interrupt handlers for each interrupt. Note that not all
+  slots can be filled, because interrupts at level > EXCM_LEVEL will not be
+  dispatched to a C handler by default.
+-------------------------------------------------------------------------------
+*/
+/*
+    in SDK we use _xtos_interrupt_table_ which is provided as symbol
+    _xt_interrupt_table_ by ld script
+*/
+#ifndef MODULE_ESP_SDK
+    .data
+    .global _xt_interrupt_table
+    .align  8
+
+_xt_interrupt_table:
+
+    .set    i, 0
+    .rept   XCHAL_NUM_INTERRUPTS
+    .word   xt_unhandled_interrupt      /* handler address               */
+    .word   i                           /* handler arg (default: intnum) */
+    .set    i, i+1
+    .endr
+#endif
+
+#endif /* XCHAL_HAVE_INTERRUPTS */
+
+
+#if XCHAL_HAVE_EXCEPTIONS
+
+/*
+-------------------------------------------------------------------------------
+  Table of C-callable exception handlers for each exception. Note that not all
+  slots will be active, because some exceptions (e.g. coprocessor exceptions)
+  are always handled by the OS and cannot be hooked by user handlers.
+-------------------------------------------------------------------------------
+*/
+
+    .data
+    .global _xt_exception_table
+    .align  4
+
+_xt_exception_table:
+    .rept   XCHAL_EXCCAUSE_NUM
+    .word   xt_unhandled_exception    /* handler address */
+    .endr
+
+#endif
+
+
+/*
+-------------------------------------------------------------------------------
+  unsigned int xt_ints_on ( unsigned int mask )
+
+  Enables a set of interrupts. Does not simply set INTENABLE directly, but
+  computes it as a function of the current virtual priority.
+  Can be called from interrupt handlers.
+-------------------------------------------------------------------------------
+*/
+
+    .text
+    .align  4
+    .global xt_ints_on
+    .type   xt_ints_on,@function
+
+xt_ints_on:
+
+    ENTRY0
+#if XCHAL_HAVE_INTERRUPTS
+    movi    a3, 0
+    movi    a4, _xt_intdata
+    xsr     a3, INTENABLE        /* Disables all interrupts   */
+    rsync
+    l32i    a3, a4, 0            /* a3 = _xt_intenable        */
+    l32i    a6, a4, 4            /* a6 = _xt_vpri_mask        */
+    or      a5, a3, a2           /* a5 = _xt_intenable | mask */
+    s32i    a5, a4, 0            /* _xt_intenable |= mask     */
+    and     a5, a5, a6           /* a5 = _xt_intenable & _xt_vpri_mask */
+    wsr     a5, INTENABLE        /* Reenable interrupts       */
+    mov     a2, a3               /* Previous mask             */
+#else
+    movi    a2, 0                /* Return zero */
+#endif
+    RET0
+
+    .size   xt_ints_on, . - xt_ints_on
+
+
+/*
+-------------------------------------------------------------------------------
+  unsigned int xt_ints_off ( unsigned int mask )
+
+  Disables a set of interrupts. Does not simply set INTENABLE directly,
+  but computes it as a function of the current virtual priority.
+  Can be called from interrupt handlers.
+-------------------------------------------------------------------------------
+*/
+
+    .text
+    .align  4
+    .global xt_ints_off
+    .type   xt_ints_off,@function
+
+xt_ints_off:
+
+    ENTRY0
+#if XCHAL_HAVE_INTERRUPTS
+    movi    a3, 0
+    movi    a4, _xt_intdata
+    xsr     a3, INTENABLE        /* Disables all interrupts    */
+    rsync
+    l32i    a3, a4, 0            /* a3 = _xt_intenable         */
+    l32i    a6, a4, 4            /* a6 = _xt_vpri_mask         */
+    or      a5, a3, a2           /* a5 = _xt_intenable | mask  */
+    xor     a5, a5, a2           /* a5 = _xt_intenable & ~mask */
+    s32i    a5, a4, 0            /* _xt_intenable &= ~mask     */
+    and     a5, a5, a6           /* a5 = _xt_intenable & _xt_vpri_mask */
+    wsr     a5, INTENABLE        /* Reenable interrupts        */
+    mov     a2, a3               /* Previous mask              */
+#else
+    movi    a2, 0                /* return zero */
+#endif
+    RET0
+
+    .size   xt_ints_off, . - xt_ints_off
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_rtos.h b/cpu/esp8266/vendor/xtensa/xtensa_rtos.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecf0fc27c9fe1bad6c29e04c9b8fcef90e0cfac1
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_rtos.h
@@ -0,0 +1,247 @@
+/*******************************************************************************
+// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
+//
+// 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.
+--------------------------------------------------------------------------------
+
+        RTOS-SPECIFIC INFORMATION FOR XTENSA RTOS ASSEMBLER SOURCES
+                            (FreeRTOS Port)
+
+This header is the primary glue between generic Xtensa RTOS support
+sources and a specific RTOS port for Xtensa.  It contains definitions
+and macros for use primarily by Xtensa assembly coded source files.
+
+Macros in this header map callouts from generic Xtensa files to specific
+RTOS functions. It may also be included in C source files.
+
+Xtensa RTOS ports support all RTOS-compatible configurations of the Xtensa
+architecture, using the Xtensa hardware abstraction layer (HAL) to deal
+with configuration specifics.
+
+Should be included by all Xtensa generic and RTOS port-specific sources.
+
+*******************************************************************************/
+
+#ifndef XTENSA_RTOS_H
+#define XTENSA_RTOS_H
+
+#ifdef __ASSEMBLER__
+#include    <xtensa/coreasm.h>
+#else
+#include    <xtensa/config/core.h>
+#endif
+
+#include    <xtensa/corebits.h>
+#include    <xtensa/config/system.h>
+#ifndef RIOT_VERSION
+#include    <xtensa/simcall.h>
+#endif
+#define XT_BOARD 1
+
+/*
+Include any RTOS specific definitions that are needed by this header.
+*/
+#ifndef RIOT_VERSION
+#include    <FreeRTOSConfig.h>
+#endif
+
+/*
+Convert FreeRTOSConfig definitions to XTENSA definitions.
+However these can still be overridden from the command line.
+*/
+
+#ifndef XT_SIMULATOR
+  #if configXT_SIMULATOR
+    #define XT_SIMULATOR             1  /* Simulator mode */
+  #endif
+#endif
+
+#ifndef XT_BOARD
+  #if configXT_BOARD
+    #define XT_BOARD                 1  /* Board mode */
+  #endif
+#endif
+
+#ifndef XT_TIMER_INDEX
+  #if defined configXT_TIMER_INDEX
+    #define XT_TIMER_INDEX           configXT_TIMER_INDEX  /* Index of hardware timer to be used */
+  #endif
+#endif
+
+#ifndef XT_INTEXC_HOOKS
+  #if configXT_INTEXC_HOOKS
+    #define XT_INTEXC_HOOKS          1  /* Enables exception hooks */
+  #endif
+#endif
+
+#if (!XT_SIMULATOR) && (!XT_BOARD)
+  #error Either XT_SIMULATOR or XT_BOARD must be defined.
+#endif
+
+
+/*
+Name of RTOS (for messages).
+*/
+#define XT_RTOS_NAME    RIOT-OS
+
+/*
+Check some Xtensa configuration requirements and report error if not met.
+Error messages can be customize to the RTOS port.
+*/
+
+#if !XCHAL_HAVE_XEA2
+#error "RIOT-OS/Xtensa requires XEA2 (exception architecture 2)."
+#endif
+
+
+/*******************************************************************************
+
+RTOS CALLOUT MACROS MAPPED TO RTOS PORT-SPECIFIC FUNCTIONS.
+
+Define callout macros used in generic Xtensa code to interact with the RTOS.
+The macros are simply the function names for use in calls from assembler code.
+Some of these functions may call back to generic functions in xtensa_context.h .
+
+*******************************************************************************/
+
+/*
+Inform RTOS of entry into an interrupt handler that will affect it.
+Allows RTOS to manage switch to any system stack and count nesting level.
+Called after minimal context has been saved, with interrupts disabled.
+RTOS port can call0 _xt_context_save to save the rest of the context.
+May only be called from assembly code by the 'call0' instruction.
+*/
+// void XT_RTOS_INT_ENTER(void)
+#define XT_RTOS_INT_ENTER   _frxt_int_enter
+
+/*
+Inform RTOS of completion of an interrupt handler, and give control to
+RTOS to perform thread/task scheduling, switch back from any system stack
+and restore the context, and return to the exit dispatcher saved in the
+stack frame at XT_STK_EXIT. RTOS port can call0 _xt_context_restore
+to save the context saved in XT_RTOS_INT_ENTER via _xt_context_save,
+leaving only a minimal part of the context to be restored by the exit
+dispatcher. This function does not return to the place it was called from.
+May only be called from assembly code by the 'call0' instruction.
+*/
+// void XT_RTOS_INT_EXIT(void)
+#define XT_RTOS_INT_EXIT    _frxt_int_exit
+
+/*
+Inform RTOS of the occurrence of a tick timer interrupt.
+If RTOS has no tick timer, leave XT_RTOS_TIMER_INT undefined.
+May be coded in or called from C or assembly, per ABI conventions.
+RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro).
+*/
+// void XT_RTOS_TIMER_INT(void)
+#define XT_RTOS_TIMER_INT   _frxt_timer_int
+#ifndef RIOT_VERSION
+    #define XT_TICK_PER_SEC     configTICK_RATE_HZ
+#endif
+
+/*
+Return in a15 the base address of the co-processor state save area for the
+thread that triggered a co-processor exception, or 0 if no thread was running.
+The state save area is structured as defined in xtensa_context.h and has size
+XT_CP_SIZE. Co-processor instructions should only be used in thread code, never
+in interrupt handlers or the RTOS kernel. May only be called from assembly code
+and by the 'call0' instruction. A result of 0 indicates an unrecoverable error.
+The implementation may use only a2-4, a15 (all other regs must be preserved).
+*/
+// void* XT_RTOS_CP_STATE(void)
+#define XT_RTOS_CP_STATE    _frxt_task_coproc_state
+
+
+/*******************************************************************************
+
+HOOKS TO DYNAMICALLY INSTALL INTERRUPT AND EXCEPTION HANDLERS PER LEVEL.
+
+This Xtensa RTOS port provides hooks for dynamically installing exception
+and interrupt handlers to facilitate automated testing where each test
+case can install its own handler for user exceptions and each interrupt
+priority (level). This consists of an array of function pointers indexed
+by interrupt priority, with index 0 being the user exception handler hook.
+Each entry in the array is initially 0, and may be replaced by a function
+pointer of type XT_INTEXC_HOOK. A handler may be uninstalled by installing 0.
+
+The handler for low and medium priority obeys ABI conventions so may be coded
+in C. For the exception handler, the cause is the contents of the EXCCAUSE
+reg, and the result is -1 if handled, else the cause (still needs handling).
+For interrupt handlers, the cause is a mask of pending enabled interrupts at
+that level, and the result is the same mask with the bits for the handled
+interrupts cleared (those not cleared still need handling). This allows a test
+case to either pre-handle or override the default handling for the exception
+or interrupt level (see xtensa_vectors.S).
+
+High priority handlers (including NMI) must be coded in assembly, are always
+called by 'call0' regardless of ABI, must preserve all registers except a0,
+and must not use or modify the interrupted stack. The hook argument 'cause'
+is not passed and the result is ignored, so as not to burden the caller with
+saving and restoring a2 (it assumes only one interrupt per level - see the
+discussion in high priority interrupts in xtensa_vectors.S). The handler
+therefore should be coded to prototype 'void h(void)' even though it plugs
+into an array of handlers of prototype 'unsigned h(unsigned)'.
+
+To enable interrupt/exception hooks, compile the RTOS with '-DXT_INTEXC_HOOKS'.
+
+*******************************************************************************/
+
+#define XT_INTEXC_HOOK_NUM  (1 + XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI)
+
+#ifndef __ASSEMBLER__
+typedef unsigned (*XT_INTEXC_HOOK)(unsigned cause);
+extern  volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM];
+#endif
+
+
+/*******************************************************************************
+
+CONVENIENCE INCLUSIONS.
+
+Ensures RTOS specific files need only include this one Xtensa-generic header.
+These headers are included last so they can use the RTOS definitions above.
+
+*******************************************************************************/
+
+#include    "xtensa_context.h"
+
+#ifdef XT_RTOS_TIMER_INT
+#include    "xtensa_timer.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*******************************************************************************
+
+Xtensa Port Version.
+
+*******************************************************************************/
+
+#define XTENSA_PORT_VERSION             1.5
+#define XTENSA_PORT_VERSION_STRING      "1.5"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XTENSA_RTOS_H */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_timer.h b/cpu/esp8266/vendor/xtensa/xtensa_timer.h
new file mode 100644
index 0000000000000000000000000000000000000000..a477dc3375e991fe6e4c324f865d8a6d0ba59de2
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_timer.h
@@ -0,0 +1,170 @@
+/*******************************************************************************
+// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
+//
+// 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.
+--------------------------------------------------------------------------------
+
+        XTENSA INFORMATION FOR RTOS TICK TIMER AND CLOCK FREQUENCY
+
+This header contains definitions and macros for use primarily by Xtensa
+RTOS assembly coded source files. It includes and uses the Xtensa hardware
+abstraction layer (HAL) to deal with config specifics. It may also be
+included in C source files.
+
+User may edit to modify timer selection and to specify clock frequency and
+tick duration to match timer interrupt to the real-time tick duration.
+
+If the RTOS has no timer interrupt, then there is no tick timer and the
+clock frequency is irrelevant, so all of these macros are left undefined
+and the Xtensa core configuration need not have a timer.
+
+*******************************************************************************/
+
+#ifndef XTENSA_TIMER_H
+#define XTENSA_TIMER_H
+
+#ifdef __ASSEMBLER__
+#include    <xtensa/coreasm.h>
+#endif
+
+#include    <xtensa/corebits.h>
+#include    <xtensa/config/system.h>
+
+#ifndef RIOT_VERSION
+#include    "xtensa_rtos.h"     /* in case this wasn't included directly */
+#include    <FreeRTOSConfig.h>
+#endif /* ifndef RIOT_VERSION */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Select timer to use for periodic tick, and determine its interrupt number
+and priority. User may specify a timer by defining XT_TIMER_INDEX with -D,
+in which case its validity is checked (it must exist in this core and must
+not be on a high priority interrupt - an error will be reported in invalid).
+Otherwise select the first low or medium priority interrupt timer available.
+*/
+#if XCHAL_NUM_TIMERS == 0
+
+  #error "This Xtensa configuration is unsupported, it has no timers."
+
+#else
+
+#ifndef XT_TIMER_INDEX
+  #if XCHAL_TIMER3_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
+    #if XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT) <= XCHAL_EXCM_LEVEL
+      #undef  XT_TIMER_INDEX
+      #define XT_TIMER_INDEX    3
+    #endif
+  #endif
+  #if XCHAL_TIMER2_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
+    #if XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL
+      #undef  XT_TIMER_INDEX
+      #define XT_TIMER_INDEX    2
+    #endif
+  #endif
+  #if XCHAL_TIMER1_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
+    #if XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL
+      #undef  XT_TIMER_INDEX
+      #define XT_TIMER_INDEX    1
+    #endif
+  #endif
+  #if XCHAL_TIMER0_INTERRUPT != XTHAL_TIMER_UNCONFIGURED
+    #if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL
+      #undef  XT_TIMER_INDEX
+      #define XT_TIMER_INDEX    0
+    #endif
+  #endif
+#endif
+#ifndef XT_TIMER_INDEX
+  #error "There is no suitable timer in this Xtensa configuration."
+#endif
+
+#define XT_CCOMPARE             (CCOMPARE + XT_TIMER_INDEX)
+#define XT_TIMER_INTNUM         XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX)
+#define XT_TIMER_INTPRI         XCHAL_INT_LEVEL(XT_TIMER_INTNUM)
+#define XT_TIMER_INTEN          (1 << XT_TIMER_INTNUM)
+
+#if XT_TIMER_INTNUM == XTHAL_TIMER_UNCONFIGURED
+  #error "The timer selected by XT_TIMER_INDEX does not exist in this core."
+#elif XT_TIMER_INTPRI > XCHAL_EXCM_LEVEL
+  #error "The timer interrupt cannot be high priority (use medium or low)."
+#endif
+
+#endif /* XCHAL_NUM_TIMERS */
+
+#ifndef RIOT_VERSION
+/*
+Set processor clock frequency, used to determine clock divisor for timer tick.
+User should BE SURE TO ADJUST THIS for the Xtensa platform being used.
+If using a supported board via the board-independent API defined in xtbsp.h,
+this may be left undefined and frequency and tick divisor will be computed
+and cached during run-time initialization.
+
+NOTE ON SIMULATOR:
+Under the Xtensa instruction set simulator, the frequency can only be estimated
+because it depends on the speed of the host and the version of the simulator.
+Also because it runs much slower than hardware, it is not possible to achieve
+real-time performance for most applications under the simulator. A frequency
+too low does not allow enough time between timer interrupts, starving threads.
+To obtain a more convenient but non-real-time tick duration on the simulator,
+compile with xt-xcc option "-DXT_SIMULATOR".
+Adjust this frequency to taste (it's not real-time anyway!).
+*/
+#if defined(XT_SIMULATOR) && !defined(XT_CLOCK_FREQ)
+#define XT_CLOCK_FREQ       configCPU_CLOCK_HZ
+#endif
+
+#if !defined(XT_CLOCK_FREQ) && !defined(XT_BOARD)
+  #error "XT_CLOCK_FREQ must be defined for the target platform."
+#endif
+
+/*
+Default number of timer "ticks" per second (default 100 for 10ms tick).
+RTOS may define this in its own way (if applicable) in xtensa_rtos.h.
+User may redefine this to an optimal value for the application, either by
+editing this here or in xtensa_rtos.h, or compiling with xt-xcc option
+"-DXT_TICK_PER_SEC=<value>" where <value> is a suitable number.
+*/
+
+#ifndef XT_TICK_PER_SEC
+#define XT_TICK_PER_SEC    configTICK_RATE_HZ        /* 10 ms tick = 100 ticks per second */
+#endif
+
+/*
+Derivation of clock divisor for timer tick and interrupt (one per tick).
+*/
+#ifdef XT_CLOCK_FREQ
+#define XT_TICK_DIVISOR     (XT_CLOCK_FREQ / XT_TICK_PER_SEC)
+#endif
+#endif /* ifndef RIOT_VERSION */
+
+#ifndef __ASSEMBLER__
+extern unsigned _xt_tick_divisor;
+extern void     _xt_tick_divisor_init(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XTENSA_TIMER_H */
diff --git a/cpu/esp8266/vendor/xtensa/xtensa_vectors.S b/cpu/esp8266/vendor/xtensa/xtensa_vectors.S
new file mode 100644
index 0000000000000000000000000000000000000000..e620f5facc0dc197ed0db1925e334d030edfef13
--- /dev/null
+++ b/cpu/esp8266/vendor/xtensa/xtensa_vectors.S
@@ -0,0 +1,1924 @@
+/*******************************************************************************
+Copyright (c) 2006-2015 Cadence Design Systems Inc.
+
+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.
+--------------------------------------------------------------------------------
+
+        XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS
+
+  Xtensa low level exception and interrupt vectors and handlers for an RTOS.
+
+  Interrupt handlers and user exception handlers support interaction with
+  the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and
+  after user's specific interrupt handlers. These macros are defined in
+  xtensa_<rtos>.h to call suitable functions in a specific RTOS.
+
+  Users can install application-specific interrupt handlers for low and
+  medium level interrupts, by calling xt_set_interrupt_handler(). These
+  handlers can be written in C, and must obey C calling convention. The
+  handler table is indexed by the interrupt number. Each handler may be
+  provided with an argument.
+
+  Note that the system timer interrupt is handled specially, and is
+  dispatched to the RTOS-specific handler. This timer cannot be hooked
+  by application code.
+
+  Optional hooks are also provided to install a handler per level at
+  run-time, made available by compiling this source file with
+  '-DXT_INTEXC_HOOKS' (useful for automated testing).
+
+!!  This file is a template that usually needs to be modified to handle       !!
+!!  application specific interrupts. Search USER_EDIT for helpful comments    !!
+!!  on where to insert handlers and how to write them.                        !!
+
+  Users can also install application-specific exception handlers in the
+  same way, by calling xt_set_exception_handler(). One handler slot is
+  provided for each exception type. Note that some exceptions are handled
+  by the porting layer itself, and cannot be taken over by application
+  code in this manner. These are the alloca, syscall, and coprocessor
+  exceptions.
+
+  The exception handlers can be written in C, and must follow C calling
+  convention. Each handler is passed a pointer to an exception frame as
+  its single argument. The exception frame is created on the stack, and
+  holds the saved context of the thread that took the exception. If the
+  handler returns, the context will be restored and the instruction that
+  caused the exception will be retried. If the handler makes any changes
+  to the saved state in the exception frame, the changes will be applied
+  when restoring the context.
+
+  Because Xtensa is a configurable architecture, this port supports all user
+  generated configurations (except restrictions stated in the release notes).
+  This is accomplished by conditional compilation using macros and functions
+  defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
+  Only the relevant parts of this file will be included in your RTOS build.
+  For example, this file provides interrupt vector templates for all types and
+  all priority levels, but only the ones in your configuration are built.
+
+  NOTES on the use of 'call0' for long jumps instead of 'j':
+   1. This file should be assembled with the -mlongcalls option to xt-xcc.
+   2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to
+      a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the
+      distance from the call to the destination. The linker then relaxes
+      it back to 'call0 dest' if it determines that dest is within range.
+      This allows more flexibility in locating code without the performance
+      overhead of the 'l32r' literal data load in cases where the destination
+      is in range of 'call0'. There is an additional benefit in that 'call0'
+      has a longer range than 'j' due to the target being word-aligned, so
+      the 'l32r' sequence is less likely needed.
+   3. The use of 'call0' with -mlongcalls requires that register a0 not be
+      live at the time of the call, which is always the case for a function
+      call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'.
+   4. This use of 'call0' is independent of the C function call ABI.
+
+*******************************************************************************/
+
+#include "xtensa_context.h"
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING
+
+#include "xtensa_rtos.h"
+
+/* Enable stack backtrace across exception/interrupt - see below */
+#define XT_DEBUG_BACKTRACE    1
+
+
+/*
+--------------------------------------------------------------------------------
+  Defines used to access _xtos_interrupt_table.
+--------------------------------------------------------------------------------
+*/
+#define XIE_HANDLER     0
+#define XIE_ARG         4
+#define XIE_SIZE        8
+
+/*
+--------------------------------------------------------------------------------
+  Macro extract_msb - return the input with only the highest bit set.
+
+  Input  : "ain"  - Input value, clobbered.
+  Output : "aout" - Output value, has only one bit set, MSB of "ain".
+  The two arguments must be different AR registers.
+--------------------------------------------------------------------------------
+*/
+
+    .macro  extract_msb     aout ain
+1:
+    addi    \aout, \ain, -1         /* aout = ain - 1        */
+    and     \ain, \ain, \aout       /* ain  = ain & aout     */
+    bnez    \ain, 1b                /* repeat until ain == 0 */
+    addi    \aout, \aout, 1         /* return aout + 1       */
+    .endm
+
+/*
+--------------------------------------------------------------------------------
+  Macro dispatch_c_isr - dispatch interrupts to user ISRs.
+  This will dispatch to user handlers (if any) that are registered in the
+  XTOS dispatch table (_xtos_interrupt_table). These handlers would have
+  been registered by calling _xtos_set_interrupt_handler(). There is one
+  exception - the timer interrupt used by the OS will not be dispatched
+  to a user handler - this must be handled by the caller of this macro.
+
+  Level triggered and software interrupts are automatically deasserted by
+  this code.
+
+  ASSUMPTIONS:
+    -- PS.INTLEVEL is set to "level" at entry
+    -- PS.EXCM = 0, C calling enabled
+
+  NOTE: For CALL0 ABI, a12-a15 have not yet been saved.
+
+  NOTE: This macro will use registers a0 and a2-a6. The arguments are:
+    level -- interrupt level
+    mask  -- interrupt bitmask for this level
+--------------------------------------------------------------------------------
+*/
+
+    .macro  dispatch_c_isr    level  mask
+
+    /* Get mask of pending, enabled interrupts at this level into a2. */
+
+.L_xt_user_int_&level&:
+    rsr     a2, INTENABLE
+    rsr     a3, INTERRUPT
+    movi    a4, \mask
+    and     a2, a2, a3
+    and     a2, a2, a4
+    beqz    a2, 9f                          /* nothing to do */
+
+    /* This bit of code provides a nice debug backtrace in the debugger.
+       It does take a few more instructions, so undef XT_DEBUG_BACKTRACE
+       if you want to save the cycles.
+    */
+    #if XT_DEBUG_BACKTRACE
+    #ifndef __XTENSA_CALL0_ABI__
+    rsr     a0, EPC_1 + \level - 1          /* return address */
+    movi    a4, 0xC0000000                  /* constant with top 2 bits set (call size) */
+    or      a0, a0, a4                      /* set top 2 bits */
+    addx2   a0, a4, a0                      /* clear top bit -- simulating call4 size   */
+    #endif
+    #endif
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a4, _xt_intexc_hooks
+    l32i    a4, a4, \level << 2
+    beqz    a4, 2f
+    #ifdef __XTENSA_CALL0_ABI__
+    callx0  a4
+    beqz    a2, 9f
+    #else
+    mov     a6, a2
+    callx4  a4
+    beqz    a6, 9f
+    mov     a2, a6
+    #endif
+2:
+    #endif
+
+    /* Now look up in the dispatch table and call user ISR if any. */
+    /* If multiple bits are set then MSB has highest priority.     */
+
+    extract_msb  a4, a2                     /* a4 = MSB of a2, a2 trashed */
+
+    #ifdef XT_USE_SWPRI
+    /* Enable all interrupts at this level that are numerically higher
+       than the one we just selected, since they are treated as higher
+       priority.
+    */
+    movi    a3, \mask                       /* a3 = all interrupts at this level */
+    add     a2, a4, a4                      /* a2 = a4 << 1 */
+    addi    a2, a2, -1                      /* a2 = mask of 1's <= a4 bit */
+    and     a2, a2, a3                      /* a2 = mask of all bits <= a4 at this level */
+    movi    a3, _xt_intdata
+    l32i    a6, a3, 4                       /* a6 = _xt_vpri_mask */
+    neg     a2, a2
+    addi    a2, a2, -1                      /* a2 = mask to apply */
+    and     a5, a6, a2                      /* mask off all bits <= a4 bit */
+    s32i    a5, a3, 4                       /* update _xt_vpri_mask */
+    rsr     a3, INTENABLE
+    and     a3, a3, a2                      /* mask off all bits <= a4 bit */
+    wsr     a3, INTENABLE
+    rsil    a3, \level - 1                  /* lower interrupt level by 1 */
+    #endif
+
+    movi    a3, XT_TIMER_INTEN              /* a3 = timer interrupt bit */
+    wsr     a4, INTCLEAR                    /* clear sw or edge-triggered interrupt */
+
+    #ifndef RIOT_VERSION                    /* we use it as hardware timer in RIOT OS */
+    beq     a3, a4, 7f                      /* if timer interrupt then skip table */
+    #endif
+
+    find_ms_setbit a3, a4, a3, 0            /* a3 = interrupt number */
+
+#if MODULE_ESP_SDK                                /* _xtos_interrupt_table is in reverse order */
+    movi    a4, XCHAL_NUM_INTERRUPTS        /* intnum = XCHAL_NUM_INTERRUPTS - intnum */
+    sub     a3, a4, a3
+#endif
+    movi    a4, _xt_interrupt_table
+    addx8   a3, a3, a4                      /* a3 = address of interrupt table entry */
+    l32i    a4, a3, XIE_HANDLER             /* a4 = handler address */
+    #ifdef __XTENSA_CALL0_ABI__
+    mov     a12, a6                         /* save in callee-saved reg */
+    l32i    a2, a3, XIE_ARG                 /* a2 = handler arg */
+    callx0  a4                              /* call handler */
+    mov     a2, a12
+    #else
+    mov     a2, a6                          /* save in windowed reg */
+    l32i    a6, a3, XIE_ARG                 /* a6 = handler arg */
+    callx4  a4                              /* call handler */
+    #endif
+
+    #ifdef XT_USE_SWPRI
+    j       8f
+    #else
+    j       .L_xt_user_int_&level&          /* check for more interrupts */
+    #endif
+
+7:
+
+    .ifeq XT_TIMER_INTPRI - \level
+.L_xt_user_int_timer_&level&:
+    /*
+    Interrupt handler for the RTOS tick timer if at this level.
+    We'll be reading the interrupt state again after this call
+    so no need to preserve any registers except a6 (vpri_mask).
+    */
+    #ifdef __XTENSA_CALL0_ABI__
+    mov     a12, a6
+    call0   XT_RTOS_TIMER_INT
+    mov     a2, a12
+    #else
+    mov     a2, a6
+    call4   XT_RTOS_TIMER_INT
+    #endif
+    .endif
+
+    #ifdef XT_USE_SWPRI
+    j       8f
+    #else
+    j       .L_xt_user_int_&level&          /* check for more interrupts */
+    #endif
+
+    #ifdef XT_USE_SWPRI
+8:
+    /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from
+       virtual _xt_intenable which _could_ have changed during interrupt
+       processing. */
+
+    movi    a3, _xt_intdata
+    l32i    a4, a3, 0                       /* a4 = _xt_intenable    */
+    s32i    a2, a3, 4                       /* update _xt_vpri_mask  */
+    and     a4, a4, a2                      /* a4 = masked intenable */
+    wsr     a4, INTENABLE                   /* update INTENABLE      */
+    #endif
+
+9:
+    /* done */
+
+    .endm
+
+
+/*
+--------------------------------------------------------------------------------
+  Panic handler.
+  Should be reached by call0 (preferable) or jump only. If call0, a0 says where
+  from. If on simulator, display panic message and abort, else loop indefinitely.
+--------------------------------------------------------------------------------
+*/
+
+    .text
+    .global     _xt_panic
+    .type       _xt_panic,@function
+    .align      4
+
+_xt_panic:
+    #ifdef XT_SIMULATOR
+    addi    a4, a0, -3                      /* point to call0 */
+    movi    a3, _xt_panic_message
+    movi    a2, SYS_log_msg
+    simcall
+    movi    a2, SYS_gdb_abort
+    simcall
+    #else
+    rsil    a2, XCHAL_EXCM_LEVEL            /* disable all low & med ints */
+1:  j       1b                              /* loop infinitely */
+    #endif
+
+    .section    .rodata, "a"
+    .align      4
+
+_xt_panic_message:
+    .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n"
+
+
+/*
+--------------------------------------------------------------------------------
+    Hooks to dynamically install handlers for exceptions and interrupts.
+    Allows automated regression frameworks to install handlers per test.
+    Consists of an array of function pointers indexed by interrupt level,
+    with index 0 containing the entry for user exceptions.
+    Initialized with all 0s, meaning no handler is installed at each level.
+    See comment in xtensa_rtos.h for more details.
+--------------------------------------------------------------------------------
+*/
+
+    #ifdef XT_INTEXC_HOOKS
+    .data
+    .global     _xt_intexc_hooks
+    .type       _xt_intexc_hooks,@object
+    .align      4
+
+_xt_intexc_hooks:
+    .fill       XT_INTEXC_HOOK_NUM, 4, 0
+    #endif
+
+
+/*
+--------------------------------------------------------------------------------
+  EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS
+  (except window exception vectors).
+
+  Each vector goes at a predetermined location according to the Xtensa
+  hardware configuration, which is ensured by its placement in a special
+  section known to the Xtensa linker support package (LSP). It performs
+  the minimum necessary before jumping to the handler in the .text section.
+
+  The corresponding handler goes in the normal .text section. It sets up
+  the appropriate stack frame, saves a few vector-specific registers and
+  calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
+  and enter the RTOS, then sets up a C environment. It then calls the
+  user's interrupt handler code (which may be coded in C) and finally
+  calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
+
+  While XT_RTOS_INT_EXIT does not return directly to the interruptee,
+  eventually the RTOS scheduler will want to dispatch the interrupted
+  task or handler. The scheduler will return to the exit point that was
+  saved in the interrupt stack frame at XT_STK_EXIT.
+--------------------------------------------------------------------------------
+*/
+
+
+/*
+--------------------------------------------------------------------------------
+Debug Exception.
+--------------------------------------------------------------------------------
+*/
+
+#if XCHAL_HAVE_DEBUG
+
+    .begin      literal_prefix .DebugExceptionVector
+    .section    .DebugExceptionVector.text, "ax"
+    .global     _DebugExceptionVector
+    .literal_position
+    .align      4
+
+_DebugExceptionVector:
+
+    #ifdef XT_SIMULATOR
+    /*
+    In the simulator, let the debugger (if any) handle the debug exception,
+    or simply stop the simulation:
+    */
+    wsr     a2, EXCSAVE+XCHAL_DEBUGLEVEL    /* save a2 where sim expects it */
+    movi    a2, SYS_gdb_enter_sktloop
+    simcall                                 /* have ISS handle debug exc. */
+    #elif 0 /* change condition to 1 to use the HAL minimal debug handler */
+    wsr     a3, EXCSAVE+XCHAL_DEBUGLEVEL
+    movi    a3, xthal_debugexc_defhndlr_nw  /* use default debug handler */
+    jx      a3
+    #else
+    wsr     a0, EXCSAVE+XCHAL_DEBUGLEVEL    /* save original a0 somewhere */
+    call0   _xt_panic                       /* does not return */
+    rfi     XCHAL_DEBUGLEVEL                /* make a0 point here not later */
+    #endif
+
+    .end        literal_prefix
+
+#endif
+
+/*
+--------------------------------------------------------------------------------
+Double Exception.
+Double exceptions are not a normal occurrence. They indicate a bug of some kind.
+--------------------------------------------------------------------------------
+*/
+
+#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR
+
+    .begin      literal_prefix .DoubleExceptionVector
+    .section    .DoubleExceptionVector.text, "ax"
+    .literal_position
+    .global     _DoubleExceptionVector
+    .align      4
+
+_DoubleExceptionVector:
+
+    #if XCHAL_HAVE_DEBUG
+    break   1, 4                            /* unhandled double exception */
+    #endif
+    call0   _xt_panic                       /* does not return */
+    rfde                                    /* make a0 point here not later */
+
+    .end        literal_prefix
+
+#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */
+
+/*
+--------------------------------------------------------------------------------
+Kernel Exception (including Level 1 Interrupt from kernel mode).
+--------------------------------------------------------------------------------
+*/
+
+    .begin      literal_prefix .KernelExceptionVector
+    .section    .KernelExceptionVector.text, "ax"
+    .literal_position
+    .global     _KernelExceptionVector
+    .align      4
+
+_KernelExceptionVector:
+
+    wsr     a0, EXCSAVE_1                   /* preserve a0 */
+    call0   _xt_kernel_exc                  /* kernel exception handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .literal_position
+    .align      4
+
+_xt_kernel_exc:
+    #if XCHAL_HAVE_DEBUG
+    break   1, 0                            /* unhandled kernel exception */
+    #endif
+    call0   _xt_panic                       /* does not return */
+    rfe                                     /* make a0 point here not there */
+
+
+/*
+--------------------------------------------------------------------------------
+User Exception (including Level 1 Interrupt from user mode).
+--------------------------------------------------------------------------------
+*/
+
+    .begin      literal_prefix .UserExceptionVector
+    .section    .UserExceptionVector.text, "ax"
+    .literal_position
+    .global     _UserExceptionVector
+    .type       _UserExceptionVector,@function
+    .align      4
+
+_UserExceptionVector:
+
+    wsr     a0, EXCSAVE_1                   /* preserve a0 */
+    call0   _xt_user_exc                    /* user exception handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+/*
+--------------------------------------------------------------------------------
+  Insert some waypoints for jumping beyond the signed 8-bit range of
+  conditional branch instructions, so the conditional branchces to specific
+  exception handlers are not taken in the mainline. Saves some cycles in the
+  mainline.
+--------------------------------------------------------------------------------
+*/
+
+    .text
+
+    #if XCHAL_HAVE_WINDOWED
+    .align      4
+_xt_to_alloca_exc:
+    call0   _xt_alloca_exc                  /* in window vectors section */
+    /* never returns here - call0 is used as a jump (see note at top) */
+    #endif
+
+    .align      4
+_xt_to_syscall_exc:
+    call0   _xt_syscall_exc
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    #if XCHAL_CP_NUM > 0
+    .align      4
+_xt_to_coproc_exc:
+    call0   _xt_coproc_exc
+    /* never returns here - call0 is used as a jump (see note at top) */
+    #endif
+
+
+/*
+--------------------------------------------------------------------------------
+  User exception handler.
+--------------------------------------------------------------------------------
+*/
+
+    .type       _xt_user_exc,@function
+    .align      4
+
+_xt_user_exc:
+
+    /* If level 1 interrupt then jump to the dispatcher */
+    rsr     a0, EXCCAUSE
+    beqi    a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1
+
+    /* Handle any coprocessor exceptions. Rely on the fact that exception
+       numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors.
+    */
+    #if XCHAL_CP_NUM > 0
+    bgeui   a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc
+    #endif
+
+    /* Handle alloca and syscall exceptions */
+    #if XCHAL_HAVE_WINDOWED
+    beqi    a0, EXCCAUSE_ALLOCA,  _xt_to_alloca_exc
+    #endif
+    beqi    a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc
+
+    /* Handle all other exceptions. All can have user-defined handlers. */
+    /* NOTE: we'll stay on the user stack for exception handling.       */
+
+    /* Allocate exception frame and save minimal context. */
+    mov     a0, sp
+    addi    sp, sp, -XT_STK_FRMSZ
+    s32i    a0, sp, XT_STK_A1
+    #if XCHAL_HAVE_WINDOWED
+    s32e    a0, sp, -12                     /* for debug backtrace */
+    #endif
+    rsr     a0, PS                          /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_1                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    #if XCHAL_HAVE_WINDOWED
+    s32e    a0, sp, -16                     /* for debug backtrace */
+    #endif
+    s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires A12- */
+    s32i    a13, sp, XT_STK_A13             /* A13 to have already been saved */
+    call0   _xt_context_save
+
+    /* Save exc cause and vaddr into exception frame */
+    rsr     a0, EXCCAUSE
+    s32i    a0, sp, XT_STK_EXCCAUSE
+    rsr     a0, EXCVADDR
+    s32i    a0, sp, XT_STK_EXCVADDR
+
+    /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+
+    #ifdef XT_DEBUG_BACKTRACE
+    #ifndef __XTENSA_CALL0_ABI__
+    rsr     a0, EPC_1                       /* return address for debug backtrace */
+    movi    a5, 0xC0000000                  /* constant with top 2 bits set (call size) */
+    rsync                                   /* wait for WSR.PS to complete */
+    or      a0, a0, a5                      /* set top 2 bits */
+    addx2   a0, a5, a0                      /* clear top bit -- thus simulating call4 size */
+    #else
+    rsync                                   /* wait for WSR.PS to complete */
+    #endif
+    #endif
+
+    rsr     a2, EXCCAUSE                    /* recover exc cause */
+
+    #ifdef XT_INTEXC_HOOKS
+    /*
+    Call exception hook to pre-handle exceptions (if installed).
+    Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling).
+    */
+    movi    a4, _xt_intexc_hooks
+    l32i    a4, a4, 0                       /* user exception hook index 0 */
+    beqz    a4, 1f
+.Ln_xt_user_exc_call_hook:
+    #ifdef __XTENSA_CALL0_ABI__
+    callx0  a4
+    beqi    a2, -1, .L_xt_user_done
+    #else
+    mov     a6, a2
+    callx4  a4
+    beqi    a6, -1, .L_xt_user_done
+    mov     a2, a6
+    #endif
+1:
+    #endif
+
+    rsr     a2, EXCCAUSE                    /* recover exc cause */
+    movi    a3, _xt_exception_table
+    addx4   a4, a2, a3                      /* a4 = address of exception table entry */
+    l32i    a4, a4, 0                       /* a4 = handler address */
+    #ifdef __XTENSA_CALL0_ABI__
+    mov     a2, sp                          /* a2 = pointer to exc frame */
+    callx0  a4                              /* call handler */
+    #else
+    mov     a6, sp                          /* a6 = pointer to exc frame */
+    callx4  a4                              /* call handler */
+    #endif
+
+.L_xt_user_done:
+
+    /* Restore context and return */
+    call0   _xt_context_restore
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, PS
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_1
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove exception frame */
+    rsync                                   /* ensure PS and EPC written */
+    rfe                                     /* PS.EXCM is cleared */
+
+#else
+
+    .text
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
+
+/*
+--------------------------------------------------------------------------------
+  Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+  on entry and used to return to a thread or interrupted interrupt handler.
+--------------------------------------------------------------------------------
+*/
+
+    .global     _xt_user_exit
+    .type       _xt_user_exit,@function
+    .align      4
+_xt_user_exit:
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, PS
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_1
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure PS and EPC written */
+    rfe                                     /* PS.EXCM is cleared */
+
+#ifndef MODULE_ESP_SDK_INT_HANDLING
+/*
+--------------------------------------------------------------------------------
+Syscall Exception Handler (jumped to from User Exception Handler).
+Syscall 0 is required to spill the register windows (no-op in Call 0 ABI).
+Only syscall 0 is handled here. Other syscalls return -1 to caller in a2.
+--------------------------------------------------------------------------------
+*/
+
+    .text
+    .type       _xt_syscall_exc,@function
+    .align      4
+_xt_syscall_exc:
+
+    #ifdef __XTENSA_CALL0_ABI__
+    /*
+    Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI.
+    Use a minimal stack frame (16B) to save A2 & A3 for scratch.
+    PS.EXCM could be cleared here, but unlikely to improve worst-case latency.
+    rsr     a0, PS
+    addi    a0, a0, -PS_EXCM_MASK
+    wsr     a0, PS
+    */
+    addi    sp, sp, -16
+    s32i    a2, sp, 8
+    s32i    a3, sp, 12
+    #else   /* Windowed ABI */
+    /*
+    Save necessary context and spill the register windows.
+    PS.EXCM is still set and must remain set until after the spill.
+    Reuse context save function though it saves more than necessary.
+    For this reason, a full interrupt stack frame is allocated.
+    */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires A12- */
+    s32i    a13, sp, XT_STK_A13             /* A13 to have already been saved */
+    call0   _xt_context_save
+    #endif
+
+    /*
+    Grab the interruptee's PC and skip over the 'syscall' instruction.
+    If it's at the end of a zero-overhead loop and it's not on the last
+    iteration, decrement loop counter and skip to beginning of loop.
+    */
+    rsr     a2, EPC_1                       /* a2 = PC of 'syscall' */
+    addi    a3, a2, 3                       /* ++PC                 */
+    #if XCHAL_HAVE_LOOPS
+    rsr     a0, LEND                        /* if (PC == LEND       */
+    bne     a3, a0, 1f
+    rsr     a0, LCOUNT                      /*     && LCOUNT != 0)  */
+    beqz    a0, 1f                          /* {                    */
+    addi    a0, a0, -1                      /*   --LCOUNT           */
+    rsr     a3, LBEG                        /*   PC = LBEG          */
+    wsr     a0, LCOUNT                      /* }                    */
+    #endif
+1:  wsr     a3, EPC_1                       /* update PC            */
+
+    /* Restore interruptee's context and return from exception. */
+    #ifdef __XTENSA_CALL0_ABI__
+    l32i    a2, sp, 8
+    l32i    a3, sp, 12
+    addi    sp, sp, 16
+    #else
+    call0   _xt_context_restore
+    addi    sp, sp, XT_STK_FRMSZ
+    #endif
+    movi    a0, -1
+    movnez  a2, a0, a2                      /* return -1 if not syscall 0 */
+    rsr     a0, EXCSAVE_1
+    rfe
+
+/*
+--------------------------------------------------------------------------------
+Co-Processor Exception Handler (jumped to from User Exception Handler).
+These exceptions are generated by co-processor instructions, which are only
+allowed in thread code (not in interrupts or kernel code). This restriction is
+deliberately imposed to reduce the burden of state-save/restore in interrupts.
+--------------------------------------------------------------------------------
+*/
+#if XCHAL_CP_NUM > 0
+
+    .section .rodata, "a"
+
+/* Offset to CP n save area in thread's CP save area. */
+    .global _xt_coproc_sa_offset
+    .type   _xt_coproc_sa_offset,@object
+    .align  16                      /* minimize crossing cache boundaries */
+_xt_coproc_sa_offset:
+    .word   XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA
+    .word   XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA
+
+/* Bitmask for CP n's CPENABLE bit. */
+    .type   _xt_coproc_mask,@object
+    .align  16,,8                   /* try to keep it all in one cache line */
+    .set    i, 0
+_xt_coproc_mask:
+    .rept   XCHAL_CP_MAX
+    .long   (i<<16) | (1<<i)    // upper 16-bits = i, lower = bitmask
+    .set    i, i+1
+    .endr
+
+    .data
+
+/* Owner thread of CP n, identified by thread's CP save area (0 = unowned). */
+    .global _xt_coproc_owner_sa
+    .type   _xt_coproc_owner_sa,@object
+    .align  16,,XCHAL_CP_MAX<<2     /* minimize crossing cache boundaries */
+_xt_coproc_owner_sa:
+    .space  XCHAL_CP_MAX << 2
+
+    .text
+
+
+    .align  4
+.L_goto_invalid:
+    j   .L_xt_coproc_invalid    /* not in a thread (invalid) */
+    .align  4
+.L_goto_done:
+    j   .L_xt_coproc_done
+
+
+/*
+--------------------------------------------------------------------------------
+  Coprocessor exception handler.
+  At entry, only a0 has been saved (in EXCSAVE_1).
+--------------------------------------------------------------------------------
+*/
+
+    .type   _xt_coproc_exc,@function
+    .align  4
+
+_xt_coproc_exc:
+
+    /* Allocate interrupt stack frame and save minimal context. */
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    #if XCHAL_HAVE_WINDOWED
+    s32e    a0, sp, -12                     /* for debug backtrace */
+    #endif
+    rsr     a0, PS                          /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_1                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    #if XCHAL_HAVE_WINDOWED
+    s32e    a0, sp, -16                     /* for debug backtrace */
+    #endif
+    movi    a0, _xt_user_exit               /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    rsr     a0, EXCCAUSE
+    s32i    a5, sp, XT_STK_A5               /* save a5 */
+    addi    a5, a0, -EXCCAUSE_CP0_DISABLED  /* a5 = CP index */
+
+    /* Save a few more of interruptee's registers (a5 was already saved). */
+    s32i    a2,  sp, XT_STK_A2
+    s32i    a3,  sp, XT_STK_A3
+    s32i    a4,  sp, XT_STK_A4
+    s32i    a15, sp, XT_STK_A15
+
+    /* Get co-processor state save area of new owner thread. */
+    call0   XT_RTOS_CP_STATE                /* a15 = new owner's save area */
+    beqz    a15, .L_goto_invalid            /* not in a thread (invalid) */
+
+    /* Enable the co-processor's bit in CPENABLE. */
+    movi    a0, _xt_coproc_mask
+    rsr     a4, CPENABLE                    /* a4 = CPENABLE */
+    addx4   a0, a5, a0                      /* a0 = &_xt_coproc_mask[n] */
+    l32i    a0, a0, 0                       /* a0 = (n << 16) | (1 << n) */
+    movi    a3, _xt_coproc_owner_sa     /* (placed here for load slot) */
+    extui   a2, a0, 0, 16                   /* coprocessor bitmask portion */
+    or      a4, a4, a2                      /* a4 = CPENABLE | (1 << n) */
+    wsr     a4, CPENABLE
+
+    /* Get old coprocessor owner thread (save area ptr) and assign new one.  */
+    addx4   a3,  a5, a3                      /* a3 = &_xt_coproc_owner_sa[n] */
+    l32i    a2,  a3, 0                       /* a2 = old owner's save area */
+    s32i    a15, a3, 0                       /* _xt_coproc_owner_sa[n] = new */
+    rsync                                    /* ensure wsr.CPENABLE is complete */
+
+    /* Only need to context switch if new owner != old owner. */
+    beq     a15, a2, .L_goto_done           /* new owner == old, we're done */
+
+    /* If no old owner then nothing to save. */
+    beqz    a2, .L_check_new
+
+    /* If old owner not actively using CP then nothing to save. */
+    l16ui   a4,  a2,  XT_CPENABLE           /* a4 = old owner's CPENABLE */
+    bnone   a4,  a0,  .L_check_new          /* old owner not using CP    */
+
+.L_save_old:
+    /* Save old owner's coprocessor state. */
+
+    movi    a5, _xt_coproc_sa_offset
+
+    /* Mark old owner state as no longer active (CPENABLE bit n clear). */
+    xor     a4,  a4,  a0                    /* clear CP bit in CPENABLE    */
+    s16i    a4,  a2,  XT_CPENABLE           /* update old owner's CPENABLE */
+
+    extui   a4,  a0,  16,  5                /* a4 = CP index = n */
+    addx4   a5,  a4,  a5                    /* a5 = &_xt_coproc_sa_offset[n] */
+
+    /* Mark old owner state as saved (CPSTORED bit n set). */
+    l16ui   a4,  a2,  XT_CPSTORED           /* a4 = old owner's CPSTORED */
+    l32i    a5,  a5,  0                     /* a5 = XT_CP[n]_SA offset */
+    or      a4,  a4,  a0                    /* set CP in old owner's CPSTORED */
+    s16i    a4,  a2,  XT_CPSTORED           /* update old owner's CPSTORED */
+    l32i    a2, a2, XT_CP_ASA               /* ptr to actual (aligned) save area */
+    extui   a3, a0, 16, 5                   /* a3 = CP index = n */
+    add     a2, a2, a5                      /* a2 = old owner's area for CP n */
+
+    /*
+    The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
+    It is theoretically possible for Xtensa processor designers to write TIE
+    that causes more address registers to be affected, but it is generally
+    unlikely. If that ever happens, more registers needs to be saved/restored
+    around this macro invocation, and the value in a15 needs to be recomputed.
+    */
+    xchal_cpi_store_funcbody
+
+.L_check_new:
+    /* Check if any state has to be restored for new owner. */
+    /* NOTE: a15 = new owner's save area, cannot be zero when we get here. */
+
+    l16ui   a3,  a15, XT_CPSTORED           /* a3 = new owner's CPSTORED */
+    movi    a4, _xt_coproc_sa_offset
+    bnone   a3,  a0,  .L_check_cs           /* full CP not saved, check callee-saved */
+    xor     a3,  a3,  a0                    /* CPSTORED bit is set, clear it */
+    s16i    a3,  a15, XT_CPSTORED           /* update new owner's CPSTORED */
+
+    /* Adjust new owner's save area pointers to area for CP n. */
+    extui   a3,  a0, 16, 5                  /* a3 = CP index = n */
+    addx4   a4,  a3, a4                     /* a4 = &_xt_coproc_sa_offset[n] */
+    l32i    a4,  a4, 0                      /* a4 = XT_CP[n]_SA */
+    l32i    a5, a15, XT_CP_ASA              /* ptr to actual (aligned) save area */
+    add     a2,  a4, a5                     /* a2 = new owner's area for CP */
+
+    /*
+    The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
+    It is theoretically possible for Xtensa processor designers to write TIE
+    that causes more address registers to be affected, but it is generally
+    unlikely. If that ever happens, more registers needs to be saved/restored
+    around this macro invocation.
+    */
+    xchal_cpi_load_funcbody
+
+    /* Restore interruptee's saved registers. */
+    /* Can omit rsync for wsr.CPENABLE here because _xt_user_exit does it. */
+.L_xt_coproc_done:
+    l32i    a15, sp, XT_STK_A15
+    l32i    a5,  sp, XT_STK_A5
+    l32i    a4,  sp, XT_STK_A4
+    l32i    a3,  sp, XT_STK_A3
+    l32i    a2,  sp, XT_STK_A2
+    call0   _xt_user_exit                   /* return via exit dispatcher */
+    /* Never returns here - call0 is used as a jump (see note at top) */
+
+.L_check_cs:
+    /* a0 = CP mask in low bits, a15 = new owner's save area */
+    l16ui   a2, a15, XT_CP_CS_ST            /* a2 = mask of CPs saved    */
+    bnone   a2,  a0, .L_xt_coproc_done      /* if no match then done     */
+    and     a2,  a2, a0                     /* a2 = which CPs to restore */
+    extui   a2,  a2, 0, 8                   /* extract low 8 bits        */
+    s32i    a6,  sp, XT_STK_A6              /* save extra needed regs    */
+    s32i    a7,  sp, XT_STK_A7
+    s32i    a13, sp, XT_STK_A13
+    s32i    a14, sp, XT_STK_A14
+    call0   _xt_coproc_restorecs            /* restore CP registers      */
+    l32i    a6,  sp, XT_STK_A6              /* restore saved registers   */
+    l32i    a7,  sp, XT_STK_A7
+    l32i    a13, sp, XT_STK_A13
+    l32i    a14, sp, XT_STK_A14
+    j       .L_xt_coproc_done
+
+    /* Co-processor exception occurred outside a thread (not supported). */
+.L_xt_coproc_invalid:
+    #if XCHAL_HAVE_DEBUG
+    break   1, 1                            /* unhandled user exception */
+    #endif
+    call0   _xt_panic                       /* not in a thread (invalid) */
+    /* never returns */
+
+
+#endif /* XCHAL_CP_NUM */
+
+
+/*
+-------------------------------------------------------------------------------
+  Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet.
+-------------------------------------------------------------------------------
+*/
+
+    .text
+    .type       _xt_lowint1,@function
+    .align      4
+
+_xt_lowint1:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, PS                          /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_1                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_1                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_user_exit               /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(1) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(1) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+
+/*
+-------------------------------------------------------------------------------
+  MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS.
+
+  Medium priority interrupts are by definition those with priority greater
+  than 1 and not greater than XCHAL_EXCM_LEVEL. These are disabled by
+  setting PS.EXCM and therefore can easily support a C environment for
+  handlers in C, and interact safely with an RTOS.
+
+  Each vector goes at a predetermined location according to the Xtensa
+  hardware configuration, which is ensured by its placement in a special
+  section known to the Xtensa linker support package (LSP). It performs
+  the minimum necessary before jumping to the handler in the .text section.
+
+  The corresponding handler goes in the normal .text section. It sets up
+  the appropriate stack frame, saves a few vector-specific registers and
+  calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
+  and enter the RTOS, then sets up a C environment. It then calls the
+  user's interrupt handler code (which may be coded in C) and finally
+  calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
+
+  While XT_RTOS_INT_EXIT does not return directly to the interruptee,
+  eventually the RTOS scheduler will want to dispatch the interrupted
+  task or handler. The scheduler will return to the exit point that was
+  saved in the interrupt stack frame at XT_STK_EXIT.
+-------------------------------------------------------------------------------
+*/
+
+#if XCHAL_EXCM_LEVEL >= 2
+
+    .begin      literal_prefix .Level2InterruptVector
+    .section    .Level2InterruptVector.text, "ax"
+    .global     _Level2Vector
+    .type       _Level2Vector,@function
+    .align      4
+_Level2Vector:
+    wsr     a0, EXCSAVE_2                   /* preserve a0 */
+    call0   _xt_medint2                     /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_medint2,@function
+    .align      4
+_xt_medint2:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, EPS_2                       /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_2                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_2                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_medint2_exit            /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(2) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(2) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+    /*
+    Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+    on entry and used to return to a thread or interrupted interrupt handler.
+    */
+    .global     _xt_medint2_exit
+    .type       _xt_medint2_exit,@function
+    .align      4
+_xt_medint2_exit:
+    /* Restore only level-specific regs (the rest were already restored) */
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, EPS_2
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_2
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure EPS and EPC written */
+    rfi     2
+
+#endif  /* Level 2 */
+
+#if XCHAL_EXCM_LEVEL >= 3
+
+    .begin      literal_prefix .Level3InterruptVector
+    .section    .Level3InterruptVector.text, "ax"
+    .global     _Level3Vector
+    .type       _Level3Vector,@function
+    .align      4
+_Level3Vector:
+    wsr     a0, EXCSAVE_3                   /* preserve a0 */
+    call0   _xt_medint3                     /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_medint3,@function
+    .align      4
+_xt_medint3:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, EPS_3                       /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_3                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_3                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_medint3_exit            /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(3) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(3) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+    /*
+    Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+    on entry and used to return to a thread or interrupted interrupt handler.
+    */
+    .global     _xt_medint3_exit
+    .type       _xt_medint3_exit,@function
+    .align      4
+_xt_medint3_exit:
+    /* Restore only level-specific regs (the rest were already restored) */
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, EPS_3
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_3
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure EPS and EPC written */
+    rfi     3
+
+#endif  /* Level 3 */
+
+#if XCHAL_EXCM_LEVEL >= 4
+
+    .begin      literal_prefix .Level4InterruptVector
+    .section    .Level4InterruptVector.text, "ax"
+    .global     _Level4Vector
+    .type       _Level4Vector,@function
+    .align      4
+_Level4Vector:
+    wsr     a0, EXCSAVE_4                   /* preserve a0 */
+    call0   _xt_medint4                     /* load interrupt handler */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_medint4,@function
+    .align      4
+_xt_medint4:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, EPS_4                       /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_4                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_4                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_medint4_exit            /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(4) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(4) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+    /*
+    Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+    on entry and used to return to a thread or interrupted interrupt handler.
+    */
+    .global     _xt_medint4_exit
+    .type       _xt_medint4_exit,@function
+    .align      4
+_xt_medint4_exit:
+    /* Restore only level-specific regs (the rest were already restored) */
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, EPS_4
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_4
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure EPS and EPC written */
+    rfi     4
+
+#endif  /* Level 4 */
+
+#if XCHAL_EXCM_LEVEL >= 5
+
+    .begin      literal_prefix .Level5InterruptVector
+    .section    .Level5InterruptVector.text, "ax"
+    .global     _Level5Vector
+    .type       _Level5Vector,@function
+    .align      4
+_Level5Vector:
+    wsr     a0, EXCSAVE_5                   /* preserve a0 */
+    call0   _xt_medint5                     /* load interrupt handler */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_medint5,@function
+    .align      4
+_xt_medint5:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, EPS_5                       /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_5                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_5                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_medint5_exit            /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(5) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+    /*
+    Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+    on entry and used to return to a thread or interrupted interrupt handler.
+    */
+    .global     _xt_medint5_exit
+    .type       _xt_medint5_exit,@function
+    .align      4
+_xt_medint5_exit:
+    /* Restore only level-specific regs (the rest were already restored) */
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, EPS_5
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_5
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure EPS and EPC written */
+    rfi     5
+
+#endif  /* Level 5 */
+
+#if XCHAL_EXCM_LEVEL >= 6
+
+    .begin      literal_prefix .Level6InterruptVector
+    .section    .Level6InterruptVector.text, "ax"
+    .global     _Level6Vector
+    .type       _Level6Vector,@function
+    .align      4
+_Level6Vector:
+    wsr     a0, EXCSAVE_6                   /* preserve a0 */
+    call0   _xt_medint6                     /* load interrupt handler */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_medint6,@function
+    .align      4
+_xt_medint6:
+    mov     a0, sp                          /* sp == a1 */
+    addi    sp, sp, -XT_STK_FRMSZ           /* allocate interrupt stack frame */
+    s32i    a0, sp, XT_STK_A1               /* save pre-interrupt SP */
+    rsr     a0, EPS_6                       /* save interruptee's PS */
+    s32i    a0, sp, XT_STK_PS
+    rsr     a0, EPC_6                       /* save interruptee's PC */
+    s32i    a0, sp, XT_STK_PC
+    rsr     a0, EXCSAVE_6                   /* save interruptee's a0 */
+    s32i    a0, sp, XT_STK_A0
+    movi    a0, _xt_medint6_exit            /* save exit point for dispatch */
+    s32i    a0, sp, XT_STK_EXIT
+
+    /* Save rest of interrupt context and enter RTOS. */
+    call0   XT_RTOS_INT_ENTER               /* common RTOS interrupt entry */
+
+    /* !! We are now on the RTOS system stack !! */
+
+    /* Set up PS for C, enable interrupts above this level and clear EXCM. */
+    #ifdef __XTENSA_CALL0_ABI__
+    movi    a0, PS_INTLEVEL(6) | PS_UM
+    #else
+    movi    a0, PS_INTLEVEL(6) | PS_UM | PS_WOE
+    #endif
+    wsr     a0, PS
+    rsync
+
+    /* OK to call C code at this point, dispatch user ISRs */
+
+    dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK
+
+    /* Done handling interrupts, transfer control to OS */
+    call0   XT_RTOS_INT_EXIT                /* does not return directly here */
+
+    /*
+    Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
+    on entry and used to return to a thread or interrupted interrupt handler.
+    */
+    .global     _xt_medint6_exit
+    .type       _xt_medint6_exit,@function
+    .align      4
+_xt_medint6_exit:
+    /* Restore only level-specific regs (the rest were already restored) */
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, EPS_6
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_6
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove interrupt stack frame */
+    rsync                                   /* ensure EPS and EPC written */
+    rfi     6
+
+#endif  /* Level 6 */
+
+
+/*******************************************************************************
+
+HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
+
+High priority interrupts are by definition those with priorities greater
+than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority
+interrupts cannot interact with the RTOS, that is they must save all regs
+they use and not call any RTOS function.
+
+A further restriction imposed by the Xtensa windowed architecture is that
+high priority interrupts must not modify the stack area even logically
+"above" the top of the interrupted stack (they need to provide their
+own stack or static save area).
+
+Cadence Design Systems recommends high priority interrupt handlers be coded in assembly
+and used for purposes requiring very short service times.
+
+Here are templates for high priority (level 2+) interrupt vectors.
+They assume only one interrupt per level to avoid the burden of identifying
+which interrupts at this level are pending and enabled. This allows for
+minimum latency and avoids having to save/restore a2 in addition to a0.
+If more than one interrupt per high priority level is configured, this burden
+is on the handler which in any case must provide a way to save and restore
+registers it uses without touching the interrupted stack.
+
+Each vector goes at a predetermined location according to the Xtensa
+hardware configuration, which is ensured by its placement in a special
+section known to the Xtensa linker support package (LSP). It performs
+the minimum necessary before jumping to the handler in the .text section.
+
+*******************************************************************************/
+
+/*
+Currently only shells for high priority interrupt handlers are provided
+here. However a template and example can be found in the Cadence Design Systems tools
+documentation: "Microprocessor Programmer's Guide".
+*/
+
+#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
+
+    .begin      literal_prefix .Level2InterruptVector
+    .section    .Level2InterruptVector.text, "ax"
+    .global     _Level2Vector
+    .type       _Level2Vector,@function
+    .align      4
+_Level2Vector:
+    wsr     a0, EXCSAVE_2                   /* preserve a0 */
+    call0   _xt_highint2                    /* load interrupt handler */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_highint2,@function
+    .align      4
+_xt_highint2:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, 2<<2
+    beqz    a0, 1f
+.Ln_xt_highint2_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_highint2_exit:
+    rsr     a0, EXCSAVE_2                   /* restore a0 */
+    rfi     2
+
+#endif  /* Level 2 */
+
+#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
+
+    .begin      literal_prefix .Level3InterruptVector
+    .section    .Level3InterruptVector.text, "ax"
+    .global     _Level3Vector
+    .type       _Level3Vector,@function
+    .align      4
+_Level3Vector:
+    wsr     a0, EXCSAVE_3                   /* preserve a0 */
+    call0   _xt_highint3                    /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_highint3,@function
+    .align      4
+_xt_highint3:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, 3<<2
+    beqz    a0, 1f
+.Ln_xt_highint3_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_highint3_exit:
+    rsr     a0, EXCSAVE_3                   /* restore a0 */
+    rfi     3
+
+#endif  /* Level 3 */
+
+#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
+
+    .begin      literal_prefix .Level4InterruptVector
+    .section    .Level4InterruptVector.text, "ax"
+    .global     _Level4Vector
+    .type       _Level4Vector,@function
+    .align      4
+_Level4Vector:
+    wsr     a0, EXCSAVE_4                   /* preserve a0 */
+    call0   _xt_highint4                    /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_highint4,@function
+    .align      4
+_xt_highint4:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, 4<<2
+    beqz    a0, 1f
+.Ln_xt_highint4_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_highint4_exit:
+    rsr     a0, EXCSAVE_4                   /* restore a0 */
+    rfi     4
+
+#endif  /* Level 4 */
+
+#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
+
+    .begin      literal_prefix .Level5InterruptVector
+    .section    .Level5InterruptVector.text, "ax"
+    .global     _Level5Vector
+    .type       _Level5Vector,@function
+    .align      4
+_Level5Vector:
+    wsr     a0, EXCSAVE_5                   /* preserve a0 */
+    call0   _xt_highint5                    /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_highint5,@function
+    .align      4
+_xt_highint5:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, 5<<2
+    beqz    a0, 1f
+.Ln_xt_highint5_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_highint5_exit:
+    rsr     a0, EXCSAVE_5                   /* restore a0 */
+    rfi     5
+
+#endif  /* Level 5 */
+
+#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
+
+    .begin      literal_prefix .Level6InterruptVector
+    .section    .Level6InterruptVector.text, "ax"
+    .global     _Level6Vector
+    .type       _Level6Vector,@function
+    .align      4
+_Level6Vector:
+    wsr     a0, EXCSAVE_6                   /* preserve a0 */
+    call0   _xt_highint6                    /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_highint6,@function
+    .align      4
+_xt_highint6:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, 6<<2
+    beqz    a0, 1f
+.Ln_xt_highint6_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_highint6_exit:
+    rsr     a0, EXCSAVE_6                   /* restore a0 */
+    rfi     6
+
+#endif  /* Level 6 */
+
+#if XCHAL_HAVE_NMI
+
+    .begin      literal_prefix .NMIExceptionVector
+    .section    .NMIExceptionVector.text, "ax"
+    .literal_position
+    .global     _NMIExceptionVector
+    .type       _NMIExceptionVector,@function
+    .align      4
+_NMIExceptionVector:
+    wsr     a0, EXCSAVE + XCHAL_NMILEVEL  _ /* preserve a0 */
+    call0   _xt_nmi                         /* load interrupt handler */
+    /* never returns here - call0 is used as a jump (see note at top) */
+
+    .end        literal_prefix
+
+    .text
+    .type       _xt_nmi,@function
+    .align      4
+_xt_nmi:
+
+    #ifdef XT_INTEXC_HOOKS
+    /* Call interrupt hook if present to (pre)handle interrupts. */
+    movi    a0, _xt_intexc_hooks
+    l32i    a0, a0, XCHAL_NMILEVEL<<2
+    beqz    a0, 1f
+.Ln_xt_nmi_call_hook:
+    callx0  a0                              /* must NOT disturb stack! */
+1:
+    #endif
+
+    /* USER_EDIT:
+    ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE.
+    */
+
+    .align  4
+.L_xt_nmi_exit:
+    rsr     a0, EXCSAVE + XCHAL_NMILEVEL    /* restore a0 */
+    rfi     XCHAL_NMILEVEL
+
+#endif  /* NMI */
+
+
+/*******************************************************************************
+
+WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER
+
+Here is the code for each window overflow/underflow exception vector and
+(interspersed) efficient code for handling the alloca exception cause.
+Window exceptions are handled entirely in the vector area and are very
+tight for performance. The alloca exception is also handled entirely in
+the window vector area so comes at essentially no cost in code size.
+Users should never need to modify them and Cadence Design Systems recommends
+they do not.
+
+Window handlers go at predetermined vector locations according to the
+Xtensa hardware configuration, which is ensured by their placement in a
+special section known to the Xtensa linker support package (LSP). Since
+their offsets in that section are always the same, the LSPs do not define
+a section per vector.
+
+These things are coded for XEA2 only (XEA1 is not supported).
+
+Note on Underflow Handlers:
+The underflow handler for returning from call[i+1] to call[i]
+must preserve all the registers from call[i+1]'s window.
+In particular, a0 and a1 must be preserved because the RETW instruction
+will be reexecuted (and may even underflow if an intervening exception
+has flushed call[i]'s registers).
+Registers a2 and up may contain return values.
+
+*******************************************************************************/
+
+#if XCHAL_HAVE_WINDOWED
+
+    .section .WindowVectors.text, "ax"
+
+/*
+--------------------------------------------------------------------------------
+Window Overflow Exception for Call4.
+
+Invoked if a call[i] referenced a register (a4-a15)
+that contains data from ancestor call[j];
+call[j] had done a call4 to call[j+1].
+On entry here:
+    window rotated to call[j] start point;
+        a0-a3 are registers to be saved;
+        a4-a15 must be preserved;
+        a5 is call[j+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org    0x0
+    .global _WindowOverflow4
+_WindowOverflow4:
+
+    s32e    a0, a5, -16     /* save a0 to call[j+1]'s stack frame */
+    s32e    a1, a5, -12     /* save a1 to call[j+1]'s stack frame */
+    s32e    a2, a5,  -8     /* save a2 to call[j+1]'s stack frame */
+    s32e    a3, a5,  -4     /* save a3 to call[j+1]'s stack frame */
+    rfwo                    /* rotates back to call[i] position */
+
+/*
+--------------------------------------------------------------------------------
+Window Underflow Exception for Call4
+
+Invoked by RETW returning from call[i+1] to call[i]
+where call[i]'s registers must be reloaded (not live in ARs);
+where call[i] had done a call4 to call[i+1].
+On entry here:
+        window rotated to call[i] start point;
+        a0-a3 are undefined, must be reloaded with call[i].reg[0..3];
+        a4-a15 must be preserved (they are call[i+1].reg[0..11]);
+        a5 is call[i+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org    0x40
+    .global _WindowUnderflow4
+_WindowUnderflow4:
+
+    l32e    a0, a5, -16     /* restore a0 from call[i+1]'s stack frame */
+    l32e    a1, a5, -12     /* restore a1 from call[i+1]'s stack frame */
+    l32e    a2, a5,  -8     /* restore a2 from call[i+1]'s stack frame */
+    l32e    a3, a5,  -4     /* restore a3 from call[i+1]'s stack frame */
+    rfwu
+
+/*
+--------------------------------------------------------------------------------
+Handle alloca exception generated by interruptee executing 'movsp'.
+This uses space between the window vectors, so is essentially "free".
+All interruptee's regs are intact except a0 which is saved in EXCSAVE_1,
+and PS.EXCM has been set by the exception hardware (can't be interrupted).
+The fact the alloca exception was taken means the registers associated with
+the base-save area have been spilled and will be restored by the underflow
+handler, so those 4 registers are available for scratch.
+The code is optimized to avoid unaligned branches and minimize cache misses.
+--------------------------------------------------------------------------------
+*/
+
+    .align  4
+    .global _xt_alloca_exc
+_xt_alloca_exc:
+
+    rsr     a0, WINDOWBASE  /* grab WINDOWBASE before rotw changes it */
+    rotw    -1              /* WINDOWBASE goes to a4, new a0-a3 are scratch */
+    rsr     a2, PS
+    extui   a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+    xor     a3, a3, a4      /* bits changed from old to current windowbase */
+    rsr     a4, EXCSAVE_1   /* restore original a0 (now in a4) */
+    slli    a3, a3, XCHAL_PS_OWB_SHIFT
+    xor     a2, a2, a3      /* flip changed bits in old window base */
+    wsr     a2, PS          /* update PS.OWB to new window base */
+    rsync
+
+    _bbci.l a4, 31, _WindowUnderflow4
+    rotw    -1              /* original a0 goes to a8 */
+    _bbci.l a8, 30, _WindowUnderflow8
+    rotw    -1
+    j               _WindowUnderflow12
+
+/*
+--------------------------------------------------------------------------------
+Window Overflow Exception for Call8
+
+Invoked if a call[i] referenced a register (a4-a15)
+that contains data from ancestor call[j];
+call[j] had done a call8 to call[j+1].
+On entry here:
+    window rotated to call[j] start point;
+        a0-a7 are registers to be saved;
+        a8-a15 must be preserved;
+        a9 is call[j+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org    0x80
+    .global _WindowOverflow8
+_WindowOverflow8:
+
+    s32e    a0, a9, -16     /* save a0 to call[j+1]'s stack frame */
+    l32e    a0, a1, -12     /* a0 <- call[j-1]'s sp
+                               (used to find end of call[j]'s frame) */
+    s32e    a1, a9, -12     /* save a1 to call[j+1]'s stack frame */
+    s32e    a2, a9,  -8     /* save a2 to call[j+1]'s stack frame */
+    s32e    a3, a9,  -4     /* save a3 to call[j+1]'s stack frame */
+    s32e    a4, a0, -32     /* save a4 to call[j]'s stack frame */
+    s32e    a5, a0, -28     /* save a5 to call[j]'s stack frame */
+    s32e    a6, a0, -24     /* save a6 to call[j]'s stack frame */
+    s32e    a7, a0, -20     /* save a7 to call[j]'s stack frame */
+    rfwo                    /* rotates back to call[i] position */
+
+/*
+--------------------------------------------------------------------------------
+Window Underflow Exception for Call8
+
+Invoked by RETW returning from call[i+1] to call[i]
+where call[i]'s registers must be reloaded (not live in ARs);
+where call[i] had done a call8 to call[i+1].
+On entry here:
+        window rotated to call[i] start point;
+        a0-a7 are undefined, must be reloaded with call[i].reg[0..7];
+        a8-a15 must be preserved (they are call[i+1].reg[0..7]);
+        a9 is call[i+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org    0xC0
+    .global _WindowUnderflow8
+_WindowUnderflow8:
+
+    l32e    a0, a9, -16     /* restore a0 from call[i+1]'s stack frame */
+    l32e    a1, a9, -12     /* restore a1 from call[i+1]'s stack frame */
+    l32e    a2, a9,  -8     /* restore a2 from call[i+1]'s stack frame */
+    l32e    a7, a1, -12     /* a7 <- call[i-1]'s sp
+                               (used to find end of call[i]'s frame) */
+    l32e    a3, a9,  -4     /* restore a3 from call[i+1]'s stack frame */
+    l32e    a4, a7, -32     /* restore a4 from call[i]'s stack frame */
+    l32e    a5, a7, -28     /* restore a5 from call[i]'s stack frame */
+    l32e    a6, a7, -24     /* restore a6 from call[i]'s stack frame */
+    l32e    a7, a7, -20     /* restore a7 from call[i]'s stack frame */
+    rfwu
+
+/*
+--------------------------------------------------------------------------------
+Window Overflow Exception for Call12
+
+Invoked if a call[i] referenced a register (a4-a15)
+that contains data from ancestor call[j];
+call[j] had done a call12 to call[j+1].
+On entry here:
+    window rotated to call[j] start point;
+        a0-a11 are registers to be saved;
+        a12-a15 must be preserved;
+        a13 is call[j+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org    0x100
+    .global _WindowOverflow12
+_WindowOverflow12:
+
+    s32e    a0,  a13, -16   /* save a0 to call[j+1]'s stack frame */
+    l32e    a0,  a1,  -12   /* a0 <- call[j-1]'s sp
+                               (used to find end of call[j]'s frame) */
+    s32e    a1,  a13, -12   /* save a1 to call[j+1]'s stack frame */
+    s32e    a2,  a13,  -8   /* save a2 to call[j+1]'s stack frame */
+    s32e    a3,  a13,  -4   /* save a3 to call[j+1]'s stack frame */
+    s32e    a4,  a0,  -48   /* save a4 to end of call[j]'s stack frame */
+    s32e    a5,  a0,  -44   /* save a5 to end of call[j]'s stack frame */
+    s32e    a6,  a0,  -40   /* save a6 to end of call[j]'s stack frame */
+    s32e    a7,  a0,  -36   /* save a7 to end of call[j]'s stack frame */
+    s32e    a8,  a0,  -32   /* save a8 to end of call[j]'s stack frame */
+    s32e    a9,  a0,  -28   /* save a9 to end of call[j]'s stack frame */
+    s32e    a10, a0,  -24   /* save a10 to end of call[j]'s stack frame */
+    s32e    a11, a0,  -20   /* save a11 to end of call[j]'s stack frame */
+    rfwo                    /* rotates back to call[i] position */
+
+/*
+--------------------------------------------------------------------------------
+Window Underflow Exception for Call12
+
+Invoked by RETW returning from call[i+1] to call[i]
+where call[i]'s registers must be reloaded (not live in ARs);
+where call[i] had done a call12 to call[i+1].
+On entry here:
+        window rotated to call[i] start point;
+        a0-a11 are undefined, must be reloaded with call[i].reg[0..11];
+        a12-a15 must be preserved (they are call[i+1].reg[0..3]);
+        a13 is call[i+1]'s stack pointer.
+--------------------------------------------------------------------------------
+*/
+
+    .org 0x140
+    .global _WindowUnderflow12
+_WindowUnderflow12:
+
+    l32e    a0,  a13, -16   /* restore a0 from call[i+1]'s stack frame */
+    l32e    a1,  a13, -12   /* restore a1 from call[i+1]'s stack frame */
+    l32e    a2,  a13,  -8   /* restore a2 from call[i+1]'s stack frame */
+    l32e    a11, a1,  -12   /* a11 <- call[i-1]'s sp
+                               (used to find end of call[i]'s frame) */
+    l32e    a3,  a13,  -4   /* restore a3 from call[i+1]'s stack frame */
+    l32e    a4,  a11, -48   /* restore a4 from end of call[i]'s stack frame */
+    l32e    a5,  a11, -44   /* restore a5 from end of call[i]'s stack frame */
+    l32e    a6,  a11, -40   /* restore a6 from end of call[i]'s stack frame */
+    l32e    a7,  a11, -36   /* restore a7 from end of call[i]'s stack frame */
+    l32e    a8,  a11, -32   /* restore a8 from end of call[i]'s stack frame */
+    l32e    a9,  a11, -28   /* restore a9 from end of call[i]'s stack frame */
+    l32e    a10, a11, -24   /* restore a10 from end of call[i]'s stack frame */
+    l32e    a11, a11, -20   /* restore a11 from end of call[i]'s stack frame */
+    rfwu
+
+#endif /* XCHAL_HAVE_WINDOWED */
+
+#endif /* MODULE_ESP_SDK_INT_HANDLING */
diff --git a/dist/tools/licenses/patterns/mit-espressif b/dist/tools/licenses/patterns/mit-espressif
new file mode 100644
index 0000000000000000000000000000000000000000..ea93e1ac61f6badc1ed86c78f3bfdcb328552465
--- /dev/null
+++ b/dist/tools/licenses/patterns/mit-espressif
@@ -0,0 +1,16 @@
+Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+it is 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\.
diff --git a/examples/lua_REPL/Makefile b/examples/lua_REPL/Makefile
index 90bcaf8304cf02fc4a1fa34c11f605ef294b4b34..67ecf11d95f2ca7111117cec6bbd3a7e56588d78 100644
--- a/examples/lua_REPL/Makefile
+++ b/examples/lua_REPL/Makefile
@@ -23,7 +23,8 @@ BOARD_INSUFFICIENT_MEMORY := bluepill calliope-mini cc2650-launchpad \
                              saml21-xpro samr21-xpro seeeduino_arch-pro \
                              sensebox_samd21 slstk3401a sltb001a slwstk6220a \
                              sodaq-autonomo sodaq-explorer sodaq-one stk3600 \
-                             stm32f3discovery yunjia-nrf51822
+                             stm32f3discovery yunjia-nrf51822 \
+                             esp8266-esp-12x esp8266-olimex-mod esp8266-sparkfun-thing
 
 BOARD_BLACKLIST := arduino-duemilanove arduino-mega2560 arduino-uno \
                    chronos hifive1 jiminy-mega256rfr2 mega-xplained mips-malta \
diff --git a/tests/ssp/Makefile b/tests/ssp/Makefile
index 5e6c29fc35c6c1d0ad83f09f9ba162d8b098f089..a4e7aeb5b5d1e549a1c75b3c70c2f92e7c5596b2 100644
--- a/tests/ssp/Makefile
+++ b/tests/ssp/Makefile
@@ -1,9 +1,10 @@
 include ../Makefile.tests_common
 
-# avr8, msp430 and mips don't support ssp (yet)
+# avr8, msp430, esp8266 and mips don't support ssp (yet)
 BOARD_BLACKLIST := arduino-mega2560 waspmote-pro arduino-uno arduino-duemilanove \
                    chronos msb-430 msb-430h telosb wsn430-v1_3b wsn430-v1_4 z1 \
-                   pic32-clicker pic32-wifire jiminy-mega256rfr2 mega-xplained
+                   pic32-clicker pic32-wifire jiminy-mega256rfr2 mega-xplained \
+                   esp8266-esp-12x esp8266-olimex-mod esp8266-sparkfun-thing
 
 USEMODULE += ssp