Commit 7b83bbb2 authored by Arnim Läuger's avatar Arnim Läuger Committed by GitHub
Browse files

Merge pull request #1519 from nodemcu/dev

Next 1.5.4.1 master drop
parents 8e48483c d96d7f23
......@@ -7,7 +7,7 @@ Use one of the two templates below and delete the rest.
### Actual behavior
### Test code
Provide a minimal and isolated test which will reproduce the problem.
Provide a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) which will reproduce the problem.
```Lua
-- add code here
```
......
......@@ -2,10 +2,9 @@ Fixes #\<GitHub-issue-number\>.
Make sure all boxes are checked (add x inside the brackets) when you submit your contribution, remove this sentence before doing so.
- [ ] This PR is compliant with the [contributing guidelines](https://github.com/nodemcu/nodemcu-firmware/blob/dev/CONTRIBUTING.md) (if not, please describe why).
- [ ] This PR is for the `dev` branch rather than for `master`.
- [ ] This PR is compliant with the [other contributing guidelines](https://github.com/nodemcu/nodemcu-firmware/blob/dev/CONTRIBUTING.md) as well (if not, please describe why).
- [ ] I have thoroughly tested my contribution.
- [ ] The code changes are reflected in the documentation at `docs/en/*`.
\<Description of and rational behind this PR\>
Committers supporting this PR: leave blank
\ No newline at end of file
\<Description of and rational behind this PR\>
\ No newline at end of file
......@@ -4,7 +4,7 @@
The following is a set of guidelines for contributing to NodeMCU on GitHub. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
It is appreciated but optional if you raise an issue _before_ you start changing NodeMCU, discussing the proposed change; emphasising that the you are proposing to develop the patch yourself, and outling the strategy for implementation. This type of discussion is what we should be doing on the issues list and it is better to do this before or in parallel to developing the patch rather than having "you should have done it this way" type of feedback on the PR itself.
It is appreciated but optional if you raise an issue _before_ you start changing NodeMCU, discussing the proposed change; emphasing that the you are proposing to develop the patch yourself, and outlining the strategy for implementation. This type of discussion is what we should be doing on the issues list and it is better to do this before or in parallel to developing the patch rather than having "you should have done it this way" type of feedback on the PR itself.
### Table Of Contents
......@@ -17,7 +17,7 @@ It is appreciated but optional if you raise an issue _before_ you start changing
## Development environment setup
Use the platform and tools you feel most comfortable with. There are no constraints imposed by this project. You have (at least) two options to set up the toolchain to build the NodeMCU firmware:
- [Full-fledged Linux enviroment](http://www.esp8266.com/wiki/doku.php?id=toolchain#how_to_setup_a_vm_to_host_your_toolchain), either physical or virtual.
- [Full-fledged Linux environment](http://www.esp8266.com/wiki/doku.php?id=toolchain#how_to_setup_a_vm_to_host_your_toolchain), either physical or virtual.
- [Docker image](https://hub.docker.com/r/marcelstoer/nodemcu-build/) which allows to run the build inside the container as if you were running a build script on your local machine.
## Writing Documentation
......@@ -32,7 +32,7 @@ There are essentially only two things to keep in mind if you're contributing a P
If you also want to verify that all is well with your Markdown files you can install Python-based [MkDocs](http://www.mkdocs.org/), which is used by RTD to build the static HTML files, and run `mkdocs serve` in the root of your NodeMCU firmware directory.
A note on Markdown *syntax*. As Mkdocs is Python-based it's no surprise it uses a [Python Markdown implementation](https://pythonhosted.org/Markdown/). The good news is that it sticks pretty closely to John Gruber's Markdown and also [supports tables and fenced code blocks](http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions) just like GitHub does.
A note on Markdown *syntax*. As MkDocs is Python-based it's no surprise it uses a [Python Markdown implementation](https://pythonhosted.org/Markdown/). The good news is that it sticks pretty closely to John Gruber's Markdown and also [supports tables and fenced code blocks](http://www.mkdocs.org/user-guide/writing-your-docs/#markdown-extensions) just like GitHub does.
A collection of doc-writing hints and tips is maintained on the [wiki](https://github.com/nodemcu/nodemcu-firmware/wiki/Notes-about-writing-docs).
......@@ -40,7 +40,7 @@ If you're interested in some NodeMCU history you're welcome to read [issue #774]
## Working with Git and GitHub
*Pull requests for new features and major fixes should be opened against the `dev` branch.*
*Pull requests for new features and fixes should be opened against the `dev` branch.*
Avoid intermediate merge commits. [Rebase](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) your feature branch onto `dev` to pull updates and verify your local changes against them before placing the pull request.
......@@ -52,12 +52,12 @@ Avoid intermediate merge commits. [Rebase](https://www.atlassian.com/git/tutoria
1. `git checkout <branch-name>`
1. Make changes to the code base and commit them using e.g. `git commit -a -m 'Look ma, I did it'`
1. When you're done:
1. [Squash your commits](http://www.andrewconnell.com/blog/squash-multiple-git-commits-into-one) into one. There are [several ways](http://stackoverflow.com/a/5201642/131929) of doing this.
1. [Squash your commits](http://www.andrewconnell.com/blog/squash-multiple-git-commits-into-one). There are [several ways](http://stackoverflow.com/a/5201642/131929) of doing this.
1. Bring your fork up-to-date with the NodeMCU upstream repo ([see below](#keeping-your-fork-in-sync)). Then rebase your branch on `dev` running `git rebase dev`.
1. `git push`
1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/) (PR) on GitHub.
This is just one way of doing things. If you're proficient in Git matters you're free to choose your own. If you want to read more then the [GitHub chapter in the Git book](http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project#The-GitHub-Flow) is a way to start. [GitHub's own documenation](https://help.github.com/categories/collaborating/) contains a wealth of information as well.
This is just one way of doing things. If you're proficient in Git matters you're free to choose your own. If you want to read more then the [GitHub chapter in the Git book](http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project#The-GitHub-Flow) is a way to start. [GitHub's own documentation](https://help.github.com/categories/collaborating/) contains a wealth of information as well.
### Keeping your fork in sync
You need to sync your fork with the NodeMCU upstream repository from time to time, latest before you rebase (see flow above).
......
......@@ -24,6 +24,13 @@ SDK_DIR:=$(TOP_DIR)/sdk/esp_iot_sdk_v$(SDK_VER)
CCFLAGS:= -I$(TOP_DIR)/sdk-overrides/include -I$(SDK_DIR)/include
LDFLAGS:= -L$(SDK_DIR)/lib -L$(SDK_DIR)/ld $(LDFLAGS)
ifdef DEBUG
CCFLAGS += -ggdb -O0
LDFLAGS += -ggdb
else
CCFLAGS += -Os
endif
#############################################################
# Select compile
#
......@@ -38,11 +45,11 @@ ifeq ($(OS),Windows_NT)
CPP = xt-cpp
OBJCOPY = xt-objcopy
#MAKE = xt-make
CCFLAGS += -Os --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal
CCFLAGS += --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal
else
# It is gcc, may be cygwin
# Can we use -fdata-sections?
CCFLAGS += -Os -ffunction-sections -fno-jump-tables -fdata-sections
CCFLAGS += -ffunction-sections -fno-jump-tables -fdata-sections
AR = xtensa-lx106-elf-ar
CC = xtensa-lx106-elf-gcc
NM = xtensa-lx106-elf-nm
......@@ -69,7 +76,7 @@ else
else
ESPPORT = $(COMPORT)
endif
CCFLAGS += -Os -ffunction-sections -fno-jump-tables -fdata-sections
CCFLAGS += -ffunction-sections -fno-jump-tables -fdata-sections
AR = xtensa-lx106-elf-ar
CC = xtensa-lx106-elf-gcc
NM = xtensa-lx106-elf-nm
......@@ -231,11 +238,22 @@ clobber: $(SPECIAL_CLOBBER)
$(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clobber;)
$(RM) -r $(ODIR)
flash:
flash:
@echo "use one of the following targets to flash the firmware"
@echo " make flash512k - for ESP with 512kB flash size"
@echo " make flash4m - for ESP with 4MB flash size"
flash512k:
$(MAKE) -e FLASHOPTIONS="-fm qio -fs 4m -ff 40m" flashinternal
flash4m:
$(MAKE) -e FLASHOPTIONS="-fm dio -fs 32m -ff 40m" flashinternal
flashinternal:
ifndef PDIR
$(MAKE) -C ./app flash
$(MAKE) -C ./app flashinternal
else
$(ESPTOOL) --port $(ESPPORT) write_flash 0x00000 $(FIRMWAREDIR)0x00000.bin 0x10000 $(FIRMWAREDIR)0x10000.bin
$(ESPTOOL) --port $(ESPPORT) write_flash $(FLASHOPTIONS) 0x00000 $(FIRMWAREDIR)0x00000.bin 0x10000 $(FIRMWAREDIR)0x10000.bin
endif
.subdirs:
......@@ -255,7 +273,7 @@ endif
.PHONY: spiffs-image-remove
spiffs-image-remove:
$(MAKE) -C tools remove-image
$(MAKE) -C tools remove-image spiffsimg/spiffsimg
.PHONY: spiffs-image
......
......@@ -42,7 +42,10 @@ SUBDIRS= \
dhtlib \
tsl2561 \
net \
http
http \
fatfs \
esp-gdbstub \
websocket
endif # } PDIR
......@@ -82,11 +85,14 @@ COMPONENTS_eagle.app.v6 = \
ucglib/ucglib.a \
smart/smart.a \
spiffs/spiffs.a \
fatfs/libfatfs.a \
cjson/libcjson.a \
crypto/libcrypto.a \
dhtlib/libdhtlib.a \
tsl2561/tsl2561lib.a \
http/libhttp.a \
websocket/libwebsocket.a \
esp-gdbstub/libgdbstub.a \
net/libnodemcu_net.a \
modules/libmodules.a \
......
......@@ -2,19 +2,14 @@
#include "../lua/lauxlib.h"
#include <c_stdlib.h>
static lua_State *gL;
static const char errfmt[] = "cjson %salloc: out of mem (%d bytes)";
void cjson_mem_setlua (lua_State *L)
{
gL = L;
}
void *cjson_mem_malloc (uint32_t sz)
{
void *p = (void*)c_malloc (sz);
if (!p && gL)
luaL_error (gL, errfmt, "m", sz);
lua_State *L = lua_getstate();
if (!p)
luaL_error (L, errfmt, "m", sz);
return p;
}
......@@ -22,7 +17,8 @@ void *cjson_mem_malloc (uint32_t sz)
void *cjson_mem_realloc (void *o, uint32_t sz)
{
void *p = (void*)c_realloc (o, sz);
if (!p && gL)
luaL_error (gL, errfmt, "re", sz);
lua_State *L = lua_getstate();
if (!p)
luaL_error (L, errfmt, "re", sz);
return p;
}
......@@ -3,8 +3,6 @@
#include "../lua/lua.h"
void cjson_mem_setlua (lua_State *L);
void *cjson_mem_malloc (uint32_t sz);
void *cjson_mem_realloc (void *p, uint32_t sz);
......
......@@ -155,7 +155,6 @@ typedef struct
typedef struct coap_luser_entry coap_luser_entry;
struct coap_luser_entry{
lua_State *L;
// int ref;
// char name[MAX_SEGMENTS_SIZE+1]; // +1 for string '\0'
const char *name;
......
......@@ -37,6 +37,7 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
const coap_option_t *opt;
uint8_t count;
int n;
lua_State *L = lua_getstate();
if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
{
if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
......@@ -58,19 +59,17 @@ static int handle_get_variable(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
NODE_DBG("/v1/v/");
NODE_DBG((char *)h->name);
NODE_DBG(" match.\n");
if(h->L == NULL)
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
if(c_strlen(h->name))
{
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name);
if (!lua_isnumber(h->L, -1) && !lua_isstring(h->L, -1)) {
n = lua_gettop(L);
lua_getglobal(L, h->name);
if (!lua_isnumber(L, -1) && !lua_isstring(L, -1)) {
NODE_DBG ("should be a number or string.\n");
lua_settop(h->L, n);
lua_settop(L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} else {
const char *res = lua_tostring(h->L,-1);
lua_settop(h->L, n);
const char *res = lua_tostring(L,-1);
lua_settop(L, n);
return coap_make_response(scratch, outpkt, (const uint8_t *)res, c_strlen(res), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, h->content_type);
}
}
......@@ -94,6 +93,7 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr
const coap_option_t *opt;
uint8_t count;
int n;
lua_State *L = lua_getstate();
if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
{
if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
......@@ -116,37 +116,34 @@ static int handle_post_function(const coap_endpoint_t *ep, coap_rw_buffer_t *scr
NODE_DBG((char *)h->name);
NODE_DBG(" match.\n");
if(h->L == NULL)
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
if(c_strlen(h->name))
{
n = lua_gettop(h->L);
lua_getglobal(h->L, h->name);
if (lua_type(h->L, -1) != LUA_TFUNCTION) {
n = lua_gettop(L);
lua_getglobal(L, h->name);
if (lua_type(L, -1) != LUA_TFUNCTION) {
NODE_DBG ("should be a function\n");
lua_settop(h->L, n);
lua_settop(L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} else {
lua_pushlstring(h->L, inpkt->payload.p, inpkt->payload.len); // make sure payload.p is filled with '\0' after payload.len, or use lua_pushlstring
lua_call(h->L, 1, 1);
if (!lua_isnil(h->L, -1)){ /* get return? */
if( lua_isstring(h->L, -1) ) // deal with the return string
lua_pushlstring(L, inpkt->payload.p, inpkt->payload.len); // make sure payload.p is filled with '\0' after payload.len, or use lua_pushlstring
lua_call(L, 1, 1);
if (!lua_isnil(L, -1)){ /* get return? */
if( lua_isstring(L, -1) ) // deal with the return string
{
size_t len = 0;
const char *ret = luaL_checklstring( h->L, -1, &len );
const char *ret = luaL_checklstring( L, -1, &len );
if(len > MAX_PAYLOAD_SIZE){
lua_settop(h->L, n);
luaL_error( h->L, "return string:<MAX_PAYLOAD_SIZE" );
lua_settop(L, n);
luaL_error( L, "return string:<MAX_PAYLOAD_SIZE" );
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
}
NODE_DBG((char *)ret);
NODE_DBG("\n");
lua_settop(h->L, n);
lua_settop(L, n);
return coap_make_response(scratch, outpkt, ret, len, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
} else {
lua_settop(h->L, n);
lua_settop(L, n);
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
}
......@@ -198,10 +195,10 @@ static int handle_get_id(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, c
return coap_make_response(scratch, outpkt, (const uint8_t *)(&id), sizeof(uint32_t), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}
coap_luser_entry var_head = {NULL,NULL,NULL,0};
coap_luser_entry var_head = {NULL,NULL,0};
coap_luser_entry *variable_entry = &var_head;
coap_luser_entry func_head = {NULL,NULL,NULL,0};
coap_luser_entry func_head = {NULL,NULL,0};
coap_luser_entry *function_entry = &func_head;
const coap_endpoint_t endpoints[] =
......
......@@ -41,6 +41,7 @@ STD_CFLAGS=-std=gnu11 -Wimplicit
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
INCLUDES += -I ../platform
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
......@@ -27,6 +27,7 @@
* SUCH DAMAGE.
*
*/
#include "vfs.h"
#include "digests.h"
#include "user_config.h"
#include "rom.h"
......@@ -155,31 +156,22 @@ int ICACHE_FLASH_ATTR crypto_fhash (const digest_mech_info_t *mi,
}
int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
const char *data, size_t data_len,
const char *key, size_t key_len,
uint8_t *digest)
void crypto_hmac_begin (void *ctx, const digest_mech_info_t *mi,
const char *key, size_t key_len, uint8_t *k_opad)
{
if (!mi)
return EINVAL;
void *ctx = (void *)os_malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
// If key too long, it needs to be hashed before use
char tmp[mi->digest_size];
if (key_len > mi->block_size)
{
mi->create (ctx);
mi->update (ctx, key, key_len);
mi->finalize (digest, ctx);
key = digest;
mi->finalize (tmp, ctx);
key = tmp;
key_len = mi->digest_size;
mi->create (ctx); // refresh
}
const size_t bs = mi->block_size;
uint8_t k_ipad[bs];
uint8_t k_opad[bs];
os_memset (k_ipad, 0x36, bs);
os_memset (k_opad, 0x5c, bs);
......@@ -190,16 +182,42 @@ int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
k_opad[i] ^= key[i];
}
mi->create (ctx);
mi->update (ctx, k_ipad, bs);
mi->update (ctx, data, data_len);
}
void crypto_hmac_finalize (void *ctx, const digest_mech_info_t *mi,
const uint8_t *k_opad, uint8_t *digest)
{
mi->finalize (digest, ctx);
mi->create (ctx);
mi->update (ctx, k_opad, bs);
mi->update (ctx, k_opad, mi->block_size);
mi->update (ctx, digest, mi->digest_size);
mi->finalize (digest, ctx);
}
os_free (ctx);
int crypto_hmac (const digest_mech_info_t *mi,
const char *data, size_t data_len,
const char *key, size_t key_len,
uint8_t *digest)
{
if (!mi)
return EINVAL;
struct {
uint8_t ctx[mi->ctx_size];
uint8_t k_opad[mi->block_size];
} *tmp = os_malloc (sizeof (*tmp));
if (!tmp)
return ENOMEM;
mi->create (tmp->ctx);
crypto_hmac_begin (tmp->ctx, mi, key, key_len, tmp->k_opad);
mi->update (tmp->ctx, data, data_len);
crypto_hmac_finalize (tmp->ctx, mi, tmp->k_opad, digest);
os_free (tmp);
return 0;
}
......@@ -6,7 +6,7 @@
typedef void (*create_ctx_fn)(void *ctx);
typedef void (*update_ctx_fn)(void *ctx, const uint8_t *msg, int len);
typedef void (*finalize_ctx_fn)(uint8_t *digest, void *ctx);
typedef size_t ( *read_fn )(int fd, void *ptr, size_t len);
typedef sint32_t ( *read_fn )(int fd, void *ptr, size_t len);
/**
* Description of a message digest mechanism.
......@@ -66,7 +66,35 @@ int crypto_hash (const digest_mech_info_t *mi, const char *data, size_t data_len
int crypto_fhash (const digest_mech_info_t *mi, read_fn read, int readarg, uint8_t *digest);
/**
* Generate a HMAC signature.
* Commence calculating a HMAC signature.
*
* Once this fuction returns successfully, the @c ctx may be updated with
* data in multiple passes uses @c mi->update(), before being finalized via
* @c crypto_hmac_finalize().
*
* @param ctx A created context for the given mech @c mi.
* @param mi A mech from @c crypto_digest_mech().
* @param key The key bytes to use.
* @param key_len Number of bytes the @c key comprises.
* @param k_opad Buffer of size @c mi->block_size bytes to store the second
* round of key material in.
* Must be passed to @c crypto_hmac_finalize().
*/
void crypto_hmac_begin (void *ctx, const digest_mech_info_t *mi, const char *key, size_t key_len, uint8_t *k_opad);
/**
* Finalizes calculating a HMAC signature.
* @param ctx The created context used with @c crypto_hmac_begin().
* @param mi The mech used with @c crypto_hmac_begin().
* @param k_opad Second round of keying material, obtained
* from @c crypto_hmac_begin().
* @param digest Output buffer, must be at least @c mi->digest_size in size.
*/
void crypto_hmac_finalize (void *ctx, const digest_mech_info_t *mi, const uint8_t *k_opad, uint8_t *digest);
/**
* Generate a HMAC signature in one pass.
* Implemented in terms of @c crypto_hmac_begin() / @c crypto_hmac_end().
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param data The data to generate a signature for.
......
#include "driver/spi.h"
typedef union {
uint32 word[2];
uint64 dword;
} spi_buf_t;
static uint32_t spi_clkdiv[2];
/******************************************************************************
* FunctionName : spi_lcd_mode_init
......@@ -59,6 +66,45 @@ void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); //transmission start
}
/******************************************************************************
* FunctionName : spi_set_clkdiv
* Description : Set the clock divider
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* uint32 clock_div - new clock divider
* Returns : uint32 - previous clock divider
*******************************************************************************/
uint32_t spi_set_clkdiv(uint8 spi_no, uint32_t clock_div)
{
uint32_t tmp_clkdiv;
if (spi_no > 1) return 0; //handle invalid input number
tmp_clkdiv = spi_clkdiv[spi_no];
if (clock_div > 1) {
uint8 i, k;
i = (clock_div / 40) ? (clock_div / 40) : 1;
k = clock_div / i;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
if(spi_no==SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div <= 1 ? 0x100 : 0));
}
else if(spi_no==HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div <= 1 ? 0x200 : 0));
}
spi_clkdiv[spi_no] = clock_div;
return tmp_clkdiv;
}
/******************************************************************************
* FunctionName : spi_master_init
* Description : SPI master initial function for common byte units transmission
......@@ -96,28 +142,15 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
//clear Dual or Quad lines transmission mode
CLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);
if (clock_div > 1) {
uint8 i, k;
i = (clock_div / 40) ? (clock_div / 40) : 1;
k = clock_div / i;
WRITE_PERI_REG(SPI_CLOCK(spi_no),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
spi_set_clkdiv(spi_no, clock_div);
if(spi_no==SPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div <= 1 ? 0x100 : 0));
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode
}
else if(spi_no==HSPI){
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div <= 1 ? 0x200 : 0));
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
......@@ -125,6 +158,44 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
}
}
void spi_mast_byte_order(uint8 spi_no, uint8 order)
{
if(spi_no > 1)
return;
if (order == SPI_ORDER_MSB) {
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER | SPI_WR_BYTE_ORDER);
} else if (order == SPI_ORDER_LSB) {
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER | SPI_WR_BYTE_ORDER);
}
}
/******************************************************************************
* FunctionName : spi_mast_blkset
* Description : Copy a block of data to the MOSI FIFO
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* size_t bitlen - number of bits to copy, multiple of 8
* uint8 *data - pointer to data buffer
*******************************************************************************/
void spi_mast_blkset(uint8 spi_no, size_t bitlen, const uint8 *data)
{
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
os_memcpy((void *)SPI_W0(spi_no), (const void *)data, bitlen >> 3);
}
/******************************************************************************
* FunctionName : spi_mast_blkget
* Description : Copy a block of data from the MISO FIFO
* Parameters : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
* size_t bitlen - number of bits to copy, multiple of 8
* uint8 *data - pointer to data buffer
*******************************************************************************/
void spi_mast_blkget(uint8 spi_no, size_t bitlen, uint8 *data)
{
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
os_memcpy((void *)data, (void *)SPI_W0(spi_no), bitlen >> 3);
}
/******************************************************************************
* FunctionName : spi_mast_set_mosi
* Description : Enter provided data into MOSI buffer.
......@@ -137,48 +208,36 @@ void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_
*******************************************************************************/
void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data)
{
uint8 wn, wn_offset, wn_bitlen;
uint32 wn_data;
uint8 wn, shift;
spi_buf_t spi_buf;
if (spi_no > 1)
return; // handle invalid input number
if (bitlen > 32)
return; // handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15)
if (wn > 15) {
return; // out of range
wn_offset = offset & 0x1f;
if (32 - wn_offset < bitlen)
{
// splitting required
wn_bitlen = 32 - wn_offset;
wn_data = data >> (bitlen - wn_bitlen);
}
else
{
wn_bitlen = bitlen;
wn_data = data;
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// transfer Wn to buf
spi_buf.word[1] = READ_PERI_REG(SPI_W0(spi_no) + wn*4);
if (wn < 15) {
spi_buf.word[0] = READ_PERI_REG(SPI_W0(spi_no) + (wn+1)*4);
}
do
{
// write payload data to SPI_Wn
SET_PERI_REG_BITS(REG_SPI_BASE(spi_no) +0x40 + wn*4, BIT(wn_bitlen) - 1, wn_data, 32 - (wn_offset + wn_bitlen));
// prepare writing of dangling data part
wn += 1;
wn_offset = 0;
if (wn <= 15)
bitlen -= wn_bitlen;
else
bitlen = 0; // force abort
wn_bitlen = bitlen;
wn_data = data;
} while (bitlen > 0);
shift = 64 - (offset & 0x1f) - bitlen;
spi_buf.dword &= ~((1ULL << bitlen)-1 << shift);
spi_buf.dword |= (uint64)data << shift;
if (wn < 15) {
WRITE_PERI_REG(SPI_W0(spi_no) + (wn+1)*4, spi_buf.word[0]);
}
WRITE_PERI_REG(SPI_W0(spi_no) + wn*4, spi_buf.word[1]);
return;
}
......@@ -194,46 +253,30 @@ void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data)
*******************************************************************************/
uint32 spi_mast_get_miso(uint8 spi_no, uint16 offset, uint8 bitlen)
{
uint8 wn, wn_offset, wn_bitlen;
uint32 wn_data = 0;
uint8 wn;
spi_buf_t spi_buf;
uint32 result;
if (spi_no > 1)
return 0; // handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// determine which SPI_Wn register is addressed
wn = offset >> 5;
if (wn > 15)
return 0; // out of range
wn_offset = offset & 0x1f;
if (bitlen > (32 - wn_offset))
{
// splitting required
wn_bitlen = 32 - wn_offset;
}
else
{
wn_bitlen = bitlen;
while(READ_PERI_REG(SPI_CMD(spi_no)) & SPI_USR);
// transfer Wn to buf
spi_buf.word[1] = READ_PERI_REG(SPI_W0(spi_no) + wn*4);
if (wn < 15) {
spi_buf.word[0] = READ_PERI_REG(SPI_W0(spi_no) + (wn+1)*4);
}
do
{
wn_data |= (READ_PERI_REG(REG_SPI_BASE(spi_no) +0x40 + wn*4) >> (32 - (wn_offset + wn_bitlen))) & (BIT(wn_bitlen) - 1);
// prepare reading of dangling data part
wn_data <<= bitlen - wn_bitlen;
wn += 1;
wn_offset = 0;
if (wn <= 15)
bitlen -= wn_bitlen;
else
bitlen = 0; // force abort
wn_bitlen = bitlen;
} while (bitlen > 0);
return wn_data;
result = (uint32)(spi_buf.dword >> (64 - ((offset & 0x1f) + bitlen)));
result &= (1UL << bitlen)-1;
return result;
}
/******************************************************************************
......
......@@ -36,6 +36,8 @@ extern UartDevice UartDev;
static os_timer_t autobaud_timer;
static void (*alt_uart0_tx)(char txchar);
LOCAL void ICACHE_RAM_ATTR
uart0_rx_intr_handler(void *para);
......@@ -125,6 +127,11 @@ uart0_alt(uint8 on)
STATUS ICACHE_FLASH_ATTR
uart_tx_one_char(uint8 uart, uint8 TxChar)
{
if (uart == 0 && alt_uart0_tx) {
(*alt_uart0_tx)(TxChar);
return OK;
}
while (true)
{
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
......@@ -339,3 +346,7 @@ uart_setup(uint8 uart_no)
uart_config(uart_no);
ETS_UART_INTR_ENABLE();
}
void ICACHE_FLASH_ATTR uart_set_alt_output_uart0(void (*fn)(char)) {
alt_uart0_tx = fn;
}
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.
乐鑫 MIT 许可证
版权 (c) 2015 <乐鑫信息科技(上海)有限公司>
该许可证授权仅限于乐鑫信息科技 ESP8266 产品的应用开发。在此情况下,该许可证免费授权任何获得该软件及其相关文档(统称为“软件”)的人无限制地经营该软件,包括无限制的使用、复制、修改、合并、出版发行、散布、再授权、及贩售软件及软件副本的权利。被授权人在享受这些权利的同时,需服从下面的条件:
在软件和软件的所有副本中都必须包含以上的版权声明和授权声明。
该软件按本来的样子提供,没有任何明确或暗含的担保,包括但不仅限于关于试销性、适合某一特定用途和非侵权的保证。作者和版权持有人在任何情况下均不就由软件或软件使用引起的以合同形式、民事侵权或其它方式提出的任何索赔、损害或其它责任负责。
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libgdbstub.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES += -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../../include/ets
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
#ifndef GDBSTUB_CFG_H
#define GDBSTUB_CFG_H
/*
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 0
#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 0
#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 0
#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 0
#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 ICACHE_RAM_ATTR
#endif
#endif
/******************************************************************************
* 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
#ifndef GDBSTUB_ENTRY_H
#define GDBSTUB_ENTRY_H
#ifdef __cplusplus
extern "C" {
#endif
void gdbstub_init_debug_entry();
void gdbstub_do_break();
void gdbstub_icount_ena_single_step();
void gdbstub_save_extra_sfrs_for_exception();
void gdbstub_uart_entry();
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
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment