From: OpenOCD-Gerrit <ope...@us...> - 2020-06-27 14:35:14
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via 64733434e23d42bfd75932c1e71c39800a5c01e4 (commit) via 057aed11a2f80645322ff76c7dd0c7908582d0a4 (commit) from 2e6904eef5e81e71453168ed8c6f649e3a5c0f6c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 64733434e23d42bfd75932c1e71c39800a5c01e4 Author: Moritz Fischer <mo...@go...> Date: Sat Feb 8 16:09:04 2020 -0800 jtag: drivers: xlnx-pcie-xvc: Add support for SWD mode. Add support for SWD debug to the Xilinx XVC/PCIe driver. This is possible since the device is essentially a shift-register. So doing SWD vs JTAG is a matter of wiring things correctly on the RTL side (use TMS for SWDI, TDO for SWDO). The clang static checker doesn't find any new problems with this change. Change-Id: I3959e21440cd1036769e8e56a55e601d3e4aee9a Signed-off-by: Moritz Fischer <mo...@go...> Reviewed-on: http://openocd.zylin.com/5447 Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 1ddf09ffa..a0ce7e349 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -610,7 +610,7 @@ produced, PDF schematics are easily found and it is easy to make. @* Link: @url{http://github.com/fjullien/jtag_vpi} @item @b{xlnx_pcie_xvc} -@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG interface. +@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. @end itemize @@ -3149,7 +3149,7 @@ version). @deffn {Interface Driver} {xlnx_pcie_xvc} This driver supports the Xilinx Virtual Cable (XVC) over PCI Express. It is commonly found in Xilinx based PCI Express designs. It allows debugging -fabric based JTAG devices such as Cortex-M1/M3 microcontrollers. Access to this is +fabric based JTAG/SWD devices such as Cortex-M1/M3 microcontrollers. Access to this is exposed via extended capability registers in the PCI Express configuration space. For more information see Xilinx PG245 (Section on From_PCIE_to_JTAG mode). diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 17438593a..704c1d96b 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -37,6 +37,9 @@ #define XLNX_XVC_VSEC_ID 0x8 #define XLNX_XVC_MAX_BITS 0x20 +#define MASK_ACK(x) (((x) >> 9) & 0x7) +#define MASK_PAR(x) ((int)((x) & 0x1)) + struct xlnx_pcie_xvc { int fd; unsigned offset; @@ -471,17 +474,224 @@ static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static struct jtag_interface xlnx_pcie_xvc_interface = { +static struct jtag_interface xlnx_pcie_xvc_jtag_ops = { .execute_queue = &xlnx_pcie_xvc_execute_queue, }; +static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) +{ + size_t left, write; + uint32_t send; + int err; + + left = length; + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + send = buf_get_u32(seq, 0, write); + err = xlnx_pcie_xvc_transact(write, send, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + seq += sizeof(uint32_t); + }; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) +{ + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + return xlnx_pcie_xvc_swd_sequence(swd_seq_line_reset, + swd_seq_line_reset_len); + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + return xlnx_pcie_xvc_swd_sequence(swd_seq_jtag_to_swd, + swd_seq_jtag_to_swd_len); + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + return xlnx_pcie_xvc_swd_sequence(swd_seq_swd_to_jtag, + swd_seq_swd_to_jtag_len); + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int queued_retval; + +static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk); + +static void swd_clear_sticky_errors(void) +{ + xlnx_pcie_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); +} + +static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk) +{ + uint32_t res, ack, rpar; + int err; + + assert(cmd & SWD_CMD_RnW); + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + /* cmd + ack */ + err = xlnx_pcie_xvc_transact(12, cmd, 0, &res); + if (err != ERROR_OK) + goto err_out; + + ack = MASK_ACK(res); + + /* read data */ + err = xlnx_pcie_xvc_transact(32, 0, 0, &res); + if (err != ERROR_OK) + goto err_out; + + /* parity + trn */ + err = xlnx_pcie_xvc_transact(2, 0, 0, &rpar); + if (err != ERROR_OK) + goto err_out; + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? + "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + res); + switch (ack) { + case SWD_ACK_OK: + if (MASK_PAR(rpar) != parity_u32(res)) { + LOG_DEBUG_IO("Wrong parity detected"); + queued_retval = ERROR_FAIL; + return; + } + if (value) + *value = res; + if (cmd & SWD_CMD_APnDP) + err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + queued_retval = err; + return; + case SWD_ACK_WAIT: + LOG_DEBUG_IO("SWD_ACK_WAIT"); + swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG_IO("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + queued_retval = ack; + return; + } +err_out: + queued_retval = err; +} + +static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + uint32_t res, ack; + int err; + + assert(!(cmd & SWD_CMD_RnW)); + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + /* cmd + trn + ack */ + err = xlnx_pcie_xvc_transact(13, cmd, 0, &res); + if (err != ERROR_OK) + goto err_out; + + ack = MASK_ACK(res); + + /* write data */ + err = xlnx_pcie_xvc_transact(32, value, 0, NULL); + if (err != ERROR_OK) + goto err_out; + + /* parity + trn */ + err = xlnx_pcie_xvc_transact(2, parity_u32(value), 0, NULL); + if (err != ERROR_OK) + goto err_out; + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? + "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + value); + + switch (ack) { + case SWD_ACK_OK: + if (cmd & SWD_CMD_APnDP) + err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + queued_retval = err; + return; + case SWD_ACK_WAIT: + LOG_DEBUG_IO("SWD_ACK_WAIT"); + swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG_IO("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + queued_retval = ack; + return; + } + +err_out: + queued_retval = err; +} + +static int xlnx_pcie_xvc_swd_run_queue(void) +{ + int err; + + /* we want at least 8 idle cycles between each transaction */ + err = xlnx_pcie_xvc_transact(8, 0, 0, NULL); + if (err != ERROR_OK) + return err; + + err = queued_retval; + queued_retval = ERROR_OK; + LOG_DEBUG("SWD queue return value: %02x", err); + + return err; +} + +static int xlnx_pcie_xvc_swd_init(void) +{ + return ERROR_OK; +} + +static const struct swd_driver xlnx_pcie_xvc_swd_ops = { + .init = xlnx_pcie_xvc_swd_init, + .switch_seq = xlnx_pcie_xvc_swd_switch_seq, + .read_reg = xlnx_pcie_xvc_swd_read_reg, + .write_reg = xlnx_pcie_xvc_swd_write_reg, + .run = xlnx_pcie_xvc_swd_run_queue, +}; + +static const char * const xlnx_pcie_xvc_transports[] = { "jtag", "swd", NULL }; + struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", - .transports = jtag_only, + .transports = xlnx_pcie_xvc_transports, .commands = xlnx_pcie_xvc_command_handlers, .init = &xlnx_pcie_xvc_init, .quit = &xlnx_pcie_xvc_quit, - .jtag_ops = &xlnx_pcie_xvc_interface, + .jtag_ops = &xlnx_pcie_xvc_jtag_ops, + .swd_ops = &xlnx_pcie_xvc_swd_ops, }; commit 057aed11a2f80645322ff76c7dd0c7908582d0a4 Author: Evgeniy Didin <di...@sy...> Date: Fri May 15 23:04:01 2020 +0300 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 <di...@sy...> Reviewed-on: http://openocd.zylin.com/5688 Reviewed-by: Oleksij Rempel <li...@re...> Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/arc.c b/src/target/arc.c index 6cf0ec7af..e9709f485 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -86,6 +86,26 @@ struct reg *arc_reg_get_by_name(struct reg_cache *first, 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 */ 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; } + /* 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 */ INIT_LIST_HEAD(&arc->reg_data_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$ * will not be flushed/invalidated when required. */ + CHECK_RETVAL(arc_reset_caches_states(target)); CHECK_RETVAL(arc_examine_debug_reason(target)); 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," " 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) { LOG_WARNING("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"); 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; } @@ -1462,8 +1498,8 @@ static int arc_unset_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. - * TODO: Add cache invalidation function */ + /* core instruction cache is now invalid. */ + CHECK_RETVAL(arc_cache_invalidate(target)); 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 */ struct target_type arcv2_target = { diff --git a/src/target/arc.h b/src/target/arc.h index defa3fa97..664141159 100644 --- a/src/target/arc.h +++ b/src/target/arc.h @@ -60,6 +60,24 @@ /* ARC 16bits opcodes */ #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 reg_data_type_bitfield bitfield; char name[REG_TYPE_MAX_NAME_LENGTH]; @@ -109,6 +127,22 @@ struct arc_common { struct reg_cache *core_and_aux_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) */ bool core_aux_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, 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 */ diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index fad8ca947..59e1645d6 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -909,10 +909,60 @@ static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const * 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 ------------------------------------------ */ +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[] = { -{ + { .name = "add-reg-type-flags", .jim_handler = jim_arc_add_reg_type_flags, .mode = COMMAND_CONFIG, @@ -967,6 +1017,13 @@ static const struct command_registration arc_core_command_handlers[] = { .usage = "", .chain = arc_jtag_command_group, }, + { + .name = "cache", + .mode = COMMAND_ANY, + .help = "cache command group", + .usage = "", + .chain = arc_cache_group_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c index e80bfb4e4..866c71fc2 100644 --- a/src/target/arc_mem.c +++ b/src/target/arc_mem.c @@ -41,10 +41,18 @@ static int arc_mem_write_block32(struct target *target, uint32_t addr, /* Check arguments */ 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. */ CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count, (uint32_t *)buf)); + /* Invalidate caches. */ + CHECK_RETVAL(arc_cache_invalidate(target)); + return ERROR_OK; } @@ -64,6 +72,9 @@ static int arc_mem_write_block16(struct target *target, uint32_t addr, /* Check arguments */ 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 * allowe ourselves to write this in a cycle, instead of calling arc_jtag * 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)); } + /* Invalidate caches. */ + CHECK_RETVAL(arc_cache_invalidate(target)); + 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, 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 * allowe ourselves to write this in a cycle, instead of calling arc_jtag * 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)); } + /* Invalidate caches. */ + CHECK_RETVAL(arc_cache_invalidate(target)); + return ERROR_OK; } @@ -205,6 +225,9 @@ static int arc_mem_read_block(struct target *target, target_addr_t addr, assert(!(addr & 3)); 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, arc_mem_is_slow_memory(arc, addr, size, count))); ----------------------------------------------------------------------- Summary of changes: doc/openocd.texi | 4 +- src/jtag/drivers/xlnx-pcie-xvc.c | 216 ++++++++++++++++++++++++++++++++++++++- src/target/arc.c | 214 +++++++++++++++++++++++++++++++++++++- src/target/arc.h | 37 +++++++ src/target/arc_cmd.c | 59 ++++++++++- src/target/arc_mem.c | 23 +++++ 6 files changed, 543 insertions(+), 10 deletions(-) hooks/post-receive -- Main OpenOCD repository |