This is an automated email from Gerrit. "Daniel Goehring <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9253
-- gerrit commit 42858f6af9dc0bf48d1a7ab3646f8119829c7d1d Author: Daniel Goehring <[email protected]> Date: Tue Aug 5 11:01:26 2025 -0600 target/arm: add nested AP DAP 'apreg_gw' cmd support Create a new DAP 'apreg_gw' command for nested AP support. The abbreviation 'gw' refers to 'gateway', the top-level nested access port. Change-Id: Iaebf0a44cd3394767eefce5ec0e9d280dd3f3500 Signed-off-by: Daniel Goehring <[email protected]> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 77e3202927..9fdf32476f 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -3009,6 +3009,100 @@ COMMAND_HANDLER(dap_apreg_command) return retval; } +COMMAND_HANDLER(dap_apreg_gw_command) +{ + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; + uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; + uint32_t reg, value; + int retval; + + if (CMD_ARGC < 2 || CMD_ARGC > 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], reg); + if (is_adiv6(dap)) { + if (reg >= 4096 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } else { /* ADI version 5 */ + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], value); + /* see if user supplied register address is a match for the CSW or TAR register */ + if (reg == MEM_AP_REG_CSW(dap)) { + ap->csw_value = 0; /* invalid, in case write fails */ + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) + ap->csw_value = value; + } else if (reg == MEM_AP_REG_TAR(dap)) { + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) { + ap->tar_value = (ap->tar_value & ~0xFFFFFFFFull) | value; + } else { + /* To track independent writes to TAR and TAR64, two tar_valid flags */ + /* should be used. To keep it simple, tar_valid is only invalidated on a */ + /* write fail. This approach causes a later re-write of the TAR and TAR64 */ + /* if tar_valid is false. */ + ap->tar_valid = false; + } + } else if (reg == MEM_AP_REG_TAR64(dap)) { + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) { + ap->tar_value = (ap->tar_value & 0xFFFFFFFFull) | (((target_addr_t)value) << 32); + } else { + /* See above comment for the MEM_AP_REG_TAR failed write case */ + ap->tar_valid = false; + } + } else { + retval = dap_queue_ap_write(ap, reg, value); + } + } else { + retval = dap_queue_ap_read(ap, reg, &value); + } + if (retval == ERROR_OK) + retval = dap_run(dap); + + dap_put_ap(ap); + + if (retval != ERROR_OK) + return retval; + + if (CMD_ARGC == 3) + command_print(CMD, "0x%08" PRIx32, value); + + return retval; +} + COMMAND_HANDLER(dap_dpreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); @@ -3093,10 +3187,18 @@ const struct command_registration dap_instance_commands[] = { .name = "apreg", .handler = dap_apreg_command, .mode = COMMAND_EXEC, - .help = "read/write a register from AP " + .help = "read/write a register from a non-nested AP " "(reg is byte address of a word register, like 0 4 8...)", .usage = "ap_num reg [value]", }, + { + .name = "apreg_gw", + .handler = dap_apreg_gw_command, + .mode = COMMAND_EXEC, + .help = "read/write a register from a nested AP " + "(reg is byte address of a word register, like 0 4 8...)", + .usage = "ap_num ap_num_gateway reg [value]", + }, { .name = "dpreg", .handler = dap_dpreg_command, --
