Skip to content
Snippets Groups Projects
arm11.c 40.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • int arm11_deassert_reset(struct target_s *target)
    {
        FNC_INFO;
    
    #if 0
    
        LOG_DEBUG("target->state: %s", target_state_strings[target->state]);
    
    
        /* deassert reset lines */
        jtag_add_reset(0, 0);
    
        arm11_common_t * arm11 = target->arch_info;
        arm11->trst_active = false;
    
        if (arm11->halt_requested)
    	return arm11_halt(target);
    #endif
    
        return ERROR_OK;
    }
    
    int arm11_soft_reset_halt(struct target_s *target)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    
    
    /* target register access for gdb */
    int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size)
    {
        FNC_INFO;
    
        arm11_common_t * arm11 = target->arch_info;
    
        *reg_list_size  = ARM11_GDB_REGISTER_COUNT;
        *reg_list	    = malloc(sizeof(reg_t*) * ARM11_GDB_REGISTER_COUNT);
    
        {size_t i;
        for (i = 16; i < 24; i++)
        {
    	(*reg_list)[i] = &arm11_gdb_dummy_fp_reg;
        }}
    
        (*reg_list)[24] = &arm11_gdb_dummy_fps_reg;
    
    
        {size_t i;
        for (i = 0; i < ARM11_REGCACHE_COUNT; i++)
        {
    	if (arm11_reg_defs[i].gdb_num == -1)
    	    continue;
    
    	(*reg_list)[arm11_reg_defs[i].gdb_num] = arm11->reg_list + i;
        }}
    
        return ERROR_OK;
    }
    
    
    /* target memory access 
    * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
    * count: number of items of <size>
    */
    int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
    {
        /** \todo TODO: check if buffer cast to u32* and u16* might cause alignment problems */
    
        FNC_INFO;
    
    
        if (target->state != TARGET_HALTED)
        {
    
    	LOG_WARNING("target was not halted");
    
        LOG_DEBUG("ADDR %08x  SIZE %08x  COUNT %08x", address, size, count);
    
    
        arm11_common_t * arm11 = target->arch_info;
    
        arm11_run_instr_data_prepare(arm11);
    
        /* MRC p14,0,r0,c0,c5,0 */
        arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
    
        switch (size)
        {
        case 1:
    	/** \todo TODO: check if dirty is the right choice to force a rewrite on arm11_resume() */
    	arm11->reg_list[ARM11_RC_R1].dirty = 1;
    
    
    oharboe's avatar
    oharboe committed
    	{size_t i;
    	for (i = 0; i < count; i++)
    
    	{
    	    /* ldrb    r1, [r0], #1 */
    	    arm11_run_instr_no_data1(arm11, 0xe4d01001);
    
    	    u32 res;
    	    /* MCR p14,0,R1,c0,c5,0 */
    	    arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1);
    
    	    *buffer++ = res;
    
    oharboe's avatar
    oharboe committed
    	}}
    
    
    	break;
    
        case 2:
        {
    	arm11->reg_list[ARM11_RC_R1].dirty = 1;
    
    	u16 * buf16 = (u16*)buffer;
    
    
    oharboe's avatar
    oharboe committed
    	{size_t i;
    	for (i = 0; i < count; i++)
    
    	{
    	    /* ldrh    r1, [r0], #2 */
    	    arm11_run_instr_no_data1(arm11, 0xe0d010b2);
    
    	    u32 res;
    
    	    /* MCR p14,0,R1,c0,c5,0 */
    	    arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1);
    
    	    *buf16++ = res;
    
    oharboe's avatar
    oharboe committed
    	}}
    
    
    	break;
        }
    
        case 4:
    
    	/* LDC p14,c5,[R0],#4 */
    	arm11_run_instr_data_from_core(arm11, 0xecb05e01, (u32 *)buffer, count);
    	break;
        }
    
        arm11_run_instr_data_finish(arm11);
    
        return ERROR_OK;
    }
    
    int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer)
    {
        FNC_INFO;
    
    
        if (target->state != TARGET_HALTED)
        {
    
    	LOG_WARNING("target was not halted");
    
        LOG_DEBUG("ADDR %08x  SIZE %08x  COUNT %08x", address, size, count);
    
    
        arm11_common_t * arm11 = target->arch_info;
    
        arm11_run_instr_data_prepare(arm11);
    
        /* MRC p14,0,r0,c0,c5,0 */
        arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
    
        switch (size)
        {
        case 1:
    
    oharboe's avatar
    oharboe committed
        {
    
    	arm11->reg_list[ARM11_RC_R1].dirty = 1;
    
    
    oharboe's avatar
    oharboe committed
    	{size_t i;
    	for (i = 0; i < count; i++)
    
    	{
    	    /* MRC p14,0,r1,c0,c5,0 */
    	    arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++);
    
    	    /* strb    r1, [r0], #1 */
    	    arm11_run_instr_no_data1(arm11, 0xe4c01001);
    
    oharboe's avatar
    oharboe committed
    	}}
    
    
    oharboe's avatar
    oharboe committed
        }
    
    
        case 2:
        {
    	arm11->reg_list[ARM11_RC_R1].dirty = 1;
    
    	u16 * buf16 = (u16*)buffer;
    
    
    oharboe's avatar
    oharboe committed
    	{size_t i;
    	for (i = 0; i < count; i++)
    
    	{
    	    /* MRC p14,0,r1,c0,c5,0 */
    	    arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buf16++);
    
    	    /* strh    r1, [r0], #2 */
    	    arm11_run_instr_no_data1(arm11, 0xe0c010b2);
    
    oharboe's avatar
    oharboe committed
    	}}
    
    
    	break;
        }
    
        case 4:
    	/** \todo TODO: check if buffer cast to u32* might cause alignment problems */
    
    
    oharboe's avatar
    oharboe committed
    	if (!arm11_config_memwrite_burst)
    	{
    	    /* STC p14,c5,[R0],#4 */
    	    arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count);
    	}
    	else
    	{
    	    /* STC p14,c5,[R0],#4 */
    	    arm11_run_instr_data_to_core_noack(arm11, 0xeca05e01, (u32 *)buffer, count);
    	}
    
    
    oharboe's avatar
    oharboe committed
    #if 1
        /* r0 verification */
        {
    	u32 r0;
    
    	/* MCR p14,0,R0,c0,c5,0 */
    	arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1);
    
    	if (address + size * count != r0)
    	{
    
    	    LOG_ERROR("Data transfer failed. (%d)", (r0 - address) - size * count);
    
    oharboe's avatar
    oharboe committed
    
    	    if (arm11_config_memwrite_burst)
    
    		LOG_ERROR("use 'arm11 memwrite burst disable' to disable fast burst mode");
    
    oharboe's avatar
    oharboe committed
    
    	    if (arm11_config_memwrite_error_fatal)
    		exit(-1);
    	}
        }
    #endif
    
    
    
        arm11_run_instr_data_finish(arm11);
    
    
        return ERROR_OK;
    }
    
    
    /* write target memory in multiples of 4 byte, optimized for writing large quantities of data */
    int arm11_bulk_write_memory(struct target_s *target, u32 address, u32 count, u8 *buffer)
    {
        FNC_INFO;
    
    
        if (target->state != TARGET_HALTED)
        {
    
    	LOG_WARNING("target was not halted");
    
        return arm11_write_memory(target, address, 4, count, buffer);
    }
    
    
    int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    
    /* target break-/watchpoint control 
    * rw: 0 = write, 1 = read, 2 = access
    */
    int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
    {
    
    oharboe's avatar
    oharboe committed
        FNC_INFO;
    
        arm11_common_t * arm11 = target->arch_info;
    
    #if 0
        if (breakpoint->type == BKPT_SOFT)
        {
    
    	LOG_INFO("sw breakpoint requested, but software breakpoints not enabled");
    
    oharboe's avatar
    oharboe committed
    	return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
    #endif
    
        if (!arm11->free_brps)
        {
    
    	LOG_INFO("no breakpoint unit available for hardware breakpoint");
    
    oharboe's avatar
    oharboe committed
    	return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
    
        if (breakpoint->length != 4)
        {
    
    	LOG_INFO("only breakpoints of four bytes length supported");
    
    oharboe's avatar
    oharboe committed
    	return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
    
        arm11->free_brps--;
    
    
        return ERROR_OK;
    }
    
    int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint)
    {
    
    oharboe's avatar
    oharboe committed
        FNC_INFO;
    
        arm11_common_t * arm11 = target->arch_info;
    	
        arm11->free_brps++;
    
    
        return ERROR_OK;
    }
    
    int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    
    /* target algorithm support */
    int arm11_run_algorithm(struct target_s *target, int num_mem_params, mem_param_t *mem_params, int num_reg_params, reg_param_t *reg_param, u32 entry_point, u32 exit_point, int timeout_ms, void *arch_info)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target)
    {
        FNC_INFO;
    
        if (argc < 4)
        {
    
    	LOG_ERROR("'target arm11' 4th argument <jtag chain pos>");
    
    	exit(-1);
        }
    
        int chain_pos = strtoul(args[3], NULL, 0);
    
        NEW(arm11_common_t, arm11, 1);
    
        arm11->target = target;
    
        /* prepare JTAG information for the new target */
        arm11->jtag_info.chain_pos	= chain_pos;
        arm11->jtag_info.scann_size	= 5;
    
        arm_jtag_setup_connection(&arm11->jtag_info);
    
        jtag_device_t *device = jtag_get_device(chain_pos);
    
        if (device->ir_length != 5)
        {
    
    	LOG_ERROR("'target arm11' expects 'jtag_device 5 0x01 0x1F 0x1E'");
    
    	exit(-1);
        }
    
        target->arch_info = arm11;
    
        return ERROR_OK;
    }
    
    int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target)
    
    {
    	/* Initialize anything we can set up without talking to the target */
    	return ERROR_OK;
    }
    
    /* talk to the target and set things up */
    int arm11_examine(struct command_context_s *cmd_ctx, struct target_s *target)
    
    {
        FNC_INFO;
    
        arm11_common_t * arm11 = target->arch_info;
    
        /* check IDCODE */
    
        arm11_add_IR(arm11, ARM11_IDCODE, -1);
    
        scan_field_t		idcode_field;
    
        arm11_setup_field(arm11, 32, NULL, &arm11->device_id, &idcode_field);
    
    
    oharboe's avatar
    oharboe committed
        arm11_add_dr_scan_vc(1, &idcode_field, TAP_PD);
    
    
        /* check DIDR */
    
        arm11_add_debug_SCAN_N(arm11, 0x00, -1);
    
        arm11_add_IR(arm11, ARM11_INTEST, -1);
    
        scan_field_t		chain0_fields[2];
    
        arm11_setup_field(arm11, 32, NULL,	&arm11->didr,		chain0_fields + 0);
        arm11_setup_field(arm11,  8, NULL,	&arm11->implementor,	chain0_fields + 1);
    
    
    oharboe's avatar
    oharboe committed
        arm11_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI);
    
    
        jtag_execute_queue();
    
    
        switch (arm11->device_id & 0x0FFFF000)
        {
    
        case 0x07B36000:	LOG_INFO("found ARM1136"); break;
        case 0x07B56000:	LOG_INFO("found ARM1156"); break;
        case 0x07B76000:	LOG_INFO("found ARM1176"); break;
    
    	LOG_ERROR("'target arm11' expects IDCODE 0x*7B*7****");
    
    oharboe's avatar
    oharboe committed
        arm11->debug_version = (arm11->didr >> 16) & 0x0F;
    
        if (arm11->debug_version != ARM11_DEBUG_V6 &&
    	arm11->debug_version != ARM11_DEBUG_V61)
        {
    
    	LOG_ERROR("Only ARMv6 v6 and v6.1 architectures supported.");
    
    oharboe's avatar
    oharboe committed
    	exit(-1);
        }
    
    
    
        arm11->brp	= ((arm11->didr >> 24) & 0x0F) + 1;
        arm11->wrp	= ((arm11->didr >> 28) & 0x0F) + 1;
    
    
    oharboe's avatar
    oharboe committed
        /** \todo TODO: reserve one brp slot if we allow breakpoints during step */
        arm11->free_brps = arm11->brp;
        arm11->free_wrps = arm11->wrp;
    
        LOG_DEBUG("IDCODE %08x IMPLEMENTOR %02x DIDR %08x",
    
    	arm11->device_id,
    	arm11->implementor,
    	arm11->didr);
    
        arm11_build_reg_cache(target);
    
    
        /* as a side-effect this reads DSCR and thus
         * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag
         * as suggested by the spec.
         */
    
        arm11_check_init(arm11, NULL);
    
        return ERROR_OK;
    }
    
    int arm11_quit(void)
    {
        FNC_INFO_NOTIMPLEMENTED;
    
        return ERROR_OK;
    }
    
    /** Load a register that is marked !valid in the register cache */
    int arm11_get_reg(reg_t *reg)
    {
        FNC_INFO;
    
        target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target;
    
        if (target->state != TARGET_HALTED)
        {
    
    	LOG_WARNING("target was not halted");
    
    	return ERROR_TARGET_NOT_HALTED;
        }
    
    
    oharboe's avatar
    oharboe committed
        /** \todo TODO: Check this. We assume that all registers are fetched at debug entry. */
    
    
    #if 0
        arm11_common_t *arm11 = target->arch_info;
        const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index;
    #endif
    
        return ERROR_OK;
    }
    
    /** Change a value in the register cache */
    int arm11_set_reg(reg_t *reg, u8 *buf)
    {
        FNC_INFO;
    
        target_t * target = ((arm11_reg_state_t *)reg->arch_info)->target;
        arm11_common_t *arm11 = target->arch_info;
    
    oharboe's avatar
    oharboe committed
    //    const arm11_reg_defs_t * arm11_reg_info = arm11_reg_defs + ((arm11_reg_state_t *)reg->arch_info)->def_index;
    
    
        arm11->reg_values[((arm11_reg_state_t *)reg->arch_info)->def_index] = buf_get_u32(buf, 0, 32);
        reg->valid	= 1;
        reg->dirty	= 1;
    
        return ERROR_OK;
    }
    
    
    void arm11_build_reg_cache(target_t *target)
    {
        arm11_common_t *arm11 = target->arch_info;
    
        NEW(reg_cache_t,		cache,			1);
        NEW(reg_t,			reg_list,		ARM11_REGCACHE_COUNT);
        NEW(arm11_reg_state_t,	arm11_reg_states,	ARM11_REGCACHE_COUNT);
    
        if (arm11_regs_arch_type == -1)
    	arm11_regs_arch_type = register_reg_arch_type(arm11_get_reg, arm11_set_reg);
    
        arm11->reg_list	= reg_list;
    
        /* Build the process context cache */ 
        cache->name		= "arm11 registers";
        cache->next		= NULL;
        cache->reg_list	= reg_list;
        cache->num_regs	= ARM11_REGCACHE_COUNT;
    
        reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache);
        (*cache_p) = cache;
    
    
    oharboe's avatar
    oharboe committed
    //    armv7m->core_cache = cache;
    //    armv7m->process_context = cache;
    
    
        size_t i;
    
        /* Not very elegant assertion */
        if (ARM11_REGCACHE_COUNT != asizeof(arm11->reg_values) ||
    	ARM11_REGCACHE_COUNT != asizeof(arm11_reg_defs) ||
    	ARM11_REGCACHE_COUNT != ARM11_RC_MAX)
        {
    
    	LOG_ERROR("arm11->reg_values inconsistent (%d " ZU " " ZU " %d)", ARM11_REGCACHE_COUNT, asizeof(arm11->reg_values), asizeof(arm11_reg_defs), ARM11_RC_MAX);
    
    	exit(-1);
        }
    
        for (i = 0; i < ARM11_REGCACHE_COUNT; i++)
        {
    	reg_t *				r	= reg_list		+ i;
    	const arm11_reg_defs_t *	rd	= arm11_reg_defs	+ i;
    	arm11_reg_state_t *		rs	= arm11_reg_states	+ i;
    
    	r->name			= rd->name;
    	r->size			= 32;
    	r->value		= (u8 *)(arm11->reg_values + i);
    	r->dirty		= 0;
    	r->valid		= 0;
    	r->bitfield_desc	= NULL;
    	r->num_bitfields	= 0;
    	r->arch_type		= arm11_regs_arch_type;
    	r->arch_info		= rs;
    
    	rs->def_index		= i;
    	rs->target		= target;
        }
    }
    
    
    
    
    oharboe's avatar
    oharboe committed
    int arm11_handle_bool(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, bool * var, char * name)
    
    oharboe's avatar
    oharboe committed
    {
        if (argc == 0)
        {
    
    	LOG_INFO("%s is %s.", name, *var ? "enabled" : "disabled");
    
    oharboe's avatar
    oharboe committed
    	return ERROR_OK;
        }
    
        if (argc != 1)
    	return ERROR_COMMAND_SYNTAX_ERROR;
    
        switch (args[0][0])
        {
        case '0':	/* 0 */
        case 'f':	/* false */
        case 'F':
        case 'd':	/* disable */
        case 'D':
    
    oharboe's avatar
    oharboe committed
    	*var = false;
    
    oharboe's avatar
    oharboe committed
    	break;
    
        case '1':	/* 1 */
        case 't':	/* true */
        case 'T':
        case 'e':	/* enable */
        case 'E':
    
    oharboe's avatar
    oharboe committed
    	*var = true;
    
    oharboe's avatar
    oharboe committed
    	break;
        }
    
    
        LOG_INFO("%s %s.", *var ? "Enabled" : "Disabled", name);
    
    oharboe's avatar
    oharboe committed
    
        return ERROR_OK;
    }
    
    
    #define BOOL_WRAPPER(name, print_name)  \
    int arm11_handle_bool_##name(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) \
    { \
        return arm11_handle_bool(cmd_ctx, cmd, args, argc, &arm11_config_##name, print_name); \
    }
    
    #define RC_TOP(name, descr, more)  \
    { \
        command_t * new_cmd = register_command(cmd_ctx, top_cmd, name, NULL, COMMAND_ANY, descr);  \
        command_t * top_cmd = new_cmd; \
        more \
    }
    
    oharboe's avatar
    oharboe committed
    #define RC_FINAL(name, descr, handler)  \
        register_command(cmd_ctx, top_cmd, name, handler, COMMAND_ANY, descr);
    
    oharboe's avatar
    oharboe committed
    #define RC_FINAL_BOOL(name, descr, var)  \
        register_command(cmd_ctx, top_cmd, name, arm11_handle_bool_##var, COMMAND_ANY, descr);
    
    
    BOOL_WRAPPER(memwrite_burst,		"memory write burst mode")
    BOOL_WRAPPER(memwrite_error_fatal,	"fatal error mode for memory writes")
    
    
    int arm11_handle_vcr(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
    {
        if (argc == 1)
        {
    	arm11_vcr = strtoul(args[0], NULL, 0);
        }
        else if (argc != 0)
        {
    	return ERROR_COMMAND_SYNTAX_ERROR;
        }
    
    
        LOG_INFO("VCR 0x%08X", arm11_vcr);
    
    oharboe's avatar
    oharboe committed
        return ERROR_OK;
    }
    
    
    const u32 arm11_coproc_instruction_limits[] =
    {
        15,			/* coprocessor */
        7,			/* opcode 1 */
        15,			/* CRn */
        15,			/* CRm */
        7,			/* opcode 2 */
        0xFFFFFFFF,		/* value */
    };
    
    const char arm11_mrc_syntax[] = "Syntax: mrc <jtag_target> <coprocessor> <opcode 1> <CRn> <CRm> <opcode 2>. All parameters are numbers only.";
    const char arm11_mcr_syntax[] = "Syntax: mcr <jtag_target> <coprocessor> <opcode 1> <CRn> <CRm> <opcode 2> <32bit value to write>. All parameters are numbers only.";
    
    
    arm11_common_t * arm11_find_target(const char * arg)
    {
        size_t jtag_target		= strtoul(arg, NULL, 0);
    
        {target_t * t;
        for (t = targets; t; t = t->next)
        {
    	if (t->type != &arm11_target)
    	    continue;
    
    	arm11_common_t * arm11 = t->arch_info;
    
    	if (arm11->jtag_info.chain_pos != jtag_target)
    	    continue;
    
    	return arm11;
        }}
    
        return 0;
    }
    
    int arm11_handle_mrc_mcr(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, bool read)
    {
        if (argc != (read ? 6 : 7))
        {
    
    	LOG_ERROR("Invalid number of arguments. %s", read ? arm11_mrc_syntax : arm11_mcr_syntax);
    
    	return -1;
        }
    
        arm11_common_t * arm11 = arm11_find_target(args[0]);
    
        if (!arm11)
        {
    
    	LOG_ERROR("Parameter 1 is not a the JTAG chain position of an ARM11 device. %s",
    
    		read ? arm11_mrc_syntax : arm11_mcr_syntax);
    
    	return -1;
    
        }
    
        if (arm11->target->state != TARGET_HALTED)
        {
    
    	LOG_WARNING("target was not halted");
    
    	return ERROR_TARGET_NOT_HALTED;
        }
    
    	
        u32	values[6];
    
        {size_t i;
        for (i = 0; i < (read ? 5 : 6); i++)
        {
    	values[i] = strtoul(args[i + 1], NULL, 0);
    
    	if (values[i] > arm11_coproc_instruction_limits[i])
    	{
    
    oharboe's avatar
     
    oharboe committed
    	    LOG_ERROR("Parameter %ld out of bounds (%d max). %s",
    
    		i + 2, arm11_coproc_instruction_limits[i],
    		read ? arm11_mrc_syntax : arm11_mcr_syntax);
    	    return -1;
    	}
        }}
    
        u32 instr = 0xEE000010  |
    	(values[0] <<  8) |
    	(values[1] << 21) |
    	(values[2] << 16) |
    	(values[3] <<  0) |
    	(values[4] <<  5);
    
        if (read)
    	instr |= 0x00100000;
    
    
        arm11_run_instr_data_prepare(arm11);
    
        if (read)
        {    
    	u32 result;	
    	arm11_run_instr_data_from_core_via_r0(arm11, instr, &result);
    
    
    	LOG_INFO("MRC p%d, %d, R0, c%d, c%d, %d = 0x%08x (%d)",
    
    	    values[0], values[1], values[2], values[3], values[4], result, result);
        }
        else
        {
    	arm11_run_instr_data_to_core_via_r0(arm11, instr, values[5]);
    
    
    	LOG_INFO("MRC p%d, %d, R0 (#0x%08x), c%d, c%d, %d",
    
    	    values[0], values[1], 
    	    values[5],
    	    values[2], values[3], values[4]);
        }
    
        arm11_run_instr_data_finish(arm11);
    
    
        return ERROR_OK;
    }
    
    int arm11_handle_mrc(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
    {
        return arm11_handle_mrc_mcr(cmd_ctx, cmd, args, argc, true);
    }
    
    int arm11_handle_mcr(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
    {
        return arm11_handle_mrc_mcr(cmd_ctx, cmd, args, argc, false);
    }
    
    oharboe's avatar
    oharboe committed
    
    int arm11_register_commands(struct command_context_s *cmd_ctx)
    {
        FNC_INFO;
    
        command_t * top_cmd = NULL;
    
        RC_TOP(			"arm11",	"arm11 specific commands",
    
    	RC_TOP(			"memwrite",	"Control memory write transfer mode",
    
    	    RC_FINAL_BOOL(	"burst",	"Enable/Disable non-standard but fast burst mode (default: enabled)",
    						memwrite_burst)
    
    	    RC_FINAL_BOOL(	"error_fatal",
    						"Terminate program if transfer error was found (default: enabled)",
    						memwrite_error_fatal)
    	)
    
    	RC_FINAL(		"vcr",		"Control (Interrupt) Vector Catch Register",
    						arm11_handle_vcr)
    
    
    	RC_FINAL(		"mrc",		"Read Coprocessor register",
    						arm11_handle_mrc)
    
    	RC_FINAL(		"mcr",		"Write Coprocessor register",
    						arm11_handle_mcr)
    
    oharboe's avatar
    oharboe committed
        )
    
        return ERROR_OK;
    }