mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-29 05:21:37 +03:00
Update GDBStub library with the source of esp-gdbstub
This commit is contained in:
@ -1,355 +0,0 @@
|
||||
/* GDB Server stub by Marko Mikulicic (Cesanta)
|
||||
|
||||
Copyright (c) 2013-2014 Cesanta Software Limited
|
||||
All rights reserved
|
||||
|
||||
This software is dual-licensed: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation. For the terms of this
|
||||
license, see <http://www.gnu.org/licenses>.
|
||||
|
||||
You are free to use this software under the terms of the GNU General
|
||||
Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
Alternatively, you can license this software under a commercial
|
||||
license, as set out in <https://www.cesanta.com/license>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
#include "esp8266_peri.h"
|
||||
|
||||
#include "xtensa/corebits.h"
|
||||
#include "xtensa/specreg.h"
|
||||
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
#define RSR(sr) \
|
||||
({ \
|
||||
uint32_t r; \
|
||||
asm volatile("rsr %0,"__stringify(sr) : "=a"(r)); \
|
||||
r; \
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
* the saved registers begin at a fixed position in the xtos
|
||||
* low-level exception handler. I don't know if 0x100 it's just an
|
||||
* artifact of the actual xtos build ESP8266EX is using (although this nice
|
||||
* round number looks deliberate). The exception handler is burned on rom
|
||||
* so it should work on future SDK updates, but not necessarily on future
|
||||
* revisions of the chip.
|
||||
*/
|
||||
#define V7_GDB_SP_OFFSET 0x100
|
||||
|
||||
/*
|
||||
* Addresses in this range are guaranteed to be readable without faulting.
|
||||
* Contains ranges that are unmapped but innocuous.
|
||||
*
|
||||
* Putative ESP8266 memory map at:
|
||||
* https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
|
||||
*/
|
||||
#define ESP_LOWER_VALID_ADDRESS 0x20000000
|
||||
#define ESP_UPPER_VALID_ADDRESS 0x60000000
|
||||
|
||||
/*
|
||||
* Constructed by xtos.
|
||||
*
|
||||
* There is a UserFrame structure in
|
||||
* ./esp_iot_rtos_sdk/extra_include/xtensa/xtruntime-frames.h
|
||||
*/
|
||||
struct xtos_saved_regs {
|
||||
uint32_t pc; /* instruction causing the trap */
|
||||
uint32_t ps;
|
||||
uint32_t sar;
|
||||
uint32_t vpri; /* current xtos virtual priority */
|
||||
uint32_t a0; /* when __XTENSA_CALL0_ABI__ is true */
|
||||
uint32_t a[16]; /* a2 - a15 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
struct regfile {
|
||||
uint32_t a[16];
|
||||
uint32_t pc;
|
||||
uint32_t sar;
|
||||
uint32_t litbase;
|
||||
uint32_t sr176;
|
||||
uint32_t sr208;
|
||||
uint32_t ps;
|
||||
};
|
||||
|
||||
#define printf ets_printf
|
||||
extern void uart_write_char_d(char c);
|
||||
|
||||
/* TODO(mkm): not sure if gdb guarantees lowercase hex digits */
|
||||
#define fromhex(c) \
|
||||
(((c) &0x40) ? ((c) &0x20 ? (c) - 'a' + 10 : (c) - 'A' + 10) : (c) - '0')
|
||||
#define hexdigit(n) (((n) < 10) ? '0' + (n) : 'a' + ((n) -10))
|
||||
|
||||
static struct regfile regs = {0};
|
||||
static uint8_t gdb_send_checksum;
|
||||
|
||||
int gdb_read_uart() {
|
||||
static char buf[512];
|
||||
static char pos = 0;
|
||||
|
||||
if (pos == 0) {
|
||||
size_t rx_count;
|
||||
while ((rx_count = (USS(0) >> USRXC) & 0xff)>0 && pos < sizeof(buf)) {
|
||||
buf[pos++] = U0F;
|
||||
}
|
||||
}
|
||||
if (pos == 0) {
|
||||
return -1;
|
||||
}
|
||||
return buf[--pos];
|
||||
}
|
||||
|
||||
|
||||
uint8_t read_unaligned_byte(uint8_t *addr) {
|
||||
uint32_t *base = (uint32_t *) ((uintptr_t) addr & ~0x3);
|
||||
uint32_t word;
|
||||
|
||||
word = *base;
|
||||
return (uint8_t)(word >> 8 * ((uintptr_t) addr & 0x3));
|
||||
}
|
||||
|
||||
void gdb_nack() {
|
||||
printf("-");
|
||||
}
|
||||
|
||||
void gdb_ack() {
|
||||
printf("+");
|
||||
}
|
||||
|
||||
void gdb_begin_packet() {
|
||||
printf("$");
|
||||
gdb_send_checksum = 0;
|
||||
}
|
||||
|
||||
void gdb_end_packet() {
|
||||
printf("#%c%c", hexdigit(gdb_send_checksum >> 4),
|
||||
hexdigit(gdb_send_checksum & 0xF));
|
||||
}
|
||||
|
||||
void gdb_putchar(char ch) {
|
||||
gdb_send_checksum += (uint8_t) ch;
|
||||
printf("%c", ch);
|
||||
}
|
||||
|
||||
/* output a string while computing the checksum */
|
||||
void gdb_putstr(char *str) {
|
||||
while (*str) gdb_putchar(*str++);
|
||||
}
|
||||
|
||||
void gdb_putbyte(uint8_t val) {
|
||||
gdb_putchar(hexdigit(val >> 4));
|
||||
gdb_putchar(hexdigit(val & 0xF));
|
||||
}
|
||||
|
||||
/* 32-bit integer in native byte order */
|
||||
void gdb_putint(uint32_t val) {
|
||||
int i;
|
||||
uint8_t *v = (uint8_t *) &val;
|
||||
for (i = 0; i < 4; i++) {
|
||||
gdb_putbyte(v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* send a gdb packet with checksum */
|
||||
void gdb_send_packet(char *str) {
|
||||
gdb_begin_packet();
|
||||
gdb_putstr(str);
|
||||
gdb_end_packet();
|
||||
}
|
||||
|
||||
uint8_t gdb_read_unaligned(uint8_t *addr) {
|
||||
if (addr < (uint8_t *) ESP_LOWER_VALID_ADDRESS ||
|
||||
addr >= (uint8_t *) ESP_UPPER_VALID_ADDRESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return read_unaligned_byte(addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles the GDB server protocol.
|
||||
* We currently support only the simple command set.
|
||||
*
|
||||
* Data is exchanged in packets like `$Cxxxxx#cc`
|
||||
* where `C` is a single letter command name, `xxxx` is some data payload,
|
||||
* and `cc` is a two digit hex checksum of the packet body.
|
||||
* Replies follow the same structure except that they lack the command symbol.
|
||||
*
|
||||
* For a more complete description of the protocol, see
|
||||
* https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html
|
||||
*/
|
||||
void gdb_handle_char(int ch) {
|
||||
static enum {
|
||||
GDB_JUNK,
|
||||
GDB_DATA,
|
||||
GDB_CHECKSUM,
|
||||
GDB_CHECKSUM2
|
||||
} state = GDB_JUNK;
|
||||
static char data[128];
|
||||
static int pos = 0;
|
||||
static uint8_t checksum;
|
||||
|
||||
switch (state) {
|
||||
case GDB_JUNK:
|
||||
if (ch == '$') {
|
||||
checksum = 0;
|
||||
state = GDB_DATA;
|
||||
}
|
||||
break;
|
||||
case GDB_DATA:
|
||||
if (ch == '#') {
|
||||
state = GDB_CHECKSUM;
|
||||
break;
|
||||
}
|
||||
/* ignore too long commands, by acking and sending empty response */
|
||||
if (pos > sizeof(data)) {
|
||||
state = GDB_JUNK;
|
||||
gdb_ack();
|
||||
gdb_send_packet("");
|
||||
break;
|
||||
}
|
||||
checksum += (uint8_t) ch;
|
||||
data[pos++] = ch;
|
||||
break;
|
||||
case GDB_CHECKSUM:
|
||||
if (fromhex(ch) != (checksum >> 4)) {
|
||||
gdb_nack();
|
||||
state = GDB_JUNK;
|
||||
} else {
|
||||
state = GDB_CHECKSUM2;
|
||||
}
|
||||
break;
|
||||
case GDB_CHECKSUM2:
|
||||
state = GDB_JUNK;
|
||||
if (fromhex(ch) != (checksum & 0xF)) {
|
||||
gdb_nack();
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
gdb_ack();
|
||||
|
||||
/* process commands */
|
||||
switch (data[0]) {
|
||||
case '?':
|
||||
/* stop status */
|
||||
gdb_send_packet("S09"); /* TRAP */
|
||||
break;
|
||||
case 'm': {
|
||||
/* read memory */
|
||||
int i;
|
||||
uint32_t addr = 0;
|
||||
uint32_t num = 0;
|
||||
for (i = 1; i < pos && data[i] != ','; i++) {
|
||||
addr <<= 4;
|
||||
addr |= fromhex(data[i]);
|
||||
}
|
||||
for (i++; i < pos; i++) {
|
||||
num <<= 4;
|
||||
num |= fromhex(data[i]); /* should be decimal */
|
||||
}
|
||||
gdb_begin_packet();
|
||||
for (i = 0; i < num; i++) {
|
||||
gdb_putbyte(gdb_read_unaligned(((uint8_t *) addr) + i));
|
||||
}
|
||||
gdb_end_packet();
|
||||
break;
|
||||
}
|
||||
case 'g': {
|
||||
/* dump registers */
|
||||
int i;
|
||||
gdb_begin_packet();
|
||||
for (i = 0; i < sizeof(regs); i++) {
|
||||
gdb_putbyte(((uint8_t *) ®s)[i]);
|
||||
}
|
||||
gdb_end_packet();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gdb_send_packet("");
|
||||
break;
|
||||
}
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The user should detach and let gdb do the talkin' */
|
||||
void gdb_server() {
|
||||
printf("waiting for gdb\n");
|
||||
/*
|
||||
* polling since we cannot wait for interrupts inside
|
||||
* an interrupt handler of unknown level.
|
||||
*
|
||||
* Interrupts disabled so that the user (or v7 prompt)
|
||||
* uart interrupt handler doesn't interfere.
|
||||
*/
|
||||
xthal_set_intenable(0);
|
||||
for (;;) {
|
||||
int ch = gdb_read_uart();
|
||||
if (ch != -1) gdb_handle_char(ch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* xtos low level exception handler (in rom)
|
||||
* populates an xtos_regs structure with (most) registers
|
||||
* present at the time of the exception and passes it to the
|
||||
* high-level handler.
|
||||
*
|
||||
* Note that the a1 (sp) register is clobbered (bug? necessity?),
|
||||
* however the original stack pointer can be inferred from the address
|
||||
* of the saved registers area, since the exception handler uses the same
|
||||
* user stack. This might be different in other execution modes on the
|
||||
* quite variegated xtensa platform family, but that's how it works on ESP8266.
|
||||
*/
|
||||
void ICACHE_RAM_ATTR gdb_exception_handler(struct xtos_saved_regs *frame) {
|
||||
ESP8266_REG(0x900) &= 0x7e; // Disable WDT
|
||||
int i;
|
||||
uint32_t cause = RSR(EXCCAUSE);
|
||||
uint32_t vaddr = RSR(EXCVADDR);
|
||||
memcpy(®s.a[2], frame->a, sizeof(frame->a));
|
||||
|
||||
regs.a[0] = frame->a0;
|
||||
regs.a[1] = (uint32_t) frame + V7_GDB_SP_OFFSET;
|
||||
regs.pc = frame->pc;
|
||||
regs.sar = frame->sar;
|
||||
regs.ps = frame->ps;
|
||||
regs.litbase = RSR(LITBASE);
|
||||
|
||||
U0IE = 0;
|
||||
ets_install_putc1(&uart_write_char_d);
|
||||
|
||||
printf("\nTrap %d: pc=%p va=%p\n", cause, frame->pc, vaddr);
|
||||
gdb_server();
|
||||
|
||||
_ResetVector();
|
||||
}
|
||||
|
||||
void gdb_init() {
|
||||
char causes[] = {EXCCAUSE_ILLEGAL, EXCCAUSE_INSTR_ERROR,
|
||||
EXCCAUSE_LOAD_STORE_ERROR, EXCCAUSE_DIVIDE_BY_ZERO,
|
||||
EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_PROHIBITED,
|
||||
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
|
||||
int i;
|
||||
for (i = 0; i < (int) sizeof(causes); i++) {
|
||||
_xtos_set_exception_handler(causes[i], gdb_exception_handler);
|
||||
}
|
||||
}
|
61
libraries/GDBStub/src/internal/gdbstub-cfg.h
Normal file
61
libraries/GDBStub/src/internal/gdbstub-cfg.h
Normal file
@ -0,0 +1,61 @@
|
||||
#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
|
||||
#define ATTR_GDBFN
|
||||
|
||||
#endif
|
404
libraries/GDBStub/src/internal/gdbstub-entry.S
Normal file
404
libraries/GDBStub/src/internal/gdbstub-entry.S
Normal file
@ -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
|
25
libraries/GDBStub/src/internal/gdbstub-entry.h
Normal file
25
libraries/GDBStub/src/internal/gdbstub-entry.h
Normal file
@ -0,0 +1,25 @@
|
||||
#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
|
790
libraries/GDBStub/src/internal/gdbstub.c
Normal file
790
libraries/GDBStub/src/internal/gdbstub.c
Normal file
@ -0,0 +1,790 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2015 Espressif Systems
|
||||
*
|
||||
* Description: A stub to make the ESP8266 debuggable by GDB over the serial
|
||||
* port.
|
||||
*
|
||||
* License: ESPRESSIF MIT License
|
||||
*******************************************************************************/
|
||||
|
||||
#include "gdbstub.h"
|
||||
#include <stddef.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;
|
||||
};
|
||||
|
||||
#if GDBSTUB_FREERTOS
|
||||
/*
|
||||
Definitions for FreeRTOS. This redefines some os_* functions to use their non-os* counterparts. It
|
||||
also sets up some function pointers for ROM functions that aren't in the FreeRTOS ld files.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
void _xt_isr_attach(int inum, void *fn);
|
||||
void _xt_isr_unmask(int inum);
|
||||
void os_install_putc1(void (*p)(char c));
|
||||
#define os_printf(...) printf(__VA_ARGS__)
|
||||
#define os_memcpy(a,b,c) memcpy(a,b,c)
|
||||
typedef void wdtfntype();
|
||||
static wdtfntype *ets_wdt_disable=(wdtfntype *)0x400030f0;
|
||||
static wdtfntype *ets_wdt_enable=(wdtfntype *)0x40002fa0;
|
||||
|
||||
#else
|
||||
/*
|
||||
OS-less SDK defines. Defines some headers for things that aren't in the include files, plus
|
||||
the xthal stack frame struct.
|
||||
*/
|
||||
#include "osapi.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame));
|
||||
int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
#endif
|
||||
|
||||
#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() {
|
||||
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() {
|
||||
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() {
|
||||
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() {
|
||||
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;
|
||||
char c;
|
||||
no=bits/4;
|
||||
if (bits==-1) no=64;
|
||||
for (i=0; i<no; i++) {
|
||||
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() {
|
||||
#if 0
|
||||
char *reason=""; //default
|
||||
#endif
|
||||
//exception-to-signal mapping
|
||||
char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
|
||||
int i=0;
|
||||
gdbPacketStart();
|
||||
gdbPacketChar('T');
|
||||
if (gdbstub_savedRegs.reason==0xff) {
|
||||
gdbPacketHex(2, 8); //sigint
|
||||
} else if (gdbstub_savedRegs.reason&0x80) {
|
||||
//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)) return 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() {
|
||||
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);
|
||||
// os_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) {
|
||||
os_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() {
|
||||
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 {
|
||||
os_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() {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
#if GDBSTUB_FREERTOS
|
||||
//Freetos exception. This routine is called by an assembly routine in gdbstub-entry.S
|
||||
void ATTR_GDBFN gdbstub_handle_user_exception() {
|
||||
ets_wdt_disable();
|
||||
gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
|
||||
sendReason();
|
||||
while(gdbReadCommand()!=ST_CONT);
|
||||
ets_wdt_enable();
|
||||
}
|
||||
#else
|
||||
|
||||
//Non-OS exception handler. Gets called by the Xtensa HAL.
|
||||
static void ATTR_GDBFN gdb_exception_handler(struct XTensa_exception_frame_s *frame) {
|
||||
//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
|
||||
os_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();
|
||||
*((uint32_t*)UART_INT_ENA(0)) = 0;
|
||||
sendReason();
|
||||
while(gdbReadCommand()!=ST_CONT);
|
||||
ets_wdt_enable();
|
||||
|
||||
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||
os_memcpy(frame, &gdbstub_savedRegs, 19*4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
int i;
|
||||
obuf[obufpos++]=c;
|
||||
if (c=='\n' || obufpos==OBUFLEN) {
|
||||
gdbPacketStart();
|
||||
gdbPacketChar('O');
|
||||
for (i=0; i<obufpos; i++) gdbPacketHex(obuf[i], 8);
|
||||
gdbPacketEnd();
|
||||
obufpos=0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !GDBSTUB_FREERTOS
|
||||
//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() {
|
||||
int i;
|
||||
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);
|
||||
}
|
||||
}
|
||||
#else
|
||||
//FreeRTOS doesn't use the Xtensa HAL for exceptions, but uses its own fatal exception handler.
|
||||
//We use a small hack to replace that with a jump to our own handler, which then has the task of
|
||||
//decyphering and re-instating the registers the FreeRTOS code left.
|
||||
extern void user_fatal_exception_handler();
|
||||
extern void gdbstub_user_exception_entry();
|
||||
|
||||
static void ATTR_GDBINIT install_exceptions() {
|
||||
//Replace the user_fatal_exception_handler by a jump to our own code
|
||||
int *ufe=(int*)user_fatal_exception_handler;
|
||||
//This mess encodes as a relative jump instruction to user_fatal_exception_handler
|
||||
*ufe=((((int)gdbstub_user_exception_entry-(int)user_fatal_exception_handler)-4)<<6)|6;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if GDBSTUB_CTRLC_BREAK
|
||||
|
||||
#if !GDBSTUB_FREERTOS
|
||||
|
||||
static void ATTR_GDBFN uart_hdlr(void *arg, void *frame) {
|
||||
int doDebug=0, 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) {
|
||||
if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
|
||||
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
|
||||
os_memcpy(&gdbstub_savedRegs, frame, 19*4);
|
||||
gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
||||
|
||||
gdbstub_savedRegs.reason=0xff; //mark as user break reason
|
||||
|
||||
ets_wdt_disable();
|
||||
sendReason();
|
||||
while(gdbReadCommand()!=ST_CONT);
|
||||
ets_wdt_enable();
|
||||
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||
os_memcpy(frame, &gdbstub_savedRegs, 19*4);
|
||||
}
|
||||
}
|
||||
|
||||
static void ATTR_GDBINIT install_uart_hdlr() {
|
||||
ets_isr_attach(ETS_UART_INUM, uart_hdlr, NULL);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||
ets_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ATTR_GDBFN gdbstub_handle_uart_int(struct XTensa_rtos_int_frame_s *frame) {
|
||||
int doDebug=0, fifolen=0, x;
|
||||
|
||||
fifolen=(READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
|
||||
while (fifolen!=0) {
|
||||
if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
|
||||
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
|
||||
gdbstub_savedRegs.pc=frame->pc;
|
||||
gdbstub_savedRegs.ps=frame->ps;
|
||||
gdbstub_savedRegs.sar=frame->sar;
|
||||
gdbstub_savedRegs.a0=frame->a[0];
|
||||
gdbstub_savedRegs.a1=frame->a[1];
|
||||
for (x=2; x<16; x++) gdbstub_savedRegs.a[x-2]=frame->a[x];
|
||||
|
||||
// gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
||||
|
||||
gdbstub_savedRegs.reason=0xff; //mark as user break reason
|
||||
|
||||
// ets_wdt_disable();
|
||||
sendReason();
|
||||
while(gdbReadCommand()!=ST_CONT);
|
||||
// ets_wdt_enable();
|
||||
//Copy any changed registers back to the frame the Xtensa HAL uses.
|
||||
frame->pc=gdbstub_savedRegs.pc;
|
||||
frame->ps=gdbstub_savedRegs.ps;
|
||||
frame->sar=gdbstub_savedRegs.sar;
|
||||
frame->a[0]=gdbstub_savedRegs.a0;
|
||||
frame->a[1]=gdbstub_savedRegs.a1;
|
||||
for (x=2; x<16; x++) frame->a[x]=gdbstub_savedRegs.a[x-2];
|
||||
}
|
||||
}
|
||||
|
||||
static void ATTR_GDBINIT install_uart_hdlr() {
|
||||
_xt_isr_attach(ETS_UART_INUM, gdbstub_uart_entry);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||
_xt_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//gdbstub initialization routine.
|
||||
void ATTR_GDBINIT gdbstub_init() {
|
||||
#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
|
||||
os_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
|
||||
}
|
||||
|
||||
extern void gdb_init() __attribute__((weak, alias("gdbstub_init")));
|
14
libraries/GDBStub/src/internal/gdbstub.h
Normal file
14
libraries/GDBStub/src/internal/gdbstub.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef GDBSTUB_H
|
||||
#define GDBSTUB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void gdbstub_init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
459
libraries/GDBStub/src/xtensa/config/core-isa.h
Normal file
459
libraries/GDBStub/src/xtensa/config/core-isa.h
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa
|
||||
* processor CORE configuration
|
||||
*
|
||||
* See <xtensa/config/core.h>, which includes this file, for more details.
|
||||
*/
|
||||
|
||||
/* Xtensa processor core configuration information.
|
||||
|
||||
Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica 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. */
|
||||
|
||||
#ifndef _XTENSA_CORE_CONFIGURATION_H
|
||||
#define _XTENSA_CORE_CONFIGURATION_H
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Parameters Useful for Any Code, USER or PRIVILEGED
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
|
||||
* configured, and a value of 0 otherwise. These macros are always defined.
|
||||
*/
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
ISA
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */
|
||||
#define XCHAL_HAVE_WINDOWED 0 /* windowed registers option */
|
||||
#define XCHAL_NUM_AREGS 16 /* num of physical addr regs */
|
||||
#define XCHAL_NUM_AREGS_LOG2 4 /* log2(XCHAL_NUM_AREGS) */
|
||||
#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */
|
||||
#define XCHAL_HAVE_DEBUG 1 /* debug option */
|
||||
#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */
|
||||
#define XCHAL_HAVE_LOOPS 0 /* zero-overhead loops */
|
||||
#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */
|
||||
#define XCHAL_HAVE_MINMAX 0 /* MIN/MAX instructions */
|
||||
#define XCHAL_HAVE_SEXT 0 /* SEXT instruction */
|
||||
#define XCHAL_HAVE_CLAMPS 0 /* CLAMPS instruction */
|
||||
#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */
|
||||
#define XCHAL_HAVE_MUL32 1 /* MULL instruction */
|
||||
#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */
|
||||
#define XCHAL_HAVE_DIV32 0 /* QUOS/QUOU/REMS/REMU instructions */
|
||||
#define XCHAL_HAVE_L32R 1 /* L32R instruction */
|
||||
#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */
|
||||
#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */
|
||||
#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */
|
||||
#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */
|
||||
#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */
|
||||
#define XCHAL_HAVE_CALL4AND12 0 /* (obsolete option) */
|
||||
#define XCHAL_HAVE_ABS 1 /* ABS instruction */
|
||||
/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */
|
||||
/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */
|
||||
#define XCHAL_HAVE_RELEASE_SYNC 0 /* L32AI/S32RI instructions */
|
||||
#define XCHAL_HAVE_S32C1I 0 /* S32C1I instruction */
|
||||
#define XCHAL_HAVE_SPECULATION 0 /* speculation */
|
||||
#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */
|
||||
#define XCHAL_NUM_CONTEXTS 1 /* */
|
||||
#define XCHAL_NUM_MISC_REGS 0 /* num of scratch regs (0..4) */
|
||||
#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */
|
||||
#define XCHAL_HAVE_PRID 1 /* processor ID register */
|
||||
#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */
|
||||
#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */
|
||||
#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */
|
||||
#define XCHAL_HAVE_THREADPTR 0 /* THREADPTR register */
|
||||
#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */
|
||||
#define XCHAL_HAVE_CP 0 /* CPENABLE reg (coprocessor) */
|
||||
#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one */
|
||||
#define XCHAL_HAVE_MAC16 0 /* MAC16 package */
|
||||
#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */
|
||||
#define XCHAL_HAVE_FP 0 /* floating point pkg */
|
||||
#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */
|
||||
#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */
|
||||
#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */
|
||||
#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */
|
||||
#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */
|
||||
#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */
|
||||
#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
MISC
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_NUM_WRITEBUFFER_ENTRIES 1 /* size of write buffer */
|
||||
#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */
|
||||
#define XCHAL_DATA_WIDTH 4 /* data width in bytes */
|
||||
/* In T1050, applies to selected core load and store instructions (see ISA): */
|
||||
#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */
|
||||
#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/
|
||||
#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */
|
||||
#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/
|
||||
|
||||
#define XCHAL_SW_VERSION 800001 /* sw version of this header */
|
||||
|
||||
#define XCHAL_CORE_ID "lx106" /* alphanum core name
|
||||
(CoreID) set in the Xtensa
|
||||
Processor Generator */
|
||||
|
||||
#define XCHAL_BUILD_UNIQUE_ID 0x0002B6F6 /* 22-bit sw build ID */
|
||||
|
||||
/*
|
||||
* These definitions describe the hardware targeted by this software.
|
||||
*/
|
||||
#define XCHAL_HW_CONFIGID0 0xC28CDAFA /* ConfigID hi 32 bits*/
|
||||
#define XCHAL_HW_CONFIGID1 0x1082B6F6 /* ConfigID lo 32 bits*/
|
||||
#define XCHAL_HW_VERSION_NAME "LX3.0.1" /* full version name */
|
||||
#define XCHAL_HW_VERSION_MAJOR 2300 /* major ver# of targeted hw */
|
||||
#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */
|
||||
#define XCHAL_HW_VERSION 230001 /* major*100+minor */
|
||||
#define XCHAL_HW_REL_LX3 1
|
||||
#define XCHAL_HW_REL_LX3_0 1
|
||||
#define XCHAL_HW_REL_LX3_0_1 1
|
||||
#define XCHAL_HW_CONFIGID_RELIABLE 1
|
||||
/* If software targets a *range* of hardware versions, these are the bounds: */
|
||||
#define XCHAL_HW_MIN_VERSION_MAJOR 2300 /* major v of earliest tgt hw */
|
||||
#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */
|
||||
#define XCHAL_HW_MIN_VERSION 230001 /* earliest targeted hw */
|
||||
#define XCHAL_HW_MAX_VERSION_MAJOR 2300 /* major v of latest tgt hw */
|
||||
#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */
|
||||
#define XCHAL_HW_MAX_VERSION 230001 /* latest targeted hw */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
CACHE
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_ICACHE_LINESIZE 4 /* I-cache line size in bytes */
|
||||
#define XCHAL_DCACHE_LINESIZE 4 /* D-cache line size in bytes */
|
||||
#define XCHAL_ICACHE_LINEWIDTH 2 /* log2(I line size in bytes) */
|
||||
#define XCHAL_DCACHE_LINEWIDTH 2 /* log2(D line size in bytes) */
|
||||
|
||||
#define XCHAL_ICACHE_SIZE 0 /* I-cache size in bytes or 0 */
|
||||
#define XCHAL_DCACHE_SIZE 0 /* D-cache size in bytes or 0 */
|
||||
|
||||
#define XCHAL_DCACHE_IS_WRITEBACK 0 /* writeback feature */
|
||||
#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */
|
||||
|
||||
#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
CACHE
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */
|
||||
|
||||
/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */
|
||||
|
||||
/* Number of cache sets in log2(lines per way): */
|
||||
#define XCHAL_ICACHE_SETWIDTH 0
|
||||
#define XCHAL_DCACHE_SETWIDTH 0
|
||||
|
||||
/* Cache set associativity (number of ways): */
|
||||
#define XCHAL_ICACHE_WAYS 1
|
||||
#define XCHAL_DCACHE_WAYS 1
|
||||
|
||||
/* Cache features: */
|
||||
#define XCHAL_ICACHE_LINE_LOCKABLE 0
|
||||
#define XCHAL_DCACHE_LINE_LOCKABLE 0
|
||||
#define XCHAL_ICACHE_ECC_PARITY 0
|
||||
#define XCHAL_DCACHE_ECC_PARITY 0
|
||||
|
||||
/* Cache access size in bytes (affects operation of SICW instruction): */
|
||||
#define XCHAL_ICACHE_ACCESS_SIZE 1
|
||||
#define XCHAL_DCACHE_ACCESS_SIZE 1
|
||||
|
||||
/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */
|
||||
#define XCHAL_CA_BITS 4
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
INTERNAL I/D RAM/ROMs and XLMI
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_NUM_INSTROM 1 /* number of core instr. ROMs */
|
||||
#define XCHAL_NUM_INSTRAM 2 /* number of core instr. RAMs */
|
||||
#define XCHAL_NUM_DATAROM 1 /* number of core data ROMs */
|
||||
#define XCHAL_NUM_DATARAM 2 /* number of core data RAMs */
|
||||
#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/
|
||||
#define XCHAL_NUM_XLMI 1 /* number of core XLMI ports */
|
||||
|
||||
/* Instruction ROM 0: */
|
||||
#define XCHAL_INSTROM0_VADDR 0x40200000
|
||||
#define XCHAL_INSTROM0_PADDR 0x40200000
|
||||
#define XCHAL_INSTROM0_SIZE 1048576
|
||||
#define XCHAL_INSTROM0_ECC_PARITY 0
|
||||
|
||||
/* Instruction RAM 0: */
|
||||
#define XCHAL_INSTRAM0_VADDR 0x40000000
|
||||
#define XCHAL_INSTRAM0_PADDR 0x40000000
|
||||
#define XCHAL_INSTRAM0_SIZE 1048576
|
||||
#define XCHAL_INSTRAM0_ECC_PARITY 0
|
||||
|
||||
/* Instruction RAM 1: */
|
||||
#define XCHAL_INSTRAM1_VADDR 0x40100000
|
||||
#define XCHAL_INSTRAM1_PADDR 0x40100000
|
||||
#define XCHAL_INSTRAM1_SIZE 1048576
|
||||
#define XCHAL_INSTRAM1_ECC_PARITY 0
|
||||
|
||||
/* Data ROM 0: */
|
||||
#define XCHAL_DATAROM0_VADDR 0x3FF40000
|
||||
#define XCHAL_DATAROM0_PADDR 0x3FF40000
|
||||
#define XCHAL_DATAROM0_SIZE 262144
|
||||
#define XCHAL_DATAROM0_ECC_PARITY 0
|
||||
|
||||
/* Data RAM 0: */
|
||||
#define XCHAL_DATARAM0_VADDR 0x3FFC0000
|
||||
#define XCHAL_DATARAM0_PADDR 0x3FFC0000
|
||||
#define XCHAL_DATARAM0_SIZE 262144
|
||||
#define XCHAL_DATARAM0_ECC_PARITY 0
|
||||
|
||||
/* Data RAM 1: */
|
||||
#define XCHAL_DATARAM1_VADDR 0x3FF80000
|
||||
#define XCHAL_DATARAM1_PADDR 0x3FF80000
|
||||
#define XCHAL_DATARAM1_SIZE 262144
|
||||
#define XCHAL_DATARAM1_ECC_PARITY 0
|
||||
|
||||
/* XLMI Port 0: */
|
||||
#define XCHAL_XLMI0_VADDR 0x3FF00000
|
||||
#define XCHAL_XLMI0_PADDR 0x3FF00000
|
||||
#define XCHAL_XLMI0_SIZE 262144
|
||||
#define XCHAL_XLMI0_ECC_PARITY 0
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
INTERRUPTS and TIMERS
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */
|
||||
#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */
|
||||
#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */
|
||||
#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */
|
||||
#define XCHAL_NUM_TIMERS 1 /* number of CCOMPAREn regs */
|
||||
#define XCHAL_NUM_INTERRUPTS 15 /* number of interrupts */
|
||||
#define XCHAL_NUM_INTERRUPTS_LOG2 4 /* ceil(log2(NUM_INTERRUPTS)) */
|
||||
#define XCHAL_NUM_EXTINTERRUPTS 13 /* num of external interrupts */
|
||||
#define XCHAL_NUM_INTLEVELS 2 /* number of interrupt levels
|
||||
(not including level zero) */
|
||||
#define XCHAL_EXCM_LEVEL 1 /* level masked by PS.EXCM */
|
||||
/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
|
||||
|
||||
/* Masks of interrupts at each interrupt level: */
|
||||
#define XCHAL_INTLEVEL1_MASK 0x00003FFF
|
||||
#define XCHAL_INTLEVEL2_MASK 0x00000000
|
||||
#define XCHAL_INTLEVEL3_MASK 0x00004000
|
||||
#define XCHAL_INTLEVEL4_MASK 0x00000000
|
||||
#define XCHAL_INTLEVEL5_MASK 0x00000000
|
||||
#define XCHAL_INTLEVEL6_MASK 0x00000000
|
||||
#define XCHAL_INTLEVEL7_MASK 0x00000000
|
||||
|
||||
/* Masks of interrupts at each range 1..n of interrupt levels: */
|
||||
#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x00003FFF
|
||||
#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x00003FFF
|
||||
#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x00007FFF
|
||||
#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x00007FFF
|
||||
#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x00007FFF
|
||||
#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x00007FFF
|
||||
#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x00007FFF
|
||||
|
||||
/* Level of each interrupt: */
|
||||
#define XCHAL_INT0_LEVEL 1
|
||||
#define XCHAL_INT1_LEVEL 1
|
||||
#define XCHAL_INT2_LEVEL 1
|
||||
#define XCHAL_INT3_LEVEL 1
|
||||
#define XCHAL_INT4_LEVEL 1
|
||||
#define XCHAL_INT5_LEVEL 1
|
||||
#define XCHAL_INT6_LEVEL 1
|
||||
#define XCHAL_INT7_LEVEL 1
|
||||
#define XCHAL_INT8_LEVEL 1
|
||||
#define XCHAL_INT9_LEVEL 1
|
||||
#define XCHAL_INT10_LEVEL 1
|
||||
#define XCHAL_INT11_LEVEL 1
|
||||
#define XCHAL_INT12_LEVEL 1
|
||||
#define XCHAL_INT13_LEVEL 1
|
||||
#define XCHAL_INT14_LEVEL 3
|
||||
#define XCHAL_DEBUGLEVEL 2 /* debug interrupt level */
|
||||
#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */
|
||||
#define XCHAL_NMILEVEL 3 /* NMI "level" (for use with
|
||||
EXCSAVE/EPS/EPC_n, RFI n) */
|
||||
|
||||
/* Type of each interrupt: */
|
||||
#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
|
||||
#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER
|
||||
#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE
|
||||
#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT10_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT11_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT13_TYPE XTHAL_INTTYPE_EXTERN_EDGE
|
||||
#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI
|
||||
|
||||
/* Masks of interrupts for each type of interrupt: */
|
||||
#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFF8000
|
||||
#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000080
|
||||
#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00003F00
|
||||
#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000003F
|
||||
#define XCHAL_INTTYPE_MASK_TIMER 0x00000040
|
||||
#define XCHAL_INTTYPE_MASK_NMI 0x00004000
|
||||
#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
|
||||
|
||||
/* Interrupt numbers assigned to specific interrupt sources: */
|
||||
#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */
|
||||
#define XCHAL_TIMER1_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||
#define XCHAL_TIMER2_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||
#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
|
||||
#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */
|
||||
|
||||
/* Interrupt numbers for levels at which only one interrupt is configured: */
|
||||
#define XCHAL_INTLEVEL3_NUM 14
|
||||
/* (There are many interrupts each at level(s) 1.) */
|
||||
|
||||
|
||||
/*
|
||||
* External interrupt vectors/levels.
|
||||
* These macros describe how Xtensa processor interrupt numbers
|
||||
* (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
|
||||
* map to external BInterrupt<n> pins, for those interrupts
|
||||
* configured as external (level-triggered, edge-triggered, or NMI).
|
||||
* See the Xtensa processor databook for more details.
|
||||
*/
|
||||
|
||||
/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
|
||||
#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT6_NUM 8 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT7_NUM 9 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT8_NUM 10 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT9_NUM 11 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT10_NUM 12 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT11_NUM 13 /* (intlevel 1) */
|
||||
#define XCHAL_EXTINT12_NUM 14 /* (intlevel 3) */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
EXCEPTIONS and VECTORS
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture
|
||||
number: 1 == XEA1 (old)
|
||||
2 == XEA2 (new)
|
||||
0 == XEAX (extern) */
|
||||
#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */
|
||||
#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */
|
||||
#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */
|
||||
#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */
|
||||
#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */
|
||||
#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */
|
||||
#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */
|
||||
#define XCHAL_VECBASE_RESET_VADDR 0x40000000 /* VECBASE reset value */
|
||||
#define XCHAL_VECBASE_RESET_PADDR 0x40000000
|
||||
#define XCHAL_RESET_VECBASE_OVERLAP 0
|
||||
|
||||
#define XCHAL_RESET_VECTOR0_VADDR 0x50000000
|
||||
#define XCHAL_RESET_VECTOR0_PADDR 0x50000000
|
||||
#define XCHAL_RESET_VECTOR1_VADDR 0x40000080
|
||||
#define XCHAL_RESET_VECTOR1_PADDR 0x40000080
|
||||
#define XCHAL_RESET_VECTOR_VADDR 0x50000000
|
||||
#define XCHAL_RESET_VECTOR_PADDR 0x50000000
|
||||
#define XCHAL_USER_VECOFS 0x00000050
|
||||
#define XCHAL_USER_VECTOR_VADDR 0x40000050
|
||||
#define XCHAL_USER_VECTOR_PADDR 0x40000050
|
||||
#define XCHAL_KERNEL_VECOFS 0x00000030
|
||||
#define XCHAL_KERNEL_VECTOR_VADDR 0x40000030
|
||||
#define XCHAL_KERNEL_VECTOR_PADDR 0x40000030
|
||||
#define XCHAL_DOUBLEEXC_VECOFS 0x00000070
|
||||
#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x40000070
|
||||
#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x40000070
|
||||
#define XCHAL_INTLEVEL2_VECOFS 0x00000010
|
||||
#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x40000010
|
||||
#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x40000010
|
||||
#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL2_VECOFS
|
||||
#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL2_VECTOR_VADDR
|
||||
#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL2_VECTOR_PADDR
|
||||
#define XCHAL_NMI_VECOFS 0x00000020
|
||||
#define XCHAL_NMI_VECTOR_VADDR 0x40000020
|
||||
#define XCHAL_NMI_VECTOR_PADDR 0x40000020
|
||||
#define XCHAL_INTLEVEL3_VECOFS XCHAL_NMI_VECOFS
|
||||
#define XCHAL_INTLEVEL3_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR
|
||||
#define XCHAL_INTLEVEL3_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
DEBUG
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */
|
||||
#define XCHAL_NUM_IBREAK 1 /* number of IBREAKn regs */
|
||||
#define XCHAL_NUM_DBREAK 1 /* number of DBREAKn regs */
|
||||
#define XCHAL_HAVE_OCD_DIR_ARRAY 0 /* faster OCD option */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
MMU
|
||||
----------------------------------------------------------------------*/
|
||||
|
||||
/* See core-matmap.h header file for more details. */
|
||||
|
||||
#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */
|
||||
#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */
|
||||
#define XCHAL_SPANNING_WAY 0 /* TLB spanning way number */
|
||||
#define XCHAL_HAVE_IDENTITY_MAP 1 /* vaddr == paddr always */
|
||||
#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */
|
||||
#define XCHAL_HAVE_MIMIC_CACHEATTR 1 /* region protection */
|
||||
#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */
|
||||
#define XCHAL_HAVE_PTP_MMU 0 /* full MMU (with page table
|
||||
[autorefill] and protection)
|
||||
usable for an MMU-based OS */
|
||||
/* If none of the above last 4 are set, it's a custom TLB configuration. */
|
||||
|
||||
#define XCHAL_MMU_ASID_BITS 0 /* number of bits in ASIDs */
|
||||
#define XCHAL_MMU_RINGS 1 /* number of rings (1..4) */
|
||||
#define XCHAL_MMU_RING_BITS 0 /* num of bits in RING field */
|
||||
|
||||
#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
|
||||
|
||||
|
||||
#endif /* _XTENSA_CORE_CONFIGURATION_H */
|
||||
|
80
libraries/GDBStub/src/xtensa/config/specreg.h
Normal file
80
libraries/GDBStub/src/xtensa/config/specreg.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Xtensa Special Register symbolic names
|
||||
*/
|
||||
|
||||
/* $Id: //depot/rel/Boreal/Xtensa/SWConfig/hal/specreg.h.tpp#2 $ */
|
||||
|
||||
/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1998-2002 Tensilica 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. */
|
||||
|
||||
#ifndef XTENSA_SPECREG_H
|
||||
#define XTENSA_SPECREG_H
|
||||
|
||||
/* Include these special register bitfield definitions, for historical reasons: */
|
||||
#include <xtensa/corebits.h>
|
||||
|
||||
|
||||
/* Special registers: */
|
||||
#define SAR 3
|
||||
#define LITBASE 5
|
||||
#define IBREAKENABLE 96
|
||||
#define DDR 104
|
||||
#define IBREAKA_0 128
|
||||
#define DBREAKA_0 144
|
||||
#define DBREAKC_0 160
|
||||
#define EPC_1 177
|
||||
#define EPC_2 178
|
||||
#define EPC_3 179
|
||||
#define DEPC 192
|
||||
#define EPS_2 194
|
||||
#define EPS_3 195
|
||||
#define EXCSAVE_1 209
|
||||
#define EXCSAVE_2 210
|
||||
#define EXCSAVE_3 211
|
||||
#define INTERRUPT 226
|
||||
#define INTENABLE 228
|
||||
#define PS 230
|
||||
#define VECBASE 231
|
||||
#define EXCCAUSE 232
|
||||
#define DEBUGCAUSE 233
|
||||
#define CCOUNT 234
|
||||
#define PRID 235
|
||||
#define ICOUNT 236
|
||||
#define ICOUNTLEVEL 237
|
||||
#define EXCVADDR 238
|
||||
#define CCOMPARE_0 240
|
||||
|
||||
/* Special cases (bases of special register series): */
|
||||
#define IBREAKA 128
|
||||
#define DBREAKA 144
|
||||
#define DBREAKC 160
|
||||
#define EPC 176
|
||||
#define EPS 192
|
||||
#define EXCSAVE 208
|
||||
#define CCOMPARE 240
|
||||
|
||||
/* Special names for read-only and write-only interrupt registers: */
|
||||
#define INTREAD 226
|
||||
#define INTSET 226
|
||||
#define INTCLEAR 227
|
||||
|
||||
#endif /* XTENSA_SPECREG_H */
|
||||
|
164
libraries/GDBStub/src/xtensa/corebits.h
Normal file
164
libraries/GDBStub/src/xtensa/corebits.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* xtensa/corebits.h - Xtensa Special Register field positions, masks, values.
|
||||
*
|
||||
* (In previous releases, these were defined in specreg.h, a generated file.
|
||||
* This file is not generated, ie. it is processor configuration independent.)
|
||||
*/
|
||||
|
||||
/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/corebits.h#2 $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2007 Tensilica 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.
|
||||
*/
|
||||
|
||||
#ifndef XTENSA_COREBITS_H
|
||||
#define XTENSA_COREBITS_H
|
||||
|
||||
/* EXCCAUSE register fields: */
|
||||
#define EXCCAUSE_EXCCAUSE_SHIFT 0
|
||||
#define EXCCAUSE_EXCCAUSE_MASK 0x3F
|
||||
/* EXCCAUSE register values: */
|
||||
/*
|
||||
* General Exception Causes
|
||||
* (values of EXCCAUSE special register set by general exceptions,
|
||||
* which vector to the user, kernel, or double-exception vectors).
|
||||
*/
|
||||
#define EXCCAUSE_ILLEGAL 0 /* Illegal Instruction */
|
||||
#define EXCCAUSE_SYSCALL 1 /* System Call (SYSCALL instruction) */
|
||||
#define EXCCAUSE_INSTR_ERROR 2 /* Instruction Fetch Error */
|
||||
# define EXCCAUSE_IFETCHERROR 2 /* (backward compatibility macro, deprecated, avoid) */
|
||||
#define EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error */
|
||||
# define EXCCAUSE_LOADSTOREERROR 3 /* (backward compatibility macro, deprecated, avoid) */
|
||||
#define EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt */
|
||||
# define EXCCAUSE_LEVEL1INTERRUPT 4 /* (backward compatibility macro, deprecated, avoid) */
|
||||
#define EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (MOVSP instruction) for alloca */
|
||||
#define EXCCAUSE_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero */
|
||||
#define EXCCAUSE_SPECULATION 7 /* Use of Failed Speculative Access (not implemented) */
|
||||
#define EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction */
|
||||
#define EXCCAUSE_UNALIGNED 9 /* Unaligned Load or Store */
|
||||
/* Reserved 10..11 */
|
||||
#define EXCCAUSE_INSTR_DATA_ERROR 12 /* PIF Data Error on Instruction Fetch (RB-200x and later) */
|
||||
#define EXCCAUSE_LOAD_STORE_DATA_ERROR 13 /* PIF Data Error on Load or Store (RB-200x and later) */
|
||||
#define EXCCAUSE_INSTR_ADDR_ERROR 14 /* PIF Address Error on Instruction Fetch (RB-200x and later) */
|
||||
#define EXCCAUSE_LOAD_STORE_ADDR_ERROR 15 /* PIF Address Error on Load or Store (RB-200x and later) */
|
||||
#define EXCCAUSE_ITLB_MISS 16 /* ITLB Miss (no ITLB entry matches, hw refill also missed) */
|
||||
#define EXCCAUSE_ITLB_MULTIHIT 17 /* ITLB Multihit (multiple ITLB entries match) */
|
||||
#define EXCCAUSE_INSTR_RING 18 /* Ring Privilege Violation on Instruction Fetch */
|
||||
/* Reserved 19 */ /* Size Restriction on IFetch (not implemented) */
|
||||
#define EXCCAUSE_INSTR_PROHIBITED 20 /* Cache Attribute does not allow Instruction Fetch */
|
||||
/* Reserved 21..23 */
|
||||
#define EXCCAUSE_DTLB_MISS 24 /* DTLB Miss (no DTLB entry matches, hw refill also missed) */
|
||||
#define EXCCAUSE_DTLB_MULTIHIT 25 /* DTLB Multihit (multiple DTLB entries match) */
|
||||
#define EXCCAUSE_LOAD_STORE_RING 26 /* Ring Privilege Violation on Load or Store */
|
||||
/* Reserved 27 */ /* Size Restriction on Load/Store (not implemented) */
|
||||
#define EXCCAUSE_LOAD_PROHIBITED 28 /* Cache Attribute does not allow Load */
|
||||
#define EXCCAUSE_STORE_PROHIBITED 29 /* Cache Attribute does not allow Store */
|
||||
/* Reserved 30..31 */
|
||||
#define EXCCAUSE_CP_DISABLED(n) (32+(n)) /* Access to Coprocessor 'n' when disabled */
|
||||
#define EXCCAUSE_CP0_DISABLED 32 /* Access to Coprocessor 0 when disabled */
|
||||
#define EXCCAUSE_CP1_DISABLED 33 /* Access to Coprocessor 1 when disabled */
|
||||
#define EXCCAUSE_CP2_DISABLED 34 /* Access to Coprocessor 2 when disabled */
|
||||
#define EXCCAUSE_CP3_DISABLED 35 /* Access to Coprocessor 3 when disabled */
|
||||
#define EXCCAUSE_CP4_DISABLED 36 /* Access to Coprocessor 4 when disabled */
|
||||
#define EXCCAUSE_CP5_DISABLED 37 /* Access to Coprocessor 5 when disabled */
|
||||
#define EXCCAUSE_CP6_DISABLED 38 /* Access to Coprocessor 6 when disabled */
|
||||
#define EXCCAUSE_CP7_DISABLED 39 /* Access to Coprocessor 7 when disabled */
|
||||
/*#define EXCCAUSE_FLOATING_POINT 40*/ /* Floating Point Exception (not implemented) */
|
||||
/* Reserved 40..63 */
|
||||
|
||||
/* PS register fields: */
|
||||
#define PS_WOE_SHIFT 18
|
||||
#define PS_WOE_MASK 0x00040000
|
||||
#define PS_WOE PS_WOE_MASK
|
||||
#define PS_CALLINC_SHIFT 16
|
||||
#define PS_CALLINC_MASK 0x00030000
|
||||
#define PS_CALLINC(n) (((n)&3)<<PS_CALLINC_SHIFT) /* n = 0..3 */
|
||||
#define PS_OWB_SHIFT 8
|
||||
#define PS_OWB_MASK 0x00000F00
|
||||
#define PS_OWB(n) (((n)&15)<<PS_OWB_SHIFT) /* n = 0..15 (or 0..7) */
|
||||
#define PS_RING_SHIFT 6
|
||||
#define PS_RING_MASK 0x000000C0
|
||||
#define PS_RING(n) (((n)&3)<<PS_RING_SHIFT) /* n = 0..3 */
|
||||
#define PS_UM_SHIFT 5
|
||||
#define PS_UM_MASK 0x00000020
|
||||
#define PS_UM PS_UM_MASK
|
||||
#define PS_EXCM_SHIFT 4
|
||||
#define PS_EXCM_MASK 0x00000010
|
||||
#define PS_EXCM PS_EXCM_MASK
|
||||
#define PS_INTLEVEL_SHIFT 0
|
||||
#define PS_INTLEVEL_MASK 0x0000000F
|
||||
#define PS_INTLEVEL(n) ((n)&PS_INTLEVEL_MASK) /* n = 0..15 */
|
||||
/* Backward compatibility (deprecated): */
|
||||
#define PS_PROGSTACK_SHIFT PS_UM_SHIFT
|
||||
#define PS_PROGSTACK_MASK PS_UM_MASK
|
||||
#define PS_PROG_SHIFT PS_UM_SHIFT
|
||||
#define PS_PROG_MASK PS_UM_MASK
|
||||
#define PS_PROG PS_UM
|
||||
|
||||
/* DBREAKCn register fields: */
|
||||
#define DBREAKC_MASK_SHIFT 0
|
||||
#define DBREAKC_MASK_MASK 0x0000003F
|
||||
#define DBREAKC_LOADBREAK_SHIFT 30
|
||||
#define DBREAKC_LOADBREAK_MASK 0x40000000
|
||||
#define DBREAKC_STOREBREAK_SHIFT 31
|
||||
#define DBREAKC_STOREBREAK_MASK 0x80000000
|
||||
|
||||
/* DEBUGCAUSE register fields: */
|
||||
#define DEBUGCAUSE_DEBUGINT_SHIFT 5
|
||||
#define DEBUGCAUSE_DEBUGINT_MASK 0x20 /* debug interrupt */
|
||||
#define DEBUGCAUSE_BREAKN_SHIFT 4
|
||||
#define DEBUGCAUSE_BREAKN_MASK 0x10 /* BREAK.N instruction */
|
||||
#define DEBUGCAUSE_BREAK_SHIFT 3
|
||||
#define DEBUGCAUSE_BREAK_MASK 0x08 /* BREAK instruction */
|
||||
#define DEBUGCAUSE_DBREAK_SHIFT 2
|
||||
#define DEBUGCAUSE_DBREAK_MASK 0x04 /* DBREAK match */
|
||||
#define DEBUGCAUSE_IBREAK_SHIFT 1
|
||||
#define DEBUGCAUSE_IBREAK_MASK 0x02 /* IBREAK match */
|
||||
#define DEBUGCAUSE_ICOUNT_SHIFT 0
|
||||
#define DEBUGCAUSE_ICOUNT_MASK 0x01 /* ICOUNT would increment to zero */
|
||||
|
||||
/* MESR register fields: */
|
||||
#define MESR_MEME 0x00000001 /* memory error */
|
||||
#define MESR_MEME_SHIFT 0
|
||||
#define MESR_DME 0x00000002 /* double memory error */
|
||||
#define MESR_DME_SHIFT 1
|
||||
#define MESR_RCE 0x00000010 /* recorded memory error */
|
||||
#define MESR_RCE_SHIFT 4
|
||||
#define MESR_LCE
|
||||
#define MESR_LCE_SHIFT ?
|
||||
#define MESR_LCE_L
|
||||
#define MESR_ERRENAB 0x00000100
|
||||
#define MESR_ERRENAB_SHIFT 8
|
||||
#define MESR_ERRTEST 0x00000200
|
||||
#define MESR_ERRTEST_SHIFT 9
|
||||
#define MESR_DATEXC 0x00000400
|
||||
#define MESR_DATEXC_SHIFT 10
|
||||
#define MESR_INSEXC 0x00000800
|
||||
#define MESR_INSEXC_SHIFT 11
|
||||
#define MESR_WAYNUM_SHIFT 16
|
||||
#define MESR_ACCTYPE_SHIFT 20
|
||||
#define MESR_MEMTYPE_SHIFT 24
|
||||
#define MESR_ERRTYPE_SHIFT 30
|
||||
|
||||
|
||||
#endif /*XTENSA_COREBITS_H*/
|
||||
|
Reference in New Issue
Block a user