aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorHsiangkai Wang <hsiangkai@gmail.com>2013-05-07 21:43:35 +0800
committerSpencer Oliver <spen@spen-soft.co.uk>2013-08-07 21:00:40 +0000
commitd979d78e97786667d168ba183c9fc60c622d29c1 (patch)
tree19e03565245a64cb7f3138433f78abce8c6acc9a /src/target
parent9f2922aa7abb385d1fb24def91fac7eb4e2304c5 (diff)
downloadriscv-openocd-d979d78e97786667d168ba183c9fc60c622d29c1.zip
riscv-openocd-d979d78e97786667d168ba183c9fc60c622d29c1.tar.gz
riscv-openocd-d979d78e97786667d168ba183c9fc60c622d29c1.tar.bz2
gdb_server: support gdb target description
* Add a parameter in .get_gdb_reg_list() to return different register lists as generating target description. * Modify STRUCT REG to let gdb generate target description according to register information. The modified structure of register is struct reg { const char *name; uint32_t number; /* for regnum="num" */ struct reg_feature *feature; /* for register group feature name */ bool caller_save; /* for save-restore="yes|no" */ void *value; bool dirty; bool valid; bool exist; uint32_t size; struct reg_data_type *reg_data_type; /* for type="type" */ const char *group; /* for group="general|float|vector" */ void *arch_info; const struct reg_arch_type *type; }; Change-Id: I2096b67adf94518ba0b8b23d8c6a9f64ad7932b8 Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com> Reviewed-on: http://openocd.zylin.com/1382 Tested-by: jenkins Reviewed-by: Franck Jullien <franck.jullien@gmail.com> Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src/target')
-rw-r--r--src/target/arm.h3
-rw-r--r--src/target/armv4_5.c3
-rw-r--r--src/target/armv7m.c3
-rw-r--r--src/target/armv7m.h3
-rw-r--r--src/target/avr32_ap7k.c3
-rw-r--r--src/target/dsp563xx.c3
-rw-r--r--src/target/mips32.c3
-rw-r--r--src/target/mips32.h3
-rw-r--r--src/target/nds32.c134
-rw-r--r--src/target/nds32.h5
-rw-r--r--src/target/register.h93
-rw-r--r--src/target/target.c5
-rw-r--r--src/target/target.h9
-rw-r--r--src/target/target_type.h3
14 files changed, 239 insertions, 34 deletions
diff --git a/src/target/arm.h b/src/target/arm.h
index 4a4d928..e2d2646 100644
--- a/src/target/arm.h
+++ b/src/target/arm.h
@@ -211,7 +211,8 @@ extern const struct command_registration arm_command_handlers[];
int arm_arch_state(struct target *target);
int arm_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class);
int arm_init_arch_info(struct target *target, struct arm *arm);
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 91830f5..a2f0557 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -1051,7 +1051,8 @@ const struct command_registration arm_command_handlers[] = {
};
int arm_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size)
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class)
{
struct arm *arm = target_to_arm(target);
int i;
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index 622de49..d32352a 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -259,7 +259,8 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r,
* hardware, so this also fakes a set of long-obsolete FPA registers that
* are not used in EABI based software stacks.
*/
-int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
int i;
diff --git a/src/target/armv7m.h b/src/target/armv7m.h
index bc245fb..d028f4e 100644
--- a/src/target/armv7m.h
+++ b/src/target/armv7m.h
@@ -195,7 +195,8 @@ int armv7m_mode_to_number(enum armv7m_mode mode);
int armv7m_arch_state(struct target *target);
int armv7m_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class);
int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m);
diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c
index cc9ab5a..7c97234 100644
--- a/src/target/avr32_ap7k.c
+++ b/src/target/avr32_ap7k.c
@@ -576,7 +576,8 @@ int avr32_ap7k_arch_state(struct target *target)
return ERROR_OK;
}
-int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
{
#if 0
/* get pointers to arch-specific information */
diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c
index 1211ac5..8c47016 100644
--- a/src/target/dsp563xx.c
+++ b/src/target/dsp563xx.c
@@ -354,7 +354,8 @@ static uint8_t gdb_reg_list_idx[] = {
static int dsp563xx_get_gdb_reg_list(struct target *target,
struct reg **reg_list[],
- int *reg_list_size)
+ int *reg_list_size,
+ enum target_register_class reg_class)
{
int i;
struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target);
diff --git a/src/target/mips32.c b/src/target/mips32.c
index 1067f7b..c9cbf86 100644
--- a/src/target/mips32.c
+++ b/src/target/mips32.c
@@ -173,7 +173,8 @@ static int mips32_write_core_reg(struct target *target, int num)
return ERROR_OK;
}
-int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size)
+int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
{
/* get pointers to arch-specific information */
struct mips32_common *mips32 = target_to_mips32(target);
diff --git a/src/target/mips32.h b/src/target/mips32.h
index 97fb5d0..951b2ed 100644
--- a/src/target/mips32.h
+++ b/src/target/mips32.h
@@ -243,7 +243,8 @@ int mips32_examine(struct target *target);
int mips32_register_commands(struct command_context *cmd_ctx);
int mips32_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class);
int mips32_checksum_memory(struct target *target, uint32_t address,
uint32_t count, uint32_t *checksum);
int mips32_blank_check_memory(struct target *target,
diff --git a/src/target/nds32.c b/src/target/nds32.c
index 2d47709..95a249d 100644
--- a/src/target/nds32.c
+++ b/src/target/nds32.c
@@ -91,21 +91,23 @@ static int nds32_get_core_reg(struct reg *reg)
return ERROR_OK;
}
+ int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
if (reg_arch_info->enable == false) {
reg_arch_info->value = NDS32_REGISTER_DISABLE;
retval = ERROR_FAIL;
} else {
if ((nds32->fpu_enable == false) &&
- (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
reg_arch_info->value = 0;
retval = ERROR_OK;
} else if ((nds32->audio_enable == false) &&
- (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
reg_arch_info->value = 0;
retval = ERROR_OK;
} else {
retval = aice_read_register(aice,
- reg_arch_info->num, &(reg_arch_info->value));
+ mapped_regnum, &(reg_arch_info->value));
}
LOG_DEBUG("reading register %i(%s), value: 0x%8.8" PRIx32,
@@ -301,44 +303,46 @@ static int nds32_set_core_reg(struct reg *reg, uint8_t *buf)
return ERROR_TARGET_NOT_HALTED;
}
+ int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
/* ignore values that will generate exception */
- if (nds32_reg_exception(reg_arch_info->num, value))
+ if (nds32_reg_exception(mapped_regnum, value))
return ERROR_OK;
LOG_DEBUG("writing register %i(%s) with value 0x%8.8" PRIx32,
reg_arch_info->num, reg->name, value);
if ((nds32->fpu_enable == false) &&
- (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
buf_set_u32(reg->value, 0, 32, 0);
} else if ((nds32->audio_enable == false) &&
- (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
buf_set_u32(reg->value, 0, 32, 0);
} else {
buf_set_u32(reg->value, 0, 32, value);
- aice_write_register(aice, reg_arch_info->num, reg_arch_info->value);
+ aice_write_register(aice, mapped_regnum, reg_arch_info->value);
/* After set value to registers, read the value from target
* to avoid W1C inconsistency. */
- aice_read_register(aice, reg_arch_info->num, &(reg_arch_info->value));
+ aice_read_register(aice, mapped_regnum, &(reg_arch_info->value));
}
reg->valid = true;
reg->dirty = false;
/* update registers to take effect right now */
- if (IR0 == reg_arch_info->num) {
+ if (IR0 == mapped_regnum) {
nds32_update_psw(nds32);
- } else if (MR0 == reg_arch_info->num) {
+ } else if (MR0 == mapped_regnum) {
nds32_update_mmu_info(nds32);
- } else if ((MR6 == reg_arch_info->num) || (MR7 == reg_arch_info->num)) {
+ } else if ((MR6 == mapped_regnum) || (MR7 == mapped_regnum)) {
/* update lm information */
nds32_update_lm_info(nds32);
- } else if (MR8 == reg_arch_info->num) {
+ } else if (MR8 == mapped_regnum) {
nds32_update_cache_info(nds32);
- } else if (FUCPR == reg_arch_info->num) {
+ } else if (FUCPR == mapped_regnum) {
/* update audio/fpu setting */
nds32_check_extension(nds32);
}
@@ -415,17 +419,62 @@ static struct reg_cache *nds32_build_reg_cache(struct target *target,
reg_arch_info[i].enable = false;
reg_list[i].name = nds32_reg_simple_name(i);
+ reg_list[i].number = reg_arch_info[i].num;
reg_list[i].size = nds32_reg_size(i);
reg_list[i].arch_info = &reg_arch_info[i];
+ reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
+
if (FD0 <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31) {
reg_list[i].value = &(reg_arch_info[i].value_64);
reg_list[i].type = &nds32_reg_access_type_64;
+
+ reg_list[i].reg_data_type->type = REG_TYPE_IEEE_DOUBLE;
+ reg_list[i].reg_data_type->id = "ieee_double";
+ reg_list[i].group = "float";
} else {
reg_list[i].value = &(reg_arch_info[i].value);
reg_list[i].type = &nds32_reg_access_type;
+ reg_list[i].group = "general";
+
+ if ((FS0 <= reg_arch_info[i].num) && (reg_arch_info[i].num <= FS31)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_IEEE_SINGLE;
+ reg_list[i].reg_data_type->id = "ieee_single";
+ reg_list[i].group = "float";
+ } else if ((reg_arch_info[i].num == FPCSR) ||
+ (reg_arch_info[i].num == FPCFG)) {
+ reg_list[i].group = "float";
+ } else if ((reg_arch_info[i].num == R28) ||
+ (reg_arch_info[i].num == R29) ||
+ (reg_arch_info[i].num == R31)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR;
+ reg_list[i].reg_data_type->id = "data_ptr";
+ } else if ((reg_arch_info[i].num == R30) ||
+ (reg_arch_info[i].num == PC)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR;
+ reg_list[i].reg_data_type->id = "code_ptr";
+ } else {
+ reg_list[i].reg_data_type->type = REG_TYPE_UINT32;
+ reg_list[i].reg_data_type->id = "uint32";
+ }
}
+ if (R16 <= reg_arch_info[i].num && reg_arch_info[i].num <= R25)
+ reg_list[i].caller_save = true;
+ else
+ reg_list[i].caller_save = false;
+
+ reg_list[i].feature = malloc(sizeof(struct reg_feature));
+
+ if (R0 <= reg_arch_info[i].num && reg_arch_info[i].num <= IFC_LP)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.core";
+ else if (CR0 <= reg_arch_info[i].num && reg_arch_info[i].num <= SECUR0)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.system";
+ else if (D0L24 <= reg_arch_info[i].num && reg_arch_info[i].num <= CBE3)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.audio";
+ else if (FPCSR <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.fpu";
+
cache->num_regs++;
}
@@ -451,9 +500,7 @@ static struct reg *nds32_reg_current(struct nds32 *nds32, unsigned regnum)
{
struct reg *r;
- /* Register mapping, pass user-view registers to gdb */
- int mapped_regnum = nds32->register_map(nds32, regnum);
- r = nds32->core_cache->reg_list + mapped_regnum;
+ r = nds32->core_cache->reg_list + regnum;
return r;
}
@@ -512,12 +559,36 @@ int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value)
return r->type->set(r, set_value);
}
+/** get general register list */
+static int nds32_get_general_reg_list(struct nds32 *nds32,
+ struct reg **reg_list[], int *reg_list_size)
+{
+ struct reg *reg_current;
+ int i;
+ int current_idx;
+
+ /** freed in gdb_server.c */
+ *reg_list = malloc(sizeof(struct reg *) * (IFC_LP - R0 + 1));
+ current_idx = 0;
+
+ for (i = R0; i < IFC_LP + 1; i++) {
+ reg_current = nds32_reg_current(nds32, i);
+ if (((struct nds32_reg *)reg_current->arch_info)->enable) {
+ (*reg_list)[current_idx] = reg_current;
+ current_idx++;
+ }
+ }
+ *reg_list_size = current_idx;
+
+ return ERROR_OK;
+}
+
/** get all register list */
-int nds32_get_gdb_reg_list(struct target *target,
+static int nds32_get_all_reg_list(struct nds32 *nds32,
struct reg **reg_list[], int *reg_list_size)
{
- struct nds32 *nds32 = target_to_nds32(target);
struct reg_cache *reg_cache = nds32->core_cache;
+ struct reg *reg_current;
unsigned int i;
*reg_list_size = reg_cache->num_regs;
@@ -525,12 +596,35 @@ int nds32_get_gdb_reg_list(struct target *target,
/** freed in gdb_server.c */
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
- for (i = 0; i < reg_cache->num_regs; i++)
- (*reg_list)[i] = nds32_reg_current(nds32, i);
+ for (i = 0; i < reg_cache->num_regs; i++) {
+ reg_current = nds32_reg_current(nds32, i);
+ reg_current->exist = ((struct nds32_reg *)
+ reg_current->arch_info)->enable;
+ (*reg_list)[i] = reg_current;
+ }
return ERROR_OK;
}
+/** get all register list */
+int nds32_get_gdb_reg_list(struct target *target,
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class)
+{
+ struct nds32 *nds32 = target_to_nds32(target);
+
+ switch (reg_class) {
+ case REG_CLASS_ALL:
+ return nds32_get_all_reg_list(nds32, reg_list, reg_list_size);
+ case REG_CLASS_GENERAL:
+ return nds32_get_general_reg_list(nds32, reg_list, reg_list_size);
+ default:
+ return ERROR_FAIL;
+ }
+
+ return ERROR_FAIL;
+}
+
static int nds32_select_memory_mode(struct target *target, uint32_t address,
uint32_t length, uint32_t *end_address)
{
diff --git a/src/target/nds32.h b/src/target/nds32.h
index f585c2d..b7e787c 100644
--- a/src/target/nds32.h
+++ b/src/target/nds32.h
@@ -341,7 +341,7 @@ struct nds32 {
};
struct nds32_reg {
- uint32_t num;
+ int32_t num;
uint32_t value;
uint64_t value_64;
struct target *target;
@@ -364,7 +364,8 @@ extern int nds32_remove_software_breakpoint(struct target *target,
struct breakpoint *breakpoint);
extern int nds32_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class);
extern int nds32_write_buffer(struct target *target, uint32_t address,
uint32_t size, const uint8_t *buffer);
diff --git a/src/target/register.h b/src/target/register.h
index 3810d14..9e0f1ce 100644
--- a/src/target/register.h
+++ b/src/target/register.h
@@ -26,12 +26,105 @@
struct target;
+enum reg_type {
+ REG_TYPE_INT8,
+ REG_TYPE_INT16,
+ REG_TYPE_INT32,
+ REG_TYPE_INT64,
+ REG_TYPE_INT128,
+ REG_TYPE_UINT8,
+ REG_TYPE_UINT16,
+ REG_TYPE_UINT32,
+ REG_TYPE_UINT64,
+ REG_TYPE_UINT128,
+ REG_TYPE_CODE_PTR,
+ REG_TYPE_DATA_PTR,
+ REG_TYPE_IEEE_SINGLE,
+ REG_TYPE_IEEE_DOUBLE,
+ REG_TYPE_ARCH_DEFINED,
+};
+
+struct reg_feature {
+ const char *name;
+};
+
+struct reg_data_type_vector {
+ struct reg_data_type *type;
+ uint32_t count;
+};
+
+struct reg_data_type_union_field {
+ const char *name;
+ struct reg_data_type *type;
+ struct reg_data_type_union_field *next;
+};
+
+struct reg_data_type_union {
+ struct reg_data_type_union_field *fields;
+};
+
+struct reg_data_type_bitfield {
+ uint32_t start;
+ uint32_t end;
+};
+
+struct reg_data_type_struct_field {
+ const char *name;
+ bool use_bitfields;
+ union {
+ struct reg_data_type_bitfield *bitfield;
+ struct reg_data_type *type;
+ };
+ struct reg_data_type_struct_field *next;
+};
+
+struct reg_data_type_struct {
+ uint32_t size;
+ struct reg_data_type_struct_field *fields;
+};
+
+struct reg_data_type_flags_field {
+ const char *name;
+ struct reg_data_type_bitfield *bitfield;
+ struct reg_data_type_flags_field *next;
+};
+
+struct reg_data_type_flags {
+ uint32_t size;
+ struct reg_data_type_flags_field *fields;
+};
+
+enum reg_data_type_class {
+ REG_TYPE_CLASS_VECTOR,
+ REG_TYPE_CLASS_UNION,
+ REG_TYPE_CLASS_STRUCT,
+ REG_TYPE_CLASS_FLAGS,
+};
+
+struct reg_data_type {
+ enum reg_type type;
+ const char *id;
+ enum reg_data_type_class type_class;
+ union {
+ struct reg_data_type_vector *reg_type_vector;
+ struct reg_data_type_union *reg_type_union;
+ struct reg_data_type_struct *reg_type_struct;
+ struct reg_data_type_flags *reg_type_flags;
+ };
+};
+
struct reg {
const char *name;
+ uint32_t number;
+ struct reg_feature *feature;
+ bool caller_save;
void *value;
bool dirty;
bool valid;
+ bool exist;
uint32_t size;
+ struct reg_data_type *reg_data_type;
+ const char *group;
void *arch_info;
const struct reg_arch_type *type;
};
diff --git a/src/target/target.c b/src/target/target.c
index 1f517ac..c5b80d6 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -1037,9 +1037,10 @@ int target_remove_watchpoint(struct target *target,
}
int target_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size)
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class)
{
- return target->type->get_gdb_reg_list(target, reg_list, reg_list_size);
+ return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
}
int target_step(struct target *target,
int current, uint32_t address, int handle_breakpoints)
diff --git a/src/target/target.h b/src/target/target.h
index 38bb875..42414c6 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -114,6 +114,12 @@ struct backoff_timer {
int count;
};
+/* split target registers into multiple class */
+enum target_register_class {
+ REG_CLASS_ALL,
+ REG_CLASS_GENERAL,
+};
+
/* target_type.h contains the full definition of struct target_type */
struct target {
struct target_type *type; /* target type definition (name, access functions) */
@@ -399,7 +405,8 @@ int target_remove_watchpoint(struct target *target,
* This routine is a wrapper for target->type->get_gdb_reg_list.
*/
int target_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class);
/**
* Step the target.
diff --git a/src/target/target_type.h b/src/target/target_type.h
index 3a3de7a..4d9a33f 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -101,7 +101,8 @@ struct target_type {
* list, however it is after GDB is connected that monitor commands can
* be run to properly initialize the target
*/
- int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size);
+ int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class);
/* target memory access
* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)