target/arc: Introduce L1I,L1D,L2 caches support
With this commit we introduce L1 and L2 cache flush and invalidate operations which are necessary for getting/setting actual data during memory r/w operations. We introduce L2 cache support, which is not presented on currently support EMSK board. But L2 is presented on HSDK board, which soon will be introduced. Change-Id: I2fda505a47ecb8833cc9f5ffe24f6a4e22ab6eb0 Signed-off-by: Evgeniy Didin <didin@synopsys.com> Reviewed-on: http://openocd.zylin.com/5688 Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
2e6904eef5
commit
057aed11a2
214
src/target/arc.c
214
src/target/arc.c
|
@ -86,6 +86,26 @@ struct reg *arc_reg_get_by_name(struct reg_cache *first,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset internal states of caches. Must be called when entering debugging.
|
||||||
|
*
|
||||||
|
* @param target Target for which to reset caches states.
|
||||||
|
*/
|
||||||
|
int arc_reset_caches_states(struct target *target)
|
||||||
|
{
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
LOG_DEBUG("Resetting internal variables of caches states");
|
||||||
|
|
||||||
|
/* Reset caches states. */
|
||||||
|
arc->dcache_flushed = false;
|
||||||
|
arc->l2cache_flushed = false;
|
||||||
|
arc->icache_invalidated = false;
|
||||||
|
arc->dcache_invalidated = false;
|
||||||
|
arc->l2cache_invalidated = false;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize arc_common structure, which passes to openocd target instance */
|
/* Initialize arc_common structure, which passes to openocd target instance */
|
||||||
static int arc_init_arch_info(struct target *target, struct arc_common *arc,
|
static int arc_init_arch_info(struct target *target, struct arc_common *arc,
|
||||||
|
@ -102,6 +122,15 @@ static int arc_init_arch_info(struct target *target, struct arc_common *arc,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* On most ARC targets there is a dcache, so we enable its flushing
|
||||||
|
* by default. If there no dcache, there will be no error, just a slight
|
||||||
|
* performance penalty from unnecessary JTAG operations. */
|
||||||
|
arc->has_dcache = true;
|
||||||
|
arc->has_icache = true;
|
||||||
|
/* L2$ is not available in a target by default. */
|
||||||
|
arc->has_l2cache = false;
|
||||||
|
arc_reset_caches_states(target);
|
||||||
|
|
||||||
/* Add standard GDB data types */
|
/* Add standard GDB data types */
|
||||||
INIT_LIST_HEAD(&arc->reg_data_types);
|
INIT_LIST_HEAD(&arc->reg_data_types);
|
||||||
struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types),
|
struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types),
|
||||||
|
@ -900,6 +929,7 @@ static int arc_debug_entry(struct target *target)
|
||||||
|
|
||||||
/* TODO: reset internal indicators of caches states, otherwise D$/I$
|
/* TODO: reset internal indicators of caches states, otherwise D$/I$
|
||||||
* will not be flushed/invalidated when required. */
|
* will not be flushed/invalidated when required. */
|
||||||
|
CHECK_RETVAL(arc_reset_caches_states(target));
|
||||||
CHECK_RETVAL(arc_examine_debug_reason(target));
|
CHECK_RETVAL(arc_examine_debug_reason(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1152,6 +1182,11 @@ static int arc_resume(struct target *target, int current, target_addr_t address,
|
||||||
LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i,"
|
LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i,"
|
||||||
" debug_execution:%i", current, address, handle_breakpoints, debug_execution);
|
" debug_execution:%i", current, address, handle_breakpoints, debug_execution);
|
||||||
|
|
||||||
|
/* We need to reset ARC cache variables so caches
|
||||||
|
* would be invalidated and actual data
|
||||||
|
* would be fetched from memory. */
|
||||||
|
CHECK_RETVAL(arc_reset_caches_states(target));
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_WARNING("target not halted");
|
LOG_WARNING("target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
@ -1396,8 +1431,9 @@ static int arc_set_breakpoint(struct target *target,
|
||||||
LOG_DEBUG("ERROR: setting unknown breakpoint type");
|
LOG_DEBUG("ERROR: setting unknown breakpoint type");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
/* core instruction cache is now invalid,
|
|
||||||
* TODO: add cache invalidation function here (when implemented). */
|
/* core instruction cache is now invalid. */
|
||||||
|
CHECK_RETVAL(arc_cache_invalidate(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1462,8 +1498,8 @@ static int arc_unset_breakpoint(struct target *target,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* core instruction cache is now invalid.
|
/* core instruction cache is now invalid. */
|
||||||
* TODO: Add cache invalidation function */
|
CHECK_RETVAL(arc_cache_invalidate(target));
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -1596,6 +1632,176 @@ int arc_step(struct target *target, int current, target_addr_t address,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function invalidates icache. */
|
||||||
|
static int arc_icache_invalidate(struct target *target)
|
||||||
|
{
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
/* Don't waste time if already done. */
|
||||||
|
if (!arc->has_icache || arc->icache_invalidated)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
LOG_DEBUG("Invalidating I$.");
|
||||||
|
|
||||||
|
value = IC_IVIC_INVALIDATE; /* invalidate I$ */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_IC_IVIC_REG, value));
|
||||||
|
|
||||||
|
arc->icache_invalidated = true;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function invalidates dcache */
|
||||||
|
static int arc_dcache_invalidate(struct target *target)
|
||||||
|
{
|
||||||
|
uint32_t value, dc_ctrl_value;
|
||||||
|
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
if (!arc->has_dcache || arc->dcache_invalidated)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
LOG_DEBUG("Invalidating D$.");
|
||||||
|
|
||||||
|
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &value));
|
||||||
|
dc_ctrl_value = value;
|
||||||
|
value &= ~DC_CTRL_IM;
|
||||||
|
|
||||||
|
/* set DC_CTRL invalidate mode to invalidate-only (no flushing!!) */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value));
|
||||||
|
value = DC_IVDC_INVALIDATE; /* invalidate D$ */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value));
|
||||||
|
|
||||||
|
/* restore DC_CTRL invalidate mode */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value));
|
||||||
|
|
||||||
|
arc->dcache_invalidated = true;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function invalidates l2 cache. */
|
||||||
|
static int arc_l2cache_invalidate(struct target *target)
|
||||||
|
{
|
||||||
|
uint32_t value, slc_ctrl_value;
|
||||||
|
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
if (!arc->has_l2cache || arc->l2cache_invalidated)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
LOG_DEBUG("Invalidating L2$.");
|
||||||
|
|
||||||
|
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value));
|
||||||
|
slc_ctrl_value = value;
|
||||||
|
value &= ~L2_CTRL_IM;
|
||||||
|
|
||||||
|
/* set L2_CTRL invalidate mode to invalidate-only (no flushing!!) */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, value));
|
||||||
|
/* invalidate L2$ */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_INV, L2_INV_IV));
|
||||||
|
|
||||||
|
/* Wait until invalidate operation ends */
|
||||||
|
do {
|
||||||
|
LOG_DEBUG("Waiting for invalidation end.");
|
||||||
|
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value));
|
||||||
|
} while (value & L2_CTRL_BS);
|
||||||
|
|
||||||
|
/* restore L2_CTRL invalidate mode */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, slc_ctrl_value));
|
||||||
|
|
||||||
|
arc->l2cache_invalidated = true;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int arc_cache_invalidate(struct target *target)
|
||||||
|
{
|
||||||
|
CHECK_RETVAL(arc_icache_invalidate(target));
|
||||||
|
CHECK_RETVAL(arc_dcache_invalidate(target));
|
||||||
|
CHECK_RETVAL(arc_l2cache_invalidate(target));
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush data cache. This function is cheap to call and return quickly if D$
|
||||||
|
* already has been flushed since target had been halted. JTAG debugger reads
|
||||||
|
* values directly from memory, bypassing cache, so if there are unflushed
|
||||||
|
* lines debugger will read invalid values, which will cause a lot of troubles.
|
||||||
|
* */
|
||||||
|
int arc_dcache_flush(struct target *target)
|
||||||
|
{
|
||||||
|
uint32_t value, dc_ctrl_value;
|
||||||
|
bool has_to_set_dc_ctrl_im;
|
||||||
|
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
/* Don't waste time if already done. */
|
||||||
|
if (!arc->has_dcache || arc->dcache_flushed)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
LOG_DEBUG("Flushing D$.");
|
||||||
|
|
||||||
|
/* Store current value of DC_CTRL */
|
||||||
|
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &dc_ctrl_value));
|
||||||
|
|
||||||
|
/* Set DC_CTRL invalidate mode to flush (if not already set) */
|
||||||
|
has_to_set_dc_ctrl_im = (dc_ctrl_value & DC_CTRL_IM) == 0;
|
||||||
|
if (has_to_set_dc_ctrl_im) {
|
||||||
|
value = dc_ctrl_value | DC_CTRL_IM;
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush D$ */
|
||||||
|
value = DC_IVDC_INVALIDATE;
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value));
|
||||||
|
|
||||||
|
/* Restore DC_CTRL invalidate mode (even of flush failed) */
|
||||||
|
if (has_to_set_dc_ctrl_im)
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value));
|
||||||
|
|
||||||
|
arc->dcache_flushed = true;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function flushes l2cache. */
|
||||||
|
static int arc_l2cache_flush(struct target *target)
|
||||||
|
{
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
struct arc_common *arc = target_to_arc(target);
|
||||||
|
|
||||||
|
/* Don't waste time if already done. */
|
||||||
|
if (!arc->has_l2cache || arc->l2cache_flushed)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
LOG_DEBUG("Flushing L2$.");
|
||||||
|
|
||||||
|
/* Flush L2 cache */
|
||||||
|
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_FLUSH, L2_FLUSH_FL));
|
||||||
|
|
||||||
|
/* Wait until flush operation ends */
|
||||||
|
do {
|
||||||
|
LOG_DEBUG("Waiting for flushing end.");
|
||||||
|
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value));
|
||||||
|
} while (value & L2_CTRL_BS);
|
||||||
|
|
||||||
|
arc->l2cache_flushed = true;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arc_cache_flush(struct target *target)
|
||||||
|
{
|
||||||
|
CHECK_RETVAL(arc_dcache_flush(target));
|
||||||
|
CHECK_RETVAL(arc_l2cache_flush(target));
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* ARC v2 target */
|
/* ARC v2 target */
|
||||||
struct target_type arcv2_target = {
|
struct target_type arcv2_target = {
|
||||||
|
|
|
@ -60,6 +60,24 @@
|
||||||
/* ARC 16bits opcodes */
|
/* ARC 16bits opcodes */
|
||||||
#define ARC_SDBBP_16 0x7FFF /* BRK_S */
|
#define ARC_SDBBP_16 0x7FFF /* BRK_S */
|
||||||
|
|
||||||
|
/* Cache registers */
|
||||||
|
#define AUX_IC_IVIC_REG 0X10
|
||||||
|
#define IC_IVIC_INVALIDATE 0XFFFFFFFF
|
||||||
|
|
||||||
|
#define AUX_DC_IVDC_REG 0X47
|
||||||
|
#define DC_IVDC_INVALIDATE BIT(0)
|
||||||
|
#define AUX_DC_CTRL_REG 0X48
|
||||||
|
#define DC_CTRL_IM BIT(6)
|
||||||
|
|
||||||
|
/* L2 cache registers */
|
||||||
|
#define SLC_AUX_CACHE_CTRL 0x903
|
||||||
|
#define L2_CTRL_IM BIT(6)
|
||||||
|
#define L2_CTRL_BS BIT(8) /* Busy flag */
|
||||||
|
#define SLC_AUX_CACHE_FLUSH 0x904
|
||||||
|
#define L2_FLUSH_FL BIT(0)
|
||||||
|
#define SLC_AUX_CACHE_INV 0x905
|
||||||
|
#define L2_INV_IV BIT(0)
|
||||||
|
|
||||||
struct arc_reg_bitfield {
|
struct arc_reg_bitfield {
|
||||||
struct reg_data_type_bitfield bitfield;
|
struct reg_data_type_bitfield bitfield;
|
||||||
char name[REG_TYPE_MAX_NAME_LENGTH];
|
char name[REG_TYPE_MAX_NAME_LENGTH];
|
||||||
|
@ -109,6 +127,22 @@ struct arc_common {
|
||||||
struct reg_cache *core_and_aux_cache;
|
struct reg_cache *core_and_aux_cache;
|
||||||
struct reg_cache *bcr_cache;
|
struct reg_cache *bcr_cache;
|
||||||
|
|
||||||
|
/* Cache control */
|
||||||
|
bool has_dcache;
|
||||||
|
bool has_icache;
|
||||||
|
bool has_l2cache;
|
||||||
|
/* If true, then D$ has been already flushed since core has been
|
||||||
|
* halted. */
|
||||||
|
bool dcache_flushed;
|
||||||
|
/* If true, then L2 has been already flushed since core has been
|
||||||
|
* halted. */
|
||||||
|
bool l2cache_flushed;
|
||||||
|
/* If true, then caches have been already flushed since core has been
|
||||||
|
* halted. */
|
||||||
|
bool icache_invalidated;
|
||||||
|
bool dcache_invalidated;
|
||||||
|
bool l2cache_invalidated;
|
||||||
|
|
||||||
/* Indicate if cach was built (for deinit function) */
|
/* Indicate if cach was built (for deinit function) */
|
||||||
bool core_aux_cache_built;
|
bool core_aux_cache_built;
|
||||||
bool bcr_cache_built;
|
bool bcr_cache_built;
|
||||||
|
@ -247,4 +281,7 @@ struct reg *arc_reg_get_by_name(struct reg_cache *first,
|
||||||
int arc_reg_get_field(struct target *target, const char *reg_name,
|
int arc_reg_get_field(struct target *target, const char *reg_name,
|
||||||
const char *field_name, uint32_t *value_ptr);
|
const char *field_name, uint32_t *value_ptr);
|
||||||
|
|
||||||
|
int arc_cache_flush(struct target *target);
|
||||||
|
int arc_cache_invalidate(struct target *target);
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_ARC_H */
|
#endif /* OPENOCD_TARGET_ARC_H */
|
||||||
|
|
|
@ -909,10 +909,60 @@ static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(arc_l1_cache_disable_auto_cmd)
|
||||||
|
{
|
||||||
|
bool value;
|
||||||
|
int retval = 0;
|
||||||
|
struct arc_common *arc = target_to_arc(get_current_target(CMD_CTX));
|
||||||
|
retval = CALL_COMMAND_HANDLER(handle_command_parse_bool,
|
||||||
|
&value, "target has caches enabled");
|
||||||
|
arc->has_l2cache = value;
|
||||||
|
arc->has_dcache = value;
|
||||||
|
arc->has_icache = value;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(arc_l2_cache_disable_auto_cmd)
|
||||||
|
{
|
||||||
|
struct arc_common *arc = target_to_arc(get_current_target(CMD_CTX));
|
||||||
|
return CALL_COMMAND_HANDLER(handle_command_parse_bool,
|
||||||
|
&arc->has_l2cache, "target has l2 cache enabled");
|
||||||
|
}
|
||||||
|
|
||||||
/* ----- Exported target commands ------------------------------------------ */
|
/* ----- Exported target commands ------------------------------------------ */
|
||||||
|
|
||||||
|
const struct command_registration arc_l2_cache_group_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "auto",
|
||||||
|
.handler = arc_l2_cache_disable_auto_cmd,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "(1|0)",
|
||||||
|
.help = "Disable or enable L2",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct command_registration arc_cache_group_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "auto",
|
||||||
|
.handler = arc_l1_cache_disable_auto_cmd,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "Disable or enable L1",
|
||||||
|
.usage = "(1|0)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "l2",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "L2 cache command group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = arc_l2_cache_group_handlers,
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static const struct command_registration arc_core_command_handlers[] = {
|
static const struct command_registration arc_core_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "add-reg-type-flags",
|
.name = "add-reg-type-flags",
|
||||||
.jim_handler = jim_arc_add_reg_type_flags,
|
.jim_handler = jim_arc_add_reg_type_flags,
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
|
@ -967,6 +1017,13 @@ static const struct command_registration arc_core_command_handlers[] = {
|
||||||
.usage = "",
|
.usage = "",
|
||||||
.chain = arc_jtag_command_group,
|
.chain = arc_jtag_command_group,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "cache",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "cache command group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = arc_cache_group_handlers,
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,18 @@ static int arc_mem_write_block32(struct target *target, uint32_t addr,
|
||||||
/* Check arguments */
|
/* Check arguments */
|
||||||
assert(!(addr & 3));
|
assert(!(addr & 3));
|
||||||
|
|
||||||
|
/* We need to flush the cache since it might contain dirty
|
||||||
|
* lines, so the cache invalidation may cause data inconsistency. */
|
||||||
|
CHECK_RETVAL(arc_cache_flush(target));
|
||||||
|
|
||||||
|
|
||||||
/* No need to flush cache, because we don't read values from memory. */
|
/* No need to flush cache, because we don't read values from memory. */
|
||||||
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
|
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
|
||||||
(uint32_t *)buf));
|
(uint32_t *)buf));
|
||||||
|
|
||||||
|
/* Invalidate caches. */
|
||||||
|
CHECK_RETVAL(arc_cache_invalidate(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +72,9 @@ static int arc_mem_write_block16(struct target *target, uint32_t addr,
|
||||||
/* Check arguments */
|
/* Check arguments */
|
||||||
assert(!(addr & 1));
|
assert(!(addr & 1));
|
||||||
|
|
||||||
|
/* We will read data from memory, so we need to flush the cache. */
|
||||||
|
CHECK_RETVAL(arc_cache_flush(target));
|
||||||
|
|
||||||
/* non-word writes are less common, than 4-byte writes, so I suppose we can
|
/* 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
|
* allowe ourselves to write this in a cycle, instead of calling arc_jtag
|
||||||
* with count > 1. */
|
* with count > 1. */
|
||||||
|
@ -97,6 +108,9 @@ static int arc_mem_write_block16(struct target *target, uint32_t addr,
|
||||||
(addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
|
(addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Invalidate caches. */
|
||||||
|
CHECK_RETVAL(arc_cache_invalidate(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +127,9 @@ static int arc_mem_write_block8(struct target *target, uint32_t addr,
|
||||||
LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
|
LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
|
||||||
addr, count);
|
addr, count);
|
||||||
|
|
||||||
|
/* We will read data from memory, so we need to flush the cache. */
|
||||||
|
CHECK_RETVAL(arc_cache_flush(target));
|
||||||
|
|
||||||
/* non-word writes are less common, than 4-byte writes, so I suppose we can
|
/* 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
|
* allowe ourselves to write this in a cycle, instead of calling arc_jtag
|
||||||
* with count > 1. */
|
* with count > 1. */
|
||||||
|
@ -128,6 +145,9 @@ static int arc_mem_write_block8(struct target *target, uint32_t addr,
|
||||||
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
|
CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Invalidate caches. */
|
||||||
|
CHECK_RETVAL(arc_cache_invalidate(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +225,9 @@ static int arc_mem_read_block(struct target *target, target_addr_t addr,
|
||||||
assert(!(addr & 3));
|
assert(!(addr & 3));
|
||||||
assert(size == 4);
|
assert(size == 4);
|
||||||
|
|
||||||
|
/* Flush cache before memory access */
|
||||||
|
CHECK_RETVAL(arc_cache_flush(target));
|
||||||
|
|
||||||
CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
|
CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
|
||||||
arc_mem_is_slow_memory(arc, addr, size, count)));
|
arc_mem_is_slow_memory(arc, addr, size, count)));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue