Browse Source

Introduce ARCv2 architecture related code

This patch is an initial bump of ARC-specific code
which implements the ARCv2 target(EMSK board) initializing
routine and some basic remote connection/load/continue
functionality.

Changes:
03.12.2019:
-Add return value checks.
-Using static code analizer next fixes were made:
        Mem leak in functions:
                arc_jtag_read_memory,arc_jtag_read_memory,
                arc_jtag_write_registers, arc_jtag_read_registers,
                jim_arc_add_reg_type_flags, jim_arc_add_reg_type_struct,
                arc_build_reg_cache, arc_mem_read.
        Dead code in "arc_mem_read";
        In arc_save_context, arc_restore_context correct arguments
        in"memset" calls.
        In "build_bcr_reg_cache", "arc_build_reg_cache" check
        if list is not empty.

29.12.2019
-Moved code from arc_v2.c to arc.c
-Added checks of the result of calloc/malloc calls
-Reworked arc_cmd.c: replaced spagetty code with functions
-Moved to one style in if statements - to "if(!bla)"
-Changed Licence headers

22.01.2020
-Removed unused variables in arc_common
-Renamed register operation functions
-Introduced arc_deinit_target function
-Fixed interrupt handling in halt/resume:
        * add irq_state field in arc_common
        * fix irq enable/disable calls ( now STATUS32 register is used)
-Switched from buf_set(get)_us32() usage to target_buffer_set(get)_u32()
-Made some cleanup

30.01.2020
-Removed redundant arc_register struct, moved target link to arc_reg_desc
-Introduced link to BCR reg cache in arc_common for freeing memory.
-Now arc_deinit_target frees all arc-related allocated memory.
	Valgrind shows no memory leaks.
-Inroduced arch description in arc.c

01.02.2020
-Remove small memory allocations in arc_init_reg. Instead created reg_value
	and feature fields in arc_reg_desc.
-Add return value for arc_init_reg() func.
-Replaced some integer constants(61,62,63) with defines.
-Removed redundant conversions in arc_reg_get_field().
-Moved iccm/dccm configuration code from arc_configure()
	to separate functions.

19.02.2020
-Change sizeof(struct) to sizeof(*ptr) in allocations
-Changed if/while(ptr != NULL) to if/while(ptr)
-Removed unused variables from struct arc_jtag
-Add additional structs to arc_reg_data_type
 to reduce amount of memory allocations calls
 and simplifying memory freeing.
-Add helper arc_reg_bitfield_t struct which includes
 reg_data_type_bitfield object and char[] name. Reduces
 memory allocations calls.
-Add limit for reg_type/reg_type_field names(20 symbols).
-Add in jim_arc_add_reg_type*() functions additional
 argnument checks(amount of field/name size).
-In jim_arc_add_reg_type*() reduced amount of memory allocations.
-Cleanup of jim_arc_add_reg_type*() functions.
-For commands update ".usage" fields according docopt.
-Cleanup in arc_jtag.c
-Renamed functions which require jtag_exeutre_queue() to arc_jtag_enque_*()
-Add arc_jtag_enque_register_rw() function, which r/w to jtag ir/dr regs
 during regiter r/w.

24.02:
-Change include guards in arc* files according coding style
-Remove _t suffix in struct arc_reg_bitfield_t
-Some cleanup

Change-Id: I6ab0e82b12e6ddb683c9d13dfb7dd6f49a30cb9f
Signed-off-by: Evgeniy Didin <didin@synopsys.com>
Cc: Alexey Brodkin <abrodkin@synopsys.com>
Reviewed-on: http://openocd.zylin.com/5332
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
jim
Evgeniy Didin 4 years ago
committed by Oleksij Rempel
parent
commit
9ee9bdd2f9
10 changed files with 3478 additions and 1 deletions
  1. +12
    -1
      src/target/Makefile.am
  2. +1339
    -0
      src/target/arc.c
  3. +212
    -0
      src/target/arc.h
  4. +977
    -0
      src/target/arc_cmd.c
  5. +16
    -0
      src/target/arc_cmd.h
  6. +542
    -0
      src/target/arc_jtag.c
  7. +70
    -0
      src/target/arc_jtag.h
  8. +287
    -0
      src/target/arc_mem.c
  9. +21
    -0
      src/target/arc_mem.h
  10. +2
    -0
      src/target/target.c

+ 12
- 1
src/target/Makefile.am View File

@@ -24,6 +24,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
$(STM8_SRC) \
$(INTEL_IA32_SRC) \
$(ESIRISC_SRC) \
$(ARC_SRC) \
%D%/avrt.c \
%D%/dsp563xx.c \
%D%/dsp563xx_once.c \
@@ -156,6 +157,12 @@ ESIRISC_SRC = \
%D%/esirisc_jtag.c \
%D%/esirisc_trace.c

ARC_SRC = \
%D%/arc.c \
%D%/arc_cmd.c \
%D%/arc_jtag.c \
%D%/arc_mem.c

%C%_libtarget_la_SOURCES += \
%D%/algorithm.h \
%D%/arm.h \
@@ -243,7 +250,11 @@ ESIRISC_SRC = \
%D%/esirisc.h \
%D%/esirisc_jtag.h \
%D%/esirisc_regs.h \
%D%/esirisc_trace.h
%D%/esirisc_trace.h \
%D%/arc.h \
%D%/arc_cmd.h \
%D%/arc_jtag.h \
%D%/arc_mem.h

include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am

+ 1339
- 0
src/target/arc.c
File diff suppressed because it is too large
View File


+ 212
- 0
src/target/arc.h View File

@@ -0,0 +1,212 @@
/***************************************************************************
* Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifndef OPENOCD_TARGET_ARC_H
#define OPENOCD_TARGET_ARC_H

#include <helper/time_support.h>
#include <jtag/jtag.h>

#include "algorithm.h"
#include "breakpoints.h"
#include "jtag/interface.h"
#include "register.h"
#include "target.h"
#include "target_request.h"
#include "target_type.h"
#include "helper/bits.h"

#include "arc_jtag.h"
#include "arc_cmd.h"
#include "arc_mem.h"

#define ARC_COMMON_MAGIC 0xB32EB324 /* just a unique number */

#define AUX_DEBUG_REG 0x5
#define AUX_PC_REG 0x6
#define AUX_STATUS32_REG 0xA

#define SET_CORE_FORCE_HALT BIT(1)
#define SET_CORE_HALT_BIT BIT(0) /* STATUS32[0] = H field */
#define SET_CORE_ENABLE_INTERRUPTS BIT(31)

#define AUX_STATUS32_REG_HALT_BIT BIT(0)
#define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */

/* Reserved core registers */
#define CORE_R61_NUM (61)
#define CORE_R62_NUM (62)

#define CORE_REG_MAX_NUMBER (63)

/* Limit reg_type/reg_type_field name to 20 symbols */
#define REG_TYPE_MAX_NAME_LENGTH 20

struct arc_reg_bitfield {
struct reg_data_type_bitfield bitfield;
char name[REG_TYPE_MAX_NAME_LENGTH];
};
/* Register data type */
struct arc_reg_data_type {
struct list_head list;
struct reg_data_type data_type;
struct reg_data_type_flags data_type_flags;
struct reg_data_type_struct data_type_struct;
char data_type_id[REG_TYPE_MAX_NAME_LENGTH];
struct arc_reg_bitfield *bitfields;
};



/* Standard GDB register types */
static const struct reg_data_type standard_gdb_types[] = {
{ .type = REG_TYPE_INT, .id = "int" },
{ .type = REG_TYPE_INT8, .id = "int8" },
{ .type = REG_TYPE_INT16, .id = "int16" },
{ .type = REG_TYPE_INT32, .id = "int32" },
{ .type = REG_TYPE_INT64, .id = "int64" },
{ .type = REG_TYPE_INT128, .id = "int128" },
{ .type = REG_TYPE_UINT8, .id = "uint8" },
{ .type = REG_TYPE_UINT16, .id = "uint16" },
{ .type = REG_TYPE_UINT32, .id = "uint32" },
{ .type = REG_TYPE_UINT64, .id = "uint64" },
{ .type = REG_TYPE_UINT128, .id = "uint128" },
{ .type = REG_TYPE_CODE_PTR, .id = "code_ptr" },
{ .type = REG_TYPE_DATA_PTR, .id = "data_ptr" },
{ .type = REG_TYPE_FLOAT, .id = "float" },
{ .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" },
{ .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" },
};


struct arc_common {
uint32_t common_magic;

struct arc_jtag jtag_info;

struct reg_cache *core_and_aux_cache;
struct reg_cache *bcr_cache;

/* Indicate if cach was built (for deinit function) */
bool core_aux_cache_built;
bool bcr_cache_built;
/* Closely Coupled memory(CCM) regions for performance-critical
* code (optional). */
uint32_t iccm0_start;
uint32_t iccm0_end;
uint32_t iccm1_start;
uint32_t iccm1_end;
uint32_t dccm_start;
uint32_t dccm_end;

int irq_state;

/* Register descriptions */
struct list_head reg_data_types;
struct list_head core_reg_descriptions;
struct list_head aux_reg_descriptions;
struct list_head bcr_reg_descriptions;
unsigned long num_regs;
unsigned long num_core_regs;
unsigned long num_aux_regs;
unsigned long num_bcr_regs;
unsigned long last_general_reg;

/* PC register location in register cache. */
unsigned long pc_index_in_cache;
/* DEBUG register location in register cache. */
unsigned long debug_index_in_cache;
};

/* Borrowed from nds32.h */
#define CHECK_RETVAL(action) \
do { \
int __retval = (action); \
if (__retval != ERROR_OK) { \
LOG_DEBUG("error while calling \"%s\"", \
# action); \
return __retval; \
} \
} while (0)

#define JIM_CHECK_RETVAL(action) \
do { \
int __retval = (action); \
if (__retval != JIM_OK) { \
LOG_DEBUG("error while calling \"%s\"", \
# action); \
return __retval; \
} \
} while (0)

static inline struct arc_common *target_to_arc(struct target *target)
{
return target->arch_info;
}


/* ARC Register description */
struct arc_reg_desc {

struct target *target;

/* Register name */
char *name;

/* Actual place of storing reg_value */
uint8_t reg_value[4];

/* Actual place of storing register feature */
struct reg_feature feature;

/* GDB XML feature */
char *gdb_xml_feature;

/* Is this a register in g/G-packet? */
bool is_general;

/* Architectural number: core reg num or AUX reg num */
uint32_t arch_num;

/* Core or AUX register? */
bool is_core;

/* Build configuration register? */
bool is_bcr;

/* Data type */
struct reg_data_type *data_type;

struct list_head list;
};

/* Error codes */
#define ERROR_ARC_REGISTER_NOT_FOUND (-700)
#define ERROR_ARC_REGISTER_FIELD_NOT_FOUND (-701)
#define ERROR_ARC_REGISTER_IS_NOT_STRUCT (-702)
#define ERROR_ARC_FIELD_IS_NOT_BITFIELD (-703)
#define ERROR_ARC_REGTYPE_NOT_FOUND (-704)

void free_reg_desc(struct arc_reg_desc *r);


void arc_reg_data_type_add(struct target *target,
struct arc_reg_data_type *data_type);

int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg,
const char * const type_name, const size_t type_name_len);

struct reg *arc_reg_get_by_name(struct reg_cache *first,
const char *name, bool search_all);

int arc_reg_get_field(struct target *target, const char *reg_name,
const char *field_name, uint32_t *value_ptr);

#endif /* OPENOCD_TARGET_ARC_H */

+ 977
- 0
src/target/arc_cmd.c View File

@@ -0,0 +1,977 @@
/***************************************************************************
* Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "arc.h"

/* --------------------------------------------------------------------------
*
* ARC targets expose command interface.
* It can be accessed via GDB through the (gdb) monitor command.
*
* ------------------------------------------------------------------------- */


static int arc_cmd_jim_get_uint32(Jim_GetOptInfo *goi, uint32_t *value)
{
jim_wide value_wide;
JIM_CHECK_RETVAL(Jim_GetOpt_Wide(goi, &value_wide));
*value = (uint32_t)value_wide;
return JIM_OK;
}

enum add_reg_types {
CFG_ADD_REG_TYPE_FLAG,
CFG_ADD_REG_TYPE_STRUCT,
};
/* Add flags register data type */
enum add_reg_type_flags {
CFG_ADD_REG_TYPE_FLAGS_NAME,
CFG_ADD_REG_TYPE_FLAGS_FLAG,
};

static Jim_Nvp nvp_add_reg_type_flags_opts[] = {
{ .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME },
{ .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG },
{ .name = NULL, .value = -1 }
};

/* Helper function to check if all field required for register
* are set up */
static const char *validate_register(const struct arc_reg_desc * const reg, bool arch_num_set)
{
/* Check that required fields are set */
if (!reg->name)
return "-name option is required";
if (!reg->gdb_xml_feature)
return "-feature option is required";
if (!arch_num_set)
return "-num option is required";
if (reg->is_bcr && reg->is_core)
return "Register cannot be both -core and -bcr.";
return NULL;
}

/* Helper function to read the name of register type or register from
* configure files */
static int jim_arc_read_reg_name_field(Jim_GetOptInfo *goi,
const char **name, int *name_len)
{
int e = JIM_OK;

if (!goi->argc) {
Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name <name> ...");
return JIM_ERR;
}
e = Jim_GetOpt_String(goi, name, name_len);
return e;
}

/* Helper function to read bitfields/flags of register type. */
static int jim_arc_read_reg_type_field(Jim_GetOptInfo *goi, const char **field_name, int *field_name_len,
struct arc_reg_bitfield *bitfields, int cur_field, int type)
{
jim_wide start_pos, end_pos;

int e = JIM_OK;
if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) ||
(type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) {
Jim_SetResultFormatted(goi->interp, "Not enough argmunets after -flag/-bitfield");
return JIM_ERR;
}

e = Jim_GetOpt_String(goi, field_name, field_name_len);
if (e != JIM_OK)
return e;

/* read start position of bitfield/flag */
e = Jim_GetOpt_Wide(goi, &start_pos);
if (e != JIM_OK)
return e;

end_pos = start_pos;

/* Check if any argnuments remain,
* set bitfields[cur_field].end if flag is multibit */
if (goi->argc > 0)
/* Check current argv[0], if it is equal to "-flag",
* than bitfields[cur_field].end remains start */
if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG)
|| (type == CFG_ADD_REG_TYPE_STRUCT)) {
e = Jim_GetOpt_Wide(goi, &end_pos);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi->interp, "Error reading end position");
return e;
}
}

bitfields[cur_field].bitfield.start = start_pos;
bitfields[cur_field].bitfield.end = end_pos;
if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT))
bitfields[cur_field].bitfield.type = REG_TYPE_INT;
return e;
}

static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
{
Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

LOG_DEBUG("-");

struct command_context *ctx;
struct target *target;

ctx = current_command_context(interp);
assert(ctx);
target = get_current_target(ctx);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

int e = JIM_OK;

/* Check if the amount of argnuments is not zero */
if (goi.argc <= 0) {
Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
return JIM_ERR;
}

/* Estimate number of registers as (argc - 2)/3 as each -flag option has 2
* arguments while -name is required. */
unsigned int fields_sz = (goi.argc - 2) / 3;
unsigned int cur_field = 0;

/* Tha maximum amount of bitfilds is 32 */
if (fields_sz > 32) {
Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
return JIM_ERR;
}

struct arc_reg_data_type *type = calloc(1, sizeof(*type));
struct reg_data_type_flags *flags = &type->data_type_flags;
struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields));
struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*type));
if (!(type && fields && bitfields)) {
Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
goto fail;
}

/* Initialize type */
type->bitfields = bitfields;
type->data_type.id = type->data_type_id;
type->data_type.type = REG_TYPE_ARCH_DEFINED;
type->data_type.type_class = REG_TYPE_CLASS_FLAGS;
type->data_type.reg_type_flags = flags;
flags->size = 4; /* For now ARC has only 32-bit registers */

while (goi.argc > 0 && e == JIM_OK) {
Jim_Nvp *n;
e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_flags_opts, &n);
if (e != JIM_OK) {
Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_flags_opts, 0);
continue;
}

switch (n->value) {
case CFG_ADD_REG_TYPE_FLAGS_NAME:
{
const char *name = NULL;
int name_len = 0;

e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
goto fail;
}

if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
goto fail;
}

strncpy((void *)type->data_type.id, name, name_len);
if (!type->data_type.id) {
Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
goto fail;
}

break;
}

case CFG_ADD_REG_TYPE_FLAGS_FLAG:
{
const char *field_name = NULL;
int field_name_len = 0;

e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
cur_field, CFG_ADD_REG_TYPE_FLAG);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field.");
goto fail;
}

if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
goto fail;
}

fields[cur_field].name = bitfields[cur_field].name;
strncpy(bitfields[cur_field].name, field_name, field_name_len);
if (!fields[cur_field].name) {
Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
goto fail;
}

fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
if (cur_field > 0)
fields[cur_field - 1].next = &(fields[cur_field]);
else
flags->fields = fields;

cur_field += 1;
break;
}
}
}

if (!type->data_type.id) {
Jim_SetResultFormatted(goi.interp, "-name is a required option");
goto fail;
}

arc_reg_data_type_add(target, type);

LOG_DEBUG("added flags type {name=%s}", type->data_type.id);

return JIM_OK;
fail:
free(type);
free(fields);
free(bitfields);

return JIM_ERR;
}

/* Add struct register data type */
enum add_reg_type_struct {
CFG_ADD_REG_TYPE_STRUCT_NAME,
CFG_ADD_REG_TYPE_STRUCT_BITFIELD,
};

static Jim_Nvp nvp_add_reg_type_struct_opts[] = {
{ .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME },
{ .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD },
{ .name = NULL, .value = -1 }
};

static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{

struct command_context *context;
struct target *target;
uint32_t regnum;
uint32_t value;

Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

if (goi.argc != 2) {
Jim_SetResultFormatted(goi.interp,
"usage: %s <aux_reg_num> <aux_reg_value>", Jim_GetString(argv[0], NULL));
return JIM_ERR;
}

context = current_command_context(interp);
assert(context);

target = get_current_target(context);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));

/* Register value */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));

struct arc_common *arc = target_to_arc(target);
assert(arc);

CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, regnum, value));

return ERROR_OK;
}

static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
struct command_context *context;
struct target *target;
uint32_t regnum;
uint32_t value;

Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

if (goi.argc != 1) {
Jim_SetResultFormatted(goi.interp,
"usage: %s <aux_reg_num>", Jim_GetString(argv[0], NULL));
return JIM_ERR;
}

context = current_command_context(interp);
assert(context);

target = get_current_target(context);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));

struct arc_common *arc = target_to_arc(target);
assert(arc);

CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value));
Jim_SetResultInt(interp, value);

return ERROR_OK;
}

static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
struct command_context *context;
struct target *target;
uint32_t regnum;
uint32_t value;

Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

if (goi.argc != 1) {
Jim_SetResultFormatted(goi.interp,
"usage: %s <core_reg_num>", Jim_GetString(argv[0], NULL));
return JIM_ERR;
}

context = current_command_context(interp);
assert(context);

target = get_current_target(context);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
Jim_SetResultFormatted(goi.interp, "Core register number %i " \
"is invalid. Must less then 64 and not 61 and 62.", regnum);
return JIM_ERR;
}

struct arc_common *arc = target_to_arc(target);
assert(arc);

/* Read value */
CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value));
Jim_SetResultInt(interp, value);

return ERROR_OK;
}

static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
struct command_context *context;
struct target *target;
uint32_t regnum;
uint32_t value;

Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

if (goi.argc != 2) {
Jim_SetResultFormatted(goi.interp,
"usage: %s <core_reg_num> <core_reg_value>", Jim_GetString(argv[0], NULL));
return JIM_ERR;
}

context = current_command_context(interp);
assert(context);

target = get_current_target(context);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
Jim_SetResultFormatted(goi.interp, "Core register number %i " \
"is invalid. Must less then 64 and not 61 and 62.", regnum);
return JIM_ERR;
}

/* Register value */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));

struct arc_common *arc = target_to_arc(target);
assert(arc);

CHECK_RETVAL(arc_jtag_write_core_reg_one(&arc->jtag_info, regnum, value));

return ERROR_OK;
}

static const struct command_registration arc_jtag_command_group[] = {
{
.name = "get-aux-reg",
.jim_handler = jim_arc_get_aux_reg,
.mode = COMMAND_EXEC,
.help = "Get AUX register by number. This command does a " \
"raw JTAG request that bypasses OpenOCD register cache "\
"and thus is unsafe and can have unexpected consequences. "\
"Use at your own risk.",
.usage = "arc jtag get-aux-reg <regnum>"
},
{
.name = "set-aux-reg",
.jim_handler = jim_arc_set_aux_reg,
.mode = COMMAND_EXEC,
.help = "Set AUX register by number. This command does a " \
"raw JTAG request that bypasses OpenOCD register cache "\
"and thus is unsafe and can have unexpected consequences. "\
"Use at your own risk.",
.usage = "arc jtag set-aux-reg <regnum> <value>"
},
{
.name = "get-core-reg",
.jim_handler = jim_arc_get_core_reg,
.mode = COMMAND_EXEC,
.help = "Get/Set core register by number. This command does a " \
"raw JTAG request that bypasses OpenOCD register cache "\
"and thus is unsafe and can have unexpected consequences. "\
"Use at your own risk.",
.usage = "arc jtag get-core-reg <regnum> [<value>]"
},
{
.name = "set-core-reg",
.jim_handler = jim_arc_set_core_reg,
.mode = COMMAND_EXEC,
.help = "Get/Set core register by number. This command does a " \
"raw JTAG request that bypasses OpenOCD register cache "\
"and thus is unsafe and can have unexpected consequences. "\
"Use at your own risk.",
.usage = "arc jtag set-core-reg <regnum> [<value>]"
},
COMMAND_REGISTRATION_DONE
};


/* This function supports only bitfields. */
static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
{
Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

LOG_DEBUG("-");

struct command_context *ctx;
struct target *target;

ctx = current_command_context(interp);
assert(ctx);
target = get_current_target(ctx);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

int e = JIM_OK;

/* Check if the amount of argnuments is not zero */
if (goi.argc <= 0) {
Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
return JIM_ERR;
}

/* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3
* arguments while -name is required. */
unsigned int fields_sz = (goi.argc - 2) / 4;
unsigned int cur_field = 0;

/* Tha maximum amount of bitfilds is 32 */
if (fields_sz > 32) {
Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
return JIM_ERR;
}

struct arc_reg_data_type *type = calloc(1, sizeof(*type));
struct reg_data_type_struct *struct_type = &type->data_type_struct;
struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields));
struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*type));
if (!(type && fields && bitfields)) {
Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
goto fail;
}

/* Initialize type */
type->data_type.id = type->data_type_id;
type->bitfields = bitfields;
type->data_type.type = REG_TYPE_ARCH_DEFINED;
type->data_type.type_class = REG_TYPE_CLASS_STRUCT;
type->data_type.reg_type_struct = struct_type;
struct_type->size = 4; /* For now ARC has only 32-bit registers */

while (goi.argc > 0 && e == JIM_OK) {
Jim_Nvp *n;
e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_struct_opts, &n);
if (e != JIM_OK) {
Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_struct_opts, 0);
continue;
}

switch (n->value) {
case CFG_ADD_REG_TYPE_STRUCT_NAME:
{
const char *name = NULL;
int name_len = 0;

e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
goto fail;
}

if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
goto fail;
}

strncpy((void *)type->data_type.id, name, name_len);
if (!type->data_type.id) {
Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
goto fail;
}

break;
}
case CFG_ADD_REG_TYPE_STRUCT_BITFIELD:
{
const char *field_name = NULL;
int field_name_len = 0;
e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
cur_field, CFG_ADD_REG_TYPE_STRUCT);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field.");
goto fail;
}

if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
goto fail;
}

fields[cur_field].name = bitfields[cur_field].name;
strncpy(bitfields[cur_field].name, field_name, field_name_len);
if (!fields[cur_field].name) {
Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
goto fail;
}

fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
fields[cur_field].use_bitfields = true;
if (cur_field > 0)
fields[cur_field - 1].next = &(fields[cur_field]);
else
struct_type->fields = fields;

cur_field += 1;

break;
}
}
}

if (!type->data_type.id) {
Jim_SetResultFormatted(goi.interp, "-name is a required option");
goto fail;
}

arc_reg_data_type_add(target, type);
LOG_DEBUG("added struct type {name=%s}", type->data_type.id);
return JIM_OK;

fail:
free(type);
free(fields);
free(bitfields);

return JIM_ERR;
}

/* Add register */
enum opts_add_reg {
CFG_ADD_REG_NAME,
CFG_ADD_REG_ARCH_NUM,
CFG_ADD_REG_IS_CORE,
CFG_ADD_REG_IS_BCR,
CFG_ADD_REG_GDB_FEATURE,
CFG_ADD_REG_TYPE,
CFG_ADD_REG_GENERAL,
};

static Jim_Nvp opts_nvp_add_reg[] = {
{ .name = "-name", .value = CFG_ADD_REG_NAME },
{ .name = "-num", .value = CFG_ADD_REG_ARCH_NUM },
{ .name = "-core", .value = CFG_ADD_REG_IS_CORE },
{ .name = "-bcr", .value = CFG_ADD_REG_IS_BCR },
{ .name = "-feature", .value = CFG_ADD_REG_GDB_FEATURE },
{ .name = "-type", .value = CFG_ADD_REG_TYPE },
{ .name = "-g", .value = CFG_ADD_REG_GENERAL },
{ .name = NULL, .value = -1 }
};

void free_reg_desc(struct arc_reg_desc *r)
{
free(r->name);
free(r->gdb_xml_feature);
free(r);
}

static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
Jim_GetOptInfo goi;
JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

struct arc_reg_desc *reg = calloc(1, sizeof(*reg));
if (!reg) {
Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
return JIM_ERR;
}

/* There is no architecture number that we could treat as invalid, so
* separate variable requried to ensure that arch num has been set. */
bool arch_num_set = false;
const char *type_name = "int"; /* Default type */
int type_name_len = strlen(type_name);
int e = ERROR_OK;

/* At least we need to specify 4 parameters: name, number, type and gdb_feature,
* which means there should be 8 arguments */
if (goi.argc < 8) {
free_reg_desc(reg);
Jim_SetResultFormatted(goi.interp,
"Should be at least 8 argnuments: -name <name> "
"-num <num> -type <type> -feature <gdb_feature>.");
return JIM_ERR;
}

/* Parse options. */
while (goi.argc > 0) {
Jim_Nvp *n;
e = Jim_GetOpt_Nvp(&goi, opts_nvp_add_reg, &n);
if (e != JIM_OK) {
Jim_GetOpt_NvpUnknown(&goi, opts_nvp_add_reg, 0);
free_reg_desc(reg);
return e;
}

switch (n->value) {
case CFG_ADD_REG_NAME:
{
const char *reg_name = NULL;
int reg_name_len = 0;

e = jim_arc_read_reg_name_field(&goi, &reg_name, &reg_name_len);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to read register name.");
free_reg_desc(reg);
return e;
}

reg->name = strndup(reg_name, reg_name_len);
break;
}
case CFG_ADD_REG_IS_CORE:
reg->is_core = true;
break;
case CFG_ADD_REG_IS_BCR:
reg->is_bcr = true;
break;
case CFG_ADD_REG_ARCH_NUM:
{
jim_wide archnum;

if (!goi.argc) {
free_reg_desc(reg);
Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num <int> ...");
return JIM_ERR;
}

e = Jim_GetOpt_Wide(&goi, &archnum);
if (e != JIM_OK) {
free_reg_desc(reg);
return e;
}

reg->arch_num = archnum;
arch_num_set = true;
break;
}
case CFG_ADD_REG_GDB_FEATURE:
{
const char *feature = NULL;
int feature_len = 0;

e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature.");
free_reg_desc(reg);
return e;
}

reg->gdb_xml_feature = strndup(feature, feature_len);
break;
}
case CFG_ADD_REG_TYPE:
e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len);
if (e != JIM_OK) {
Jim_SetResultFormatted(goi.interp, "Unable to read register type.");
free_reg_desc(reg);
return e;
}

break;
case CFG_ADD_REG_GENERAL:
reg->is_general = true;
break;
default:
LOG_DEBUG("Error: Unknown parameter");
free_reg_desc(reg);
return JIM_ERR;
}
}

/* Check that required fields are set */
const char * const errmsg = validate_register(reg, arch_num_set);
if (errmsg) {
Jim_SetResultFormatted(goi.interp, errmsg);
free_reg_desc(reg);
return JIM_ERR;
}

/* Add new register */
struct command_context *ctx;
struct target *target;

ctx = current_command_context(interp);
assert(ctx);
target = get_current_target(ctx);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

reg->target = target;

e = arc_reg_add(target, reg, type_name, type_name_len);
if (e == ERROR_ARC_REGTYPE_NOT_FOUND) {
Jim_SetResultFormatted(goi.interp,
"Cannot find type `%s' for register `%s'.",
type_name, reg->name);
free_reg_desc(reg);
return JIM_ERR;
}

return e;
}

/* arc set-reg-exists ($reg_name)+
* Accepts any amount of register names - will set them as existing in a loop.*/
COMMAND_HANDLER(arc_set_reg_exists)
{
struct target * const target = get_current_target(CMD_CTX);
if (!target) {
command_print(CMD, "Unable to get current target.");
return JIM_ERR;
}

if (!CMD_ARGC) {
command_print(CMD, "At least one register name must be specified.");
return ERROR_COMMAND_SYNTAX_ERROR;
}

for (unsigned int i = 0; i < CMD_ARGC; i++) {
const char * const reg_name = CMD_ARGV[i];
struct reg * const r = arc_reg_get_by_name(target->reg_cache, reg_name, true);

if (!r) {
command_print(CMD, "Register `%s' is not found.", reg_name);
return ERROR_COMMAND_ARGUMENT_INVALID;
}

r->exist = true;
}

return JIM_OK;
}

/* arc reg-field ($reg_name) ($reg_field)
* Reads struct type register field */
static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
Jim_GetOptInfo goi;
const char *reg_name, *field_name;
uint32_t value;
int retval;

JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));

LOG_DEBUG("Reading register field");
if (goi.argc != 2) {
if (!goi.argc)
Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>");
else if (goi.argc == 1)
Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<fieldname>");
else
Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>");
return ERROR_COMMAND_SYNTAX_ERROR;
}

JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &reg_name, NULL));
JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &field_name, NULL));
assert(reg_name);
assert(field_name);

struct command_context * const ctx = current_command_context(interp);
assert(ctx);
struct target * const target = get_current_target(ctx);
if (!target) {
Jim_SetResultFormatted(goi.interp, "No current target");
return JIM_ERR;
}

retval = arc_reg_get_field(target, reg_name, field_name, &value);

switch (retval) {
case ERROR_OK:
break;
case ERROR_ARC_REGISTER_NOT_FOUND:
Jim_SetResultFormatted(goi.interp,
"Register `%s' has not been found.", reg_name);
return ERROR_COMMAND_ARGUMENT_INVALID;
case ERROR_ARC_REGISTER_IS_NOT_STRUCT:
Jim_SetResultFormatted(goi.interp,
"Register `%s' must have 'struct' type.", reg_name);
return ERROR_COMMAND_ARGUMENT_INVALID;
case ERROR_ARC_REGISTER_FIELD_NOT_FOUND:
Jim_SetResultFormatted(goi.interp,
"Field `%s' has not been found in register `%s'.",
field_name, reg_name);
return ERROR_COMMAND_ARGUMENT_INVALID;
case ERROR_ARC_FIELD_IS_NOT_BITFIELD:
Jim_SetResultFormatted(goi.interp,
"Field `%s' is not a 'bitfield' field in a structure.",
field_name);
return ERROR_COMMAND_ARGUMENT_INVALID;
default:
/* Pass through other errors. */
return retval;
}

Jim_SetResultInt(interp, value);

return JIM_OK;
}

/* ----- Exported target commands ------------------------------------------ */

static const struct command_registration arc_core_command_handlers[] = {
{
.name = "add-reg-type-flags",
.jim_handler = jim_arc_add_reg_type_flags,
.mode = COMMAND_CONFIG,
.usage = "arc ardd-reg-type-flags -name <string> -flag <name> <position> "
"[-flag <name> <position>]...",
.help = "Add new 'flags' register data type. Only single bit flags "
"are supported. Type name is global. Bitsize of register is fixed "
"at 32 bits.",
},
{
.name = "add-reg-type-struct",
.jim_handler = jim_arc_add_reg_type_struct,
.mode = COMMAND_CONFIG,
.usage = "arc add-reg-type-struct -name <string> -bitfield <name> <start> <end> "
"[-bitfield <name> <start> <end>]...",
.help = "Add new 'struct' register data type. Only bit-fields are "
"supported so far, which means that for each bitfield start and end "
"position bits must be specified. GDB also support type-fields, "
"where common type can be used instead. Type name is global. Bitsize of "
"register is fixed at 32 bits.",
},
{
.name = "add-reg",
.jim_handler = jim_arc_add_reg,
.mode = COMMAND_CONFIG,
.usage = "arc add-reg -name <string> -num <int> -feature <string> [-gdbnum <int>] "
"[-core|-bcr] [-type <type_name>] [-g]",
.help = "Add new register. Name, architectural number and feature name "
"are requried options. GDB regnum will default to previous register "
"(gdbnum + 1) and shouldn't be specified in most cases. Type "
"defaults to default GDB 'int'.",
},
{
.name = "set-reg-exists",
.handler = arc_set_reg_exists,
.mode = COMMAND_ANY,
.usage = "arc set-reg-exists <register-name> [<register-name>]...",
.help = "Set that register exists. Accepts multiple register names as "
"arguments.",
},
{
.name = "get-reg-field",
.jim_handler = jim_arc_get_reg_field,
.mode = COMMAND_ANY,
.usage = "arc get-reg-field <regname> <field_name>",
.help = "Returns value of field in a register with 'struct' type.",
},
{
.name = "jtag",
.mode = COMMAND_ANY,
.help = "ARC JTAG specific commands",
.usage = "",
.chain = arc_jtag_command_group,
},
COMMAND_REGISTRATION_DONE
};

const struct command_registration arc_monitor_command_handlers[] = {
{
.name = "arc",
.mode = COMMAND_ANY,
.help = "ARC monitor command group",
.usage = "Help info ...",
.chain = arc_core_command_handlers,
},
COMMAND_REGISTRATION_DONE
};

+ 16
- 0
src/target/arc_cmd.h View File

@@ -0,0 +1,16 @@
/***************************************************************************
* Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifndef OPENOCD_TARGET_ARC_CMD_H
#define OPENOCD_TARGET_ARC_CMD_H

extern const struct command_registration arc_monitor_command_handlers[];

#endif /* OPENOCD_TARGET_ARC_CMD_H */

+ 542
- 0
src/target/arc_jtag.c View File

@@ -0,0 +1,542 @@
/***************************************************************************
* Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "arc.h"

/*
* This functions sets instruction register in TAP. TAP end state is always
* IRPAUSE.
*
* @param jtag_info
* @param new_instr Instruction to write to instruction register.
*/
static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t
new_instr)
{
uint32_t current_instr;
struct jtag_tap *tap;
uint8_t instr_buffer[sizeof(uint32_t)];

assert(jtag_info);
assert(jtag_info->tap);

tap = jtag_info->tap;

/* Do not set instruction if it is the same as current. */
current_instr = buf_get_u32(tap->cur_instr, 0, tap->ir_length);
if (current_instr == new_instr)
return;

struct scan_field field = {
.num_bits = tap->ir_length,
.out_value = instr_buffer
};
buf_set_u32(instr_buffer, 0, field.num_bits, new_instr);

/* From code in src/jtag/drivers/driver.c it look like that fields are
* copied so it is OK that field in this function is allocated in stack and
* thus this memory will be repurposed before jtag_execute_queue() will be
* invoked. */
jtag_add_ir_scan(tap, &field, TAP_IRPAUSE);
}

/**
* Read 4-byte word from data register.
*
* Unlike arc_jtag_write_data, this function returns byte-buffer, caller must
* convert this data to required format himself. This is done, because it is
* impossible to convert data before jtag_execute_queue() is invoked, so it
* cannot be done inside this function, so it has to operate with
* byte-buffers. Write function on the other hand can "write-and-forget", data
* is converted to byte-buffer before jtag_execute_queue().
*
* @param jtag_info
* @param data Array of bytes to read into.
* @param end_state End state after reading.
*/
static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data,
tap_state_t end_state)
{

assert(jtag_info);
assert(jtag_info->tap);

struct scan_field field = {
.num_bits = 32,
.in_value = data
};

jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
}

/**
* Write 4-byte word to data register.
*
* @param jtag_info
* @param data 4-byte word to write into data register.
* @param end_state End state after writing.
*/
static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data,
tap_state_t end_state)
{
uint8_t out_value[sizeof(uint32_t)];

assert(jtag_info);
assert(jtag_info->tap);

buf_set_u32(out_value, 0, 32, data);

struct scan_field field = {
.num_bits = 32,
.out_value = out_value
};

jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
}


/**
* Set transaction in command register. This function sets instruction register
* and then transaction register, there is no need to invoke write_ir before
* invoking this function.
*
* @param jtag_info
* @param new_trans Transaction to write to transaction command register.
* @param end_state End state after writing.
*/
static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info,
uint32_t new_trans, tap_state_t end_state)
{
uint8_t out_value[sizeof(uint32_t)];

assert(jtag_info);
assert(jtag_info->tap);

/* No need to do anything. */
if (jtag_info->cur_trans == new_trans)
return;

/* Set instruction. We used to call write_ir at upper levels, however
* write_ir-write_transaction were constantly in pair, so to avoid code
* duplication this function does it self. For this reasons it is "set"
* instead of "write". */
arc_jtag_enque_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG);
buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans);
struct scan_field field = {
.num_bits = ARC_TRANSACTION_CMD_REG_LENGTH,
.out_value = out_value
};

jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
jtag_info->cur_trans = new_trans;
}

/**
* Run reset through transaction set. None of the previous
* settings/commands/etc. are used anymore (or no influence).
*/
static void arc_jtag_enque_reset_transaction(struct arc_jtag *jtag_info)
{
arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_CMD_NOP, TAP_IDLE);
}

static void arc_jtag_enque_status_read(struct arc_jtag * const jtag_info,
uint8_t * const buffer)
{
assert(jtag_info);
assert(jtag_info->tap);
assert(buffer);

/* first writin code(0x8) of jtag status register in IR */
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_STATUS_REG);
/* Now reading dr performs jtag status register read */
arc_jtag_enque_read_dr(jtag_info, buffer, TAP_IDLE);
}

/* ----- Exported JTAG functions ------------------------------------------- */

int arc_jtag_startup(struct arc_jtag *jtag_info)
{
assert(jtag_info);

arc_jtag_enque_reset_transaction(jtag_info);

return jtag_execute_queue();
}

/** Read STATUS register. */
int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value)
{
uint8_t buffer[sizeof(uint32_t)];

assert(jtag_info);
assert(jtag_info->tap);

/* Fill command queue. */
arc_jtag_enque_reset_transaction(jtag_info);
arc_jtag_enque_status_read(jtag_info, buffer);
arc_jtag_enque_reset_transaction(jtag_info);

/* Execute queue. */
CHECK_RETVAL(jtag_execute_queue());

/* Parse output. */
*value = buf_get_u32(buffer, 0, 32);

return ERROR_OK;
}
/* Helper function: Adding read/write register operation to queue */
static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *addr,
uint8_t *read_buffer, const uint32_t *write_buffer, uint32_t count)
{
uint32_t i;

for (i = 0; i < count; i++) {
/* ARC jtag has optimization which is to increment ADDRESS_REG performing
* each transaction. Making sequential reads/writes we can set address for
* only first register in sequence, and than do read/write in cycle. */
if (i == 0 || (addr[i] != addr[i-1] + 1)) {
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
/* Going to TAP_IDLE state we initiate jtag transaction.
* Reading data we must go to TAP_IDLE, because further
* the data would be read. In case of write we go to TAP_DRPAUSE,
* because we need to write data to Data register first. */
if (write_buffer)
arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_DRPAUSE);
else
arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_IDLE);
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
}
if (write_buffer)
arc_jtag_enque_write_dr(jtag_info, *(write_buffer + i), TAP_IDLE);
else
arc_jtag_enque_read_dr(jtag_info, read_buffer + i * 4, TAP_IDLE);
}
/* To prevent pollution of next regiter due to optimization it is necessary *
* to reset transaction */
arc_jtag_enque_reset_transaction(jtag_info);
}

/**
* Write registers. addr is an array of addresses, and those addresses can be
* in any order, though it is recommended that they are in sequential order
* where possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param type Type of registers to write: core or aux.
* @param addr Array of registers numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type,
uint32_t *addr, uint32_t count, const uint32_t *buffer)
{
LOG_DEBUG("Writing to %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32
";buffer[0]=0x%08" PRIx32,
(type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count, *buffer);

if (!count) {
LOG_ERROR("Trying to write 0 registers");
return ERROR_FAIL;
}

arc_jtag_enque_reset_transaction(jtag_info);

/* What registers are we writing to? */
const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
ARC_JTAG_WRITE_TO_CORE_REG : ARC_JTAG_WRITE_TO_AUX_REG);
arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);

arc_jtag_enque_register_rw(jtag_info, addr, NULL, buffer, count);

return jtag_execute_queue();
}

/**
* Read registers. addr is an array of addresses, and those addresses can be in
* any order, though it is recommended that they are in sequential order where
* possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param type Type of registers to read: core or aux.
* @param addr Array of registers numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type,
uint32_t *addr, uint32_t count, uint32_t *buffer)
{
int retval;
uint32_t i;

assert(jtag_info);
assert(jtag_info->tap);

LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32,
(type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count);

if (!count) {
LOG_ERROR("Trying to read 0 registers");
return ERROR_FAIL;
}

arc_jtag_enque_reset_transaction(jtag_info);

/* What type of registers we are reading? */
const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG);
arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);

uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4);

arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count);

retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute jtag queue: %d", retval);
retval = ERROR_FAIL;
goto exit;
}

/* Convert byte-buffers to host /presentation. */
for (i = 0; i < count; i++)
buffer[i] = buf_get_u32(data_buf + 4 * i, 0, 32);

LOG_DEBUG("Read from register: buf[0]=0x%" PRIx32, buffer[0]);

exit:
free(data_buf);

return retval;
}


/** Wrapper function to ease writing of one core register. */
int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t value)
{
return arc_jtag_write_core_reg(jtag_info, &addr, 1, &value);
}

/**
* Write core registers. addr is an array of addresses, and those addresses can
* be in any order, though it is recommended that they are in sequential order
* where possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param addr Array of registers numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, const uint32_t *buffer)
{
return arc_jtag_write_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
buffer);
}

/** Wrapper function to ease reading of one core register. */
int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t *value)
{
return arc_jtag_read_core_reg(jtag_info, &addr, 1, value);
}

/**
* Read core registers. addr is an array of addresses, and those addresses can
* be in any order, though it is recommended that they are in sequential order
* where possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param addr Array of core register numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, uint32_t *buffer)
{
return arc_jtag_read_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
buffer);
}

/** Wrapper function to ease writing of one AUX register. */
int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t value)
{
return arc_jtag_write_aux_reg(jtag_info, &addr, 1, &value);
}

/**
* Write AUX registers. addr is an array of addresses, and those addresses can
* be in any order, though it is recommended that they are in sequential order
* where possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param addr Array of registers numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, const uint32_t *buffer)
{
return arc_jtag_write_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
buffer);
}

/** Wrapper function to ease reading of one AUX register. */
int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t *value)
{
return arc_jtag_read_aux_reg(jtag_info, &addr, 1, value);
}

/**
* Read AUX registers. addr is an array of addresses, and those addresses can
* be in any order, though it is recommended that they are in sequential order
* where possible, as this reduces number of JTAG commands to transfer.
*
* @param jtag_info
* @param addr Array of AUX register numbers.
* @param count Amount of registers in arrays.
* @param values Array of register values.
*/
int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, uint32_t *buffer)
{
return arc_jtag_read_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
buffer);
}

/**
* Write a sequence of 4-byte words into target memory.
*
* We can write only 4byte words via JTAG, so any non-word writes should be
* handled at higher levels by read-modify-write.
*
* This function writes directly to the memory, leaving any caches (if there
* are any) in inconsistent state. It is responsibility of upper level to
* resolve this.
*
* @param jtag_info
* @param addr Address of first word to write into.
* @param count Amount of word to write.
* @param buffer Array to write into memory.
*/
int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t count, const uint32_t *buffer)
{
assert(jtag_info);
assert(buffer);

LOG_DEBUG("Writing to memory: addr=0x%08" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32,
addr, count, *buffer);

/* No need to waste time on useless operations. */
if (!count)
return ERROR_OK;

/* We do not know where we come from. */
arc_jtag_enque_reset_transaction(jtag_info);

/* We want to write to memory. */
arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, TAP_DRPAUSE);

/* Set target memory address of the first word. */
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
arc_jtag_enque_write_dr(jtag_info, addr, TAP_DRPAUSE);

/* Start sending words. Address is auto-incremented on 4bytes by HW. */
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);

uint32_t i;
for (i = 0; i < count; i++)
arc_jtag_enque_write_dr(jtag_info, *(buffer + i), TAP_IDLE);

return jtag_execute_queue();
}

/**
* Read a sequence of 4-byte words from target memory.
*
* We can read only 4byte words via JTAG.
*
* This function read directly from the memory, so it can read invalid data if
* data cache hasn't been flushed before hand. It is responsibility of upper
* level to resolve this.
*
* @param jtag_info
* @param addr Address of first word to read from.
* @param count Amount of words to read.
* @param buffer Array of words to read into.
* @param slow_memory Whether this is a slow memory (DDR) or fast (CCM).
*/
int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t count, uint32_t *buffer, bool slow_memory)
{
uint8_t *data_buf;
uint32_t i;
int retval = ERROR_OK;


assert(jtag_info);
assert(jtag_info->tap);

LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 ";slow=%c",
addr, count, slow_memory ? 'Y' : 'N');

if (!count)
return ERROR_OK;

data_buf = calloc(sizeof(uint8_t), count * 4);
arc_jtag_enque_reset_transaction(jtag_info);

/* We are reading from memory. */
arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_READ_FROM_MEMORY, TAP_DRPAUSE);

/* Read data */
for (i = 0; i < count; i++) {
/* When several words are read at consequent addresses we can
* rely on ARC JTAG auto-incrementing address. That means that
* address can be set only once, for a first word. However it
* has been noted that at least in some cases when reading from
* DDR, JTAG returns 0 instead of a real value. To workaround
* this issue we need to do totally non-required address
* writes, which however resolve a problem by introducing
* delay. See STAR 9000832538... */
if (slow_memory || i == 0) {
/* Set address */
arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
arc_jtag_enque_write_dr(jtag_info, addr + i * 4, TAP_IDLE);

arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
}
arc_jtag_enque_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE);
}
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("Failed to execute jtag queue: %d", retval);
retval = ERROR_FAIL;
goto exit;
}

/* Convert byte-buffers to host presentation. */
for (i = 0; i < count; i++)
buffer[i] = buf_get_u32(data_buf + 4*i, 0, 32);

exit:
free(data_buf);

return retval;
}


+ 70
- 0
src/target/arc_jtag.h View File

@@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifndef OPENOCD_TARGET_ARC_JTAG_H
#define OPENOCD_TARGET_ARC_JTAG_H

#define ARC_TRANSACTION_CMD_REG 0x9 /* Command to perform */
#define ARC_TRANSACTION_CMD_REG_LENGTH 4

/* Jtag status register, value is placed in IR to read jtag status register */
#define ARC_JTAG_STATUS_REG 0x8
#define ARC_JTAG_ADDRESS_REG 0xA /* SoC address to access */
#define ARC_JTAG_DATA_REG 0xB /* Data read/written from SoC */

/* Jtag status register field */
#define ARC_JTAG_STAT_RU 0x10

/* ARC Jtag transactions */
#define ARC_JTAG_WRITE_TO_MEMORY 0x0
#define ARC_JTAG_WRITE_TO_CORE_REG 0x1
#define ARC_JTAG_WRITE_TO_AUX_REG 0x2
#define ARC_JTAG_CMD_NOP 0x3
#define ARC_JTAG_READ_FROM_MEMORY 0x4
#define ARC_JTAG_READ_FROM_CORE_REG 0x5
#define ARC_JTAG_READ_FROM_AUX_REG 0x6

#define ARC_JTAG_CORE_REG 0x0
#define ARC_JTAG_AUX_REG 0x1


struct arc_jtag {
struct jtag_tap *tap;
uint32_t cur_trans;
};

/* ----- Exported JTAG functions ------------------------------------------- */

int arc_jtag_startup(struct arc_jtag *jtag_info);
int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value);

int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, const uint32_t *buffer);
int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, uint32_t *buffer);
int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
const uint32_t buffer);
int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t *buffer);

int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, const uint32_t *buffer);
int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t value);
int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
uint32_t count, uint32_t *buffer);
int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t *value);

int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t count, const uint32_t *buffer);
int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
uint32_t count, uint32_t *buffer, bool slow_memory);
#endif /* OPENOCD_TARGET_ARC_JTAG_H */

+ 287
- 0
src/target/arc_mem.c View File

@@ -0,0 +1,287 @@
/***************************************************************************
* Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "arc.h"

/* ----- Supporting functions ---------------------------------------------- */
static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr,
uint32_t size, uint32_t count)
{
uint32_t addr_end = addr + size * count;
/* `_end` field can overflow - it points to the first byte after the end,
* therefore if DCCM is right at the end of memory address space, then
* dccm_end will be 0. */
assert(addr_end >= addr || addr_end == 0);

return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) ||
(addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) ||
(addr >= arc->iccm1_start && addr_end <= arc->iccm1_end));
}

/* Write word at word-aligned address */
static int arc_mem_write_block32(struct target *target, uint32_t addr,
uint32_t count, void *buf)
{
struct arc_common *arc = target_to_arc(target);

LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
addr, count);

/* Check arguments */
assert(!(addr & 3));

/* No need to flush cache, because we don't read values from memory. */
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
(uint32_t *)buf));

return ERROR_OK;
}

/* Write half-word at half-word-aligned address */
static int arc_mem_write_block16(struct target *target, uint32_t addr,
uint32_t count, void *buf)
{
struct arc_common *arc = target_to_arc(target);
uint32_t i;
uint32_t buffer_he;
uint8_t buffer_te[sizeof(uint32_t)];
uint8_t halfword_te[sizeof(uint16_t)];

LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
addr, count);

/* Check arguments */
assert(!(addr & 1));

/* non-word writes are less common, than 4-byte writes, so I suppose we can
* allowe ourselves to write this in a cycle, instead of calling arc_jtag
* with count > 1. */
for (i = 0; i < count; i++) {
/* We can read only word at word-aligned address. Also *jtag_read_memory
* functions return data in host endianness, so host endianness !=
* target endianness we have to convert data back to target endianness,
* or bytes will be at the wrong places.So:
* 1) read word
* 2) convert to target endianness
* 3) make changes
* 4) convert back to host endianness
* 5) write word back to target.
*/
bool is_slow_memory = arc_mem_is_slow_memory(arc,
(addr + i * sizeof(uint16_t)) & ~3u, 4, 1);
CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info,
(addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he,
is_slow_memory));
target_buffer_set_u32(target, buffer_te, buffer_he);

/* buf is in host endianness, convert to target */
target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]);

memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u),
halfword_te, sizeof(uint16_t));

buffer_he = target_buffer_get_u32(target, buffer_te);

CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info,
(addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
}

return ERROR_OK;
}

/* Write byte at address */
static int arc_mem_write_block8(struct target *target, uint32_t addr,
uint32_t count, void *buf)
{
struct arc_common *arc = target_to_arc(target);
uint32_t i;
uint32_t buffer_he;
uint8_t buffer_te[sizeof(uint32_t)];


LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
addr, count);

/* non-word writes are less common, than 4-byte writes, so I suppose we can
* allowe ourselves to write this in a cycle, instead of calling arc_jtag
* with count > 1. */
for (i = 0; i < count; i++) {
/* See comment in arc_mem_write_block16 for details. Since it is a byte
* there is not need to convert write buffer to target endianness, but
* we still have to convert read buffer. */
CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he,
arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1)));
target_buffer_set_u32(target, buffer_te, buffer_he);
memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1);
buffer_he = target_buffer_get_u32(target, buffer_te);
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
}

return ERROR_OK;
}

/* ----- Exported functions ------------------------------------------------ */
int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
int retval = ERROR_OK;
void *tunnel = NULL;

LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32,
address, size, count);

if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}

/* sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
return ERROR_COMMAND_SYNTAX_ERROR;

if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;

/* correct endianess if we have word or hword access */
if (size > 1) {
/*
* arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
* in host endianness, but byte array represents target endianness.
*/
tunnel = calloc(1, count * size * sizeof(uint8_t));

if (!tunnel) {
LOG_ERROR("Unable to allocate memory");
return ERROR_FAIL;
}

switch (size) {
case 4:
target_buffer_get_u32_array(target, buffer, count,
(uint32_t *)tunnel);
break;
case 2:
target_buffer_get_u16_array(target, buffer, count,
(uint16_t *)tunnel);
break;
}
buffer = tunnel;
}

if (size == 4) {
retval = arc_mem_write_block32(target, address, count, (void *)buffer);
} else if (size == 2) {
/* We convert buffer from host endianness to target. But then in
* write_block16, we do the reverse. Is there a way to avoid this without
* breaking other cases? */
retval = arc_mem_write_block16(target, address, count, (void *)buffer);
} else {
retval = arc_mem_write_block8(target, address, count, (void *)buffer);
}

free(tunnel);

return retval;
}

static int arc_mem_read_block(struct target *target, target_addr_t addr,
uint32_t size, uint32_t count, void *buf)
{
struct arc_common *arc = target_to_arc(target);

LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
", count=%" PRIu32, addr, size, count);
assert(!(addr & 3));
assert(size == 4);

CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
arc_mem_is_slow_memory(arc, addr, size, count)));

return ERROR_OK;
}

int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
int retval = ERROR_OK;
void *tunnel_he;
uint8_t *tunnel_te;
uint32_t words_to_read, bytes_to_read;


LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
", count=%" PRIu32, address, size, count);

if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
}

/* Sanitize arguments */
if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
return ERROR_COMMAND_SYNTAX_ERROR;

if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;

/* Reads are word-aligned, so padding might be required if count > 1.
* NB: +3 is a padding for the last word (in case it's not aligned;
* addr&3 is a padding for the first word (since address can be
* unaligned as well). */
bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u;
words_to_read = bytes_to_read >> 2;
tunnel_he = calloc(1, bytes_to_read);
tunnel_te = calloc(1, bytes_to_read);

if (!tunnel_he || !tunnel_te) {
LOG_ERROR("Unable to allocate memory");
free(tunnel_he);
free(tunnel_te);
return ERROR_FAIL;
}

/* We can read only word-aligned words. */
retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t),
words_to_read, tunnel_he);

/* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
/* endianness, but byte array should represent target endianness */

if (ERROR_OK == retval) {
switch (size) {
case 4:
target_buffer_set_u32_array(target, buffer, count,
tunnel_he);
break;
case 2:
target_buffer_set_u32_array(target, tunnel_te,
words_to_read, tunnel_he);
/* Will that work properly with count > 1 and big endian? */
memcpy(buffer, tunnel_te + (address & 3u),
count * sizeof(uint16_t));
break;
case 1:
target_buffer_set_u32_array(target, tunnel_te,
words_to_read, tunnel_he);
/* Will that work properly with count > 1 and big endian? */
memcpy(buffer, tunnel_te + (address & 3u), count);
break;
}
}

free(tunnel_he);
free(tunnel_te);

return retval;
}

+ 21
- 0
src/target/arc_mem.h View File

@@ -0,0 +1,21 @@
/***************************************************************************
* Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
* *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/

#ifndef OPENOCD_TARGET_ARC_MEM_H
#define OPENOCD_TARGET_ARC_MEM_H

/* ----- Exported functions ------------------------------------------------ */

int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
uint32_t count, uint8_t *buffer);
int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
uint32_t count, const uint8_t *buffer);


#endif /* OPENOCD_TARGET_ARC_MEM_H */

+ 2
- 0
src/target/target.c View File

@@ -111,6 +111,7 @@ extern struct target_type stm8_target;
extern struct target_type riscv_target;
extern struct target_type mem_ap_target;
extern struct target_type esirisc_target;
extern struct target_type arcv2_target;

static struct target_type *target_types[] = {
&arm7tdmi_target,
@@ -146,6 +147,7 @@ static struct target_type *target_types[] = {
&riscv_target,
&mem_ap_target,
&esirisc_target,
&arcv2_target,
#if BUILD_TARGET64
&aarch64_target,
&mips_mips64_target,


Loading…
Cancel
Save