+COMMAND_HANDLER(handle_armv4_5_mcrrmrrc)
+{
+ bool is_mcrr = false;
+ unsigned int arg_cnt = 3;
+
+ if (!strcmp(CMD_NAME, "mcrr")) {
+ is_mcrr = true;
+ arg_cnt = 4;
+ }
+
+ if (arg_cnt != CMD_ARGC)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target) {
+ command_print(CMD, "no current target");
+ return ERROR_FAIL;
+ }
+ if (!target_was_examined(target)) {
+ command_print(CMD, "%s: not yet examined", target_name(target));
+ return ERROR_TARGET_NOT_EXAMINED;
+ }
+
+ struct arm *arm = target_to_arm(target);
+ if (!is_arm(arm)) {
+ command_print(CMD, "%s: not an ARM", target_name(target));
+ return ERROR_FAIL;
+ }
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ int cpnum;
+ uint32_t op1;
+ uint32_t crm;
+ uint64_t value;
+
+ /* NOTE: parameter sequence matches ARM instruction set usage:
+ * MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2
+ * MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2
+ * The "rXn" are necessarily omitted; they use Tcl mechanisms.
+ */
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum);
+ if (cpnum & ~0xf) {
+ command_print(CMD, "coprocessor %d out of range", cpnum);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1);
+ if (op1 & ~0xf) {
+ command_print(CMD, "op1 %d out of range", op1);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm);
+ if (crm & ~0xf) {
+ command_print(CMD, "CRm %d out of range", crm);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ /*
+ * FIXME change the call syntax here ... simplest to just pass
+ * the MRC() or MCR() instruction to be executed. That will also
+ * let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit)
+ * if that's ever needed.
+ */
+ if (is_mcrr) {
+ COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value);
+
+ /* NOTE: parameters reordered! */
+ /* ARMV5_T_MCRR(cpnum, op1, crm) */
+ int retval = arm->mcrr(target, cpnum, op1, crm, value);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ value = 0;
+ /* NOTE: parameters reordered! */
+ /* ARMV5_T_MRRC(cpnum, op1, crm) */
+ int retval = arm->mrrc(target, cpnum, op1, crm, &value);
+ if (retval != ERROR_OK)
+ return retval;
+
+ command_print(CMD, "0x%" PRIx64, value);
+ }
+
+ return ERROR_OK;
+}