From: oharboe Date: Mon, 25 Feb 2008 08:22:18 +0000 (+0000) Subject: From Michael Bruck X-Git-Tag: v0.1.0~948 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=687a9553c9cc74a7ca3d3ac5f2470b34e7cc623b;p=openocd From Michael Bruck - bugfix in server.c - removed unused parameter from jtag_add_ir_scan et al. This wasn't necessary in hindsight but anyway. - arm11 source committed but not not in Makefile.am/target.c for now. git-svn-id: svn://svn.berlios.de/openocd/trunk@341 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- diff --git a/src/flash/str9xpec.c b/src/flash/str9xpec.c index 4959df9f..9df57dd5 100644 --- a/src/flash/str9xpec.c +++ b/src/flash/str9xpec.c @@ -1,1348 +1,1348 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "str9xpec.h" -#include "flash.h" -#include "target.h" -#include "log.h" -#include "armv4_5.h" -#include "arm7_9_common.h" -#include "jtag.h" -#include "binarybuffer.h" - -#include -#include -#include -#include - -str9xpec_mem_layout_t mem_layout_str9pec[] = { - {0x00000000, 0x10000, 0}, - {0x00010000, 0x10000, 1}, - {0x00020000, 0x10000, 2}, - {0x00030000, 0x10000, 3}, - {0x00040000, 0x10000, 4}, - {0x00050000, 0x10000, 5}, - {0x00060000, 0x10000, 6}, - {0x00070000, 0x10000, 7}, - {0x00080000, 0x02000, 32}, - {0x00082000, 0x02000, 33}, - {0x00084000, 0x02000, 34}, - {0x00086000, 0x02000, 35} -}; - -int str9xpec_register_commands(struct command_context_s *cmd_ctx); -int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank); -int str9xpec_erase(struct flash_bank_s *bank, int first, int last); -int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last); -int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count); -int str9xpec_probe(struct flash_bank_s *bank); -int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_protect_check(struct flash_bank_s *bank); -int str9xpec_erase_check(struct flash_bank_s *bank); -int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size); - -int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last); -int str9xpec_set_address(struct flash_bank_s *bank, u8 sector); -int str9xpec_write_options(struct flash_bank_s *bank); - -int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -flash_driver_t str9xpec_flash = -{ - .name = "str9xpec", - .register_commands = str9xpec_register_commands, - .flash_bank_command = str9xpec_flash_bank_command, - .erase = str9xpec_erase, - .protect = str9xpec_protect, - .write = str9xpec_write, - .probe = str9xpec_probe, - .auto_probe = str9xpec_probe, - .erase_check = str9xpec_erase_check, - .protect_check = str9xpec_protect_check, - .info = str9xpec_info -}; - -int str9xpec_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands"); - - register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC, - "enable str9xpec turbo mode"); - register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC, - "disable str9xpec turbo mode"); - register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC, - "configure str9xpec boot sector"); - register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC, - "configure str9xpec lvd threshold"); - register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC, - "configure str9xpec lvd selection"); - register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC, - "configure str9xpec lvd warning"); - register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC, - "read str9xpec options"); - register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC, - "write str9xpec options"); - register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC, - "lock str9xpec device"); - register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC, - "unlock str9xpec device"); - register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC, - "print part id of str9xpec flash bank "); - - return ERROR_OK; -} - -int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state) -{ - jtag_device_t *device = jtag_get_device(chain_pos); - - if (device == NULL) - { - DEBUG("Invalid Target"); - return ERROR_TARGET_INVALID; - } - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = chain_pos; - field.num_bits = device->ir_length; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_instr); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_ir_scan(1, &field, end_state, NULL); - - free(field.out_value); - } - - return ERROR_OK; -} - -u8 str9xpec_isc_status(int chain_pos) -{ - scan_field_t field; - u8 status; - - if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK) - return ISC_STATUS_ERROR; - - field.device = chain_pos; - field.num_bits = 8; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = &status; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - jtag_execute_queue(); - - DEBUG("status: 0x%2.2x", status); - - if (status & ISC_STATUS_SECURITY) - INFO("Device Security Bit Set"); - - return status; -} - -int str9xpec_isc_enable(struct flash_bank_s *bank) -{ - u8 status; - u32 chain_pos; - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - if (str9xpec_info->isc_enable) - return ERROR_OK; - - /* enter isc mode */ - if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK) - return ERROR_TARGET_INVALID; - - /* check ISC status */ - status = str9xpec_isc_status(chain_pos); - if (status & ISC_STATUS_MODE) - { - /* we have entered isc mode */ - str9xpec_info->isc_enable = 1; - DEBUG("ISC_MODE Enabled"); - } - - return ERROR_OK; -} - -int str9xpec_isc_disable(struct flash_bank_s *bank) -{ - u8 status; - u32 chain_pos; - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - if (!str9xpec_info->isc_enable) - return ERROR_OK; - - if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK) - return ERROR_TARGET_INVALID; - - /* delay to handle aborts */ - jtag_add_sleep(50); - - /* check ISC status */ - status = str9xpec_isc_status(chain_pos); - if (!(status & ISC_STATUS_MODE)) - { - /* we have left isc mode */ - str9xpec_info->isc_enable = 0; - DEBUG("ISC_MODE Disabled"); - } - - return ERROR_OK; -} - -int str9xpec_read_config(struct flash_bank_s *bank) -{ - scan_field_t field; - u8 status; - u32 chain_pos; - - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - DEBUG("ISC_CONFIGURATION"); - - /* execute ISC_CONFIGURATION command */ - str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = str9xpec_info->options; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - jtag_execute_queue(); - - status = str9xpec_isc_status(chain_pos); - - return status; -} - -int str9xpec_build_block_list(struct flash_bank_s *bank) -{ - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - int i; - int num_sectors = 0, b0_sectors = 0; - - switch (bank->size) - { - case (256 * 1024): - b0_sectors = 4; - break; - case (512 * 1024): - b0_sectors = 8; - break; - default: - ERROR("BUG: unknown bank->size encountered"); - exit(-1); - } - - /* include bank 1 sectors */ - num_sectors = b0_sectors + 4; - bank->size += (32 * 1024); - - bank->num_sectors = num_sectors; - bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); - str9xpec_info->sector_bits = malloc(sizeof(u32) * num_sectors); - - num_sectors = 0; - - for (i = 0; i < b0_sectors; i++) - { - bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start; - bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; - bank->sectors[num_sectors].is_erased = -1; - bank->sectors[num_sectors].is_protected = 1; - str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; - } - - for (i = 8; i < 12; i++) - { - bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start; - bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; - bank->sectors[num_sectors].is_erased = -1; - bank->sectors[num_sectors].is_protected = 1; - str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; - } - - return ERROR_OK; -} - -/* flash bank str9x 0 0 - */ -int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank) -{ - str9xpec_flash_controller_t *str9xpec_info; - armv4_5_common_t *armv4_5 = NULL; - arm7_9_common_t *arm7_9 = NULL; - arm_jtag_t *jtag_info = NULL; - - if (argc < 6) - { - WARNING("incomplete flash_bank str9x configuration"); - return ERROR_FLASH_BANK_INVALID; - } - - str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t)); - bank->driver_priv = str9xpec_info; - - if (bank->base != 0x00000000) - { - WARNING("overriding flash base address for STR91x device with 0x00000000"); - bank->base = 0x00000000; - } - - /* find out jtag position of flash controller - * it is always after the arm966 core */ - - armv4_5 = bank->target->arch_info; - arm7_9 = armv4_5->arch_info; - jtag_info = &arm7_9->jtag_info; - - str9xpec_info->chain_pos = (jtag_info->chain_pos - 1); - str9xpec_info->isc_enable = 0; - str9xpec_info->devarm = NULL; - - str9xpec_build_block_list(bank); - - /* clear option byte register */ - buf_set_u32(str9xpec_info->options, 0, 64, 0); - - return ERROR_OK; -} - -int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last) -{ - scan_field_t field; - u8 status; - u32 chain_pos; - int i; - u8 *buffer = NULL; - - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - if (!str9xpec_info->isc_enable) { - str9xpec_isc_enable( bank ); - } - - if (!str9xpec_info->isc_enable) { - return ERROR_FLASH_OPERATION_FAILED; - } - - buffer = calloc(CEIL(64, 8), 1); - - DEBUG("blank check: first_bank: %i, last_bank: %i", first, last); - - for (i = first; i <= last; i++) { - buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); - } - - /* execute ISC_BLANK_CHECK command */ - str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = buffer; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - jtag_add_sleep(40000); - - /* read blank check result */ - field.device = chain_pos; - field.num_bits = 64; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = buffer; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_PI, NULL); - jtag_execute_queue(); - - status = str9xpec_isc_status(chain_pos); - - for (i = first; i <= last; i++) - { - if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1)) - bank->sectors[i].is_erased = 0; - else - bank->sectors[i].is_erased = 1; - } - - free(buffer); - - str9xpec_isc_disable(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - return ERROR_OK; -} - -int str9xpec_protect_check(struct flash_bank_s *bank) -{ - u8 status; - int i; - - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - status = str9xpec_read_config(bank); - - for (i = 0; i < bank->num_sectors; i++) - { - if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1)) - bank->sectors[i].is_protected = 1; - else - bank->sectors[i].is_protected = 0; - } - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - return ERROR_OK; -} - -int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last) -{ - scan_field_t field; - u8 status; - u32 chain_pos; - int i; - u8 *buffer = NULL; - - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - if (!str9xpec_info->isc_enable) { - str9xpec_isc_enable( bank ); - } - - if (!str9xpec_info->isc_enable) { - return ISC_STATUS_ERROR; - } - - buffer = calloc(CEIL(64, 8), 1); - - DEBUG("erase: first_bank: %i, last_bank: %i", first, last); - - /* last bank: 0xFF signals a full erase (unlock complete device) */ - /* last bank: 0xFE signals a option byte erase */ - if (last == 0xFF) - { - for (i = 0; i < 64; i++) { - buf_set_u32(buffer, i, 1, 1); - } - } - else if (last == 0xFE) - { - buf_set_u32(buffer, 49, 1, 1); - } - else - { - for (i = first; i <= last; i++) { - buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); - } - } - - DEBUG("ISC_ERASE"); - - /* execute ISC_ERASE command */ - str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = buffer; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - jtag_execute_queue(); - - jtag_add_sleep(10); - - /* wait for erase completion */ - while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) { - usleep(1000); - } - - free(buffer); - - str9xpec_isc_disable(bank); - - return status; -} - -int str9xpec_erase(struct flash_bank_s *bank, int first, int last) -{ - int status; - - status = str9xpec_erase_area(bank, first, last); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; -} - -int str9xpec_lock_device(struct flash_bank_s *bank) -{ - scan_field_t field; - u8 status; - u32 chain_pos; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - str9xpec_info = bank->driver_priv; - chain_pos = str9xpec_info->chain_pos; - - if (!str9xpec_info->isc_enable) { - str9xpec_isc_enable( bank ); - } - - if (!str9xpec_info->isc_enable) { - return ISC_STATUS_ERROR; - } - - /* set security address */ - str9xpec_set_address(bank, 0x80); - - /* execute ISC_PROGRAM command */ - str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI); - - str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); - - do { - field.device = chain_pos; - field.num_bits = 8; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = &status; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, -1, NULL); - jtag_execute_queue(); - - } while(!(status & ISC_STATUS_BUSY)); - - str9xpec_isc_disable(bank); - - return status; -} - -int str9xpec_unlock_device(struct flash_bank_s *bank) -{ - u8 status; - - status = str9xpec_erase_area(bank, 0, 255); - - return status; -} - -int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last) -{ - u8 status; - int i; - - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - status = str9xpec_read_config(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - DEBUG("protect: first_bank: %i, last_bank: %i", first, last); - - /* last bank: 0xFF signals a full device protect */ - if (last == 0xFF) - { - if( set ) - { - status = str9xpec_lock_device(bank); - } - else - { - /* perform full erase to unlock device */ - status = str9xpec_unlock_device(bank); - } - } - else - { - for (i = first; i <= last; i++) - { - if( set ) - buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1); - else - buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0); - } - - status = str9xpec_write_options(bank); - } - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; -} - -int str9xpec_set_address(struct flash_bank_s *bank, u8 sector) -{ - u32 chain_pos; - scan_field_t field; - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - /* set flash controller address */ - str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI); - - field.device = chain_pos; - field.num_bits = 8; - field.out_value = §or; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, -1, NULL); - - return ERROR_OK; -} - -int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) -{ - str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; - u32 dwords_remaining = (count / 8); - u32 bytes_remaining = (count & 0x00000007); - u32 bytes_written = 0; - u8 status; - u32 check_address = offset; - u32 chain_pos; - scan_field_t field; - u8 *scanbuf; - int i; - u32 first_sector = 0; - u32 last_sector = 0; - - chain_pos = str9xpec_info->chain_pos; - - if (!str9xpec_info->isc_enable) { - str9xpec_isc_enable(bank); - } - - if (!str9xpec_info->isc_enable) { - return ERROR_FLASH_OPERATION_FAILED; - } - - if (offset & 0x7) - { - WARNING("offset 0x%x breaks required 8-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - for (i = 0; i < bank->num_sectors; i++) - { - u32 sec_start = bank->sectors[i].offset; - u32 sec_end = sec_start + bank->sectors[i].size; - - /* check if destination falls within the current sector */ - if ((check_address >= sec_start) && (check_address < sec_end)) - { - /* check if destination ends in the current sector */ - if (offset + count < sec_end) - check_address = offset + count; - else - check_address = sec_end; - } - - if ((offset >= sec_start) && (offset < sec_end)){ - first_sector = i; - } - - if ((offset + count >= sec_start) && (offset + count < sec_end)){ - last_sector = i; - } - } - - if (check_address != offset + count) - return ERROR_FLASH_DST_OUT_OF_BANK; - - DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); - - scanbuf = calloc(CEIL(64, 8), 1); - - DEBUG("ISC_PROGRAM"); - - for (i = first_sector; i <= last_sector; i++) - { - str9xpec_set_address(bank, str9xpec_info->sector_bits[i]); - - dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8); - - while (dwords_remaining > 0) - { - str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = (buffer + bytes_written); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - - /* small delay before polling */ - jtag_add_sleep(50); - - str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); - - do { - field.device = chain_pos; - field.num_bits = 8; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = scanbuf; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, -1, NULL); - jtag_execute_queue(); - - status = buf_get_u32(scanbuf, 0, 8); - - } while(!(status & ISC_STATUS_BUSY)); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) - // return ERROR_FLASH_OPERATION_FAILED; - - dwords_remaining--; - bytes_written += 8; - } - } - - if (bytes_remaining) - { - u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - int i = 0; - - while(bytes_remaining > 0) - { - last_dword[i++] = *(buffer + bytes_written); - bytes_remaining--; - bytes_written++; - } - - str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = last_dword; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - - /* small delay before polling */ - jtag_add_sleep(50); - - str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); - - do { - field.device = chain_pos; - field.num_bits = 8; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = scanbuf; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, -1, NULL); - jtag_execute_queue(); - - status = buf_get_u32(scanbuf, 0, 8); - - } while(!(status & ISC_STATUS_BUSY)); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) - // return ERROR_FLASH_OPERATION_FAILED; - } - - free(scanbuf); - - str9xpec_isc_disable(bank); - - return ERROR_OK; -} - -int str9xpec_probe(struct flash_bank_s *bank) -{ - return ERROR_OK; -} - -int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - scan_field_t field; - u8 *buffer = NULL; - u32 chain_pos; - u32 idcode; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 1) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - chain_pos = str9xpec_info->chain_pos; - - buffer = calloc(CEIL(32, 8), 1); - - str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI); - - field.device = chain_pos; - field.num_bits = 32; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = buffer; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - jtag_execute_queue(); - - idcode = buf_get_u32(buffer, 0, 32); - - command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode); - - free(buffer); - - return ERROR_OK; -} - -int str9xpec_erase_check(struct flash_bank_s *bank) -{ - return str9xpec_blank_check(bank, 0, bank->num_sectors - 1); -} - -int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size) -{ - snprintf(buf, buf_size, "str9xpec flash driver info" ); - return ERROR_OK; -} - -int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - u8 status; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec options_read "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - status = str9xpec_read_config(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - /* boot bank */ - if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1)) - command_print(cmd_ctx, "CS Map: bank1"); - else - command_print(cmd_ctx, "CS Map: bank0"); - - /* OTP lock */ - if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1)) - command_print(cmd_ctx, "OTP Lock: OTP Locked"); - else - command_print(cmd_ctx, "OTP Lock: OTP Unlocked"); - - /* LVD Threshold */ - if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1)) - command_print(cmd_ctx, "LVD Threshold: 2.7v"); - else - command_print(cmd_ctx, "LVD Threshold: 2.4v"); - - /* LVD reset warning */ - if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1)) - command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs"); - else - command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only"); - - /* LVD reset select */ - if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1)) - command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs"); - else - command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only"); - - return ERROR_OK; -} - -int str9xpec_write_options(struct flash_bank_s *bank) -{ - scan_field_t field; - u8 status; - u32 chain_pos; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - str9xpec_info = bank->driver_priv; - chain_pos = str9xpec_info->chain_pos; - - /* erase config options first */ - status = str9xpec_erase_area( bank, 0xFE, 0xFE ); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return status; - - if (!str9xpec_info->isc_enable) { - str9xpec_isc_enable( bank ); - } - - if (!str9xpec_info->isc_enable) { - return ISC_STATUS_ERROR; - } - - /* according to data 64th bit has to be set */ - buf_set_u32(str9xpec_info->options, 63, 1, 1); - - /* set option byte address */ - str9xpec_set_address(bank, 0x50); - - /* execute ISC_PROGRAM command */ - str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); - - field.device = chain_pos; - field.num_bits = 64; - field.out_value = str9xpec_info->options; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, TAP_RTI, NULL); - - /* small delay before polling */ - jtag_add_sleep(50); - - str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); - - do { - field.device = chain_pos; - field.num_bits = 8; - field.out_value = NULL; - field.out_mask = NULL; - field.in_value = &status; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_dr_scan(1, &field, -1, NULL); - jtag_execute_queue(); - - } while(!(status & ISC_STATUS_BUSY)); - - str9xpec_isc_disable(bank); - - return status; -} - -int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - u8 status; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec options_write "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - status = str9xpec_write_options(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; -} - -int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 2) - { - command_print(cmd_ctx, "str9xpec options_cmap "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - if (strcmp(args[1], "bank1") == 0) - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1); - } - else - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0); - } - - return ERROR_OK; -} - -int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 2) - { - command_print(cmd_ctx, "str9xpec options_lvdthd <2.4v|2.7v>"); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - if (strcmp(args[1], "2.7v") == 0) - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1); - } - else - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0); - } - - return ERROR_OK; -} - -int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 2) - { - command_print(cmd_ctx, "str9xpec options_lvdsel "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - if (strcmp(args[1], "vdd_vddq") == 0) - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1); - } - else - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0); - } - - return ERROR_OK; -} - -int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 2) - { - command_print(cmd_ctx, "str9xpec options_lvdwarn "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - if (strcmp(args[1], "vdd_vddq") == 0) - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1); - } - else - { - buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0); - } - - return ERROR_OK; -} - -int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 status; - flash_bank_t *bank; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec lock "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - status = str9xpec_lock_device(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; -} - -int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 status; - flash_bank_t *bank; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec unlock "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - status = str9xpec_unlock_device(bank); - - if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) - return ERROR_FLASH_OPERATION_FAILED; - - return ERROR_OK; -} - -int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - u32 chain_pos; - jtag_device_t* dev0; - jtag_device_t* dev2; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec enable_turbo "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - /* remove arm core from chain - enter turbo mode */ - - str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI); - jtag_execute_queue(); - - /* modify scan chain - str9 core has been removed */ - dev0 = jtag_get_device(chain_pos); - str9xpec_info->devarm = jtag_get_device(chain_pos+1); - dev2 = jtag_get_device(chain_pos+2); - dev0->next = dev2; - jtag_num_devices--; - - return ERROR_OK; -} - -int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - flash_bank_t *bank; - u32 chain_pos; - jtag_device_t* dev0; - str9xpec_flash_controller_t *str9xpec_info = NULL; - - if (argc < 1) - { - command_print(cmd_ctx, "str9xpec disable_turbo "); - return ERROR_OK; - } - - bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); - if (!bank) - { - command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - str9xpec_info = bank->driver_priv; - - chain_pos = str9xpec_info->chain_pos; - - dev0 = jtag_get_device(chain_pos); - - /* exit turbo mode via TLR */ - str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR); - jtag_execute_queue(); - - /* restore previous scan chain */ - if( str9xpec_info->devarm ) { - dev0->next = str9xpec_info->devarm; - jtag_num_devices++; - str9xpec_info->devarm = NULL; - } - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "str9xpec.h" +#include "flash.h" +#include "target.h" +#include "log.h" +#include "armv4_5.h" +#include "arm7_9_common.h" +#include "jtag.h" +#include "binarybuffer.h" + +#include +#include +#include +#include + +str9xpec_mem_layout_t mem_layout_str9pec[] = { + {0x00000000, 0x10000, 0}, + {0x00010000, 0x10000, 1}, + {0x00020000, 0x10000, 2}, + {0x00030000, 0x10000, 3}, + {0x00040000, 0x10000, 4}, + {0x00050000, 0x10000, 5}, + {0x00060000, 0x10000, 6}, + {0x00070000, 0x10000, 7}, + {0x00080000, 0x02000, 32}, + {0x00082000, 0x02000, 33}, + {0x00084000, 0x02000, 34}, + {0x00086000, 0x02000, 35} +}; + +int str9xpec_register_commands(struct command_context_s *cmd_ctx); +int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank); +int str9xpec_erase(struct flash_bank_s *bank, int first, int last); +int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last); +int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count); +int str9xpec_probe(struct flash_bank_s *bank); +int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_protect_check(struct flash_bank_s *bank); +int str9xpec_erase_check(struct flash_bank_s *bank); +int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size); + +int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last); +int str9xpec_set_address(struct flash_bank_s *bank, u8 sector); +int str9xpec_write_options(struct flash_bank_s *bank); + +int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +flash_driver_t str9xpec_flash = +{ + .name = "str9xpec", + .register_commands = str9xpec_register_commands, + .flash_bank_command = str9xpec_flash_bank_command, + .erase = str9xpec_erase, + .protect = str9xpec_protect, + .write = str9xpec_write, + .probe = str9xpec_probe, + .auto_probe = str9xpec_probe, + .erase_check = str9xpec_erase_check, + .protect_check = str9xpec_protect_check, + .info = str9xpec_info +}; + +int str9xpec_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *str9xpec_cmd = register_command(cmd_ctx, NULL, "str9xpec", NULL, COMMAND_ANY, "str9xpec flash specific commands"); + + register_command(cmd_ctx, str9xpec_cmd, "enable_turbo", str9xpec_handle_flash_enable_turbo_command, COMMAND_EXEC, + "enable str9xpec turbo mode"); + register_command(cmd_ctx, str9xpec_cmd, "disable_turbo", str9xpec_handle_flash_disable_turbo_command, COMMAND_EXEC, + "disable str9xpec turbo mode"); + register_command(cmd_ctx, str9xpec_cmd, "options_cmap", str9xpec_handle_flash_options_cmap_command, COMMAND_EXEC, + "configure str9xpec boot sector"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdthd", str9xpec_handle_flash_options_lvdthd_command, COMMAND_EXEC, + "configure str9xpec lvd threshold"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdsel", str9xpec_handle_flash_options_lvdsel_command, COMMAND_EXEC, + "configure str9xpec lvd selection"); + register_command(cmd_ctx, str9xpec_cmd, "options_lvdwarn", str9xpec_handle_flash_options_lvdwarn_command, COMMAND_EXEC, + "configure str9xpec lvd warning"); + register_command(cmd_ctx, str9xpec_cmd, "options_read", str9xpec_handle_flash_options_read_command, COMMAND_EXEC, + "read str9xpec options"); + register_command(cmd_ctx, str9xpec_cmd, "options_write", str9xpec_handle_flash_options_write_command, COMMAND_EXEC, + "write str9xpec options"); + register_command(cmd_ctx, str9xpec_cmd, "lock", str9xpec_handle_flash_lock_command, COMMAND_EXEC, + "lock str9xpec device"); + register_command(cmd_ctx, str9xpec_cmd, "unlock", str9xpec_handle_flash_unlock_command, COMMAND_EXEC, + "unlock str9xpec device"); + register_command(cmd_ctx, str9xpec_cmd, "part_id", str9xpec_handle_part_id_command, COMMAND_EXEC, + "print part id of str9xpec flash bank "); + + return ERROR_OK; +} + +int str9xpec_set_instr(int chain_pos, u32 new_instr, enum tap_state end_state) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (device == NULL) + { + DEBUG("Invalid Target"); + return ERROR_TARGET_INVALID; + } + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, end_state); + + free(field.out_value); + } + + return ERROR_OK; +} + +u8 str9xpec_isc_status(int chain_pos) +{ + scan_field_t field; + u8 status; + + if (str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI) != ERROR_OK) + return ISC_STATUS_ERROR; + + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + DEBUG("status: 0x%2.2x", status); + + if (status & ISC_STATUS_SECURITY) + INFO("Device Security Bit Set"); + + return status; +} + +int str9xpec_isc_enable(struct flash_bank_s *bank) +{ + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (str9xpec_info->isc_enable) + return ERROR_OK; + + /* enter isc mode */ + if (str9xpec_set_instr(chain_pos, ISC_ENABLE, TAP_RTI) != ERROR_OK) + return ERROR_TARGET_INVALID; + + /* check ISC status */ + status = str9xpec_isc_status(chain_pos); + if (status & ISC_STATUS_MODE) + { + /* we have entered isc mode */ + str9xpec_info->isc_enable = 1; + DEBUG("ISC_MODE Enabled"); + } + + return ERROR_OK; +} + +int str9xpec_isc_disable(struct flash_bank_s *bank) +{ + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) + return ERROR_OK; + + if (str9xpec_set_instr(chain_pos, ISC_DISABLE, TAP_RTI) != ERROR_OK) + return ERROR_TARGET_INVALID; + + /* delay to handle aborts */ + jtag_add_sleep(50); + + /* check ISC status */ + status = str9xpec_isc_status(chain_pos); + if (!(status & ISC_STATUS_MODE)) + { + /* we have left isc mode */ + str9xpec_info->isc_enable = 0; + DEBUG("ISC_MODE Disabled"); + } + + return ERROR_OK; +} + +int str9xpec_read_config(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + DEBUG("ISC_CONFIGURATION"); + + /* execute ISC_CONFIGURATION command */ + str9xpec_set_instr(chain_pos, ISC_CONFIGURATION, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = str9xpec_info->options; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + status = str9xpec_isc_status(chain_pos); + + return status; +} + +int str9xpec_build_block_list(struct flash_bank_s *bank) +{ + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + int i; + int num_sectors = 0, b0_sectors = 0; + + switch (bank->size) + { + case (256 * 1024): + b0_sectors = 4; + break; + case (512 * 1024): + b0_sectors = 8; + break; + default: + ERROR("BUG: unknown bank->size encountered"); + exit(-1); + } + + /* include bank 1 sectors */ + num_sectors = b0_sectors + 4; + bank->size += (32 * 1024); + + bank->num_sectors = num_sectors; + bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); + str9xpec_info->sector_bits = malloc(sizeof(u32) * num_sectors); + + num_sectors = 0; + + for (i = 0; i < b0_sectors; i++) + { + bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start; + bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; + bank->sectors[num_sectors].is_erased = -1; + bank->sectors[num_sectors].is_protected = 1; + str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; + } + + for (i = 8; i < 12; i++) + { + bank->sectors[num_sectors].offset = mem_layout_str9pec[i].sector_start; + bank->sectors[num_sectors].size = mem_layout_str9pec[i].sector_size; + bank->sectors[num_sectors].is_erased = -1; + bank->sectors[num_sectors].is_protected = 1; + str9xpec_info->sector_bits[num_sectors++] = mem_layout_str9pec[i].sector_bit; + } + + return ERROR_OK; +} + +/* flash bank str9x 0 0 + */ +int str9xpec_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank) +{ + str9xpec_flash_controller_t *str9xpec_info; + armv4_5_common_t *armv4_5 = NULL; + arm7_9_common_t *arm7_9 = NULL; + arm_jtag_t *jtag_info = NULL; + + if (argc < 6) + { + WARNING("incomplete flash_bank str9x configuration"); + return ERROR_FLASH_BANK_INVALID; + } + + str9xpec_info = malloc(sizeof(str9xpec_flash_controller_t)); + bank->driver_priv = str9xpec_info; + + if (bank->base != 0x00000000) + { + WARNING("overriding flash base address for STR91x device with 0x00000000"); + bank->base = 0x00000000; + } + + /* find out jtag position of flash controller + * it is always after the arm966 core */ + + armv4_5 = bank->target->arch_info; + arm7_9 = armv4_5->arch_info; + jtag_info = &arm7_9->jtag_info; + + str9xpec_info->chain_pos = (jtag_info->chain_pos - 1); + str9xpec_info->isc_enable = 0; + str9xpec_info->devarm = NULL; + + str9xpec_build_block_list(bank); + + /* clear option byte register */ + buf_set_u32(str9xpec_info->options, 0, 64, 0); + + return ERROR_OK; +} + +int str9xpec_blank_check(struct flash_bank_s *bank, int first, int last) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + int i; + u8 *buffer = NULL; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ERROR_FLASH_OPERATION_FAILED; + } + + buffer = calloc(CEIL(64, 8), 1); + + DEBUG("blank check: first_bank: %i, last_bank: %i", first, last); + + for (i = first; i <= last; i++) { + buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); + } + + /* execute ISC_BLANK_CHECK command */ + str9xpec_set_instr(chain_pos, ISC_BLANK_CHECK, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = buffer; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_add_sleep(40000); + + /* read blank check result */ + field.device = chain_pos; + field.num_bits = 64; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_PI); + jtag_execute_queue(); + + status = str9xpec_isc_status(chain_pos); + + for (i = first; i <= last; i++) + { + if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1)) + bank->sectors[i].is_erased = 0; + else + bank->sectors[i].is_erased = 1; + } + + free(buffer); + + str9xpec_isc_disable(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + return ERROR_OK; +} + +int str9xpec_protect_check(struct flash_bank_s *bank) +{ + u8 status; + int i; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + for (i = 0; i < bank->num_sectors; i++) + { + if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1)) + bank->sectors[i].is_protected = 1; + else + bank->sectors[i].is_protected = 0; + } + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + return ERROR_OK; +} + +int str9xpec_erase_area(struct flash_bank_s *bank, int first, int last) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + int i; + u8 *buffer = NULL; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + buffer = calloc(CEIL(64, 8), 1); + + DEBUG("erase: first_bank: %i, last_bank: %i", first, last); + + /* last bank: 0xFF signals a full erase (unlock complete device) */ + /* last bank: 0xFE signals a option byte erase */ + if (last == 0xFF) + { + for (i = 0; i < 64; i++) { + buf_set_u32(buffer, i, 1, 1); + } + } + else if (last == 0xFE) + { + buf_set_u32(buffer, 49, 1, 1); + } + else + { + for (i = first; i <= last; i++) { + buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); + } + } + + DEBUG("ISC_ERASE"); + + /* execute ISC_ERASE command */ + str9xpec_set_instr(chain_pos, ISC_ERASE, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = buffer; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + jtag_add_sleep(10); + + /* wait for erase completion */ + while (!((status = str9xpec_isc_status(chain_pos)) & ISC_STATUS_BUSY)) { + usleep(1000); + } + + free(buffer); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_erase(struct flash_bank_s *bank, int first, int last) +{ + int status; + + status = str9xpec_erase_area(bank, first, last); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_lock_device(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + /* set security address */ + str9xpec_set_address(bank, 0x80); + + /* execute ISC_PROGRAM command */ + str9xpec_set_instr(chain_pos, ISC_PROGRAM_SECURITY, TAP_RTI); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + } while(!(status & ISC_STATUS_BUSY)); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_unlock_device(struct flash_bank_s *bank) +{ + u8 status; + + status = str9xpec_erase_area(bank, 0, 255); + + return status; +} + +int str9xpec_protect(struct flash_bank_s *bank, int set, int first, int last) +{ + u8 status; + int i; + + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + DEBUG("protect: first_bank: %i, last_bank: %i", first, last); + + /* last bank: 0xFF signals a full device protect */ + if (last == 0xFF) + { + if( set ) + { + status = str9xpec_lock_device(bank); + } + else + { + /* perform full erase to unlock device */ + status = str9xpec_unlock_device(bank); + } + } + else + { + for (i = first; i <= last; i++) + { + if( set ) + buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1); + else + buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0); + } + + status = str9xpec_write_options(bank); + } + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_set_address(struct flash_bank_s *bank, u8 sector) +{ + u32 chain_pos; + scan_field_t field; + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + /* set flash controller address */ + str9xpec_set_instr(chain_pos, ISC_ADDRESS_SHIFT, TAP_PI); + + field.device = chain_pos; + field.num_bits = 8; + field.out_value = §or; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + + return ERROR_OK; +} + +int str9xpec_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) +{ + str9xpec_flash_controller_t *str9xpec_info = bank->driver_priv; + u32 dwords_remaining = (count / 8); + u32 bytes_remaining = (count & 0x00000007); + u32 bytes_written = 0; + u8 status; + u32 check_address = offset; + u32 chain_pos; + scan_field_t field; + u8 *scanbuf; + int i; + u32 first_sector = 0; + u32 last_sector = 0; + + chain_pos = str9xpec_info->chain_pos; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable(bank); + } + + if (!str9xpec_info->isc_enable) { + return ERROR_FLASH_OPERATION_FAILED; + } + + if (offset & 0x7) + { + WARNING("offset 0x%x breaks required 8-byte alignment", offset); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + for (i = 0; i < bank->num_sectors; i++) + { + u32 sec_start = bank->sectors[i].offset; + u32 sec_end = sec_start + bank->sectors[i].size; + + /* check if destination falls within the current sector */ + if ((check_address >= sec_start) && (check_address < sec_end)) + { + /* check if destination ends in the current sector */ + if (offset + count < sec_end) + check_address = offset + count; + else + check_address = sec_end; + } + + if ((offset >= sec_start) && (offset < sec_end)){ + first_sector = i; + } + + if ((offset + count >= sec_start) && (offset + count < sec_end)){ + last_sector = i; + } + } + + if (check_address != offset + count) + return ERROR_FLASH_DST_OUT_OF_BANK; + + DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); + + scanbuf = calloc(CEIL(64, 8), 1); + + DEBUG("ISC_PROGRAM"); + + for (i = first_sector; i <= last_sector; i++) + { + str9xpec_set_address(bank, str9xpec_info->sector_bits[i]); + + dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8); + + while (dwords_remaining > 0) + { + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = (buffer + bytes_written); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = scanbuf; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + status = buf_get_u32(scanbuf, 0, 8); + + } while(!(status & ISC_STATUS_BUSY)); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) + // return ERROR_FLASH_OPERATION_FAILED; + + dwords_remaining--; + bytes_written += 8; + } + } + + if (bytes_remaining) + { + u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int i = 0; + + while(bytes_remaining > 0) + { + last_dword[i++] = *(buffer + bytes_written); + bytes_remaining--; + bytes_written++; + } + + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = last_dword; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = scanbuf; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + status = buf_get_u32(scanbuf, 0, 8); + + } while(!(status & ISC_STATUS_BUSY)); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + //if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) + // return ERROR_FLASH_OPERATION_FAILED; + } + + free(scanbuf); + + str9xpec_isc_disable(bank); + + return ERROR_OK; +} + +int str9xpec_probe(struct flash_bank_s *bank) +{ + return ERROR_OK; +} + +int str9xpec_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + scan_field_t field; + u8 *buffer = NULL; + u32 chain_pos; + u32 idcode; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + buffer = calloc(CEIL(32, 8), 1); + + str9xpec_set_instr(chain_pos, ISC_IDCODE, TAP_PI); + + field.device = chain_pos; + field.num_bits = 32; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + jtag_execute_queue(); + + idcode = buf_get_u32(buffer, 0, 32); + + command_print(cmd_ctx, "str9xpec part id: 0x%8.8x", idcode); + + free(buffer); + + return ERROR_OK; +} + +int str9xpec_erase_check(struct flash_bank_s *bank) +{ + return str9xpec_blank_check(bank, 0, bank->num_sectors - 1); +} + +int str9xpec_info(struct flash_bank_s *bank, char *buf, int buf_size) +{ + snprintf(buf, buf_size, "str9xpec flash driver info" ); + return ERROR_OK; +} + +int str9xpec_handle_flash_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u8 status; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec options_read "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + status = str9xpec_read_config(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + /* boot bank */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1)) + command_print(cmd_ctx, "CS Map: bank1"); + else + command_print(cmd_ctx, "CS Map: bank0"); + + /* OTP lock */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1)) + command_print(cmd_ctx, "OTP Lock: OTP Locked"); + else + command_print(cmd_ctx, "OTP Lock: OTP Unlocked"); + + /* LVD Threshold */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1)) + command_print(cmd_ctx, "LVD Threshold: 2.7v"); + else + command_print(cmd_ctx, "LVD Threshold: 2.4v"); + + /* LVD reset warning */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1)) + command_print(cmd_ctx, "LVD Reset Warning: VDD or VDDQ Inputs"); + else + command_print(cmd_ctx, "LVD Reset Warning: VDD Input Only"); + + /* LVD reset select */ + if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1)) + command_print(cmd_ctx, "LVD Reset Selection: VDD or VDDQ Inputs"); + else + command_print(cmd_ctx, "LVD Reset Selection: VDD Input Only"); + + return ERROR_OK; +} + +int str9xpec_write_options(struct flash_bank_s *bank) +{ + scan_field_t field; + u8 status; + u32 chain_pos; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + str9xpec_info = bank->driver_priv; + chain_pos = str9xpec_info->chain_pos; + + /* erase config options first */ + status = str9xpec_erase_area( bank, 0xFE, 0xFE ); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return status; + + if (!str9xpec_info->isc_enable) { + str9xpec_isc_enable( bank ); + } + + if (!str9xpec_info->isc_enable) { + return ISC_STATUS_ERROR; + } + + /* according to data 64th bit has to be set */ + buf_set_u32(str9xpec_info->options, 63, 1, 1); + + /* set option byte address */ + str9xpec_set_address(bank, 0x50); + + /* execute ISC_PROGRAM command */ + str9xpec_set_instr(chain_pos, ISC_PROGRAM, TAP_PI); + + field.device = chain_pos; + field.num_bits = 64; + field.out_value = str9xpec_info->options; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, TAP_RTI); + + /* small delay before polling */ + jtag_add_sleep(50); + + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_PI); + + do { + field.device = chain_pos; + field.num_bits = 8; + field.out_value = NULL; + field.out_mask = NULL; + field.in_value = &status; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_dr_scan(1, &field, -1); + jtag_execute_queue(); + + } while(!(status & ISC_STATUS_BUSY)); + + str9xpec_isc_disable(bank); + + return status; +} + +int str9xpec_handle_flash_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u8 status; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec options_write "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_write_options(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_cmap_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_cmap "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "bank1") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdthd_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdthd <2.4v|2.7v>"); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "2.7v") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdsel_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdsel "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "vdd_vddq") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_options_lvdwarn_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 2) + { + command_print(cmd_ctx, "str9xpec options_lvdwarn "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + if (strcmp(args[1], "vdd_vddq") == 0) + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1); + } + else + { + buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0); + } + + return ERROR_OK; +} + +int str9xpec_handle_flash_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 status; + flash_bank_t *bank; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec lock "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_lock_device(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 status; + flash_bank_t *bank; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec unlock "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + status = str9xpec_unlock_device(bank); + + if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +int str9xpec_handle_flash_enable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u32 chain_pos; + jtag_device_t* dev0; + jtag_device_t* dev2; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec enable_turbo "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + /* remove arm core from chain - enter turbo mode */ + + str9xpec_set_instr(chain_pos+2, 0xD, TAP_RTI); + jtag_execute_queue(); + + /* modify scan chain - str9 core has been removed */ + dev0 = jtag_get_device(chain_pos); + str9xpec_info->devarm = jtag_get_device(chain_pos+1); + dev2 = jtag_get_device(chain_pos+2); + dev0->next = dev2; + jtag_num_devices--; + + return ERROR_OK; +} + +int str9xpec_handle_flash_disable_turbo_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + flash_bank_t *bank; + u32 chain_pos; + jtag_device_t* dev0; + str9xpec_flash_controller_t *str9xpec_info = NULL; + + if (argc < 1) + { + command_print(cmd_ctx, "str9xpec disable_turbo "); + return ERROR_OK; + } + + bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0)); + if (!bank) + { + command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + str9xpec_info = bank->driver_priv; + + chain_pos = str9xpec_info->chain_pos; + + dev0 = jtag_get_device(chain_pos); + + /* exit turbo mode via TLR */ + str9xpec_set_instr(chain_pos, ISC_NOOP, TAP_TLR); + jtag_execute_queue(); + + /* restore previous scan chain */ + if( str9xpec_info->devarm ) { + dev0->next = str9xpec_info->devarm; + jtag_num_devices++; + str9xpec_info->devarm = NULL; + } + + return ERROR_OK; +} diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c index c4015118..605c34cf 100644 --- a/src/jtag/jtag.c +++ b/src/jtag/jtag.c @@ -1,1836 +1,1837 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "jtag.h" - -#include "command.h" -#include "log.h" -#include "interpreter.h" - -#include "stdlib.h" -#include "string.h" -#include - -char* tap_state_strings[16] = -{ - "tlr", - "sds", "cd", "sd", "e1d", "pd", "e2d", "ud", - "rti", - "sis", "ci", "si", "e1i", "pi", "e2i", "ui" -}; - -typedef struct cmd_queue_page_s -{ - void *address; - size_t used; - struct cmd_queue_page_s *next; -} cmd_queue_page_t; - -#define CMD_QUEUE_PAGE_SIZE (1024 * 1024) -static cmd_queue_page_t *cmd_queue_pages = NULL; - -/* tap_move[i][j]: tap movement command to go from state i to state j - * 0: Test-Logic-Reset - * 1: Run-Test/Idle - * 2: Shift-DR - * 3: Pause-DR - * 4: Shift-IR - * 5: Pause-IR - * - * SD->SD and SI->SI have to be caught in interface specific code - */ -u8 tap_move[6][6] = -{ -/* TLR RTI SD PD SI PI */ - {0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16}, /* TLR */ - {0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b}, /* RTI */ - {0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f}, /* SD */ - {0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f}, /* PD */ - {0x7f, 0x31, 0x07, 0x17, 0x00, 0x01}, /* SI */ - {0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f} /* PI */ -}; - -int tap_move_map[16] = { - 0, -1, -1, 2, -1, 3, -1, -1, - 1, -1, -1, 4, -1, 5, -1, -1 -}; - -tap_transition_t tap_transitions[16] = -{ - {TAP_TLR, TAP_RTI}, /* TLR */ - {TAP_SIS, TAP_CD}, /* SDS */ - {TAP_E1D, TAP_SD}, /* CD */ - {TAP_E1D, TAP_SD}, /* SD */ - {TAP_UD, TAP_PD}, /* E1D */ - {TAP_E2D, TAP_PD}, /* PD */ - {TAP_UD, TAP_SD}, /* E2D */ - {TAP_SDS, TAP_RTI}, /* UD */ - {TAP_SDS, TAP_RTI}, /* RTI */ - {TAP_TLR, TAP_CI}, /* SIS */ - {TAP_E1I, TAP_SI}, /* CI */ - {TAP_E1I, TAP_SI}, /* SI */ - {TAP_UI, TAP_PI}, /* E1I */ - {TAP_E2I, TAP_PI}, /* PI */ - {TAP_UI, TAP_SI}, /* E2I */ - {TAP_SDS, TAP_RTI} /* UI */ -}; - -char* jtag_event_strings[] = -{ - "SRST asserted", - "TRST asserted", - "SRST released", - "TRST released" -}; - -enum tap_state end_state = TAP_TLR; -enum tap_state cur_state = TAP_TLR; -int jtag_trst = 0; -int jtag_srst = 0; - -jtag_command_t *jtag_command_queue = NULL; -jtag_command_t **last_comand_pointer = &jtag_command_queue; -jtag_device_t *jtag_devices = NULL; -int jtag_num_devices = 0; -int jtag_ir_scan_size = 0; -enum reset_types jtag_reset_config = RESET_NONE; -enum tap_state cmd_queue_end_state = TAP_TLR; -enum tap_state cmd_queue_cur_state = TAP_TLR; - -int jtag_verify_capture_ir = 1; - -/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */ -int jtag_nsrst_delay = 0; /* default to no nSRST delay */ -int jtag_ntrst_delay = 0; /* default to no nTRST delay */ - -/* maximum number of JTAG devices expected in the chain - */ -#define JTAG_MAX_CHAIN_SIZE 20 - -/* callbacks to inform high-level handlers about JTAG state changes */ -jtag_event_callback_t *jtag_event_callbacks; - -/* jtag interfaces (parport, FTDI-USB, TI-USB, ...) - */ -#if BUILD_PARPORT == 1 - extern jtag_interface_t parport_interface; -#endif - -#if BUILD_FT2232_FTD2XX == 1 - extern jtag_interface_t ft2232_interface; -#endif - -#if BUILD_FT2232_LIBFTDI == 1 - extern jtag_interface_t ft2232_interface; -#endif - -#if BUILD_AMTJTAGACCEL == 1 - extern jtag_interface_t amt_jtagaccel_interface; -#endif - -#if BUILD_EP93XX == 1 - extern jtag_interface_t ep93xx_interface; -#endif - -#if BUILD_AT91RM9200 == 1 - extern jtag_interface_t at91rm9200_interface; -#endif - -#if BUILD_GW16012 == 1 - extern jtag_interface_t gw16012_interface; -#endif - -#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 - extern jtag_interface_t presto_interface; -#endif - -#if BUILD_USBPROG == 1 - extern jtag_interface_t usbprog_interface; -#endif - -jtag_interface_t *jtag_interfaces[] = { -#if BUILD_PARPORT == 1 - &parport_interface, -#endif -#if BUILD_FT2232_FTD2XX == 1 - &ft2232_interface, -#endif -#if BUILD_FT2232_LIBFTDI == 1 - &ft2232_interface, -#endif -#if BUILD_AMTJTAGACCEL == 1 - &amt_jtagaccel_interface, -#endif -#if BUILD_EP93XX == 1 - &ep93xx_interface, -#endif -#if BUILD_AT91RM9200 == 1 - &at91rm9200_interface, -#endif -#if BUILD_GW16012 == 1 - &gw16012_interface, -#endif -#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 - &presto_interface, -#endif -#if BUILD_USBPROG == 1 - &usbprog_interface, -#endif - NULL, -}; - -jtag_interface_t *jtag = NULL; - -/* configuration */ -char* jtag_interface = NULL; -int jtag_speed = -1; - - -/* forward declarations */ -int jtag_add_statemove(enum tap_state endstate); -int jtag_add_pathmove(int num_states, enum tap_state *path); -int jtag_add_runtest(int num_cycles, enum tap_state endstate); -int jtag_add_reset(int trst, int srst); -int jtag_add_end_state(enum tap_state endstate); -int jtag_add_sleep(u32 us); -int jtag_execute_queue(void); -int jtag_cancel_queue(void); - -/* jtag commands */ -int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv) -{ - jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - if (*callbacks_p) - { - while ((*callbacks_p)->next) - callbacks_p = &((*callbacks_p)->next); - callbacks_p = &((*callbacks_p)->next); - } - - (*callbacks_p) = malloc(sizeof(jtag_event_callback_t)); - (*callbacks_p)->callback = callback; - (*callbacks_p)->priv = priv; - (*callbacks_p)->next = NULL; - - return ERROR_OK; -} - -int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv)) -{ - jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - while (*callbacks_p) - { - jtag_event_callback_t **next = &((*callbacks_p)->next); - if ((*callbacks_p)->callback == callback) - { - free(*callbacks_p); - *callbacks_p = *next; - } - callbacks_p = next; - } - - return ERROR_OK; -} - -int jtag_call_event_callbacks(enum jtag_event event) -{ - jtag_event_callback_t *callback = jtag_event_callbacks; - - DEBUG("jtag event: %s", jtag_event_strings[event]); - - while (callback) - { - callback->callback(event, callback->priv); - callback = callback->next; - } - - return ERROR_OK; -} - -/* returns a pointer to the pointer of the last command in queue - * this may be a pointer to the root pointer (jtag_command_queue) - * or to the next member of the last but one command - */ -jtag_command_t** jtag_get_last_command_p(void) -{ -/* jtag_command_t *cmd = jtag_command_queue; - - if (cmd) - while (cmd->next) - cmd = cmd->next; - else - return &jtag_command_queue; - - return &cmd->next;*/ - - return last_comand_pointer; -} - -/* returns a pointer to the n-th device in the scan chain */ -jtag_device_t* jtag_get_device(int num) -{ - jtag_device_t *device = jtag_devices; - int i = 0; - - while (device) - { - if (num == i) - return device; - device = device->next; - i++; - } - - ERROR("jtag device number %d not defined", num); - exit(-1); -} - -void* cmd_queue_alloc(size_t size) -{ - cmd_queue_page_t **p_page = &cmd_queue_pages; - int offset; - - if (*p_page) - { - while ((*p_page)->next) - p_page = &((*p_page)->next); - if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) - p_page = &((*p_page)->next); - } - - if (!*p_page) - { - *p_page = malloc(sizeof(cmd_queue_page_t)); - (*p_page)->used = 0; - (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE); - (*p_page)->next = NULL; - } - - offset = (*p_page)->used; - (*p_page)->used += size; - - u8 *t=(u8 *)((*p_page)->address); - return t + offset; -} - -void cmd_queue_free() -{ - cmd_queue_page_t *page = cmd_queue_pages; - - while (page) - { - cmd_queue_page_t *last = page; - free(page->address); - page = page->next; - free(last); - } - - cmd_queue_pages = NULL; -} - -int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism) -{ - jtag_command_t **last_cmd; - jtag_device_t *device; - int i, j; - int scan_size = 0; - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - last_cmd = jtag_get_last_command_p(); - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_SCAN; - - /* allocate memory for ir scan command */ - (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - (*last_cmd)->cmd.scan->ir_scan = 1; - (*last_cmd)->cmd.scan->num_fields = jtag_num_devices; /* one field per device */ - (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t)); - (*last_cmd)->cmd.scan->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - for (i = 0; i < jtag_num_devices; i++) - { - int found = 0; - device = jtag_get_device(i); - scan_size = device->ir_length; - (*last_cmd)->cmd.scan->fields[i].device = i; - (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size; - (*last_cmd)->cmd.scan->fields[i].in_value = NULL; - (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; /* disable verification by default */ - - /* search the list */ - for (j = 0; j < num_fields; j++) - { - if (i == fields[j].device) - { - found = 1; - (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - - if (jtag_verify_capture_ir) - { - if (fields[j].in_handler==NULL) - { - jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL); - } else - { - (*last_cmd)->cmd.scan->fields[i].in_handler = fields[j].in_handler; - (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[j].in_handler_priv; - (*last_cmd)->cmd.scan->fields[i].in_check_value = device->expected; - (*last_cmd)->cmd.scan->fields[i].in_check_mask = device->expected_mask; - } - } - - device->bypass = 0; - break; - } - } - - if (!found) - { - /* if a device isn't listed, set it to BYPASS */ - (*last_cmd)->cmd.scan->fields[i].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - (*last_cmd)->cmd.scan->fields[i].out_mask = NULL; - device->bypass = 1; - - } - - /* update device information */ - buf_cpy((*last_cmd)->cmd.scan->fields[i].out_value, jtag_get_device(i)->cur_instr, scan_size); - } - - return ERROR_OK; -} - -int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism) -{ - jtag_command_t **last_cmd; - int i; - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - last_cmd = jtag_get_last_command_p(); - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_SCAN; - - /* allocate memory for ir scan command */ - (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - (*last_cmd)->cmd.scan->ir_scan = 1; - (*last_cmd)->cmd.scan->num_fields = num_fields; - (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); - (*last_cmd)->cmd.scan->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - for (i = 0; i < num_fields; i++) - { - int num_bits = fields[i].num_bits; - int num_bytes = CEIL(fields[i].num_bits, 8); - (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; - (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; - (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); - (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); - (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; - (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; - (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; - (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; - (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL; - } - return ERROR_OK; -} - -int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism) -{ - int i, j; - int bypass_devices = 0; - int field_count = 0; - jtag_command_t **last_cmd = jtag_get_last_command_p(); - jtag_device_t *device = jtag_devices; - int scan_size; - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - /* count devices in bypass */ - while (device) - { - if (device->bypass) - bypass_devices++; - device = device->next; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->next = NULL; - (*last_cmd)->type = JTAG_SCAN; - - /* allocate memory for dr scan command */ - (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - (*last_cmd)->cmd.scan->ir_scan = 0; - (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices; - (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t)); - (*last_cmd)->cmd.scan->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - for (i = 0; i < jtag_num_devices; i++) - { - int found = 0; - (*last_cmd)->cmd.scan->fields[field_count].device = i; - - for (j = 0; j < num_fields; j++) - { - if (i == fields[j].device) - { - found = 1; - scan_size = fields[j].num_bits; - (*last_cmd)->cmd.scan->fields[field_count].num_bits = scan_size; - (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value; - (*last_cmd)->cmd.scan->fields[field_count].in_check_value = fields[j].in_check_value; - (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask; - (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler; - (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv; - } - } - if (!found) - { - /* if a device isn't listed, the BYPASS register should be selected */ - if (!jtag_get_device(i)->bypass) - { - ERROR("BUG: no scan data for a device not in BYPASS"); - exit(-1); - } - - /* program the scan field to 1 bit length, and ignore it's value */ - (*last_cmd)->cmd.scan->fields[field_count].num_bits = 1; - (*last_cmd)->cmd.scan->fields[field_count].out_value = NULL; - (*last_cmd)->cmd.scan->fields[field_count].out_mask = NULL; - (*last_cmd)->cmd.scan->fields[field_count].in_value = NULL; - (*last_cmd)->cmd.scan->fields[field_count].in_check_value = NULL; - (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = NULL; - (*last_cmd)->cmd.scan->fields[field_count].in_handler = NULL; - (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = NULL; - } - else - { - /* if a device is listed, the BYPASS register must not be selected */ - if (jtag_get_device(i)->bypass) - { - WARNING("scan data for a device in BYPASS"); - } - } - } - return ERROR_OK; -} - -int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism) -{ - int i; - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->next = NULL; - (*last_cmd)->type = JTAG_SCAN; - - /* allocate memory for scan command */ - (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - (*last_cmd)->cmd.scan->ir_scan = 0; - (*last_cmd)->cmd.scan->num_fields = num_fields; - (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); - (*last_cmd)->cmd.scan->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - for (i = 0; i < num_fields; i++) - { - int num_bits = fields[i].num_bits; - int num_bytes = CEIL(fields[i].num_bits, 8); - (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; - (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; - (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); - (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); - (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; - (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; - (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; - (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler; - (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv; - } - - return ERROR_OK; -} -int jtag_add_statemove(enum tap_state state) -{ - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->next = NULL; - (*last_cmd)->type = JTAG_STATEMOVE; - - (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); - (*last_cmd)->cmd.statemove->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - return ERROR_OK; -} - -int jtag_add_pathmove(int num_states, enum tap_state *path) -{ - jtag_command_t **last_cmd = jtag_get_last_command_p(); - int i; - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - /* the last state has to be a stable state */ - if (tap_move_map[path[num_states - 1]] == -1) - { - ERROR("TAP path doesn't finish in a stable state"); - return ERROR_JTAG_NOT_IMPLEMENTED; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->next = NULL; - (*last_cmd)->type = JTAG_PATHMOVE; - - (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t)); - (*last_cmd)->cmd.pathmove->num_states = num_states; - (*last_cmd)->cmd.pathmove->path = cmd_queue_alloc(sizeof(enum tap_state) * num_states); - - for (i = 0; i < num_states; i++) - (*last_cmd)->cmd.pathmove->path[i] = path[i]; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = path[num_states - 1]; - - return ERROR_OK; -} - -int jtag_add_runtest(int num_cycles, enum tap_state state) -{ - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - if (jtag_trst == 1) - { - WARNING("JTAG command queued, while TRST is low (TAP in reset)"); - return ERROR_JTAG_TRST_ASSERTED; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_RUNTEST; - - (*last_cmd)->cmd.runtest = cmd_queue_alloc(sizeof(runtest_command_t)); - (*last_cmd)->cmd.runtest->num_cycles = num_cycles; - (*last_cmd)->cmd.runtest->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_RELEASED); - - if (cmd_queue_end_state == TAP_TLR) - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - - cmd_queue_cur_state = cmd_queue_end_state; - - return ERROR_OK; -} - -int jtag_add_reset(int req_trst, int req_srst) -{ - int trst_with_tms = 0; - - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - if (req_trst == -1) - req_trst = jtag_trst; - - if (req_srst == -1) - req_srst = jtag_srst; - - /* Make sure that jtag_reset_config allows the requested reset */ - /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */ - if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (req_trst == 0)) - return ERROR_JTAG_RESET_WOULD_ASSERT_TRST; - - /* if TRST pulls SRST, we reset with TAP T-L-R */ - if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_trst == 1)) && (req_srst == 0)) - { - req_trst = 0; - trst_with_tms = 1; - } - - if (req_srst && !(jtag_reset_config & RESET_HAS_SRST)) - { - ERROR("requested nSRST assertion, but the current configuration doesn't support this"); - return ERROR_JTAG_RESET_CANT_SRST; - } - - if (req_trst && !(jtag_reset_config & RESET_HAS_TRST)) - { - req_trst = 0; - trst_with_tms = 1; - } - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_RESET; - - (*last_cmd)->cmd.reset = cmd_queue_alloc(sizeof(reset_command_t)); - (*last_cmd)->cmd.reset->trst = req_trst; - (*last_cmd)->cmd.reset->srst = req_srst; - - jtag_trst = req_trst; - jtag_srst = req_srst; - - if (jtag_srst) - { - jtag_call_event_callbacks(JTAG_SRST_ASSERTED); - } - else - { - jtag_call_event_callbacks(JTAG_SRST_RELEASED); - if (jtag_nsrst_delay) - jtag_add_sleep(jtag_nsrst_delay * 1000); - } - - if (trst_with_tms) - { - last_cmd = &((*last_cmd)->next); - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_STATEMOVE; - - (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); - (*last_cmd)->cmd.statemove->end_state = TAP_TLR; - - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - cmd_queue_cur_state = TAP_TLR; - cmd_queue_end_state = TAP_TLR; - - return ERROR_OK; - } - else - { - if (jtag_trst) - { - /* we just asserted nTRST, so we're now in Test-Logic-Reset, - * and inform possible listeners about this - */ - cmd_queue_cur_state = TAP_TLR; - jtag_call_event_callbacks(JTAG_TRST_ASSERTED); - } - else - { - /* the nTRST line got deasserted, so we're still in Test-Logic-Reset, - * but we might want to add a delay to give the TAP time to settle - */ - if (jtag_ntrst_delay) - jtag_add_sleep(jtag_ntrst_delay * 1000); - } - } - - return ERROR_OK; -} - -int jtag_add_end_state(enum tap_state state) -{ - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_END_STATE; - - (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t)); - (*last_cmd)->cmd.end_state->end_state = state; - - if (state != -1) - cmd_queue_end_state = state; - - return ERROR_OK; -} - -int jtag_add_sleep(u32 us) -{ - jtag_command_t **last_cmd = jtag_get_last_command_p(); - - /* allocate memory for a new list member */ - *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - (*last_cmd)->next = NULL; - last_comand_pointer = &((*last_cmd)->next); - (*last_cmd)->type = JTAG_SLEEP; - - (*last_cmd)->cmd.sleep = cmd_queue_alloc(sizeof(sleep_command_t)); - (*last_cmd)->cmd.sleep->us = us; - - return ERROR_OK; -} - -int jtag_scan_size(scan_command_t *cmd) -{ - int bit_count = 0; - int i; - - /* count bits in scan command */ - for (i = 0; i < cmd->num_fields; i++) - { - bit_count += cmd->fields[i].num_bits; - } - - return bit_count; -} - -int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) -{ - int bit_count = 0; - int i; - - bit_count = jtag_scan_size(cmd); - *buffer = malloc(CEIL(bit_count, 8)); - - bit_count = 0; - - for (i = 0; i < cmd->num_fields; i++) - { - if (cmd->fields[i].out_value) - { -#ifdef _DEBUG_JTAG_IO_ - char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : cmd->fields[i].num_bits, 16); -#endif - buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); -#ifdef _DEBUG_JTAG_IO_ - DEBUG("fields[%i].out_value: 0x%s", i, char_buf); - free(char_buf); -#endif - } - - bit_count += cmd->fields[i].num_bits; - } - - return bit_count; - -} - -int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) -{ - int i; - int bit_count = 0; - int retval; - - /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ - retval = ERROR_OK; - - for (i = 0; i < cmd->num_fields; i++) - { - /* if neither in_value nor in_handler - * are specified we don't have to examine this field - */ - if (cmd->fields[i].in_value || cmd->fields[i].in_handler) - { - int num_bits = cmd->fields[i].num_bits; - u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits); - -#ifdef _DEBUG_JTAG_IO_ - char *char_buf; - - char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); - DEBUG("fields[%i].in_value: 0x%s", i, char_buf); - free(char_buf); -#endif - - if (cmd->fields[i].in_value) - { - buf_cpy(captured, cmd->fields[i].in_value, num_bits); - - if (cmd->fields[i].in_handler) - { - if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) - { - WARNING("in_handler reported a failed check"); - retval = ERROR_JTAG_QUEUE_FAILED; - } - } - } - - /* no in_value specified, but a handler takes care of the scanned data */ - if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value)) - { - if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) - { - /* We're going to call the error:handler later, but if the in_handler - * reported an error we report this failure upstream - */ - WARNING("in_handler reported a failed check"); - retval = ERROR_JTAG_QUEUE_FAILED; - } - } - - free(captured); - } - bit_count += cmd->fields[i].num_bits; - } - - return retval; -} - -int jtag_check_value(u8 *captured, void *priv, scan_field_t *field) -{ - int retval = ERROR_OK; - int num_bits = field->num_bits; - - int compare_failed = 0; - - if (field->in_check_mask) - compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits); - else - compare_failed = buf_cmp(captured, field->in_check_value, num_bits); - - if (compare_failed) - { - /* An error handler could have caught the failing check - * only report a problem when there wasn't a handler, or if the handler - * acknowledged the error - */ - if (compare_failed) - { - char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); - char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16); - - if (field->in_check_mask) - { - char *in_check_mask_char; - in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16); - WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char); - free(in_check_mask_char); - } - else - { - WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char); - } - - free(captured_char); - free(in_check_value_char); - - retval = ERROR_JTAG_QUEUE_FAILED; - } - - } - return retval; -} - -/* - set up checking of this field using the in_handler. The values passed in must be valid until - after jtag_execute() has completed. - */ -void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler) -{ - if (value) - field->in_handler = jtag_check_value; - else - field->in_handler = NULL; /* No check, e.g. embeddedice uses value==NULL to indicate no check */ - field->in_handler_priv = NULL; /* this will be filled in at the invocation site to point to the field duplicate */ - field->in_check_value = value; - field->in_check_mask = mask; -} - -enum scan_type jtag_scan_type(scan_command_t *cmd) -{ - int i; - int type = 0; - - for (i = 0; i < cmd->num_fields; i++) - { - if (cmd->fields[i].in_value || cmd->fields[i].in_handler) - type |= SCAN_IN; - if (cmd->fields[i].out_value) - type |= SCAN_OUT; - } - - return type; -} - -int jtag_execute_queue(void) -{ - int retval; - - retval = jtag->execute_queue(); - - cmd_queue_free(); - - jtag_command_queue = NULL; - last_comand_pointer = &jtag_command_queue; - - return retval; -} - -int jtag_reset_callback(enum jtag_event event, void *priv) -{ - jtag_device_t *device = priv; - - DEBUG("-"); - - if (event == JTAG_TRST_ASSERTED) - { - buf_set_ones(device->cur_instr, device->ir_length); - device->bypass = 1; - } - - return ERROR_OK; -} - -void jtag_sleep(u32 us) -{ - usleep(us); -} - -/* Try to examine chain layout according to IEEE 1149.1 §12 - */ -int jtag_examine_chain() -{ - jtag_device_t *device = jtag_devices; - scan_field_t field; - u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; - int i; - int bit_count; - int device_count = 0; - u8 zero_check = 0x0; - u8 one_check = 0xff; - - field.device = 0; - field.num_bits = sizeof(idcode_buffer) * 8; - field.out_value = idcode_buffer; - field.out_mask = NULL; - field.in_value = idcode_buffer; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) - { - buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF); - } - - jtag_add_plain_dr_scan(1, &field, TAP_TLR, NULL); - jtag_execute_queue(); - - for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++) - { - zero_check |= idcode_buffer[i]; - one_check &= idcode_buffer[i]; - } - - /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */ - if ((zero_check == 0x00) || (one_check == 0xff)) - { - ERROR("JTAG communication failure, check connection, JTAG interface, target power etc."); - return ERROR_JTAG_INIT_FAILED; - } - - for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;) - { - u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32); - if ((idcode & 1) == 0) - { - /* LSB must not be 0, this indicates a device in bypass */ - device_count++; - - bit_count += 1; - } - else - { - u32 manufacturer; - u32 part; - u32 version; - - if (idcode == 0x000000FF) - { - /* End of chain (invalid manufacturer ID) */ - break; - } - - if (device) - { - device->idcode = idcode; - device = device->next; - } - device_count++; - - manufacturer = (idcode & 0xffe) >> 1; - part = (idcode & 0xffff000) >> 12; - version = (idcode & 0xf0000000) >> 28; - - INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)", - idcode, manufacturer, part, version); - - bit_count += 32; - } - } - - /* see if number of discovered devices matches configuration */ - if (device_count != jtag_num_devices) - { - ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", - device_count, jtag_num_devices); - ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -int jtag_validate_chain() -{ - jtag_device_t *device = jtag_devices; - int total_ir_length = 0; - u8 *ir_test = NULL; - scan_field_t field; - int chain_pos = 0; - - while (device) - { - total_ir_length += device->ir_length; - device = device->next; - } - - total_ir_length += 2; - ir_test = malloc(CEIL(total_ir_length, 8)); - buf_set_ones(ir_test, total_ir_length); - - field.device = 0; - field.num_bits = total_ir_length; - field.out_value = ir_test; - field.out_mask = NULL; - field.in_value = ir_test; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_plain_ir_scan(1, &field, TAP_TLR, NULL); - jtag_execute_queue(); - - device = jtag_devices; - while (device) - { - if (buf_get_u32(ir_test, chain_pos, 2) != 0x1) - { - char *cbuf = buf_to_str(ir_test, total_ir_length, 16); - ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf); - free(cbuf); - free(ir_test); - return ERROR_JTAG_INIT_FAILED; - } - chain_pos += device->ir_length; - device = device->next; - } - - if (buf_get_u32(ir_test, chain_pos, 2) != 0x3) - { - char *cbuf = buf_to_str(ir_test, total_ir_length, 16); - ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf); - free(cbuf); - free(ir_test); - return ERROR_JTAG_INIT_FAILED; - } - - free(ir_test); - - return ERROR_OK; -} - -int jtag_register_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, NULL, "interface", handle_interface_command, - COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command, - COMMAND_ANY, "set jtag speed (if supported) "); - register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command, - COMMAND_CONFIG, "jtag_device "); - register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command, - COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command, - COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command, - COMMAND_CONFIG, NULL); - - register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command, - COMMAND_EXEC, "print current scan chain configuration"); - - register_command(cmd_ctx, NULL, "endstate", handle_endstate_command, - COMMAND_EXEC, "finish JTAG operations in "); - register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command, - COMMAND_EXEC, "toggle reset lines "); - register_command(cmd_ctx, NULL, "runtest", handle_runtest_command, - COMMAND_EXEC, "move to Run-Test/Idle, and execute "); - register_command(cmd_ctx, NULL, "statemove", handle_statemove_command, - COMMAND_EXEC, "move to current endstate or [tap_state]"); - register_command(cmd_ctx, NULL, "irscan", handle_irscan_command, - COMMAND_EXEC, "execute IR scan [dev2] [instr2] ..."); - register_command(cmd_ctx, NULL, "drscan", handle_drscan_command, - COMMAND_EXEC, "execute DR scan [dev2] [var2] ..."); - - register_command(cmd_ctx, NULL, "verify_ircapture", handle_verify_ircapture_command, - COMMAND_ANY, "verify value captured during Capture-IR "); - return ERROR_OK; -} - -int jtag_init(struct command_context_s *cmd_ctx) -{ - int i, validate_tries = 0; - - DEBUG("-"); - - if (jtag_speed == -1) - jtag_speed = 0; - - if (jtag_interface && (jtag_interface[0] != 0)) - /* configuration var 'jtag_interface' is set, and not empty */ - for (i = 0; jtag_interfaces[i]; i++) - { - if (strcmp(jtag_interface, jtag_interfaces[i]->name) == 0) - { - jtag_device_t *device; - device = jtag_devices; - - if (jtag_interfaces[i]->init() != ERROR_OK) - return ERROR_JTAG_INIT_FAILED; - jtag = jtag_interfaces[i]; - - jtag_ir_scan_size = 0; - jtag_num_devices = 0; - while (device != NULL) - { - jtag_ir_scan_size += device->ir_length; - jtag_num_devices++; - device = device->next; - } - - jtag_add_statemove(TAP_TLR); - jtag_execute_queue(); - - /* examine chain first, as this could discover the real chain layout */ - if (jtag_examine_chain() != ERROR_OK) - { - ERROR("trying to validate configured JTAG chain anyway..."); - } - - while (jtag_validate_chain() != ERROR_OK) - { - validate_tries++; - if (validate_tries > 5) - { - ERROR("Could not validate JTAG chain, exit"); - jtag = NULL; - return ERROR_JTAG_INVALID_INTERFACE; - } - usleep(10000); - } - - return ERROR_OK; - } - } - - /* no valid interface was found (i.e. the configuration option, - * didn't match one of the compiled-in interfaces - */ - ERROR("No valid jtag interface found (%s)", jtag_interface); - ERROR("compiled-in jtag interfaces:"); - for (i = 0; jtag_interfaces[i]; i++) - { - ERROR("%i: %s", i, jtag_interfaces[i]->name); - } - - jtag = NULL; - return ERROR_JTAG_INVALID_INTERFACE; -} - -int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int i; - - /* only if the configuration var isn't overwritten from cmdline */ - if (!jtag_interface) - { - if (args[0] && (args[0][0] != 0)) - { - for (i=0; jtag_interfaces[i]; i++) - { - if (strcmp(args[0], jtag_interfaces[i]->name) == 0) - { - if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK) - exit(-1); - - jtag_interface = jtag_interfaces[i]->name; - - return ERROR_OK; - } - } - } - - /* remember the requested interface name, so we can complain about it later */ - jtag_interface = strdup(args[0]); - DEBUG("'interface' command didn't specify a valid interface"); - } - - return ERROR_OK; -} - -int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - jtag_device_t **last_device_p = &jtag_devices; - - if (*last_device_p) - { - while ((*last_device_p)->next) - last_device_p = &((*last_device_p)->next); - last_device_p = &((*last_device_p)->next); - } - - if (argc < 3) - return ERROR_OK; - - *last_device_p = malloc(sizeof(jtag_device_t)); - (*last_device_p)->ir_length = strtoul(args[0], NULL, 0); - - (*last_device_p)->expected = malloc((*last_device_p)->ir_length); - buf_set_u32((*last_device_p)->expected, 0, (*last_device_p)->ir_length, strtoul(args[1], NULL, 0)); - (*last_device_p)->expected_mask = malloc((*last_device_p)->ir_length); - buf_set_u32((*last_device_p)->expected_mask, 0, (*last_device_p)->ir_length, strtoul(args[2], NULL, 0)); - - (*last_device_p)->cur_instr = malloc((*last_device_p)->ir_length); - (*last_device_p)->bypass = 1; - buf_set_ones((*last_device_p)->cur_instr, (*last_device_p)->ir_length); - - (*last_device_p)->next = NULL; - - jtag_register_event_callback(jtag_reset_callback, (*last_device_p)); - - jtag_num_devices++; - - return ERROR_OK; -} - -int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - jtag_device_t *device = jtag_devices; - int device_count = 0; - - while (device) - { - u32 expected, expected_mask, cur_instr; - expected = buf_get_u32(device->expected, 0, device->ir_length); - expected_mask = buf_get_u32(device->expected_mask, 0, device->ir_length); - cur_instr = buf_get_u32(device->cur_instr, 0, device->ir_length); - command_print(cmd_ctx, "%i: idcode: 0x%8.8x ir length %i, ir capture 0x%x, ir mask 0x%x, current instruction 0x%x", device_count, device->idcode, device->ir_length, expected, expected_mask, cur_instr); - device = device->next; - device_count++; - } - - return ERROR_OK; -} - -int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc >= 1) - { - if (strcmp(args[0], "none") == 0) - jtag_reset_config = RESET_NONE; - else if (strcmp(args[0], "trst_only") == 0) - jtag_reset_config = RESET_HAS_TRST; - else if (strcmp(args[0], "srst_only") == 0) - jtag_reset_config = RESET_HAS_SRST; - else if (strcmp(args[0], "trst_and_srst") == 0) - jtag_reset_config = RESET_TRST_AND_SRST; - else - { - ERROR("invalid reset_config argument, defaulting to none"); - jtag_reset_config = RESET_NONE; - return ERROR_INVALID_ARGUMENTS; - } - } - - if (argc >= 2) - { - if (strcmp(args[1], "srst_pulls_trst") == 0) - jtag_reset_config |= RESET_SRST_PULLS_TRST; - else if (strcmp(args[1], "trst_pulls_srst") == 0) - jtag_reset_config |= RESET_TRST_PULLS_SRST; - else if (strcmp(args[1], "combined") == 0) - jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; - else if (strcmp(args[1], "separate") == 0) - jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST); - else - { - ERROR("invalid reset_config argument, defaulting to none"); - jtag_reset_config = RESET_NONE; - return ERROR_INVALID_ARGUMENTS; - } - } - - if (argc >= 3) - { - if (strcmp(args[2], "trst_open_drain") == 0) - jtag_reset_config |= RESET_TRST_OPEN_DRAIN; - else if (strcmp(args[2], "trst_push_pull") == 0) - jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN; - else - { - ERROR("invalid reset_config argument, defaulting to none"); - jtag_reset_config = RESET_NONE; - return ERROR_INVALID_ARGUMENTS; - } - } - - if (argc >= 4) - { - if (strcmp(args[3], "srst_push_pull") == 0) - jtag_reset_config |= RESET_SRST_PUSH_PULL; - else if (strcmp(args[3], "srst_open_drain") == 0) - jtag_reset_config &= ~RESET_SRST_PUSH_PULL; - else - { - ERROR("invalid reset_config argument, defaulting to none"); - jtag_reset_config = RESET_NONE; - return ERROR_INVALID_ARGUMENTS; - } - } - - return ERROR_OK; -} - -int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc < 1) - { - ERROR("jtag_nsrst_delay command takes one required argument"); - exit(-1); - } - else - { - jtag_nsrst_delay = strtoul(args[0], NULL, 0); - } - - return ERROR_OK; -} - -int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc < 1) - { - ERROR("jtag_ntrst_delay command takes one required argument"); - exit(-1); - } - else - { - jtag_ntrst_delay = strtoul(args[0], NULL, 0); - } - - return ERROR_OK; -} - -int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc == 0) - command_print(cmd_ctx, "jtag_speed: %i", jtag_speed); - - if (argc > 0) - { - /* this command can be called during CONFIG, - * in which case jtag isn't initialized */ - if (jtag) - jtag->speed(strtoul(args[0], NULL, 0)); - else - jtag_speed = strtoul(args[0], NULL, 0); - } - - return ERROR_OK; -} - -int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - enum tap_state state; - - if (argc < 1) - { +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "jtag.h" + +#include "command.h" +#include "log.h" +#include "interpreter.h" + +#include "stdlib.h" +#include "string.h" +#include + +char* tap_state_strings[16] = +{ + "tlr", + "sds", "cd", "sd", "e1d", "pd", "e2d", "ud", + "rti", + "sis", "ci", "si", "e1i", "pi", "e2i", "ui" +}; + +typedef struct cmd_queue_page_s +{ + void *address; + size_t used; + struct cmd_queue_page_s *next; +} cmd_queue_page_t; + +#define CMD_QUEUE_PAGE_SIZE (1024 * 1024) +static cmd_queue_page_t *cmd_queue_pages = NULL; + +/* tap_move[i][j]: tap movement command to go from state i to state j + * 0: Test-Logic-Reset + * 1: Run-Test/Idle + * 2: Shift-DR + * 3: Pause-DR + * 4: Shift-IR + * 5: Pause-IR + * + * SD->SD and SI->SI have to be caught in interface specific code + */ +u8 tap_move[6][6] = +{ +/* TLR RTI SD PD SI PI */ + {0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16}, /* TLR */ + {0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b}, /* RTI */ + {0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f}, /* SD */ + {0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f}, /* PD */ + {0x7f, 0x31, 0x07, 0x17, 0x00, 0x01}, /* SI */ + {0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f} /* PI */ +}; + +int tap_move_map[16] = { + 0, -1, -1, 2, -1, 3, -1, -1, + 1, -1, -1, 4, -1, 5, -1, -1 +}; + +tap_transition_t tap_transitions[16] = +{ + {TAP_TLR, TAP_RTI}, /* TLR */ + {TAP_SIS, TAP_CD}, /* SDS */ + {TAP_E1D, TAP_SD}, /* CD */ + {TAP_E1D, TAP_SD}, /* SD */ + {TAP_UD, TAP_PD}, /* E1D */ + {TAP_E2D, TAP_PD}, /* PD */ + {TAP_UD, TAP_SD}, /* E2D */ + {TAP_SDS, TAP_RTI}, /* UD */ + {TAP_SDS, TAP_RTI}, /* RTI */ + {TAP_TLR, TAP_CI}, /* SIS */ + {TAP_E1I, TAP_SI}, /* CI */ + {TAP_E1I, TAP_SI}, /* SI */ + {TAP_UI, TAP_PI}, /* E1I */ + {TAP_E2I, TAP_PI}, /* PI */ + {TAP_UI, TAP_SI}, /* E2I */ + {TAP_SDS, TAP_RTI} /* UI */ +}; + +char* jtag_event_strings[] = +{ + "SRST asserted", + "TRST asserted", + "SRST released", + "TRST released" +}; + +enum tap_state end_state = TAP_TLR; +enum tap_state cur_state = TAP_TLR; +int jtag_trst = 0; +int jtag_srst = 0; + +jtag_command_t *jtag_command_queue = NULL; +jtag_command_t **last_comand_pointer = &jtag_command_queue; +jtag_device_t *jtag_devices = NULL; +int jtag_num_devices = 0; +int jtag_ir_scan_size = 0; +enum reset_types jtag_reset_config = RESET_NONE; +enum tap_state cmd_queue_end_state = TAP_TLR; +enum tap_state cmd_queue_cur_state = TAP_TLR; + +int jtag_verify_capture_ir = 1; + +/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */ +int jtag_nsrst_delay = 0; /* default to no nSRST delay */ +int jtag_ntrst_delay = 0; /* default to no nTRST delay */ + +/* maximum number of JTAG devices expected in the chain + */ +#define JTAG_MAX_CHAIN_SIZE 20 + +/* callbacks to inform high-level handlers about JTAG state changes */ +jtag_event_callback_t *jtag_event_callbacks; + +/* jtag interfaces (parport, FTDI-USB, TI-USB, ...) + */ +#if BUILD_PARPORT == 1 + extern jtag_interface_t parport_interface; +#endif + +#if BUILD_FT2232_FTD2XX == 1 + extern jtag_interface_t ft2232_interface; +#endif + +#if BUILD_FT2232_LIBFTDI == 1 + extern jtag_interface_t ft2232_interface; +#endif + +#if BUILD_AMTJTAGACCEL == 1 + extern jtag_interface_t amt_jtagaccel_interface; +#endif + +#if BUILD_EP93XX == 1 + extern jtag_interface_t ep93xx_interface; +#endif + +#if BUILD_AT91RM9200 == 1 + extern jtag_interface_t at91rm9200_interface; +#endif + +#if BUILD_GW16012 == 1 + extern jtag_interface_t gw16012_interface; +#endif + +#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 + extern jtag_interface_t presto_interface; +#endif + +#if BUILD_USBPROG == 1 + extern jtag_interface_t usbprog_interface; +#endif + +jtag_interface_t *jtag_interfaces[] = { +#if BUILD_PARPORT == 1 + &parport_interface, +#endif +#if BUILD_FT2232_FTD2XX == 1 + &ft2232_interface, +#endif +#if BUILD_FT2232_LIBFTDI == 1 + &ft2232_interface, +#endif +#if BUILD_AMTJTAGACCEL == 1 + &amt_jtagaccel_interface, +#endif +#if BUILD_EP93XX == 1 + &ep93xx_interface, +#endif +#if BUILD_AT91RM9200 == 1 + &at91rm9200_interface, +#endif +#if BUILD_GW16012 == 1 + &gw16012_interface, +#endif +#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 + &presto_interface, +#endif +#if BUILD_USBPROG == 1 + &usbprog_interface, +#endif + NULL, +}; + +jtag_interface_t *jtag = NULL; + +/* configuration */ +char* jtag_interface = NULL; +int jtag_speed = -1; + + +/* forward declarations */ +int jtag_add_statemove(enum tap_state endstate); +int jtag_add_pathmove(int num_states, enum tap_state *path); +int jtag_add_runtest(int num_cycles, enum tap_state endstate); +int jtag_add_reset(int trst, int srst); +int jtag_add_end_state(enum tap_state endstate); +int jtag_add_sleep(u32 us); +int jtag_execute_queue(void); +int jtag_cancel_queue(void); + +/* jtag commands */ +int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv) +{ + jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(jtag_event_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int jtag_unregister_event_callback(int (*callback)(enum jtag_event event, void *priv)) +{ + jtag_event_callback_t **callbacks_p = &jtag_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (*callbacks_p) + { + jtag_event_callback_t **next = &((*callbacks_p)->next); + if ((*callbacks_p)->callback == callback) + { + free(*callbacks_p); + *callbacks_p = *next; + } + callbacks_p = next; + } + + return ERROR_OK; +} + +int jtag_call_event_callbacks(enum jtag_event event) +{ + jtag_event_callback_t *callback = jtag_event_callbacks; + + DEBUG("jtag event: %s", jtag_event_strings[event]); + + while (callback) + { + callback->callback(event, callback->priv); + callback = callback->next; + } + + return ERROR_OK; +} + +/* returns a pointer to the pointer of the last command in queue + * this may be a pointer to the root pointer (jtag_command_queue) + * or to the next member of the last but one command + */ +jtag_command_t** jtag_get_last_command_p(void) +{ +/* jtag_command_t *cmd = jtag_command_queue; + + if (cmd) + while (cmd->next) + cmd = cmd->next; + else + return &jtag_command_queue; + + return &cmd->next;*/ + + return last_comand_pointer; +} + +/* returns a pointer to the n-th device in the scan chain */ +jtag_device_t* jtag_get_device(int num) +{ + jtag_device_t *device = jtag_devices; + int i = 0; + + while (device) + { + if (num == i) + return device; + device = device->next; + i++; + } + + ERROR("jtag device number %d not defined", num); + exit(-1); +} + +void* cmd_queue_alloc(size_t size) +{ + cmd_queue_page_t **p_page = &cmd_queue_pages; + int offset; + + if (*p_page) + { + while ((*p_page)->next) + p_page = &((*p_page)->next); + if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) + p_page = &((*p_page)->next); + } + + if (!*p_page) + { + *p_page = malloc(sizeof(cmd_queue_page_t)); + (*p_page)->used = 0; + (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE); + (*p_page)->next = NULL; + } + + offset = (*p_page)->used; + (*p_page)->used += size; + + u8 *t=(u8 *)((*p_page)->address); + return t + offset; +} + +void cmd_queue_free() +{ + cmd_queue_page_t *page = cmd_queue_pages; + + while (page) + { + cmd_queue_page_t *last = page; + free(page->address); + page = page->next; + free(last); + } + + cmd_queue_pages = NULL; +} + +int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + jtag_command_t **last_cmd; + jtag_device_t *device; + int i, j; + int scan_size = 0; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for ir scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 1; + (*last_cmd)->cmd.scan->num_fields = jtag_num_devices; /* one field per device */ + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < jtag_num_devices; i++) + { + int found = 0; + device = jtag_get_device(i); + scan_size = device->ir_length; + (*last_cmd)->cmd.scan->fields[i].device = i; + (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size; + (*last_cmd)->cmd.scan->fields[i].in_value = NULL; + (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; /* disable verification by default */ + + /* search the list */ + for (j = 0; j < num_fields; j++) + { + if (i == fields[j].device) + { + found = 1; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + + if (jtag_verify_capture_ir) + { + if (fields[j].in_handler==NULL) + { + jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL); + } else + { + (*last_cmd)->cmd.scan->fields[i].in_handler = fields[j].in_handler; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[j].in_handler_priv; + (*last_cmd)->cmd.scan->fields[i].in_check_value = device->expected; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = device->expected_mask; + } + } + + device->bypass = 0; + break; + } + } + + if (!found) + { + /* if a device isn't listed, set it to BYPASS */ + (*last_cmd)->cmd.scan->fields[i].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[i].out_mask = NULL; + device->bypass = 1; + + } + + /* update device information */ + buf_cpy((*last_cmd)->cmd.scan->fields[i].out_value, jtag_get_device(i)->cur_instr, scan_size); + } + + return ERROR_OK; +} + +int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + jtag_command_t **last_cmd; + int i; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for ir scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 1; + (*last_cmd)->cmd.scan->num_fields = num_fields; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < num_fields; i++) + { + int num_bits = fields[i].num_bits; + int num_bytes = CEIL(fields[i].num_bits, 8); + (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; + (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; + (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; + (*last_cmd)->cmd.scan->fields[i].in_handler = NULL; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL; + } + return ERROR_OK; +} + +int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + int i, j; + int bypass_devices = 0; + int field_count = 0; + jtag_command_t **last_cmd = jtag_get_last_command_p(); + jtag_device_t *device = jtag_devices; + int scan_size; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* count devices in bypass */ + while (device) + { + if (device->bypass) + bypass_devices++; + device = device->next; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for dr scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 0; + (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < jtag_num_devices; i++) + { + int found = 0; + (*last_cmd)->cmd.scan->fields[field_count].device = i; + + for (j = 0; j < num_fields; j++) + { + if (i == fields[j].device) + { + found = 1; + scan_size = fields[j].num_bits; + (*last_cmd)->cmd.scan->fields[field_count].num_bits = scan_size; + (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value; + (*last_cmd)->cmd.scan->fields[field_count].in_check_value = fields[j].in_check_value; + (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask; + (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler; + (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv; + } + } + if (!found) + { + /* if a device isn't listed, the BYPASS register should be selected */ + if (!jtag_get_device(i)->bypass) + { + ERROR("BUG: no scan data for a device not in BYPASS"); + exit(-1); + } + + /* program the scan field to 1 bit length, and ignore it's value */ + (*last_cmd)->cmd.scan->fields[field_count].num_bits = 1; + (*last_cmd)->cmd.scan->fields[field_count].out_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].out_mask = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_check_value = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = NULL; + (*last_cmd)->cmd.scan->fields[field_count].in_handler = NULL; + (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = NULL; + } + else + { + /* if a device is listed, the BYPASS register must not be selected */ + if (jtag_get_device(i)->bypass) + { + WARNING("scan data for a device in BYPASS"); + } + } + } + return ERROR_OK; +} + + +int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state) +{ + int i; + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_SCAN; + + /* allocate memory for scan command */ + (*last_cmd)->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); + (*last_cmd)->cmd.scan->ir_scan = 0; + (*last_cmd)->cmd.scan->num_fields = num_fields; + (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t)); + (*last_cmd)->cmd.scan->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + for (i = 0; i < num_fields; i++) + { + int num_bits = fields[i].num_bits; + int num_bytes = CEIL(fields[i].num_bits, 8); + (*last_cmd)->cmd.scan->fields[i].device = fields[i].device; + (*last_cmd)->cmd.scan->fields[i].num_bits = num_bits; + (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits); + (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value; + (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value; + (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask; + (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler; + (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv; + } + + return ERROR_OK; +} +int jtag_add_statemove(enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_STATEMOVE; + + (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); + (*last_cmd)->cmd.statemove->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + return ERROR_OK; +} + +int jtag_add_pathmove(int num_states, enum tap_state *path) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + int i; + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* the last state has to be a stable state */ + if (tap_move_map[path[num_states - 1]] == -1) + { + ERROR("TAP path doesn't finish in a stable state"); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->next = NULL; + (*last_cmd)->type = JTAG_PATHMOVE; + + (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t)); + (*last_cmd)->cmd.pathmove->num_states = num_states; + (*last_cmd)->cmd.pathmove->path = cmd_queue_alloc(sizeof(enum tap_state) * num_states); + + for (i = 0; i < num_states; i++) + (*last_cmd)->cmd.pathmove->path[i] = path[i]; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = path[num_states - 1]; + + return ERROR_OK; +} + +int jtag_add_runtest(int num_cycles, enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (jtag_trst == 1) + { + WARNING("JTAG command queued, while TRST is low (TAP in reset)"); + return ERROR_JTAG_TRST_ASSERTED; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_RUNTEST; + + (*last_cmd)->cmd.runtest = cmd_queue_alloc(sizeof(runtest_command_t)); + (*last_cmd)->cmd.runtest->num_cycles = num_cycles; + (*last_cmd)->cmd.runtest->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + if (cmd_queue_cur_state == TAP_TLR && cmd_queue_end_state != TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_RELEASED); + + if (cmd_queue_end_state == TAP_TLR) + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + + cmd_queue_cur_state = cmd_queue_end_state; + + return ERROR_OK; +} + +int jtag_add_reset(int req_trst, int req_srst) +{ + int trst_with_tms = 0; + + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + if (req_trst == -1) + req_trst = jtag_trst; + + if (req_srst == -1) + req_srst = jtag_srst; + + /* Make sure that jtag_reset_config allows the requested reset */ + /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */ + if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (req_trst == 0)) + return ERROR_JTAG_RESET_WOULD_ASSERT_TRST; + + /* if TRST pulls SRST, we reset with TAP T-L-R */ + if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_trst == 1)) && (req_srst == 0)) + { + req_trst = 0; + trst_with_tms = 1; + } + + if (req_srst && !(jtag_reset_config & RESET_HAS_SRST)) + { + ERROR("requested nSRST assertion, but the current configuration doesn't support this"); + return ERROR_JTAG_RESET_CANT_SRST; + } + + if (req_trst && !(jtag_reset_config & RESET_HAS_TRST)) + { + req_trst = 0; + trst_with_tms = 1; + } + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_RESET; + + (*last_cmd)->cmd.reset = cmd_queue_alloc(sizeof(reset_command_t)); + (*last_cmd)->cmd.reset->trst = req_trst; + (*last_cmd)->cmd.reset->srst = req_srst; + + jtag_trst = req_trst; + jtag_srst = req_srst; + + if (jtag_srst) + { + jtag_call_event_callbacks(JTAG_SRST_ASSERTED); + } + else + { + jtag_call_event_callbacks(JTAG_SRST_RELEASED); + if (jtag_nsrst_delay) + jtag_add_sleep(jtag_nsrst_delay * 1000); + } + + if (trst_with_tms) + { + last_cmd = &((*last_cmd)->next); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_STATEMOVE; + + (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t)); + (*last_cmd)->cmd.statemove->end_state = TAP_TLR; + + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + cmd_queue_cur_state = TAP_TLR; + cmd_queue_end_state = TAP_TLR; + + return ERROR_OK; + } + else + { + if (jtag_trst) + { + /* we just asserted nTRST, so we're now in Test-Logic-Reset, + * and inform possible listeners about this + */ + cmd_queue_cur_state = TAP_TLR; + jtag_call_event_callbacks(JTAG_TRST_ASSERTED); + } + else + { + /* the nTRST line got deasserted, so we're still in Test-Logic-Reset, + * but we might want to add a delay to give the TAP time to settle + */ + if (jtag_ntrst_delay) + jtag_add_sleep(jtag_ntrst_delay * 1000); + } + } + + return ERROR_OK; +} + +int jtag_add_end_state(enum tap_state state) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_END_STATE; + + (*last_cmd)->cmd.end_state = cmd_queue_alloc(sizeof(end_state_command_t)); + (*last_cmd)->cmd.end_state->end_state = state; + + if (state != -1) + cmd_queue_end_state = state; + + return ERROR_OK; +} + +int jtag_add_sleep(u32 us) +{ + jtag_command_t **last_cmd = jtag_get_last_command_p(); + + /* allocate memory for a new list member */ + *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + (*last_cmd)->next = NULL; + last_comand_pointer = &((*last_cmd)->next); + (*last_cmd)->type = JTAG_SLEEP; + + (*last_cmd)->cmd.sleep = cmd_queue_alloc(sizeof(sleep_command_t)); + (*last_cmd)->cmd.sleep->us = us; + + return ERROR_OK; +} + +int jtag_scan_size(scan_command_t *cmd) +{ + int bit_count = 0; + int i; + + /* count bits in scan command */ + for (i = 0; i < cmd->num_fields; i++) + { + bit_count += cmd->fields[i].num_bits; + } + + return bit_count; +} + +int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) +{ + int bit_count = 0; + int i; + + bit_count = jtag_scan_size(cmd); + *buffer = malloc(CEIL(bit_count, 8)); + + bit_count = 0; + + for (i = 0; i < cmd->num_fields; i++) + { + if (cmd->fields[i].out_value) + { +#ifdef _DEBUG_JTAG_IO_ + char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : cmd->fields[i].num_bits, 16); +#endif + buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); +#ifdef _DEBUG_JTAG_IO_ + DEBUG("fields[%i].out_value: 0x%s", i, char_buf); + free(char_buf); +#endif + } + + bit_count += cmd->fields[i].num_bits; + } + + return bit_count; + +} + +int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) +{ + int i; + int bit_count = 0; + int retval; + + /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ + retval = ERROR_OK; + + for (i = 0; i < cmd->num_fields; i++) + { + /* if neither in_value nor in_handler + * are specified we don't have to examine this field + */ + if (cmd->fields[i].in_value || cmd->fields[i].in_handler) + { + int num_bits = cmd->fields[i].num_bits; + u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits); + +#ifdef _DEBUG_JTAG_IO_ + char *char_buf; + + char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); + DEBUG("fields[%i].in_value: 0x%s", i, char_buf); + free(char_buf); +#endif + + if (cmd->fields[i].in_value) + { + buf_cpy(captured, cmd->fields[i].in_value, num_bits); + + if (cmd->fields[i].in_handler) + { + if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) + { + WARNING("in_handler reported a failed check"); + retval = ERROR_JTAG_QUEUE_FAILED; + } + } + } + + /* no in_value specified, but a handler takes care of the scanned data */ + if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value)) + { + if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv, cmd->fields+i) != ERROR_OK) + { + /* We're going to call the error:handler later, but if the in_handler + * reported an error we report this failure upstream + */ + WARNING("in_handler reported a failed check"); + retval = ERROR_JTAG_QUEUE_FAILED; + } + } + + free(captured); + } + bit_count += cmd->fields[i].num_bits; + } + + return retval; +} + +int jtag_check_value(u8 *captured, void *priv, scan_field_t *field) +{ + int retval = ERROR_OK; + int num_bits = field->num_bits; + + int compare_failed = 0; + + if (field->in_check_mask) + compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits); + else + compare_failed = buf_cmp(captured, field->in_check_value, num_bits); + + if (compare_failed) + { + /* An error handler could have caught the failing check + * only report a problem when there wasn't a handler, or if the handler + * acknowledged the error + */ + if (compare_failed) + { + char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16); + char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16); + + if (field->in_check_mask) + { + char *in_check_mask_char; + in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16); + WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char); + free(in_check_mask_char); + } + else + { + WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char); + } + + free(captured_char); + free(in_check_value_char); + + retval = ERROR_JTAG_QUEUE_FAILED; + } + + } + return retval; +} + +/* + set up checking of this field using the in_handler. The values passed in must be valid until + after jtag_execute() has completed. + */ +void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler) +{ + if (value) + field->in_handler = jtag_check_value; + else + field->in_handler = NULL; /* No check, e.g. embeddedice uses value==NULL to indicate no check */ + field->in_handler_priv = NULL; /* this will be filled in at the invocation site to point to the field duplicate */ + field->in_check_value = value; + field->in_check_mask = mask; +} + +enum scan_type jtag_scan_type(scan_command_t *cmd) +{ + int i; + int type = 0; + + for (i = 0; i < cmd->num_fields; i++) + { + if (cmd->fields[i].in_value || cmd->fields[i].in_handler) + type |= SCAN_IN; + if (cmd->fields[i].out_value) + type |= SCAN_OUT; + } + + return type; +} + +int jtag_execute_queue(void) +{ + int retval; + + retval = jtag->execute_queue(); + + cmd_queue_free(); + + jtag_command_queue = NULL; + last_comand_pointer = &jtag_command_queue; + + return retval; +} + +int jtag_reset_callback(enum jtag_event event, void *priv) +{ + jtag_device_t *device = priv; + + DEBUG("-"); + + if (event == JTAG_TRST_ASSERTED) + { + buf_set_ones(device->cur_instr, device->ir_length); + device->bypass = 1; + } + + return ERROR_OK; +} + +void jtag_sleep(u32 us) +{ + usleep(us); +} + +/* Try to examine chain layout according to IEEE 1149.1 §12 + */ +int jtag_examine_chain() +{ + jtag_device_t *device = jtag_devices; + scan_field_t field; + u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; + int i; + int bit_count; + int device_count = 0; + u8 zero_check = 0x0; + u8 one_check = 0xff; + + field.device = 0; + field.num_bits = sizeof(idcode_buffer) * 8; + field.out_value = idcode_buffer; + field.out_mask = NULL; + field.in_value = idcode_buffer; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) + { + buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF); + } + + jtag_add_plain_dr_scan(1, &field, TAP_TLR); + jtag_execute_queue(); + + for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++) + { + zero_check |= idcode_buffer[i]; + one_check &= idcode_buffer[i]; + } + + /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */ + if ((zero_check == 0x00) || (one_check == 0xff)) + { + ERROR("JTAG communication failure, check connection, JTAG interface, target power etc."); + return ERROR_JTAG_INIT_FAILED; + } + + for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;) + { + u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32); + if ((idcode & 1) == 0) + { + /* LSB must not be 0, this indicates a device in bypass */ + device_count++; + + bit_count += 1; + } + else + { + u32 manufacturer; + u32 part; + u32 version; + + if (idcode == 0x000000FF) + { + /* End of chain (invalid manufacturer ID) */ + break; + } + + if (device) + { + device->idcode = idcode; + device = device->next; + } + device_count++; + + manufacturer = (idcode & 0xffe) >> 1; + part = (idcode & 0xffff000) >> 12; + version = (idcode & 0xf0000000) >> 28; + + INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)", + idcode, manufacturer, part, version); + + bit_count += 32; + } + } + + /* see if number of discovered devices matches configuration */ + if (device_count != jtag_num_devices) + { + ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", + device_count, jtag_num_devices); + ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +int jtag_validate_chain() +{ + jtag_device_t *device = jtag_devices; + int total_ir_length = 0; + u8 *ir_test = NULL; + scan_field_t field; + int chain_pos = 0; + + while (device) + { + total_ir_length += device->ir_length; + device = device->next; + } + + total_ir_length += 2; + ir_test = malloc(CEIL(total_ir_length, 8)); + buf_set_ones(ir_test, total_ir_length); + + field.device = 0; + field.num_bits = total_ir_length; + field.out_value = ir_test; + field.out_mask = NULL; + field.in_value = ir_test; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_plain_ir_scan(1, &field, TAP_TLR); + jtag_execute_queue(); + + device = jtag_devices; + while (device) + { + if (buf_get_u32(ir_test, chain_pos, 2) != 0x1) + { + char *cbuf = buf_to_str(ir_test, total_ir_length, 16); + ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf); + free(cbuf); + free(ir_test); + return ERROR_JTAG_INIT_FAILED; + } + chain_pos += device->ir_length; + device = device->next; + } + + if (buf_get_u32(ir_test, chain_pos, 2) != 0x3) + { + char *cbuf = buf_to_str(ir_test, total_ir_length, 16); + ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf); + free(cbuf); + free(ir_test); + return ERROR_JTAG_INIT_FAILED; + } + + free(ir_test); + + return ERROR_OK; +} + +int jtag_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "interface", handle_interface_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command, + COMMAND_ANY, "set jtag speed (if supported) "); + register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command, + COMMAND_CONFIG, "jtag_device "); + register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command, + COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command, + COMMAND_CONFIG, NULL); + + register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command, + COMMAND_EXEC, "print current scan chain configuration"); + + register_command(cmd_ctx, NULL, "endstate", handle_endstate_command, + COMMAND_EXEC, "finish JTAG operations in "); + register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command, + COMMAND_EXEC, "toggle reset lines "); + register_command(cmd_ctx, NULL, "runtest", handle_runtest_command, + COMMAND_EXEC, "move to Run-Test/Idle, and execute "); + register_command(cmd_ctx, NULL, "statemove", handle_statemove_command, + COMMAND_EXEC, "move to current endstate or [tap_state]"); + register_command(cmd_ctx, NULL, "irscan", handle_irscan_command, + COMMAND_EXEC, "execute IR scan [dev2] [instr2] ..."); + register_command(cmd_ctx, NULL, "drscan", handle_drscan_command, + COMMAND_EXEC, "execute DR scan [dev2] [var2] ..."); + + register_command(cmd_ctx, NULL, "verify_ircapture", handle_verify_ircapture_command, + COMMAND_ANY, "verify value captured during Capture-IR "); + return ERROR_OK; +} + +int jtag_init(struct command_context_s *cmd_ctx) +{ + int i, validate_tries = 0; + + DEBUG("-"); + + if (jtag_speed == -1) + jtag_speed = 0; + + if (jtag_interface && (jtag_interface[0] != 0)) + /* configuration var 'jtag_interface' is set, and not empty */ + for (i = 0; jtag_interfaces[i]; i++) + { + if (strcmp(jtag_interface, jtag_interfaces[i]->name) == 0) + { + jtag_device_t *device; + device = jtag_devices; + + if (jtag_interfaces[i]->init() != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + jtag = jtag_interfaces[i]; + + jtag_ir_scan_size = 0; + jtag_num_devices = 0; + while (device != NULL) + { + jtag_ir_scan_size += device->ir_length; + jtag_num_devices++; + device = device->next; + } + + jtag_add_statemove(TAP_TLR); + jtag_execute_queue(); + + /* examine chain first, as this could discover the real chain layout */ + if (jtag_examine_chain() != ERROR_OK) + { + ERROR("trying to validate configured JTAG chain anyway..."); + } + + while (jtag_validate_chain() != ERROR_OK) + { + validate_tries++; + if (validate_tries > 5) + { + ERROR("Could not validate JTAG chain, exit"); + jtag = NULL; + return ERROR_JTAG_INVALID_INTERFACE; + } + usleep(10000); + } + + return ERROR_OK; + } + } + + /* no valid interface was found (i.e. the configuration option, + * didn't match one of the compiled-in interfaces + */ + ERROR("No valid jtag interface found (%s)", jtag_interface); + ERROR("compiled-in jtag interfaces:"); + for (i = 0; jtag_interfaces[i]; i++) + { + ERROR("%i: %s", i, jtag_interfaces[i]->name); + } + + jtag = NULL; + return ERROR_JTAG_INVALID_INTERFACE; +} + +int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + + /* only if the configuration var isn't overwritten from cmdline */ + if (!jtag_interface) + { + if (args[0] && (args[0][0] != 0)) + { + for (i=0; jtag_interfaces[i]; i++) + { + if (strcmp(args[0], jtag_interfaces[i]->name) == 0) + { + if (jtag_interfaces[i]->register_commands(cmd_ctx) != ERROR_OK) + exit(-1); + + jtag_interface = jtag_interfaces[i]->name; + + return ERROR_OK; + } + } + } + + /* remember the requested interface name, so we can complain about it later */ + jtag_interface = strdup(args[0]); + DEBUG("'interface' command didn't specify a valid interface"); + } + + return ERROR_OK; +} + +int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + jtag_device_t **last_device_p = &jtag_devices; + + if (*last_device_p) + { + while ((*last_device_p)->next) + last_device_p = &((*last_device_p)->next); + last_device_p = &((*last_device_p)->next); + } + + if (argc < 3) + return ERROR_OK; + + *last_device_p = malloc(sizeof(jtag_device_t)); + (*last_device_p)->ir_length = strtoul(args[0], NULL, 0); + + (*last_device_p)->expected = malloc((*last_device_p)->ir_length); + buf_set_u32((*last_device_p)->expected, 0, (*last_device_p)->ir_length, strtoul(args[1], NULL, 0)); + (*last_device_p)->expected_mask = malloc((*last_device_p)->ir_length); + buf_set_u32((*last_device_p)->expected_mask, 0, (*last_device_p)->ir_length, strtoul(args[2], NULL, 0)); + + (*last_device_p)->cur_instr = malloc((*last_device_p)->ir_length); + (*last_device_p)->bypass = 1; + buf_set_ones((*last_device_p)->cur_instr, (*last_device_p)->ir_length); + + (*last_device_p)->next = NULL; + + jtag_register_event_callback(jtag_reset_callback, (*last_device_p)); + + jtag_num_devices++; + + return ERROR_OK; +} + +int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + jtag_device_t *device = jtag_devices; + int device_count = 0; + + while (device) + { + u32 expected, expected_mask, cur_instr; + expected = buf_get_u32(device->expected, 0, device->ir_length); + expected_mask = buf_get_u32(device->expected_mask, 0, device->ir_length); + cur_instr = buf_get_u32(device->cur_instr, 0, device->ir_length); + command_print(cmd_ctx, "%i: idcode: 0x%8.8x ir length %i, ir capture 0x%x, ir mask 0x%x, current instruction 0x%x", device_count, device->idcode, device->ir_length, expected, expected_mask, cur_instr); + device = device->next; + device_count++; + } + + return ERROR_OK; +} + +int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc >= 1) + { + if (strcmp(args[0], "none") == 0) + jtag_reset_config = RESET_NONE; + else if (strcmp(args[0], "trst_only") == 0) + jtag_reset_config = RESET_HAS_TRST; + else if (strcmp(args[0], "srst_only") == 0) + jtag_reset_config = RESET_HAS_SRST; + else if (strcmp(args[0], "trst_and_srst") == 0) + jtag_reset_config = RESET_TRST_AND_SRST; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 2) + { + if (strcmp(args[1], "srst_pulls_trst") == 0) + jtag_reset_config |= RESET_SRST_PULLS_TRST; + else if (strcmp(args[1], "trst_pulls_srst") == 0) + jtag_reset_config |= RESET_TRST_PULLS_SRST; + else if (strcmp(args[1], "combined") == 0) + jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + else if (strcmp(args[1], "separate") == 0) + jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST); + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 3) + { + if (strcmp(args[2], "trst_open_drain") == 0) + jtag_reset_config |= RESET_TRST_OPEN_DRAIN; + else if (strcmp(args[2], "trst_push_pull") == 0) + jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + if (argc >= 4) + { + if (strcmp(args[3], "srst_push_pull") == 0) + jtag_reset_config |= RESET_SRST_PUSH_PULL; + else if (strcmp(args[3], "srst_open_drain") == 0) + jtag_reset_config &= ~RESET_SRST_PUSH_PULL; + else + { + ERROR("invalid reset_config argument, defaulting to none"); + jtag_reset_config = RESET_NONE; + return ERROR_INVALID_ARGUMENTS; + } + } + + return ERROR_OK; +} + +int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { + ERROR("jtag_nsrst_delay command takes one required argument"); + exit(-1); + } + else + { + jtag_nsrst_delay = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { + ERROR("jtag_ntrst_delay command takes one required argument"); + exit(-1); + } + else + { + jtag_ntrst_delay = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 0) + command_print(cmd_ctx, "jtag_speed: %i", jtag_speed); + + if (argc > 0) + { + /* this command can be called during CONFIG, + * in which case jtag isn't initialized */ + if (jtag) + jtag->speed(strtoul(args[0], NULL, 0)); + else + jtag_speed = strtoul(args[0], NULL, 0); + } + + return ERROR_OK; +} + +int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + enum tap_state state; + + if (argc < 1) + { return ERROR_COMMAND_SYNTAX_ERROR; - } - else - { - for (state = 0; state < 16; state++) - { - if (strcmp(args[0], tap_state_strings[state]) == 0) - { - jtag_add_end_state(state); - jtag_execute_queue(); - } - } - } - command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]); - - return ERROR_OK; -} - -int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int trst = -1; - int srst = -1; - int retval; - - if (argc < 1) - { + } + else + { + for (state = 0; state < 16; state++) + { + if (strcmp(args[0], tap_state_strings[state]) == 0) + { + jtag_add_end_state(state); + jtag_execute_queue(); + } + } + } + command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]); + + return ERROR_OK; +} + +int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int trst = -1; + int srst = -1; + int retval; + + if (argc < 1) + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (args[0][0] == '1') - trst = 1; - else if (args[0][0] == '0') - trst = 0; - else - { + } + + if (args[0][0] == '1') + trst = 1; + else if (args[0][0] == '0') + trst = 0; + else + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (args[1][0] == '1') - srst = 1; - else if (args[1][0] == '0') - srst = 0; - else - { + } + + if (args[1][0] == '1') + srst = 1; + else if (args[1][0] == '0') + srst = 0; + else + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK) - { - switch (retval) - { - case ERROR_JTAG_RESET_WOULD_ASSERT_TRST: - command_print(cmd_ctx, "requested reset would assert trst\nif this is acceptable, use jtag_reset 1 %c", args[1][0]); - break; - case ERROR_JTAG_RESET_CANT_SRST: - command_print(cmd_ctx, "can't assert srst because the current reset_config doesn't support it"); - break; - default: - command_print(cmd_ctx, "unknown error"); - } - } - jtag_execute_queue(); - - return ERROR_OK; -} - -int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc < 1) - { + } + + if ((retval = jtag_add_reset(trst, srst)) != ERROR_OK) + { + switch (retval) + { + case ERROR_JTAG_RESET_WOULD_ASSERT_TRST: + command_print(cmd_ctx, "requested reset would assert trst\nif this is acceptable, use jtag_reset 1 %c", args[1][0]); + break; + case ERROR_JTAG_RESET_CANT_SRST: + command_print(cmd_ctx, "can't assert srst because the current reset_config doesn't support it"); + break; + default: + command_print(cmd_ctx, "unknown error"); + } + } + jtag_execute_queue(); + + return ERROR_OK; +} + +int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc < 1) + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - jtag_add_runtest(strtol(args[0], NULL, 0), -1); - jtag_execute_queue(); - - return ERROR_OK; - -} - -int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - enum tap_state state; - - state = -1; - if (argc == 1) - { - for (state = 0; state < 16; state++) - { - if (strcmp(args[0], tap_state_strings[state]) == 0) - { - break; - } - } - } - - jtag_add_statemove(state); - jtag_execute_queue(); - - return ERROR_OK; - -} - -int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int i; - scan_field_t *fields; - - if ((argc < 2) || (argc % 2)) - { + } + + jtag_add_runtest(strtol(args[0], NULL, 0), -1); + jtag_execute_queue(); + + return ERROR_OK; + +} + +int handle_statemove_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + enum tap_state state; + + state = -1; + if (argc == 1) + { + for (state = 0; state < 16; state++) + { + if (strcmp(args[0], tap_state_strings[state]) == 0) + { + break; + } + } + } + + jtag_add_statemove(state); + jtag_execute_queue(); + + return ERROR_OK; + +} + +int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + scan_field_t *fields; + + if ((argc < 2) || (argc % 2)) + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - fields = malloc(sizeof(scan_field_t) * argc / 2); - - for (i = 0; i < argc / 2; i++) - { - int device = strtoul(args[i*2], NULL, 0); - int field_size = jtag_get_device(device)->ir_length; - fields[i].device = device; - fields[i].out_value = malloc(CEIL(field_size, 8)); - buf_set_u32(fields[i].out_value, 0, field_size, strtoul(args[i*2+1], NULL, 0)); - fields[i].out_mask = NULL; - fields[i].in_value = NULL; - fields[i].in_check_mask = NULL; - fields[i].in_handler = NULL; - fields[i].in_handler_priv = NULL; - } - - jtag_add_ir_scan(argc / 2, fields, -1, NULL); - jtag_execute_queue(); - - for (i = 0; i < argc / 2; i++) - free(fields[i].out_value); - - free (fields); - - return ERROR_OK; -} - -int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - scan_field_t *fields; - int num_fields = 0; - int field_count = 0; - var_t *var; - int i, j; - - if ((argc < 2) || (argc % 2)) - { + } + + fields = malloc(sizeof(scan_field_t) * argc / 2); + + for (i = 0; i < argc / 2; i++) + { + int device = strtoul(args[i*2], NULL, 0); + int field_size = jtag_get_device(device)->ir_length; + fields[i].device = device; + fields[i].out_value = malloc(CEIL(field_size, 8)); + buf_set_u32(fields[i].out_value, 0, field_size, strtoul(args[i*2+1], NULL, 0)); + fields[i].out_mask = NULL; + fields[i].in_value = NULL; + fields[i].in_check_mask = NULL; + fields[i].in_handler = NULL; + fields[i].in_handler_priv = NULL; + } + + jtag_add_ir_scan(argc / 2, fields, -1); + jtag_execute_queue(); + + for (i = 0; i < argc / 2; i++) + free(fields[i].out_value); + + free (fields); + + return ERROR_OK; +} + +int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + scan_field_t *fields; + int num_fields = 0; + int field_count = 0; + var_t *var; + int i, j; + + if ((argc < 2) || (argc % 2)) + { return ERROR_COMMAND_SYNTAX_ERROR; - } - - for (i = 0; i < argc; i+=2) - { - var = get_var_by_namenum(args[i+1]); - if (var) - { - num_fields += var->num_fields; - } - else - { - command_print(cmd_ctx, "variable %s doesn't exist", args[i+1]); - return ERROR_OK; - } - } - - fields = malloc(sizeof(scan_field_t) * num_fields); - - for (i = 0; i < argc; i+=2) - { - var = get_var_by_namenum(args[i+1]); - - for (j = 0; j < var->num_fields; j++) - { - fields[field_count].device = strtol(args[i], NULL, 0); - fields[field_count].num_bits = var->fields[j].num_bits; - fields[field_count].out_value = malloc(CEIL(var->fields[j].num_bits, 8)); - buf_set_u32(fields[field_count].out_value, 0, var->fields[j].num_bits, var->fields[j].value); - fields[field_count].out_mask = NULL; - fields[field_count].in_value = fields[field_count].out_value; - fields[field_count].in_check_mask = NULL; - fields[field_count].in_check_value = NULL; - fields[field_count].in_handler = field_le_to_host; - fields[field_count++].in_handler_priv = &(var->fields[j]); - } - } - - jtag_add_dr_scan(num_fields, fields, -1, NULL); - jtag_execute_queue(); - - for (i = 0; i < argc / 2; i++) - free(fields[i].out_value); - - free(fields); - - return ERROR_OK; -} - -int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ + } + + for (i = 0; i < argc; i+=2) + { + var = get_var_by_namenum(args[i+1]); + if (var) + { + num_fields += var->num_fields; + } + else + { + command_print(cmd_ctx, "variable %s doesn't exist", args[i+1]); + return ERROR_OK; + } + } + + fields = malloc(sizeof(scan_field_t) * num_fields); + + for (i = 0; i < argc; i+=2) + { + var = get_var_by_namenum(args[i+1]); + + for (j = 0; j < var->num_fields; j++) + { + fields[field_count].device = strtol(args[i], NULL, 0); + fields[field_count].num_bits = var->fields[j].num_bits; + fields[field_count].out_value = malloc(CEIL(var->fields[j].num_bits, 8)); + buf_set_u32(fields[field_count].out_value, 0, var->fields[j].num_bits, var->fields[j].value); + fields[field_count].out_mask = NULL; + fields[field_count].in_value = fields[field_count].out_value; + fields[field_count].in_check_mask = NULL; + fields[field_count].in_check_value = NULL; + fields[field_count].in_handler = field_le_to_host; + fields[field_count++].in_handler_priv = &(var->fields[j]); + } + } + + jtag_add_dr_scan(num_fields, fields, -1); + jtag_execute_queue(); + + for (i = 0; i < argc / 2; i++) + free(fields[i].out_value); + + free(fields); + + return ERROR_OK; +} + +int handle_verify_ircapture_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ if (argc == 1) - { - if (strcmp(args[0], "enable") == 0) - { - jtag_verify_capture_ir = 1; - } - else if (strcmp(args[0], "disable") == 0) - { - jtag_verify_capture_ir = 0; + { + if (strcmp(args[0], "enable") == 0) + { + jtag_verify_capture_ir = 1; + } + else if (strcmp(args[0], "disable") == 0) + { + jtag_verify_capture_ir = 0; } else { return ERROR_COMMAND_SYNTAX_ERROR; - } + } } else if (argc != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(cmd_ctx, "verify Capture-IR is %s", (jtag_verify_capture_ir) ? "enabled": "disabled"); - - return ERROR_OK; -} + + return ERROR_OK; +} diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index e5df6619..0e48a020 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -1,327 +1,327 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifndef JTAG_H -#define JTAG_H - -#include "types.h" -#include "binarybuffer.h" - -#include "command.h" - -#if 0 -#define _DEBUG_JTAG_IO_ -#endif - -/* Tap States - * TLR - Test-Logic-Reset, RTI - Run-Test/Idle, - * SDS - Select-DR-Scan, CD - Capture-DR, SD - Shift-DR, E1D - Exit1-DR, - * PD - Pause-DR, E2D - Exit2-DR, UD - Update-DR, - * SIS - Select-IR-Scan, CI - Capture-IR, SI - Shift-IR, E1I - Exit1-IR, - * PI - Pause-IR, E2I - Exit2-IR, UI - Update-IR - */ -enum tap_state -{ - TAP_TLR = 0x0, TAP_RTI = 0x8, - TAP_SDS = 0x1, TAP_CD = 0x2, TAP_SD = 0x3, TAP_E1D = 0x4, - TAP_PD = 0x5, TAP_E2D = 0x6, TAP_UD = 0x7, - TAP_SIS = 0x9, TAP_CI = 0xa, TAP_SI = 0xb, TAP_E1I = 0xc, - TAP_PI = 0xd, TAP_E2I = 0xe, TAP_UI = 0xf -}; - -typedef struct tap_transition_s -{ - enum tap_state high; - enum tap_state low; -} tap_transition_t; - -extern char* tap_state_strings[16]; -extern int tap_move_map[16]; /* map 16 TAP states to 6 stable states */ -extern u8 tap_move[6][6]; /* value scanned to TMS to move from one of six stable states to another */ -extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */ - -extern enum tap_state end_state; /* finish DR scans in dr_end_state */ -extern enum tap_state cur_state; /* current TAP state */ - -extern enum tap_state cmd_queue_end_state; /* finish DR scans in dr_end_state */ -extern enum tap_state cmd_queue_cur_state; /* current TAP state */ - -#define TAP_MOVE(from, to) tap_move[tap_move_map[from]][tap_move_map[to]] - -typedef void * error_handler_t; /* Later on we can delete error_handler_t, but keep it for now to make patches more readable */ - -struct scan_field_s; -typedef int (*in_handler_t)(u8 *in_value, void *priv, struct scan_field_s *field); - -typedef struct scan_field_s -{ - int device; /* ordinal device number this instruction refers to */ - int num_bits; /* number of bits this field specifies (up to 32) */ - u8 *out_value; /* value to be scanned into the device */ - u8 *out_mask; /* only masked bits care */ - u8 *in_value; /* pointer to a 32-bit memory location to take data scanned out */ - /* in_check_value/mask, in_handler_error_handler, in_handler_priv can be used by the in handler, otherwise they contain garbage */ - u8 *in_check_value; /* used to validate scan results */ - u8 *in_check_mask; /* check specified bits against check_value */ - in_handler_t in_handler; /* process received buffer using this handler */ - void *in_handler_priv; /* additional information for the in_handler */ -} scan_field_t; - -enum scan_type -{ - /* IN: from device to host, OUT: from host to device */ - SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3 -}; - -typedef struct scan_command_s -{ - int ir_scan; /* instruction/not data scan */ - int num_fields; /* number of fields in *fields array */ - scan_field_t *fields; /* pointer to an array of data scan fields */ - enum tap_state end_state; /* TAP state in which JTAG commands should finish */ -} scan_command_t; - -typedef struct statemove_command_s -{ - enum tap_state end_state; /* TAP state in which JTAG commands should finish */ -} statemove_command_t; - -typedef struct pathmove_command_s -{ - int num_states; /* number of states in *path */ - enum tap_state *path; /* states that have to be passed */ -} pathmove_command_t; - -typedef struct runtest_command_s -{ - int num_cycles; /* number of cycles that should be spent in Run-Test/Idle */ - enum tap_state end_state; /* TAP state in which JTAG commands should finish */ -} runtest_command_t; - -typedef struct reset_command_s -{ - int trst; /* trst/srst 0: deassert, 1: assert, -1: don't change */ - int srst; -} reset_command_t; - -typedef struct end_state_command_s -{ - enum tap_state end_state; /* TAP state in which JTAG commands should finish */ -} end_state_command_t; - -typedef struct sleep_command_s -{ - u32 us; /* number of microseconds to sleep */ -} sleep_command_t; - -typedef union jtag_command_container_u -{ - scan_command_t *scan; - statemove_command_t *statemove; - pathmove_command_t *pathmove; - runtest_command_t *runtest; - reset_command_t *reset; - end_state_command_t *end_state; - sleep_command_t *sleep; -} jtag_command_container_t; - -enum jtag_command_type -{ - JTAG_SCAN = 1, - JTAG_STATEMOVE = 2, JTAG_RUNTEST = 3, - JTAG_RESET = 4, JTAG_END_STATE = 5, - JTAG_PATHMOVE = 6, JTAG_SLEEP = 7 -}; - -typedef struct jtag_command_s -{ - jtag_command_container_t cmd; - enum jtag_command_type type; - struct jtag_command_s *next; -} jtag_command_t; - -extern jtag_command_t *jtag_command_queue; - -typedef struct jtag_device_s -{ - int ir_length; /* size of instruction register */ - u8 *expected; /* Capture-IR expected value */ - u8 *expected_mask; /* Capture-IR expected mask */ - u32 idcode; /* device identification code */ - u8 *cur_instr; /* current instruction */ - int bypass; /* bypass register selected */ - struct jtag_device_s *next; -} jtag_device_t; - -extern jtag_device_t *jtag_devices; -extern int jtag_num_devices; -extern int jtag_ir_scan_size; - -enum reset_line_mode -{ - LINE_OPEN_DRAIN = 0x0, - LINE_PUSH_PULL = 0x1, -}; - -typedef struct jtag_interface_s -{ - char* name; - - /* queued command execution - */ - int (*execute_queue)(void); - - /* interface initalization - */ - int (*speed)(int speed); - int (*register_commands)(struct command_context_s *cmd_ctx); - int (*init)(void); - int (*quit)(void); - -} jtag_interface_t; - -enum jtag_event -{ - JTAG_SRST_ASSERTED, - JTAG_TRST_ASSERTED, - JTAG_SRST_RELEASED, - JTAG_TRST_RELEASED, -}; - -extern char* jtag_event_strings[]; - -extern int jtag_trst; -extern int jtag_srst; - -typedef struct jtag_event_callback_s -{ - int (*callback)(enum jtag_event event, void *priv); - void *priv; - struct jtag_event_callback_s *next; -} jtag_event_callback_t; - -extern jtag_event_callback_t *jtag_event_callbacks; - -extern jtag_interface_t *jtag; /* global pointer to configured JTAG interface */ -extern enum tap_state end_state; -extern enum tap_state cur_state; - -extern char* jtag_interface; -extern int jtag_speed; - -enum reset_types -{ - RESET_NONE = 0x0, - RESET_HAS_TRST = 0x1, - RESET_HAS_SRST = 0x2, - RESET_TRST_AND_SRST = 0x3, - RESET_SRST_PULLS_TRST = 0x4, - RESET_TRST_PULLS_SRST = 0x8, - RESET_TRST_OPEN_DRAIN = 0x10, - RESET_SRST_PUSH_PULL = 0x20, -}; - -extern enum reset_types jtag_reset_config; - -/* JTAG subsystem */ -extern int jtag_init(struct command_context_s *cmd_ctx); -extern int jtag_register_commands(struct command_context_s *cmd_ctx); - -/* JTAG interface, can be implemented with a software or hardware fifo */ -extern int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, void *dummy_anachronism); -extern int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, void *dummy_anachronism); -extern int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, void *dummy_anachronism); -extern int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, void *dummy_anachronism); -/* execute a state transition within the JTAG standard, but the exact path - * path that is taken is undefined. Many implementations use precisely - * 7 clocks to perform a transition, but it could be more or less - * than that. - * - * The following assertions are made about certain common state moves: - * - * - A state move from Pause-[ID]R to Pause-[ID]R should always go through - * Update-[ID]R and Capture-[ID]R before returning to Pause-[ID]R, otherwise - * there's no way force a register update, if you can't go to Run-Test/Idle for - * some reason. - * - * - A state move from Pause-[ID]R to Shift-[ID]R must not go through - * Update-[ID]R. - * - * - Run-Test/Idle must not be entered unless requested, because R-T/I may have - * side effects. - */ -extern int jtag_add_statemove(enum tap_state endstate); -/* A list of unambigious single clock state transitions, not - * all drivers can support this, but it is required for e.g. - * XScale and Xilinx support - */ -extern int jtag_add_pathmove(int num_states, enum tap_state *path); -/* cycle precisely num_cycles in the TAP_RTI state */ -extern int jtag_add_runtest(int num_cycles, enum tap_state endstate); -extern int jtag_add_reset(int trst, int srst); -extern int jtag_add_end_state(enum tap_state endstate); -extern int jtag_add_sleep(u32 us); -/* - * For software FIFO implementations, the queued commands can be executed - * during this call or earlier. A sw queue might decide to push out - * some of the jtag_add_xxx() operations once the queue is "big enough". - * - * This fn will return an error code if any of the prior jtag_add_xxx() - * calls caused a failure, e.g. check failure. Note that it does not - * matter if the operation was executed *before* jtag_execute_queue(), - * jtag_execute_queue() will still return an error code. - * - * All jtag_add_xxx() calls that have in_handler!=NULL will have been - * executed when this fn returns, but if what has been queued only - * clocks data out, without reading anything back, then JTAG could - * be running *after* jtag_execute_queue() returns. The API does - * not define a way to flush a hw FIFO that runs *after* - * jtag_execute_queue() returns. - * - * jtag_add_xxx() commands can either be executed immediately or - * at some time between the jtag_add_xxx() fn call and jtag_execute_queue(). - */ -extern int jtag_execute_queue(void); - -/* JTAG support functions */ -extern void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler); -extern enum scan_type jtag_scan_type(scan_command_t *cmd); -extern int jtag_scan_size(scan_command_t *cmd); -extern int jtag_read_buffer(u8 *buffer, scan_command_t *cmd); -extern int jtag_build_buffer(scan_command_t *cmd, u8 **buffer); -extern jtag_device_t* jtag_get_device(int num); -extern void jtag_sleep(u32 us); -extern int jtag_call_event_callbacks(enum jtag_event event); -extern int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv); - -extern int jtag_verify_capture_ir; - - -/* error codes - * JTAG subsystem uses codes between -100 and -199 */ - -#define ERROR_JTAG_INIT_FAILED (-100) -#define ERROR_JTAG_INVALID_INTERFACE (-101) -#define ERROR_JTAG_NOT_IMPLEMENTED (-102) -#define ERROR_JTAG_TRST_ASSERTED (-103) -#define ERROR_JTAG_QUEUE_FAILED (-104) -#define ERROR_JTAG_RESET_WOULD_ASSERT_TRST (-105) -#define ERROR_JTAG_RESET_CANT_SRST (-106) -#define ERROR_JTAG_DEVICE_ERROR (-107) -#endif /* JTAG_H */ +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef JTAG_H +#define JTAG_H + +#include "types.h" +#include "binarybuffer.h" + +#include "command.h" + +#if 0 +#define _DEBUG_JTAG_IO_ +#endif + +/* Tap States + * TLR - Test-Logic-Reset, RTI - Run-Test/Idle, + * SDS - Select-DR-Scan, CD - Capture-DR, SD - Shift-DR, E1D - Exit1-DR, + * PD - Pause-DR, E2D - Exit2-DR, UD - Update-DR, + * SIS - Select-IR-Scan, CI - Capture-IR, SI - Shift-IR, E1I - Exit1-IR, + * PI - Pause-IR, E2I - Exit2-IR, UI - Update-IR + */ +enum tap_state +{ + TAP_TLR = 0x0, TAP_RTI = 0x8, + TAP_SDS = 0x1, TAP_CD = 0x2, TAP_SD = 0x3, TAP_E1D = 0x4, + TAP_PD = 0x5, TAP_E2D = 0x6, TAP_UD = 0x7, + TAP_SIS = 0x9, TAP_CI = 0xa, TAP_SI = 0xb, TAP_E1I = 0xc, + TAP_PI = 0xd, TAP_E2I = 0xe, TAP_UI = 0xf +}; + +typedef struct tap_transition_s +{ + enum tap_state high; + enum tap_state low; +} tap_transition_t; + +extern char* tap_state_strings[16]; +extern int tap_move_map[16]; /* map 16 TAP states to 6 stable states */ +extern u8 tap_move[6][6]; /* value scanned to TMS to move from one of six stable states to another */ +extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */ + +extern enum tap_state end_state; /* finish DR scans in dr_end_state */ +extern enum tap_state cur_state; /* current TAP state */ + +extern enum tap_state cmd_queue_end_state; /* finish DR scans in dr_end_state */ +extern enum tap_state cmd_queue_cur_state; /* current TAP state */ + +#define TAP_MOVE(from, to) tap_move[tap_move_map[from]][tap_move_map[to]] + +typedef void * error_handler_t; /* Later on we can delete error_handler_t, but keep it for now to make patches more readable */ + +struct scan_field_s; +typedef int (*in_handler_t)(u8 *in_value, void *priv, struct scan_field_s *field); + +typedef struct scan_field_s +{ + int device; /* ordinal device number this instruction refers to */ + int num_bits; /* number of bits this field specifies (up to 32) */ + u8 *out_value; /* value to be scanned into the device */ + u8 *out_mask; /* only masked bits care */ + u8 *in_value; /* pointer to a 32-bit memory location to take data scanned out */ + /* in_check_value/mask, in_handler_error_handler, in_handler_priv can be used by the in handler, otherwise they contain garbage */ + u8 *in_check_value; /* used to validate scan results */ + u8 *in_check_mask; /* check specified bits against check_value */ + in_handler_t in_handler; /* process received buffer using this handler */ + void *in_handler_priv; /* additional information for the in_handler */ +} scan_field_t; + +enum scan_type +{ + /* IN: from device to host, OUT: from host to device */ + SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3 +}; + +typedef struct scan_command_s +{ + int ir_scan; /* instruction/not data scan */ + int num_fields; /* number of fields in *fields array */ + scan_field_t *fields; /* pointer to an array of data scan fields */ + enum tap_state end_state; /* TAP state in which JTAG commands should finish */ +} scan_command_t; + +typedef struct statemove_command_s +{ + enum tap_state end_state; /* TAP state in which JTAG commands should finish */ +} statemove_command_t; + +typedef struct pathmove_command_s +{ + int num_states; /* number of states in *path */ + enum tap_state *path; /* states that have to be passed */ +} pathmove_command_t; + +typedef struct runtest_command_s +{ + int num_cycles; /* number of cycles that should be spent in Run-Test/Idle */ + enum tap_state end_state; /* TAP state in which JTAG commands should finish */ +} runtest_command_t; + +typedef struct reset_command_s +{ + int trst; /* trst/srst 0: deassert, 1: assert, -1: don't change */ + int srst; +} reset_command_t; + +typedef struct end_state_command_s +{ + enum tap_state end_state; /* TAP state in which JTAG commands should finish */ +} end_state_command_t; + +typedef struct sleep_command_s +{ + u32 us; /* number of microseconds to sleep */ +} sleep_command_t; + +typedef union jtag_command_container_u +{ + scan_command_t *scan; + statemove_command_t *statemove; + pathmove_command_t *pathmove; + runtest_command_t *runtest; + reset_command_t *reset; + end_state_command_t *end_state; + sleep_command_t *sleep; +} jtag_command_container_t; + +enum jtag_command_type +{ + JTAG_SCAN = 1, + JTAG_STATEMOVE = 2, JTAG_RUNTEST = 3, + JTAG_RESET = 4, JTAG_END_STATE = 5, + JTAG_PATHMOVE = 6, JTAG_SLEEP = 7 +}; + +typedef struct jtag_command_s +{ + jtag_command_container_t cmd; + enum jtag_command_type type; + struct jtag_command_s *next; +} jtag_command_t; + +extern jtag_command_t *jtag_command_queue; + +typedef struct jtag_device_s +{ + int ir_length; /* size of instruction register */ + u8 *expected; /* Capture-IR expected value */ + u8 *expected_mask; /* Capture-IR expected mask */ + u32 idcode; /* device identification code */ + u8 *cur_instr; /* current instruction */ + int bypass; /* bypass register selected */ + struct jtag_device_s *next; +} jtag_device_t; + +extern jtag_device_t *jtag_devices; +extern int jtag_num_devices; +extern int jtag_ir_scan_size; + +enum reset_line_mode +{ + LINE_OPEN_DRAIN = 0x0, + LINE_PUSH_PULL = 0x1, +}; + +typedef struct jtag_interface_s +{ + char* name; + + /* queued command execution + */ + int (*execute_queue)(void); + + /* interface initalization + */ + int (*speed)(int speed); + int (*register_commands)(struct command_context_s *cmd_ctx); + int (*init)(void); + int (*quit)(void); + +} jtag_interface_t; + +enum jtag_event +{ + JTAG_SRST_ASSERTED, + JTAG_TRST_ASSERTED, + JTAG_SRST_RELEASED, + JTAG_TRST_RELEASED, +}; + +extern char* jtag_event_strings[]; + +extern int jtag_trst; +extern int jtag_srst; + +typedef struct jtag_event_callback_s +{ + int (*callback)(enum jtag_event event, void *priv); + void *priv; + struct jtag_event_callback_s *next; +} jtag_event_callback_t; + +extern jtag_event_callback_t *jtag_event_callbacks; + +extern jtag_interface_t *jtag; /* global pointer to configured JTAG interface */ +extern enum tap_state end_state; +extern enum tap_state cur_state; + +extern char* jtag_interface; +extern int jtag_speed; + +enum reset_types +{ + RESET_NONE = 0x0, + RESET_HAS_TRST = 0x1, + RESET_HAS_SRST = 0x2, + RESET_TRST_AND_SRST = 0x3, + RESET_SRST_PULLS_TRST = 0x4, + RESET_TRST_PULLS_SRST = 0x8, + RESET_TRST_OPEN_DRAIN = 0x10, + RESET_SRST_PUSH_PULL = 0x20, +}; + +extern enum reset_types jtag_reset_config; + +/* JTAG subsystem */ +extern int jtag_init(struct command_context_s *cmd_ctx); +extern int jtag_register_commands(struct command_context_s *cmd_ctx); + +/* JTAG interface, can be implemented with a software or hardware fifo */ +extern int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate); +extern int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate); +extern int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate); +extern int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate); +/* execute a state transition within the JTAG standard, but the exact path + * path that is taken is undefined. Many implementations use precisely + * 7 clocks to perform a transition, but it could be more or less + * than that. + * + * The following assertions are made about certain common state moves: + * + * - A state move from Pause-[ID]R to Pause-[ID]R should always go through + * Update-[ID]R and Capture-[ID]R before returning to Pause-[ID]R, otherwise + * there's no way force a register update, if you can't go to Run-Test/Idle for + * some reason. + * + * - A state move from Pause-[ID]R to Shift-[ID]R must not go through + * Update-[ID]R. + * + * - Run-Test/Idle must not be entered unless requested, because R-T/I may have + * side effects. + */ +extern int jtag_add_statemove(enum tap_state endstate); +/* A list of unambigious single clock state transitions, not + * all drivers can support this, but it is required for e.g. + * XScale and Xilinx support + */ +extern int jtag_add_pathmove(int num_states, enum tap_state *path); +/* cycle precisely num_cycles in the TAP_RTI state */ +extern int jtag_add_runtest(int num_cycles, enum tap_state endstate); +extern int jtag_add_reset(int trst, int srst); +extern int jtag_add_end_state(enum tap_state endstate); +extern int jtag_add_sleep(u32 us); +/* + * For software FIFO implementations, the queued commands can be executed + * during this call or earlier. A sw queue might decide to push out + * some of the jtag_add_xxx() operations once the queue is "big enough". + * + * This fn will return an error code if any of the prior jtag_add_xxx() + * calls caused a failure, e.g. check failure. Note that it does not + * matter if the operation was executed *before* jtag_execute_queue(), + * jtag_execute_queue() will still return an error code. + * + * All jtag_add_xxx() calls that have in_handler!=NULL will have been + * executed when this fn returns, but if what has been queued only + * clocks data out, without reading anything back, then JTAG could + * be running *after* jtag_execute_queue() returns. The API does + * not define a way to flush a hw FIFO that runs *after* + * jtag_execute_queue() returns. + * + * jtag_add_xxx() commands can either be executed immediately or + * at some time between the jtag_add_xxx() fn call and jtag_execute_queue(). + */ +extern int jtag_execute_queue(void); + +/* JTAG support functions */ +extern void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler); +extern enum scan_type jtag_scan_type(scan_command_t *cmd); +extern int jtag_scan_size(scan_command_t *cmd); +extern int jtag_read_buffer(u8 *buffer, scan_command_t *cmd); +extern int jtag_build_buffer(scan_command_t *cmd, u8 **buffer); +extern jtag_device_t* jtag_get_device(int num); +extern void jtag_sleep(u32 us); +extern int jtag_call_event_callbacks(enum jtag_event event); +extern int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv); + +extern int jtag_verify_capture_ir; + + +/* error codes + * JTAG subsystem uses codes between -100 and -199 */ + +#define ERROR_JTAG_INIT_FAILED (-100) +#define ERROR_JTAG_INVALID_INTERFACE (-101) +#define ERROR_JTAG_NOT_IMPLEMENTED (-102) +#define ERROR_JTAG_TRST_ASSERTED (-103) +#define ERROR_JTAG_QUEUE_FAILED (-104) +#define ERROR_JTAG_RESET_WOULD_ASSERT_TRST (-105) +#define ERROR_JTAG_RESET_CANT_SRST (-106) +#define ERROR_JTAG_DEVICE_ERROR (-107) +#endif /* JTAG_H */ diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index a31c37d9..e0cd1a11 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -1,264 +1,264 @@ -/*************************************************************************** - * Copyright (C) 2006 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "virtex2.h" - -#include "pld.h" -#include "xilinx_bit.h" -#include "command.h" -#include "log.h" -#include "jtag.h" - -#include - -int virtex2_register_commands(struct command_context_s *cmd_ctx); -int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device); -int virtex2_load(struct pld_device_s *pld_device, char *filename); - -pld_driver_t virtex2_pld = -{ - .name = "virtex2", - .register_commands = virtex2_register_commands, - .pld_device_command = virtex2_pld_device_command, - .load = virtex2_load, -}; - -int virtex2_set_instr(int chain_pos, u32 new_instr) -{ - jtag_device_t *device = jtag_get_device(chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = chain_pos; - field.num_bits = device->ir_length; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_instr); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_ir_scan(1, &field, TAP_RTI, NULL); - - free(field.out_value); - } - - return ERROR_OK; -} - -int virtex2_send_32(struct pld_device_s *pld_device, int num_words, u32 *words) -{ - virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; - scan_field_t scan_field; - u8 *values; - int i; - - values = malloc(num_words * 4); - - scan_field.device = virtex2_info->chain_pos; - scan_field.num_bits = num_words * 32; - scan_field.out_value = values; - scan_field.out_mask = NULL; - scan_field.in_value = NULL; - scan_field.in_check_value = NULL; - scan_field.in_check_mask = NULL; - scan_field.in_handler = NULL; - scan_field.in_handler_priv = NULL; - - for (i = 0; i < num_words; i++) - buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); - - virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ - - jtag_add_dr_scan(1, &scan_field, TAP_PD, NULL); - - free(values); - - return ERROR_OK; -} - -int virtex2_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u32 *dest = priv; - *dest = flip_u32(le_to_h_u32(in_buf), 32); - return ERROR_OK; -} - -int virtex2_receive_32(struct pld_device_s *pld_device, int num_words, u32 *words) -{ - virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; - scan_field_t scan_field; - - scan_field.device = virtex2_info->chain_pos; - scan_field.num_bits = 32; - scan_field.out_value = NULL; - scan_field.out_mask = NULL; - scan_field.in_value = NULL; - scan_field.in_check_value = NULL; - scan_field.in_check_mask = NULL; - scan_field.in_handler = virtex2_jtag_buf_to_u32; - - virtex2_set_instr(virtex2_info->chain_pos, 0x4); /* CFG_OUT */ - - while (num_words--) - { - scan_field.in_handler_priv = words++; - jtag_add_dr_scan(1, &scan_field, TAP_PD, NULL); - } - - return ERROR_OK; -} - -int virtex2_read_stat(struct pld_device_s *pld_device, u32 *status) -{ - u32 data[5]; - - jtag_add_statemove(TAP_TLR); - - data[0] = 0xaa995566; /* synch word */ - data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ - data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ - data[3] = 0x20000000; /* NOOP */ - data[4] = 0x20000000; /* NOOP */ - virtex2_send_32(pld_device, 5, data); - - virtex2_receive_32(pld_device, 1, status); - - jtag_execute_queue(); - - DEBUG("status: 0x%8.8x", *status); - - return ERROR_OK; -} - -int virtex2_load(struct pld_device_s *pld_device, char *filename) -{ - virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; - xilinx_bit_file_t bit_file; - int retval; - int i; - - scan_field_t field; - - field.device = virtex2_info->chain_pos; - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - if ((retval = xilinx_read_bit_file(&bit_file, filename)) != ERROR_OK) - return retval; - - jtag_add_end_state(TAP_RTI); - virtex2_set_instr(virtex2_info->chain_pos, 0xb); /* JPROG_B */ - jtag_execute_queue(); - jtag_add_sleep(1000); - - virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ - jtag_execute_queue(); - - for (i = 0; i < bit_file.length; i++) - bit_file.data[i] = flip_u32(bit_file.data[i], 8); - - field.num_bits = bit_file.length * 8; - field.out_value = bit_file.data; - - jtag_add_dr_scan(1, &field, TAP_PD, NULL); - jtag_execute_queue(); - - jtag_add_statemove(TAP_TLR); - - jtag_add_end_state(TAP_RTI); - virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_RTI); - virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ - virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ - virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_RTI); - virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ - jtag_execute_queue(); - - return ERROR_OK; -} - -int virtex2_handle_read_stat_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - pld_device_t *device; - virtex2_pld_device_t *virtex2_info; - u32 status; - - if (argc < 1) - { - command_print(cmd_ctx, "usage: virtex2 read_stat "); - return ERROR_OK; - } - - device = get_pld_device_by_num(strtoul(args[0], NULL, 0)); - if (!device) - { - command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]); - return ERROR_OK; - } - - virtex2_info = device->driver_priv; - - virtex2_read_stat(device, &status); - - command_print(cmd_ctx, "virtex2 status register: 0x%8.8x", status); - - return ERROR_OK; -} - -int virtex2_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *virtex2_cmd = register_command(cmd_ctx, NULL, "virtex2", NULL, COMMAND_ANY, "virtex2 specific commands"); - - register_command(cmd_ctx, virtex2_cmd, "read_stat", virtex2_handle_read_stat_command, COMMAND_EXEC, - "read Virtex-II status register"); - - return ERROR_OK; -} - -int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device) -{ - virtex2_pld_device_t *virtex2_info; - - if (argc < 2) - { - WARNING("incomplete pld device 'virtex2' configuration"); - return ERROR_PLD_DEVICE_INVALID; - } - - virtex2_info = malloc(sizeof(virtex2_pld_device_t)); - pld_device->driver_priv = virtex2_info; - - virtex2_info->chain_pos = strtoul(args[1], NULL, 0); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2006 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "virtex2.h" + +#include "pld.h" +#include "xilinx_bit.h" +#include "command.h" +#include "log.h" +#include "jtag.h" + +#include + +int virtex2_register_commands(struct command_context_s *cmd_ctx); +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device); +int virtex2_load(struct pld_device_s *pld_device, char *filename); + +pld_driver_t virtex2_pld = +{ + .name = "virtex2", + .register_commands = virtex2_register_commands, + .pld_device_command = virtex2_pld_device_command, + .load = virtex2_load, +}; + +int virtex2_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, TAP_RTI); + + free(field.out_value); + } + + return ERROR_OK; +} + +int virtex2_send_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + u8 *values; + int i; + + values = malloc(num_words * 4); + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = num_words * 32; + scan_field.out_value = values; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = NULL; + scan_field.in_handler_priv = NULL; + + for (i = 0; i < num_words; i++) + buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + + jtag_add_dr_scan(1, &scan_field, TAP_PD); + + free(values); + + return ERROR_OK; +} + +int virtex2_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +int virtex2_receive_32(struct pld_device_s *pld_device, int num_words, u32 *words) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + scan_field_t scan_field; + + scan_field.device = virtex2_info->chain_pos; + scan_field.num_bits = 32; + scan_field.out_value = NULL; + scan_field.out_mask = NULL; + scan_field.in_value = NULL; + scan_field.in_check_value = NULL; + scan_field.in_check_mask = NULL; + scan_field.in_handler = virtex2_jtag_buf_to_u32; + + virtex2_set_instr(virtex2_info->chain_pos, 0x4); /* CFG_OUT */ + + while (num_words--) + { + scan_field.in_handler_priv = words++; + jtag_add_dr_scan(1, &scan_field, TAP_PD); + } + + return ERROR_OK; +} + +int virtex2_read_stat(struct pld_device_s *pld_device, u32 *status) +{ + u32 data[5]; + + jtag_add_statemove(TAP_TLR); + + data[0] = 0xaa995566; /* synch word */ + data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ + data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ + data[3] = 0x20000000; /* NOOP */ + data[4] = 0x20000000; /* NOOP */ + virtex2_send_32(pld_device, 5, data); + + virtex2_receive_32(pld_device, 1, status); + + jtag_execute_queue(); + + DEBUG("status: 0x%8.8x", *status); + + return ERROR_OK; +} + +int virtex2_load(struct pld_device_s *pld_device, char *filename) +{ + virtex2_pld_device_t *virtex2_info = pld_device->driver_priv; + xilinx_bit_file_t bit_file; + int retval; + int i; + + scan_field_t field; + + field.device = virtex2_info->chain_pos; + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + if ((retval = xilinx_read_bit_file(&bit_file, filename)) != ERROR_OK) + return retval; + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xb); /* JPROG_B */ + jtag_execute_queue(); + jtag_add_sleep(1000); + + virtex2_set_instr(virtex2_info->chain_pos, 0x5); /* CFG_IN */ + jtag_execute_queue(); + + for (i = 0; i < bit_file.length; i++) + bit_file.data[i] = flip_u32(bit_file.data[i], 8); + + field.num_bits = bit_file.length * 8; + field.out_value = bit_file.data; + + jtag_add_dr_scan(1, &field, TAP_PD); + jtag_execute_queue(); + + jtag_add_statemove(TAP_TLR); + + jtag_add_end_state(TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + virtex2_set_instr(virtex2_info->chain_pos, 0xc); /* JSTART */ + jtag_add_runtest(13, TAP_RTI); + virtex2_set_instr(virtex2_info->chain_pos, 0x3f); /* BYPASS */ + jtag_execute_queue(); + + return ERROR_OK; +} + +int virtex2_handle_read_stat_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + pld_device_t *device; + virtex2_pld_device_t *virtex2_info; + u32 status; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: virtex2 read_stat "); + return ERROR_OK; + } + + device = get_pld_device_by_num(strtoul(args[0], NULL, 0)); + if (!device) + { + command_print(cmd_ctx, "pld device '#%s' is out of bounds", args[0]); + return ERROR_OK; + } + + virtex2_info = device->driver_priv; + + virtex2_read_stat(device, &status); + + command_print(cmd_ctx, "virtex2 status register: 0x%8.8x", status); + + return ERROR_OK; +} + +int virtex2_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *virtex2_cmd = register_command(cmd_ctx, NULL, "virtex2", NULL, COMMAND_ANY, "virtex2 specific commands"); + + register_command(cmd_ctx, virtex2_cmd, "read_stat", virtex2_handle_read_stat_command, COMMAND_EXEC, + "read Virtex-II status register"); + + return ERROR_OK; +} + +int virtex2_pld_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct pld_device_s *pld_device) +{ + virtex2_pld_device_t *virtex2_info; + + if (argc < 2) + { + WARNING("incomplete pld device 'virtex2' configuration"); + return ERROR_PLD_DEVICE_INVALID; + } + + virtex2_info = malloc(sizeof(virtex2_pld_device_t)); + pld_device->driver_priv = virtex2_info; + + virtex2_info->chain_pos = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} diff --git a/src/target/arm11.c b/src/target/arm11.c new file mode 100644 index 00000000..11e376a6 --- /dev/null +++ b/src/target/arm11.c @@ -0,0 +1,1358 @@ +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm11.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + + +#if 0 +#define FNC_INFO DEBUG("-") +#else +#define FNC_INFO +#endif + +#if 1 +#define FNC_INFO_NOTIMPLEMENTED do { DEBUG("NOT IMPLEMENTED"); /*exit(-1);*/ } while (0) +#else +#define FNC_INFO_NOTIMPLEMENTED +#endif + +static void arm11_on_enter_debug_state(arm11_common_t * arm11); + + +#define ARM11_HANDLER(x) \ + .x = arm11_##x + +target_type_t arm11_target = +{ + .name = "arm11", + + ARM11_HANDLER(poll), + ARM11_HANDLER(arch_state), + + ARM11_HANDLER(target_request_data), + + ARM11_HANDLER(halt), + ARM11_HANDLER(resume), + ARM11_HANDLER(step), + + ARM11_HANDLER(assert_reset), + ARM11_HANDLER(deassert_reset), + ARM11_HANDLER(soft_reset_halt), + ARM11_HANDLER(prepare_reset_halt), + + ARM11_HANDLER(get_gdb_reg_list), + + ARM11_HANDLER(read_memory), + ARM11_HANDLER(write_memory), + + ARM11_HANDLER(bulk_write_memory), + + ARM11_HANDLER(checksum_memory), + + ARM11_HANDLER(add_breakpoint), + ARM11_HANDLER(remove_breakpoint), + ARM11_HANDLER(add_watchpoint), + ARM11_HANDLER(remove_watchpoint), + + ARM11_HANDLER(run_algorithm), + + ARM11_HANDLER(register_commands), + ARM11_HANDLER(target_command), + ARM11_HANDLER(init_target), + ARM11_HANDLER(quit), +}; + +int arm11_regs_arch_type = -1; + + +enum arm11_regtype +{ + ARM11_REGISTER_CORE, + ARM11_REGISTER_CPSR, + + ARM11_REGISTER_FX, + ARM11_REGISTER_FPS, + + ARM11_REGISTER_FIQ, + ARM11_REGISTER_SVC, + ARM11_REGISTER_ABT, + ARM11_REGISTER_IRQ, + ARM11_REGISTER_UND, + ARM11_REGISTER_MON, + + ARM11_REGISTER_SPSR_FIQ, + ARM11_REGISTER_SPSR_SVC, + ARM11_REGISTER_SPSR_ABT, + ARM11_REGISTER_SPSR_IRQ, + ARM11_REGISTER_SPSR_UND, + ARM11_REGISTER_SPSR_MON, + + /* debug regs */ + ARM11_REGISTER_DSCR, + ARM11_REGISTER_WDTR, + ARM11_REGISTER_RDTR, +}; + + +typedef struct arm11_reg_defs_s +{ + char * name; + u32 num; + int gdb_num; + enum arm11_regtype type; +} arm11_reg_defs_t; + +/* update arm11_regcache_ids when changing this */ +static const arm11_reg_defs_t arm11_reg_defs[] = +{ + {"r0", 0, 0, ARM11_REGISTER_CORE}, + {"r1", 1, 1, ARM11_REGISTER_CORE}, + {"r2", 2, 2, ARM11_REGISTER_CORE}, + {"r3", 3, 3, ARM11_REGISTER_CORE}, + {"r4", 4, 4, ARM11_REGISTER_CORE}, + {"r5", 5, 5, ARM11_REGISTER_CORE}, + {"r6", 6, 6, ARM11_REGISTER_CORE}, + {"r7", 7, 7, ARM11_REGISTER_CORE}, + {"r8", 8, 8, ARM11_REGISTER_CORE}, + {"r9", 9, 9, ARM11_REGISTER_CORE}, + {"r10", 10, 10, ARM11_REGISTER_CORE}, + {"r11", 11, 11, ARM11_REGISTER_CORE}, + {"r12", 12, 12, ARM11_REGISTER_CORE}, + {"sp", 13, 13, ARM11_REGISTER_CORE}, + {"lr", 14, 14, ARM11_REGISTER_CORE}, + {"pc", 15, 15, ARM11_REGISTER_CORE}, + +#if ARM11_REGCACHE_FREGS + {"f0", 0, 16, ARM11_REGISTER_FX}, + {"f1", 1, 17, ARM11_REGISTER_FX}, + {"f2", 2, 18, ARM11_REGISTER_FX}, + {"f3", 3, 19, ARM11_REGISTER_FX}, + {"f4", 4, 20, ARM11_REGISTER_FX}, + {"f5", 5, 21, ARM11_REGISTER_FX}, + {"f6", 6, 22, ARM11_REGISTER_FX}, + {"f7", 7, 23, ARM11_REGISTER_FX}, + {"fps", 0, 24, ARM11_REGISTER_FPS}, +#endif + + {"cpsr", 0, 25, ARM11_REGISTER_CPSR}, + +#if ARM11_REGCACHE_MODEREGS + {"r8_fiq", 8, -1, ARM11_REGISTER_FIQ}, + {"r9_fiq", 9, -1, ARM11_REGISTER_FIQ}, + {"r10_fiq", 10, -1, ARM11_REGISTER_FIQ}, + {"r11_fiq", 11, -1, ARM11_REGISTER_FIQ}, + {"r12_fiq", 12, -1, ARM11_REGISTER_FIQ}, + {"r13_fiq", 13, -1, ARM11_REGISTER_FIQ}, + {"r14_fiq", 14, -1, ARM11_REGISTER_FIQ}, + {"spsr_fiq", 0, -1, ARM11_REGISTER_SPSR_FIQ}, + + {"r13_svc", 13, -1, ARM11_REGISTER_SVC}, + {"r14_svc", 14, -1, ARM11_REGISTER_SVC}, + {"spsr_svc", 0, -1, ARM11_REGISTER_SPSR_SVC}, + + {"r13_abt", 13, -1, ARM11_REGISTER_ABT}, + {"r14_abt", 14, -1, ARM11_REGISTER_ABT}, + {"spsr_abt", 0, -1, ARM11_REGISTER_SPSR_ABT}, + + {"r13_irq", 13, -1, ARM11_REGISTER_IRQ}, + {"r14_irq", 14, -1, ARM11_REGISTER_IRQ}, + {"spsr_irq", 0, -1, ARM11_REGISTER_SPSR_IRQ}, + + {"r13_und", 13, -1, ARM11_REGISTER_UND}, + {"r14_und", 14, -1, ARM11_REGISTER_UND}, + {"spsr_und", 0, -1, ARM11_REGISTER_SPSR_UND}, + + /* ARM1176 only */ + {"r13_mon", 13, -1, ARM11_REGISTER_MON}, + {"r14_mon", 14, -1, ARM11_REGISTER_MON}, + {"spsr_mon", 0, -1, ARM11_REGISTER_SPSR_MON}, +#endif + + /* Debug Registers */ + {"dscr", 0, -1, ARM11_REGISTER_DSCR}, + {"wdtr", 0, -1, ARM11_REGISTER_WDTR}, + {"rdtr", 0, -1, ARM11_REGISTER_RDTR}, +}; + +enum arm11_regcache_ids +{ + ARM11_RC_R0, + ARM11_RC_RX = ARM11_RC_R0, + + ARM11_RC_R1, + ARM11_RC_R2, + ARM11_RC_R3, + ARM11_RC_R4, + ARM11_RC_R5, + ARM11_RC_R6, + ARM11_RC_R7, + ARM11_RC_R8, + ARM11_RC_R9, + ARM11_RC_R10, + ARM11_RC_R11, + ARM11_RC_R12, + ARM11_RC_R13, + ARM11_RC_SP = ARM11_RC_R13, + ARM11_RC_R14, + ARM11_RC_LR = ARM11_RC_R14, + ARM11_RC_R15, + ARM11_RC_PC = ARM11_RC_R15, + +#if ARM11_REGCACHE_FREGS + ARM11_RC_F0, + ARM11_RC_FX = ARM11_RC_F0, + ARM11_RC_F1, + ARM11_RC_F2, + ARM11_RC_F3, + ARM11_RC_F4, + ARM11_RC_F5, + ARM11_RC_F6, + ARM11_RC_F7, + ARM11_RC_FPS, +#endif + + ARM11_RC_CPSR, + +#if ARM11_REGCACHE_MODEREGS + ARM11_RC_R8_FIQ, + ARM11_RC_R9_FIQ, + ARM11_RC_R10_FIQ, + ARM11_RC_R11_FIQ, + ARM11_RC_R12_FIQ, + ARM11_RC_R13_FIQ, + ARM11_RC_R14_FIQ, + ARM11_RC_SPSR_FIQ, + + ARM11_RC_R13_SVC, + ARM11_RC_R14_SVC, + ARM11_RC_SPSR_SVC, + + ARM11_RC_R13_ABT, + ARM11_RC_R14_ABT, + ARM11_RC_SPSR_ABT, + + ARM11_RC_R13_IRQ, + ARM11_RC_R14_IRQ, + ARM11_RC_SPSR_IRQ, + + ARM11_RC_R13_UND, + ARM11_RC_R14_UND, + ARM11_RC_SPSR_UND, + + ARM11_RC_R13_MON, + ARM11_RC_R14_MON, + ARM11_RC_SPSR_MON, +#endif + + ARM11_RC_DSCR, + ARM11_RC_WDTR, + ARM11_RC_RDTR, + + + ARM11_RC_MAX, +}; + +#define ARM11_GDB_REGISTER_COUNT 26 + +u8 arm11_gdb_dummy_fp_value[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fp_reg = +{ + "GDB dummy floating-point register", arm11_gdb_dummy_fp_value, 0, 1, 96, NULL, 0, NULL, 0 +}; + +u8 arm11_gdb_dummy_fps_value[] = {0, 0, 0, 0}; + +reg_t arm11_gdb_dummy_fps_reg = +{ + "GDB dummy floating-point status register", arm11_gdb_dummy_fps_value, 0, 1, 32, NULL, 0, NULL, 0 +}; + + + +/** Check and if necessary take control of the system + * + * \param arm11 Target state variable. + * \param dscr If the current DSCR content is + * available a pointer to a word holding the + * DSCR can be passed. Otherwise use NULL. + */ +void arm11_check_init(arm11_common_t * arm11, u32 * dscr) +{ + FNC_INFO; + + u32 dscr_local_tmp_copy; + + if (!dscr) + { + dscr = &dscr_local_tmp_copy; + *dscr = arm11_read_DSCR(arm11); + } + + if (!(*dscr & ARM11_DSCR_MODE_SELECT)) + { + DEBUG("Bringing target into debug mode"); + + *dscr |= ARM11_DSCR_MODE_SELECT; /* Halt debug-mode */ + arm11_write_DSCR(arm11, *dscr); + + /* add further reset initialization here */ + + if (*dscr & ARM11_DSCR_CORE_HALTED) + { + arm11->target->state = TARGET_HALTED; + arm11->target->debug_reason = arm11_get_DSCR_debug_reason(*dscr); + } + else + { + arm11->target->state = TARGET_RUNNING; + arm11->target->debug_reason = DBG_REASON_NOTHALTED; + } + + arm11_sc7_clear_bw(arm11); + } +} + + + +#define R(x) \ + (arm11->reg_values[ARM11_RC_##x]) + +/** Save processor state. + * + * This is called when the HALT instruction has succeeded + * or on other occasions that stop the processor. + * + */ +static void arm11_on_enter_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + {size_t i; + for(i = 0; i < asizeof(arm11->reg_values); i++) + { + arm11->reg_list[i].valid = 1; + arm11->reg_list[i].dirty = 0; + }} + + /* Save DSCR */ + + R(DSCR) = arm11_read_DSCR(arm11); + + /* Save wDTR */ + + if (R(DSCR) & ARM11_DSCR_WDTR_FULL) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + arm11_setup_field(arm11, 32, NULL, &R(WDTR), chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + else + { + arm11->reg_list[ARM11_RC_WDTR].valid = 0; + } + + + /* DSCR: set ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE */ + /* ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", but not to issue ITRs + ARM1136 seems to require this to issue ITR's as well */ + + u32 new_dscr = R(DSCR) | ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE; + + /* this executes JTAG queue: */ + + arm11_write_DSCR(arm11, new_dscr); + +// jtag_execute_queue(); + + + +// DEBUG("SAVE DSCR %08x", R(DSCR)); + +// if (R(DSCR) & ARM11_DSCR_WDTR_FULL) +// DEBUG("SAVE wDTR %08x", R(WDTR)); + + + /* From the spec: + Before executing any instruction in debug state you have to drain the write buffer. + This ensures that no imprecise Data Aborts can return at a later point:*/ + + /** \todo TODO: Test drain write buffer. */ + +#if 0 + while (1) + { + /* MRC p14,0,R0,c5,c10,0 */ +// arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000); + + /* mcr 15, 0, r0, cr7, cr10, {4} */ + arm11_run_instr_no_data1(arm11, 0xee070f9a); + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) + { + arm11_run_instr_no_data1(arm11, 0xe320f000); + + dscr = arm11_read_DSCR(arm11); + + DEBUG("DRAIN, DSCR %08x (DONE)", dscr); + + break; + } + } +#endif + + + arm11_run_instr_data_prepare(arm11); + + /* save r0 - r14 */ + + + /** \todo TODO: handle other mode registers */ + + {size_t i; + for (i = 0; i < 15; i++) + { + /* MCR p14,0,R?,c0,c5,0 */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15 | (i << 12), &R(RX + i), 1); + }} + + + /* save rDTR */ + + /* check rDTRfull in DSCR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL) + { + /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &R(RDTR)); + } + else + { + arm11->reg_list[ARM11_RC_RDTR].valid = 0; + } + + /* save CPSR */ + + /* MRS r0,CPSR (move CPSR -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE10F0000, &R(CPSR)); + + /* save PC */ + + /* MOV R0,PC (move PC -> r0 (-> wDTR -> local var)) */ + arm11_run_instr_data_from_core_via_r0(arm11, 0xE1A0000F, &R(PC)); + + /* adjust PC depending on ARM state */ + + if (R(CPSR) & ARM11_CPSR_J) /* Java state */ + { + arm11->reg_values[ARM11_RC_PC] -= 0; + } + else if (R(CPSR) & ARM11_CPSR_T) /* Thumb state */ + { + arm11->reg_values[ARM11_RC_PC] -= 4; + } + else /* ARM state */ + { + arm11->reg_values[ARM11_RC_PC] -= 8; + } + +// DEBUG("SAVE PC %08x", R(PC)); + + arm11_run_instr_data_finish(arm11); + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + if (!arm11->reg_list[i].valid) + { + if (arm11->reg_history[i].valid) + INFO("%8s INVALID (%08x)", arm11_reg_defs[i].name, arm11->reg_history[i].value); + } + else + { + if (arm11->reg_history[i].valid) + { + if (arm11->reg_history[i].value != arm11->reg_values[i]) + INFO("%8s %08x (%08x)", arm11_reg_defs[i].name, arm11->reg_values[i], arm11->reg_history[i].value); + } + else + { + INFO("%8s %08x (INVALID)", arm11_reg_defs[i].name, arm11->reg_values[i]); + } + } + }} +} + + +/** Restore processor state + * + * This is called in preparation for the RESTART function. + * + */ +void arm11_leave_debug_state(arm11_common_t * arm11) +{ + FNC_INFO; + + arm11_run_instr_data_prepare(arm11); + + /** \todo TODO: handle other mode registers */ + + /* restore R1 - R14 */ + {size_t i; + for (i = 1; i < 15; i++) + { + if (!arm11->reg_list[ARM11_RC_RX + i].dirty) + continue; + + /* MRC p14,0,r?,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15 | (i << 12), R(RX + i)); + +// DEBUG("RESTORE R%d %08x", i, R(RX + i)); + }} + + arm11_run_instr_data_finish(arm11); + + + /* spec says clear wDTR and rDTR; we assume they are clear as + otherwide out programming would be sloppy */ + + { + u32 DSCR = arm11_read_DSCR(arm11); + + if (DSCR & (ARM11_DSCR_RDTR_FULL | ARM11_DSCR_WDTR_FULL)) + { + ERROR("wDTR/rDTR inconsistent (DSCR %08x)", DSCR); + } + } + + arm11_run_instr_data_prepare(arm11); + + /* restore original wDTR */ + + if ((R(DSCR) & ARM11_DSCR_WDTR_FULL) || arm11->reg_list[ARM11_RC_WDTR].dirty) + { + /* MCR p14,0,R0,c0,c5,0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, R(WDTR)); + } + + /* restore CPSR */ + + /* MSR CPSR,R0*/ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe129f000, R(CPSR)); + + + /* restore PC */ + + /* MOV PC,R0 */ + arm11_run_instr_data_to_core_via_r0(arm11, 0xe1a0f000, R(PC)); + + + /* restore R0 */ + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xee100e15, R(R0)); + + arm11_run_instr_data_finish(arm11); + + + /* restore DSCR */ + + arm11_write_DSCR(arm11, R(DSCR)); + + + /* restore rDTR */ + + if (R(DSCR) & ARM11_DSCR_RDTR_FULL || arm11->reg_list[ARM11_RC_RDTR].dirty) + { + arm11_add_debug_SCAN_N(arm11, 0x05, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u8 Ready = 0; /* ignored */ + u8 Valid = 0; /* ignored */ + + arm11_setup_field(arm11, 32, &R(RDTR), NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); + arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + } + + + {size_t i; + for(i = 0; i < ARM11_REGCACHE_COUNT; i++) + { + arm11->reg_history[i].value = arm11->reg_values[i]; + arm11->reg_history[i].valid = arm11->reg_list[i].valid; + + arm11->reg_list[i].valid = 0; + arm11->reg_list[i].dirty = 0; + }} +} + + +/* poll current target status */ +int arm11_poll(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + if (arm11->trst_active) + return ERROR_OK; + + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + arm11_check_init(arm11, &dscr); + + if (dscr & ARM11_DSCR_CORE_HALTED) + { +// DEBUG("CH %d", target->state); + + if (target->state != TARGET_HALTED) + { + DEBUG("enter TARGET_HALTED"); + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + arm11_on_enter_debug_state(arm11); + } + } + else + { +// DEBUG("CR %d", target->state); + + if (target->state != TARGET_RUNNING) + { + DEBUG("enter TARGET_RUNNING"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + } + + return ERROR_OK; +} +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + + + +/* target execution control */ +int arm11_halt(struct target_s *target) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + + if (arm11->trst_active) + { + arm11->halt_requested = true; + return ERROR_OK; + } + + arm11_add_IR(arm11, ARM11_HALT, TAP_RTI); + + jtag_execute_queue(); + + u32 dscr; + + while (1) + { + dscr = arm11_read_DSCR(arm11); + + if (dscr & ARM11_DSCR_CORE_HALTED) + break; + } + + arm11_on_enter_debug_state(arm11); + + target->state = TARGET_HALTED; + target->debug_reason = arm11_get_DSCR_debug_reason(dscr); + + return ERROR_OK; +} + + +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + FNC_INFO; + + arm11_common_t * arm11 = target->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!current) + R(PC) = address; + + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if (dscr & ARM11_DSCR_CORE_RESTARTED) + break; + } + + DEBUG("RES %d", target->state); + + return ERROR_OK; +} + +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + FNC_INFO; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state != TARGET_HALTED) + { + WARNING("target was not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + arm11_common_t * arm11 = target->arch_info; + + /** \todo TODO: check if break-/watchpoints make any sense at all in combination + * with this. */ + + /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively + the VCR might be something worth looking into. */ + + /* Set up breakpoint for stepping */ + + arm11_sc7_action_t brp[2]; + + brp[0].write = 1; + brp[0].address = ARM11_SC7_BVR0; + brp[0].value = R(PC); + brp[1].write = 1; + brp[1].address = ARM11_SC7_BCR0; + brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); + + arm11_sc7_run(arm11, brp, asizeof(brp)); + + /* resume */ + + arm11_leave_debug_state(arm11); + + arm11_add_IR(arm11, ARM11_RESTART, TAP_RTI); + + jtag_execute_queue(); + + /** \todo TODO: add a timeout */ + + /* wait for halt */ + + while (1) + { + u32 dscr = arm11_read_DSCR(arm11); + + DEBUG("DSCR %08x", dscr); + + if ((dscr & (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) == + (ARM11_DSCR_CORE_RESTARTED | ARM11_DSCR_CORE_HALTED)) + break; + } + + + /* clear breakpoint */ + + arm11_sc7_clear_bw(arm11); + + + /* save state */ + + arm11_on_enter_debug_state(arm11); + +// target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_SINGLESTEP; + + return ERROR_OK; +} + + +/* target reset control */ +int arm11_assert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + /* assert reset lines */ + /* resets only the DBGTAP, not the ARM */ + + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + + arm11_common_t * arm11 = target->arch_info; + arm11->trst_active = true; +#endif + + return ERROR_OK; +} + +int arm11_deassert_reset(struct target_s *target) +{ + FNC_INFO; + +#if 0 + 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; +} + +int arm11_prepare_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; + + if (target->state != TARGET_HALTED) + { + return ERROR_TARGET_NOT_HALTED; + } + + *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 +*/ +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; + + 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; + + while (count--) + { + /* 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; + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* 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; + } + 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; + + 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: + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + while (count--) + { + /* 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); + } + break; + + case 2: + { + arm11->reg_list[ARM11_RC_R1].dirty = 1; + + u16 * buf16 = (u16*)buffer; + + while (count--) + { + /* 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); + } + break; + } + + case 4: + /** \todo TODO: check if buffer cast to u32* might cause alignment problems */ + + /* STC p14,c5,[R0],#4 */ + arm11_run_instr_data_to_core(arm11, 0xeca05e01, (u32 *)buffer, count); + break; + } + + 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; + + 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) +{ + FNC_INFO_NOTIMPLEMENTED; + + return ERROR_OK; +} + +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + FNC_INFO_NOTIMPLEMENTED; + + 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_register_commands(struct command_context_s *cmd_ctx) +{ + FNC_INFO; + + 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) + { + ERROR("'target arm11' 4th argument "); + 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) + { + 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) +{ + 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); + + jtag_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); + + jtag_add_dr_scan_vc(asizeof(chain0_fields), chain0_fields, TAP_RTI); + + jtag_execute_queue(); + + + switch (arm11->device_id & 0x0FFFF000) + { + case 0x07B36000: INFO("found ARM1136"); break; + case 0x07B56000: INFO("found ARM1156"); break; + case 0x07B76000: INFO("found ARM1176"); break; + default: + { + ERROR("'target arm11' expects IDCODE 0x*7B*7****"); + exit(-1); + } + } + + arm11->brp = ((arm11->didr >> 24) & 0x0F) + 1; + arm11->wrp = ((arm11->didr >> 28) & 0x0F) + 1; + + + 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) + { + return ERROR_TARGET_NOT_HALTED; + } + + /** \todo TODO: Check this. We assume that all registers are fetched 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; +// 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; + +// 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) + { + ERROR("arm11->reg_values inconsistent (%d %d %d %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; + } +} + +#if 0 + arm11_run_instr_data_prepare(arm11); + + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee100e15, 0xCA00003C); + /* MRC p14,0,r1,c0,c5,0 */ + arm11_run_instr_data_to_core(arm11, 0xee101e15, 0xFFFFFFFF); + + arm11_run_instr_data_finish(arm11); +#endif + + diff --git a/src/target/arm11.h b/src/target/arm11.h new file mode 100644 index 00000000..4e061ae4 --- /dev/null +++ b/src/target/arm11.h @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef ARM11_H +#define ARM11_H + +#include "target.h" +#include "register.h" +#include "embeddedice.h" +#include "arm_jtag.h" + + +#define bool int +#define true 1 +#define false 0 + +#define asizeof(x) (sizeof(x) / sizeof((x)[0])) + +#define NEW(type, variable, items) \ + type * variable = malloc(sizeof(type) * items) + + +#define ARM11_REGCACHE_MODEREGS 0 +#define ARM11_REGCACHE_FREGS 0 + +#define ARM11_REGCACHE_COUNT (20 + \ + 23 * ARM11_REGCACHE_MODEREGS + \ + 9 * ARM11_REGCACHE_FREGS) + + +typedef struct arm11_register_history_s +{ + u32 value; + u8 valid; +}arm11_register_history_t; + + + +typedef struct arm11_common_s +{ + target_t * target; + + arm_jtag_t jtag_info; + + /** \name Processor type detection */ + /*@{*/ + + u32 device_id; /**< IDCODE readout */ + u32 didr; /**< DIDR readout (debug capabilities) */ + u8 implementor; /**< DIDR Implementor readout */ + + size_t brp; /**< Number of Breakpoint Register Pairs */ + size_t wrp; /**< Number of Watchpoint Register Pairs */ + + /*@}*/ + + + u32 last_dscr; /**< Last retrieved DSCR value; + * Can be used to detect changes */ + + u8 trst_active; + u8 halt_requested; + + /** \name Shadow registers to save processor state */ + /*@{*/ + + reg_t * reg_list; /**< target register list */ + u32 reg_values[ARM11_REGCACHE_COUNT]; /**< data for registers */ + + /*@}*/ + + arm11_register_history_t + reg_history[ARM11_REGCACHE_COUNT]; /**< register state before last resume */ + + +} arm11_common_t; + + +/** + * ARM11 DBGTAP instructions + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html + */ +enum arm11_instructions +{ + ARM11_EXTEST = 0x00, + ARM11_SCAN_N = 0x02, + ARM11_RESTART = 0x04, + ARM11_HALT = 0x08, + ARM11_INTEST = 0x0C, + ARM11_ITRSEL = 0x1D, + ARM11_IDCODE = 0x1E, + ARM11_BYPASS = 0x1F, +}; + +enum arm11_dscr +{ + ARM11_DSCR_CORE_HALTED = 1 << 0, + ARM11_DSCR_CORE_RESTARTED = 1 << 1, + + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2, + ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2, + + ARM11_DSCR_STICKY_PRECISE_DATA_ABORT = 1 << 6, + ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT = 1 << 7, + ARM11_DSCR_EXECUTE_ARM_INSTRUCTION_ENABLE = 1 << 13, + ARM11_DSCR_MODE_SELECT = 1 << 14, + ARM11_DSCR_WDTR_FULL = 1 << 29, + ARM11_DSCR_RDTR_FULL = 1 << 30, +}; + +enum arm11_cpsr +{ + ARM11_CPSR_T = 1 << 5, + ARM11_CPSR_J = 1 << 24, +}; + +enum arm11_sc7 +{ + ARM11_SC7_NULL = 0, + ARM11_SC7_VCR = 7, + ARM11_SC7_PC = 8, + ARM11_SC7_BVR0 = 64, + ARM11_SC7_BCR0 = 80, + ARM11_SC7_WVR0 = 96, + ARM11_SC7_WCR0 = 112, +}; + + + +typedef struct arm11_reg_state_s +{ + u32 def_index; + target_t * target; +} arm11_reg_state_t; + + + + +/* poll current target status */ +int arm11_poll(struct target_s *target); +/* architecture specific status reply */ +int arm11_arch_state(struct target_s *target); + +/* target request support */ +int arm11_target_request_data(struct target_s *target, u32 size, u8 *buffer); + +/* target execution control */ +int arm11_halt(struct target_s *target); +int arm11_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int arm11_step(struct target_s *target, int current, u32 address, int handle_breakpoints); + +/* target reset control */ +int arm11_assert_reset(struct target_s *target); +int arm11_deassert_reset(struct target_s *target); +int arm11_soft_reset_halt(struct target_s *target); +int arm11_prepare_reset_halt(struct target_s *target); + +/* target register access for gdb */ +int arm11_get_gdb_reg_list(struct target_s *target, struct reg_s **reg_list[], int *reg_list_size); + +/* target memory access +* size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) +* count: number of items of +*/ +int arm11_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm11_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); + +/* 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); + +int arm11_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +/* target break-/watchpoint control +* rw: 0 = write, 1 = read, 2 = access +*/ +int arm11_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int arm11_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int arm11_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); + +/* 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); + +int arm11_register_commands(struct command_context_s *cmd_ctx); +int arm11_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm11_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm11_quit(void); + + +/* helpers */ +void arm11_build_reg_cache(target_t *target); + + +/* internals */ + +void arm11_setup_field (arm11_common_t * arm11, int num_bits, void * in_data, void * out_data, scan_field_t * field); +void arm11_add_IR (arm11_common_t * arm11, u8 instr, enum tap_state state); +void arm11_add_debug_SCAN_N (arm11_common_t * arm11, u8 chain, enum tap_state state); +void arm11_add_debug_INST (arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state); +u32 arm11_read_DSCR (arm11_common_t * arm11); +void arm11_write_DSCR (arm11_common_t * arm11, u32 dscr); + +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr); + +void arm11_run_instr_data_prepare (arm11_common_t * arm11); +void arm11_run_instr_data_finish (arm11_common_t * arm11); +void arm11_run_instr_no_data (arm11_common_t * arm11, u32 * opcode, size_t count); +void arm11_run_instr_no_data1 (arm11_common_t * arm11, u32 opcode); +void arm11_run_instr_data_to_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_to_core1 (arm11_common_t * arm11, u32 opcode, u32 data); +void arm11_run_instr_data_from_core (arm11_common_t * arm11, u32 opcode, u32 * data, size_t count); +void arm11_run_instr_data_from_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 * data); +void arm11_run_instr_data_to_core_via_r0 (arm11_common_t * arm11, u32 opcode, u32 data); + + +typedef struct arm11_sc7_action_s +{ + bool write; + u8 address; + u32 value; +} arm11_sc7_action_t; + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count); +void arm11_sc7_clear_bw(arm11_common_t * arm11); + + + +#endif /* ARM11_H */ diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c new file mode 100644 index 00000000..13b412c5 --- /dev/null +++ b/src/target/arm11_dbgtap.c @@ -0,0 +1,611 @@ +/*************************************************************************** + * Copyright (C) 2008 digenius technology GmbH. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm11.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define JTAG_DEBUG(expr ...) \ + do { \ + log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \ + } while(0) +#else +#define JTAG_DEBUG(expr ...) \ + do {} while(0) +#endif + +/** Code de-clutter: Construct scan_field_t to write out a value + * + * \param arm11 Target state variable. + * \param num_bits Length of the data field + * \param out_data pointer to the data that will be sent out + * (data is read when it is added to the JTAG queue) + * \param in_data pointer to the memory that will receive data that was clocked in + * (data is written when the JTAG queue is executed) + * \param field target data structure that will be initialized + */ +void arm11_setup_field(arm11_common_t * arm11, int num_bits, void * out_data, void * in_data, scan_field_t * field) +{ + field->device = arm11->jtag_info.chain_pos; + field->num_bits = num_bits; + field->out_mask = NULL; + field->in_check_mask = NULL; + field->in_check_value = NULL; + field->in_handler = NULL; + field->in_handler_priv = NULL; + + field->out_value = out_data; + field->in_value = in_data; +} + + +/** Write JTAG instruction register + * + * \param arm11 Target state variable. + * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. + * \param state Pass the final TAP state or -1 for the default value (Pause-IR). + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_IR(arm11_common_t * arm11, u8 instr, enum tap_state state) +{ + jtag_device_t *device = jtag_get_device(arm11->jtag_info.chain_pos); + + if (buf_get_u32(device->cur_instr, 0, 5) == instr) + { + JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); + return; + } + + JTAG_DEBUG("IR <= 0x%02x", instr); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &instr, NULL, &field); + + jtag_add_ir_scan_vc(1, &field, state == -1 ? TAP_PI : state); +} + +/** Verify shifted out data from Scan Chain Register (SCREG) + * Used as parameter to scan_field_t::in_handler in + * arm11_add_debug_SCAN_N(). + * + */ +static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field) +{ + /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */ + u8 v = *in_value & 0x1F; + + if (v != 0x10) + { + ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v); + exit(-1); + } + + JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); + return ERROR_OK; +} + +/** Select and write to Scan Chain Register (SCREG) + * + * This function sets the instruction register to SCAN_N and writes + * the data register with the selected chain number. + * + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html + * + * \param arm11 Target state variable. + * \param chain Scan chain that will be selected. + * \param state Pass the final TAP state or -1 for the default + * value (Pause-DR). + * + * The chain takes effect when Update-DR is passed (usually when subsequently + * the INTEXT/EXTEST instructions are written). + * + * \warning (Obsolete) Using this twice in a row will \em fail. The first call will end + * in Pause-DR. The second call, due to the IR caching, will not + * go through Capture-DR when shifting in the new scan chain number. + * As a result the verification in arm11_in_handler_SCAN_N() must + * fail. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ + +void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, enum tap_state state) +{ + JTAG_DEBUG("SCREG <= 0x%02x", chain); + + arm11_add_IR(arm11, ARM11_SCAN_N, -1); + + scan_field_t field; + + arm11_setup_field(arm11, 5, &chain, NULL, &field); + + field.in_handler = arm11_in_handler_SCAN_N; + + jtag_add_dr_scan_vc(1, &field, state == -1 ? TAP_PD : state); +} + +/** Write an instruction into the ITR register + * + * \param arm11 Target state variable. + * \param inst An ARM11 processor instruction/opcode. + * \param flag Optional parameter to retrieve the InstCompl flag + * (this will be written when the JTAG chain is executed). + * \param state Pass the final TAP state or -1 for the default + * value (Run-Test/Idle). + * + * \remarks By default this ends with Run-Test/Idle state + * and causes the instruction to be executed. If + * a subsequent write to DTR is needed before + * executing the instruction then TAP_PD should be + * passed to \p state. + * + * \remarks This adds to the JTAG command queue but does \em not execute it. + */ +void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, enum tap_state state) +{ + JTAG_DEBUG("INST <= 0x%08x", inst); + + scan_field_t itr[2]; + + arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); + arm11_setup_field(arm11, 1, NULL, flag, itr + 1); + + jtag_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_RTI : state); +} + +/** Read the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \return DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +u32 arm11_read_DSCR(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + u32 dscr; + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + if (arm11->last_dscr != dscr) + JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; + + return dscr; +} + +/** Write the Debug Status and Control Register (DSCR) + * + * same as CP14 c1 + * + * \param arm11 Target state variable. + * \param dscr DSCR content + * + * \remarks This is a stand-alone function that executes the JTAG command queue. + */ +void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr) +{ + arm11_add_debug_SCAN_N(arm11, 0x01, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain1_field; + + arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); + + jtag_add_dr_scan_vc(1, &chain1_field, TAP_PD); + + jtag_execute_queue(); + + JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr); + + arm11->last_dscr = dscr; +} + + + +/** Get the debug reason from Debug Status and Control Register (DSCR) + * + * \param dscr DSCR value to analyze + * \return Debug reason + * + */ +enum target_debug_reason arm11_get_DSCR_debug_reason(u32 dscr) +{ + switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK) + { + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: return DBG_REASON_WATCHPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: return DBG_REASON_BREAKPOINT; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: return DBG_REASON_DBGRQ; + case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: return DBG_REASON_BREAKPOINT; + + default: + return DBG_REASON_DBGRQ; + } +}; + + + +/** Prepare the stage for ITR/DTR operations + * from the arm11_run_instr... group of functions. + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Select scan chain 5 to allow quick access to DTR. When scan + * chain 4 is needed to put in a register the ITRSel instruction + * shortcut is used instead of actually changing the Scan_N + * register. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_prepare(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x05, -1); +} + +/** Cleanup after ITR/DTR operations + * from the arm11_run_instr... group of functions + * + * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() + * around a block of arm11_run_instr_... calls. + * + * Any RTI can lead to an instruction execution when + * scan chains 4 or 5 are selected and the IR holds + * INTEST or EXTEST. So we must disable that before + * any following activities lead to an RTI. + * + * \param arm11 Target state variable. + * + */ +void arm11_run_instr_data_finish(arm11_common_t * arm11) +{ + arm11_add_debug_SCAN_N(arm11, 0x00, -1); +} + + +/** Execute one or multiple instructions via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode Pointer to sequence of ARM opcodes + * \param count Number of opcodes to execute + * + */ +void arm11_run_instr_no_data(arm11_common_t * arm11, u32 * opcode, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + while (count--) + { + arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_RTI); + + while (1) + { + u8 flag; + + arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_RTI : TAP_PD); + + jtag_execute_queue(); + + if (flag) + break; + } + } +} + +/** Execute one instruction via ITR + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * + */ +void arm11_run_instr_no_data1(arm11_common_t * arm11, u32 opcode) +{ + arm11_run_instr_no_data(arm11, &opcode, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * passing data to the core via DTR on each execution. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to the data words to be passed to the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_to_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_PD); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + Data = *data; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_RTI); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); + } + while (!Ready); + + data++; + } + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + do + { + Data = 0; + + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + +} + +/** Execute an instruction via ITR while handing data into the core via DTR. + * + * The executed instruction \em must read data from DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Data word to be passed to the core via DTR + * + */ +void arm11_run_instr_data_to_core1(arm11_common_t * arm11, u32 opcode, u32 data) +{ + arm11_run_instr_data_to_core(arm11, opcode, &data, 1); +} + + +/** Execute one instruction via ITR repeatedly while + * reading data from the core via DTR on each execution. + * + * The executed instruction \em must write data to DTR. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode + * \param data Pointer to an array that receives the data words from the core + * \param count Number of data words and instruction repetitions + * + */ +void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) +{ + arm11_add_IR(arm11, ARM11_ITRSEL, -1); + + arm11_add_debug_INST(arm11, opcode, NULL, TAP_RTI); + + arm11_add_IR(arm11, ARM11_INTEST, -1); + + scan_field_t chain5_fields[3]; + + u32 Data; + u8 Ready; + u8 nRetry; + + arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); + arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); + arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); + + while (count--) + { + do + { + jtag_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_RTI : TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); + } + while (!Ready); + + *data++ = Data; + } +} + +/** Execute one instruction via ITR + * then load r0 into DTR and read DTR from core. + * + * The first executed instruction (\p opcode) should write data to r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to write r0 with the value of interest + * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. + * + */ +void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data) +{ + arm11_run_instr_no_data1(arm11, opcode); + + /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ + arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); +} + +/** Load data into core via DTR then move it to r0 then + * execute one instruction via ITR + * + * The final executed instruction (\p opcode) should read data from r0. + * + * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block + * + * \param arm11 Target state variable. + * \param opcode ARM opcode to read r0 act upon it + * \param data Data word that will be written to r0 before \p opcode is executed + * + */ +void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data) +{ + /* MRC p14,0,r0,c0,c5,0 */ + arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); + + arm11_run_instr_no_data1(arm11, opcode); +} + + +void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count) +{ + arm11_add_debug_SCAN_N(arm11, 0x07, -1); + + arm11_add_IR(arm11, ARM11_EXTEST, -1); + + scan_field_t chain7_fields[3]; + + u8 nRW; + u32 DataOut; + u8 AddressOut; + u8 Ready; + u32 DataIn; + u8 AddressIn; + + arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); + arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); + arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); + + {size_t i; + for (i = 0; i < count + 1; i++) + { + if (i < count) + { + nRW = actions[i].write ? 1 : 0; + DataOut = actions[i].value; + AddressOut = actions[i].address; + } + else + { + nRW = 0; + DataOut = 0; + AddressOut = 0; + } + + do + { + JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW); + + jtag_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_PD); + jtag_execute_queue(); + + JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready); + } + while (!Ready); /* 'nRW' is 'Ready' on read out */ + + if (i > 0) + { + if (actions[i - 1].address != AddressIn) + { + WARNING("Scan chain 7 shifted out unexpected address"); + } + + if (!actions[i - 1].write) + { + actions[i - 1].value = DataIn; + } + else + { + if (actions[i - 1].value != DataIn) + { + WARNING("Scan chain 7 shifted out unexpected data"); + } + } + } + }} + + {size_t i; + for (i = 0; i < count; i++) + { + JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value); + }} +} + +void arm11_sc7_clear_bw(arm11_common_t * arm11) +{ + size_t actions = arm11->brp + arm11->wrp; + + arm11_sc7_action_t clear_bw[actions]; + + {size_t i; + for (i = 0; i < actions; i++) + { + clear_bw[i].write = true; + clear_bw[i].value = 0; + clear_bw[i].address = + i < arm11->brp ? + ARM11_SC7_BCR0 + i : + ARM11_SC7_WCR0 + i - arm11->brp; + }} + + arm11_sc7_run(arm11, clear_bw, actions); +} + diff --git a/src/target/arm720t.c b/src/target/arm720t.c index 62b70e3b..87a1afb4 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -1,626 +1,626 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm720t.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm720t_register_commands(struct command_context_s *cmd_ctx); - -int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* forward declarations */ -int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm720t_quit(); -int arm720t_arch_state(struct target_s *target); -int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm720t_soft_reset_halt(struct target_s *target); - -target_type_t arm720t_target = -{ - .name = "arm720t", - - .poll = arm7_9_poll, - .arch_state = arm720t_arch_state, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm720t_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm720t_read_memory, - .write_memory = arm720t_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm720t_register_commands, - .target_command = arm720t_target_command, - .init_target = arm720t_init_target, - .quit = arm720t_quit -}; - -int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[2]; - u8 out_buf[4]; - u8 instruction_buf = instruction; - - buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = &instruction_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = out_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - if (in) - { - fields[1].in_handler = arm_jtag_buf_to_u32_flip; - fields[1].in_handler_priv = in; - } else - { - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - } - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - if (clock) - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - jtag_execute_queue(); - - if (in) - DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock); - else - DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); -#else - DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); -#endif - - return ERROR_OK; -} - -int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value) -{ - /* fetch CP15 opcode */ - arm720t_scan_cp15(target, opcode, NULL, 1, 1); - /* "DECODE" stage */ - arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); - /* "EXECUTE" stage (1) */ - arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); - arm720t_scan_cp15(target, 0x0, NULL, 0, 1); - /* "EXECUTE" stage (2) */ - arm720t_scan_cp15(target, 0x0, NULL, 0, 1); - /* "EXECUTE" stage (3), CDATA is read */ - arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1); - - return ERROR_OK; -} - -int arm720t_write_cp15(target_t *target, u32 opcode, u32 value) -{ - /* fetch CP15 opcode */ - arm720t_scan_cp15(target, opcode, NULL, 1, 1); - /* "DECODE" stage */ - arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); - /* "EXECUTE" stage (1) */ - arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); - arm720t_scan_cp15(target, 0x0, NULL, 0, 1); - /* "EXECUTE" stage (2) */ - arm720t_scan_cp15(target, value, NULL, 0, 1); - arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); - - return ERROR_OK; -} - -u32 arm720t_get_ttb(target_t *target) -{ - u32 ttb = 0x0; - - arm720t_read_cp15(target, 0xee120f10, &ttb); - jtag_execute_queue(); - - ttb &= 0xffffc000; - - return ttb; -} - -void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - u32 cp15_control; - - /* read cp15 control register */ - arm720t_read_cp15(target, 0xee110f10, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control &= ~0x1U; - - if (d_u_cache || i_cache) - cp15_control &= ~0x4U; - - arm720t_write_cp15(target, 0xee010f10, cp15_control); -} - -void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - u32 cp15_control; - - /* read cp15 control register */ - arm720t_read_cp15(target, 0xee110f10, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache || i_cache) - cp15_control |= 0x4U; - - arm720t_write_cp15(target, 0xee010f10, cp15_control); -} - -void arm720t_post_debug_entry(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; - arm720t_common_t *arm720t = arm7tdmi->arch_info; - - /* examine cp15 control reg */ - arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg); - jtag_execute_queue(); - DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg); - - arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - - /* save i/d fault status and address register */ - arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); - arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); - jtag_execute_queue(); -} - -void arm720t_pre_restore_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; - arm720t_common_t *arm720t = arm7tdmi->arch_info; - - /* restore i/d fault status and address register */ - arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg); - arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); -} - -int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm7tdmi_common_t *arm7tdmi; - arm720t_common_t *arm720t; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - return -1; - } - - arm7_9 = armv4_5->arch_info; - if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) - { - return -1; - } - - arm7tdmi = arm7_9->arch_info; - if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC) - { - return -1; - } - - arm720t = arm7tdmi->arch_info; - if (arm720t->common_magic != ARM720T_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm7tdmi_p = arm7tdmi; - *arm720t_p = arm720t; - - return ERROR_OK; -} - -int arm720t_arch_state(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; - arm720t_common_t *arm720t = arm7tdmi->arch_info; - - char *state[] = - { - "disabled", "enabled" - }; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("BUG: called for a non-ARMv4/5 target"); - exit(-1); - } - - USER("target halted in %s state due to %s, current mode: %s\n" - "cpsr: 0x%8.8x pc: 0x%8.8x\n" - "MMU: %s, Cache: %s", - armv4_5_state_strings[armv4_5->core_state], - target_debug_reason_strings[target->debug_reason], - armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], - buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), - buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), - state[arm720t->armv4_5_mmu.mmu_enabled], - state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); - - return ERROR_OK; -} - -int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - int retval; - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; - arm720t_common_t *arm720t = arm7tdmi->arch_info; - - /* disable cache, but leave MMU enabled */ - if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) - arm720t_disable_mmu_caches(target, 0, 1, 0); - - retval = arm7_9_read_memory(target, address, size, count, buffer); - - if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) - arm720t_enable_mmu_caches(target, 0, 1, 0); - - return retval; -} - -int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - int retval; - - if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) - return retval; - - return retval; -} - -int arm720t_soft_reset_halt(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; - arm720t_common_t *arm720t = arm7tdmi->arch_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - - if (target->state == TARGET_RUNNING) - { - target->type->halt(target); - } - - while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) - { - embeddedice_read_reg(dbg_stat); - jtag_execute_queue(); - } - - target->state = TARGET_HALTED; - - /* SVC, ARM state, IRQ and FIQ disabled */ - buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; - - /* start fetching from 0x0 */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - - armv4_5->core_mode = ARMV4_5_MODE_SVC; - armv4_5->core_state = ARMV4_5_STATE_ARM; - - arm720t_disable_mmu_caches(target, 1, 1, 1); - arm720t->armv4_5_mmu.mmu_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; -} - -int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm7tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; - -} - -int arm720t_quit() -{ - - return ERROR_OK; -} - -int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant) -{ - arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common; - arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common; - - arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); - - arm7tdmi->arch_info = arm720t; - arm720t->common_magic = ARM720T_COMMON_MAGIC; - - arm7_9->post_debug_entry = arm720t_post_debug_entry; - arm7_9->pre_restore_context = arm720t_pre_restore_context; - - arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1; - arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb; - arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory; - arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory; - arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; - arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; - arm720t->armv4_5_mmu.has_tiny_pages = 0; - arm720t->armv4_5_mmu.mmu_enabled = 0; - - return ERROR_OK; -} - -int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t)); - - if (argc < 4) - { - ERROR("'target arm720t' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm720t_init_arch_info(target, arm720t, chain_pos, variant); - - return ERROR_OK; -} - -int arm720t_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm720t_cmd; - - - retval = arm7tdmi_register_commands(cmd_ctx); - - arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, "arm720t specific commands"); - - register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); - - register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - return ERROR_OK; -} - -int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm7tdmi_common_t *arm7tdmi; - arm720t_common_t *arm720t; - arm_jtag_t *jtag_info; - - if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM720t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (argc >= 1) - { - u32 opcode = strtoul(args[0], NULL, 0); - - if (argc == 1) - { - u32 value; - if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); - return ERROR_OK; - } - jtag_execute_queue(); - - command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); - } - else if (argc == 2) - { - u32 value = strtoul(args[1], NULL, 0); - if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); - return ERROR_OK; - } - command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); - } - } - - return ERROR_OK; -} - -int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm7tdmi_common_t *arm7tdmi; - arm720t_common_t *arm720t; - arm_jtag_t *jtag_info; - - if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM720t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); -} - -int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm7tdmi_common_t *arm7tdmi; - arm720t_common_t *arm720t; - arm_jtag_t *jtag_info; - - if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM720t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); -} - -int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm7tdmi_common_t *arm7tdmi; - arm720t_common_t *arm720t; - arm_jtag_t *jtag_info; - - if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM720t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); -} - +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm720t.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm720t_register_commands(struct command_context_s *cmd_ctx); + +int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm720t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm720t_quit(); +int arm720t_arch_state(struct target_s *target); +int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm720t_soft_reset_halt(struct target_s *target); + +target_type_t arm720t_target = +{ + .name = "arm720t", + + .poll = arm7_9_poll, + .arch_state = arm720t_arch_state, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm720t_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm720t_read_memory, + .write_memory = arm720t_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm720t_register_commands, + .target_command = arm720t_target_command, + .init_target = arm720t_init_target, + .quit = arm720t_quit +}; + +int arm720t_scan_cp15(target_t *target, u32 out, u32 *in, int instruction, int clock) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[2]; + u8 out_buf[4]; + u8 instruction_buf = instruction; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &instruction_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = out_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + if (clock) + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + + if (in) + DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock); + else + DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); +#else + DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock); +#endif + + return ERROR_OK; +} + +int arm720t_read_cp15(target_t *target, u32 opcode, u32 *value) +{ + /* fetch CP15 opcode */ + arm720t_scan_cp15(target, opcode, NULL, 1, 1); + /* "DECODE" stage */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + /* "EXECUTE" stage (1) */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (2) */ + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (3), CDATA is read */ + arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1); + + return ERROR_OK; +} + +int arm720t_write_cp15(target_t *target, u32 opcode, u32 value) +{ + /* fetch CP15 opcode */ + arm720t_scan_cp15(target, opcode, NULL, 1, 1); + /* "DECODE" stage */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + /* "EXECUTE" stage (1) */ + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); + arm720t_scan_cp15(target, 0x0, NULL, 0, 1); + /* "EXECUTE" stage (2) */ + arm720t_scan_cp15(target, value, NULL, 0, 1); + arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); + + return ERROR_OK; +} + +u32 arm720t_get_ttb(target_t *target) +{ + u32 ttb = 0x0; + + arm720t_read_cp15(target, 0xee120f10, &ttb); + jtag_execute_queue(); + + ttb &= 0xffffc000; + + return ttb; +} + +void arm720t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm720t_read_cp15(target, 0xee110f10, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache || i_cache) + cp15_control &= ~0x4U; + + arm720t_write_cp15(target, 0xee010f10, cp15_control); +} + +void arm720t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm720t_read_cp15(target, 0xee110f10, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache || i_cache) + cp15_control |= 0x4U; + + arm720t_write_cp15(target, 0xee010f10, cp15_control); +} + +void arm720t_post_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* examine cp15 control reg */ + arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm720t->cp15_control_reg); + + arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + /* save i/d fault status and address register */ + arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); + arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); + jtag_execute_queue(); +} + +void arm720t_pre_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg); + arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); +} + +int arm720t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm7tdmi_common_t **arm7tdmi_p, arm720t_common_t **arm720t_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm7tdmi = arm7_9->arch_info; + if (arm7tdmi->common_magic != ARM7TDMI_COMMON_MAGIC) + { + return -1; + } + + arm720t = arm7tdmi->arch_info; + if (arm720t->common_magic != ARM720T_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm7tdmi_p = arm7tdmi; + *arm720t_p = arm720t; + + return ERROR_OK; +} + +int arm720t_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER("target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm720t->armv4_5_mmu.mmu_enabled], + state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); + + return ERROR_OK; +} + +int arm720t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + + /* disable cache, but leave MMU enabled */ + if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + arm720t_disable_mmu_caches(target, 0, 1, 0); + + retval = arm7_9_read_memory(target, address, size, count, buffer); + + if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + arm720t_enable_mmu_caches(target, 0, 1, 0); + + return retval; +} + +int arm720t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + return retval; +} + +int arm720t_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm7tdmi_common_t *arm7tdmi = arm7_9->arch_info; + arm720t_common_t *arm720t = arm7tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm720t_disable_mmu_caches(target, 1, 1, 1); + arm720t->armv4_5_mmu.mmu_enabled = 0; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm720t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm7tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm720t_quit() +{ + + return ERROR_OK; +} + +int arm720t_init_arch_info(target_t *target, arm720t_common_t *arm720t, int chain_pos, char *variant) +{ + arm7tdmi_common_t *arm7tdmi = &arm720t->arm7tdmi_common; + arm7_9_common_t *arm7_9 = &arm7tdmi->arm7_9_common; + + arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); + + arm7tdmi->arch_info = arm720t; + arm720t->common_magic = ARM720T_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm720t_post_debug_entry; + arm7_9->pre_restore_context = arm720t_pre_restore_context; + + arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb; + arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; + arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; + arm720t->armv4_5_mmu.has_tiny_pages = 0; + arm720t->armv4_5_mmu.mmu_enabled = 0; + + return ERROR_OK; +} + +int arm720t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm720t_common_t *arm720t = malloc(sizeof(arm720t_common_t)); + + if (argc < 4) + { + ERROR("'target arm720t' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm720t_init_arch_info(target, arm720t, chain_pos, variant); + + return ERROR_OK; +} + +int arm720t_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm720t_cmd; + + + retval = arm7tdmi_register_commands(cmd_ctx); + + arm720t_cmd = register_command(cmd_ctx, NULL, "arm720t", NULL, COMMAND_ANY, "arm720t specific commands"); + + register_command(cmd_ctx, arm720t_cmd, "cp15", arm720t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + register_command(cmd_ctx, arm720t_cmd, "virt2phys", arm720t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); + + register_command(cmd_ctx, arm720t_cmd, "mdw_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdh_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm720t_cmd, "mdb_phys", arm720t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm720t_cmd, "mww_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm720t_cmd, "mwh_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm720t_cmd, "mwb_phys", arm720t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + return ERROR_OK; +} + +int arm720t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + u32 opcode = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm720t_read_cp15(target, opcode, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm720t_write_cp15(target, opcode, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access cp15 with opcode 0x%8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "0x%8.8x: 0x%8.8x", opcode, value); + } + } + + return ERROR_OK; +} + +int arm720t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + +int arm720t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + +int arm720t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm7tdmi_common_t *arm7tdmi; + arm720t_common_t *arm720t; + arm_jtag_t *jtag_info; + + if (arm720t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm7tdmi, &arm720t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM720t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm720t->armv4_5_mmu); +} + diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index c308380a..5679bbc6 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -1,874 +1,874 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm7tdmi.h" - -#include "arm7_9_common.h" -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "embeddedice.h" -#include "etm.h" -#include "log.h" -#include "jtag.h" -#include "arm_jtag.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm7tdmi_register_commands(struct command_context_s *cmd_ctx); - -/* forward declarations */ -int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm7tdmi_quit(); - -/* target function declarations */ -int arm7tdmi_poll(struct target_s *target); -int arm7tdmi_halt(target_t *target); - -target_type_t arm7tdmi_target = -{ - .name = "arm7tdmi", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm7_9_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm7_9_read_memory, - .write_memory = arm7_9_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm7tdmi_register_commands, - .target_command = arm7tdmi_target_command, - .init_target = arm7tdmi_init_target, - .quit = arm7tdmi_quit -}; - -int arm7tdmi_examine_debug_reason(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - - /* only check the debug reason if we don't know it already */ - if ((target->debug_reason != DBG_REASON_DBGRQ) - && (target->debug_reason != DBG_REASON_SINGLESTEP)) - { - scan_field_t fields[2]; - u8 databus[4]; - u8 breakpoint; - - jtag_add_end_state(TAP_PD); - - fields[0].device = arm7_9->jtag_info.chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = &breakpoint; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = arm7_9->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = databus; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - arm_jtag_scann(&arm7_9->jtag_info, 0x1); - arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); - - jtag_add_dr_scan(2, fields, TAP_PD, NULL); - jtag_execute_queue(); - - fields[0].in_value = NULL; - fields[0].out_value = &breakpoint; - fields[1].in_value = NULL; - fields[1].out_value = databus; - - jtag_add_dr_scan(2, fields, TAP_PD, NULL); - - if (breakpoint & 1) - target->debug_reason = DBG_REASON_WATCHPOINT; - else - target->debug_reason = DBG_REASON_BREAKPOINT; - } - - return ERROR_OK; -} - -/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */ -int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint) -{ - scan_field_t fields[2]; - u8 out_buf[4]; - u8 breakpoint_buf; - - buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); - buf_set_u32(&breakpoint_buf, 0, 1, breakpoint); - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = &breakpoint_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = out_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - if (in) - { - fields[1].in_handler = arm_jtag_buf_to_u32_flip; - fields[1].in_handler_priv = in; - } - else - { - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - } - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in); - } - else - DEBUG("out: 0x%8.8x", out); -} -#endif - - return ERROR_OK; -} - -/* clock the target, reading the databus */ -int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) -{ - scan_field_t fields[2]; - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = arm_jtag_buf_to_u32_flip; - fields[1].in_handler_priv = in; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } -} -#endif - - return ERROR_OK; -} - -/* clock the target, and read the databus - * the *in pointer points to a buffer where elements of 'size' bytes - * are stored in big (be==1) or little (be==0) endianness - */ -int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) -{ - scan_field_t fields[2]; - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - switch (size) - { - case 4: - fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip; - break; - case 2: - fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip; - break; - case 1: - fields[1].in_handler = arm_jtag_buf_to_8_flip; - break; - } - fields[1].in_handler_priv = in; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ -{ - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } -} -#endif - - return ERROR_OK; -} - -void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* save r0 before using it and put system in ARM state - * to allow common handling of ARM and THUMB debugging */ - - /* fetch STR r0, [r0] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* nothing fetched, STR r0, [r0] in Execute (2) */ - arm7tdmi_clock_data_in(jtag_info, r0); - - /* MOV r0, r15 fetched, STR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* nothing fetched, STR r0, [r0] in Execute (2) */ - arm7tdmi_clock_data_in(jtag_info, pc); - - /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* nothing fetched, data for LDR r0, [PC, #0] */ - arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); - /* nothing fetched, data from previous cycle is written to register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - - /* fetch BX */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); - /* NOP fetched, BX in Decode, MOV in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* NOP fetched, BX in Execute (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - - jtag_execute_queue(); - - /* fix program counter: - * MOV r0, r15 was the 4th instruction (+6) - * reading PC in Thumb state gives address of instruction + 4 - */ - *pc -= 0xa; - -} - -void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* STMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); - - /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - for (i = 0; i <= 15; i++) - { - if (mask & (1 << i)) - /* nothing fetched, STM still in EXECUTE (1+i cycle) */ - arm7tdmi_clock_data_in(jtag_info, core_regs[i]); - } - -} - -void arm7tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; - u32 *buf_u32 = buffer; - u16 *buf_u16 = buffer; - u8 *buf_u8 = buffer; - - /* STMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); - - /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - for (i = 0; i <= 15; i++) - { - /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */ - if (mask & (1 << i)) - { - switch (size) - { - case 4: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; - } - } - } - -} - -void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* MRS r0, cpsr */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); - - /* STR r0, [r15] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); - /* fetch NOP, STR in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, STR in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, STR still in EXECUTE (2nd cycle) */ - arm7tdmi_clock_data_in(jtag_info, xpsr); - -} - -void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); - - /* MSR1 fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); - /* MSR2 fetched, MSR1 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); - /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); - /* nothing fetched, MSR1 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); - /* nothing fetched, MSR2 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, MSR3 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* NOP fetched, MSR4 in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, MSR4 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); -} - -void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); - - /* MSR fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); - /* NOP fetched, MSR in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* NOP fetched, MSR in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, MSR in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - -} - -void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* LDMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); - - /* fetch NOP, LDM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - for (i = 0; i <= 15; i++) - { - if (mask & (1 << i)) - /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ - arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0); - } - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - -} - -void arm7tdmi_load_word_regs(target_t *target, u32 mask) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); - -} - -void arm7tdmi_load_hword_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); - -} - -void arm7tdmi_load_byte_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); - -} - -void arm7tdmi_store_word_regs(target_t *target, u32 mask) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); - -} - -void arm7tdmi_store_hword_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); - -} - -void arm7tdmi_store_byte_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); - -} - -void arm7tdmi_write_pc(target_t *target, u32 pc) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* LDMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); - /* fetch NOP, LDM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */ - arm7tdmi_clock_out(jtag_info, pc, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); -} - -void arm7tdmi_branch_resume(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0); - -} - -void arm7tdmi_branch_resume_thumb(target_t *target) -{ - DEBUG("-"); - - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - - /* LDMIA r0, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); - - /* fetch NOP, LDM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - /* Branch and eXchange */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); - - embeddedice_read_reg(dbg_stat); - - /* fetch NOP, BX in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - /* target is now in Thumb state */ - embeddedice_read_reg(dbg_stat); - - /* fetch NOP, BX in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - - /* target is now in Thumb state */ - embeddedice_read_reg(dbg_stat); - - /* load r0 value */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); - /* fetch NOP, LDR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* fetch NOP, LDR in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); - /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - - embeddedice_read_reg(dbg_stat); - - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); - -} - -void arm7tdmi_build_reg_cache(target_t *target) -{ - reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); - arm7_9->eice_cache = (*cache_p)->next; - - if (arm7_9->etm_ctx) - { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); - arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; - } -} - -int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - - arm7tdmi_build_reg_cache(target); - - return ERROR_OK; - -} - -int arm7tdmi_quit() -{ - - return ERROR_OK; -} - -int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant) -{ - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - arm7_9 = &arm7tdmi->arm7_9_common; - armv4_5 = &arm7_9->armv4_5_common; - - /* prepare JTAG information for the new target */ - arm7_9->jtag_info.chain_pos = chain_pos; - arm7_9->jtag_info.scann_size = 4; - - /* register arch-specific functions */ - arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason; - arm7_9->change_to_arm = arm7tdmi_change_to_arm; - arm7_9->read_core_regs = arm7tdmi_read_core_regs; - arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; - arm7_9->read_xpsr = arm7tdmi_read_xpsr; - - arm7_9->write_xpsr = arm7tdmi_write_xpsr; - arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8; - arm7_9->write_core_regs = arm7tdmi_write_core_regs; - - arm7_9->load_word_regs = arm7tdmi_load_word_regs; - arm7_9->load_hword_reg = arm7tdmi_load_hword_reg; - arm7_9->load_byte_reg = arm7tdmi_load_byte_reg; - - arm7_9->store_word_regs = arm7tdmi_store_word_regs; - arm7_9->store_hword_reg = arm7tdmi_store_hword_reg; - arm7_9->store_byte_reg = arm7tdmi_store_byte_reg; - - arm7_9->write_pc = arm7tdmi_write_pc; - arm7_9->branch_resume = arm7tdmi_branch_resume; - arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb; - - arm7_9->enable_single_step = arm7_9_enable_eice_step; - arm7_9->disable_single_step = arm7_9_disable_eice_step; - - arm7_9->pre_debug_entry = NULL; - arm7_9->post_debug_entry = NULL; - - arm7_9->pre_restore_context = NULL; - arm7_9->post_restore_context = NULL; - - /* initialize arch-specific breakpoint handling */ - arm7_9->arm_bkpt = 0xdeeedeee; - arm7_9->thumb_bkpt = 0xdeee; - - arm7_9->sw_bkpts_use_wp = 1; - arm7_9->sw_bkpts_enabled = 0; - arm7_9->dbgreq_adjust_pc = 2; - arm7_9->arch_info = arm7tdmi; - - arm7tdmi->arch_info = NULL; - arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC; - - if (variant) - { - arm7tdmi->variant = strdup(variant); - } - else - { - arm7tdmi->variant = strdup(""); - } - - arm7_9_init_arch_info(target, arm7_9); - - return ERROR_OK; -} - -/* target arm7tdmi */ -int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t)); - - if (argc < 4) - { - ERROR("'target arm7tdmi' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); - - return ERROR_OK; -} - -int arm7tdmi_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - - retval = arm7_9_register_commands(cmd_ctx); - - return ERROR_OK; - -} - +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm7tdmi.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "etm.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm7tdmi_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm7tdmi_quit(); + +/* target function declarations */ +int arm7tdmi_poll(struct target_s *target); +int arm7tdmi_halt(target_t *target); + +target_type_t arm7tdmi_target = +{ + .name = "arm7tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm7tdmi_register_commands, + .target_command = arm7tdmi_target_command, + .init_target = arm7tdmi_init_target, + .quit = arm7tdmi_quit +}; + +int arm7tdmi_examine_debug_reason(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + /* only check the debug reason if we don't know it already */ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + { + scan_field_t fields[2]; + u8 databus[4]; + u8 breakpoint; + + jtag_add_end_state(TAP_PD); + + fields[0].device = arm7_9->jtag_info.chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = &breakpoint; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = arm7_9->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = databus; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + arm_jtag_scann(&arm7_9->jtag_info, 0x1); + arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); + + jtag_add_dr_scan(2, fields, TAP_PD); + jtag_execute_queue(); + + fields[0].in_value = NULL; + fields[0].out_value = &breakpoint; + fields[1].in_value = NULL; + fields[1].out_value = databus; + + jtag_add_dr_scan(2, fields, TAP_PD); + + if (breakpoint & 1) + target->debug_reason = DBG_REASON_WATCHPOINT; + else + target->debug_reason = DBG_REASON_BREAKPOINT; + } + + return ERROR_OK; +} + +/* put an instruction in the ARM7TDMI pipeline or write the data bus, and optionally read data */ +int arm7tdmi_clock_out(arm_jtag_t *jtag_info, u32 out, u32 *in, int breakpoint) +{ + scan_field_t fields[2]; + u8 out_buf[4]; + u8 breakpoint_buf; + + buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); + buf_set_u32(&breakpoint_buf, 0, 1, breakpoint); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &breakpoint_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = out_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (in) + { + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + } + else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("out: 0x%8.8x, in: 0x%8.8x", out, *in); + } + else + DEBUG("out: 0x%8.8x", out); +} +#endif + + return ERROR_OK; +} + +/* clock the target, reading the databus */ +int arm7tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) +{ + scan_field_t fields[2]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = arm_jtag_buf_to_u32_flip; + fields[1].in_handler_priv = in; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm7tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + scan_field_t fields[2]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + switch (size) + { + case 4: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be32_flip : arm_jtag_buf_to_le32_flip; + break; + case 2: + fields[1].in_handler = (be) ? arm_jtag_buf_to_be16_flip : arm_jtag_buf_to_le16_flip; + break; + case 1: + fields[1].in_handler = arm_jtag_buf_to_8_flip; + break; + } + fields[1].in_handler_priv = in; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ +{ + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } +} +#endif + + return ERROR_OK; +} + +void arm7tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* save r0 before using it and put system in ARM state + * to allow common handling of ARM and THUMB debugging */ + + /* fetch STR r0, [r0] */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, STR r0, [r0] in Execute (2) */ + arm7tdmi_clock_data_in(jtag_info, r0); + + /* MOV r0, r15 fetched, STR in Decode */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, STR r0, [r0] in Execute (2) */ + arm7tdmi_clock_data_in(jtag_info, pc); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, data for LDR r0, [PC, #0] */ + arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); + /* nothing fetched, data from previous cycle is written to register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + /* fetch BX */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); + /* NOP fetched, BX in Decode, MOV in Execute */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* NOP fetched, BX in Execute (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + jtag_execute_queue(); + + /* fix program counter: + * MOV r0, r15 was the 4th instruction (+6) + * reading PC in Thumb state gives address of instruction + 4 + */ + *pc -= 0xa; + +} + +void arm7tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM still in EXECUTE (1+i cycle) */ + arm7tdmi_clock_data_in(jtag_info, core_regs[i]); + } + +} + +void arm7tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + /* nothing fetched, STM still in EXECUTE (1+i cycle), read databus */ + if (mask & (1 << i)) + { + switch (size) + { + case 4: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + } + +} + +void arm7tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* MRS r0, cpsr */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); + + /* STR r0, [r15] */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); + /* fetch NOP, STR in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, STR in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, STR still in EXECUTE (2nd cycle) */ + arm7tdmi_clock_data_in(jtag_info, xpsr); + +} + +void arm7tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); + + /* MSR1 fetched */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); + /* MSR2 fetched, MSR1 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); + /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR4 in EXECUTE (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR4 in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); +} + +void arm7tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); + + /* MSR fetched */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); + /* NOP fetched, MSR in DECODE */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* NOP fetched, MSR in EXECUTE (1) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, MSR in EXECUTE (2) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + +} + +void arm7tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ + arm7tdmi_clock_out(jtag_info, core_regs[i], NULL, 0); + } + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + +} + +void arm7tdmi_load_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load-multiple into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); + +} + +void arm7tdmi_load_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load half-word into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_load_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load byte into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_store_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store-multiple into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); + +} + +void arm7tdmi_store_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store half-word into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_store_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store byte into the pipeline */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); + +} + +void arm7tdmi_write_pc(target_t *target, u32 pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */ + arm7tdmi_clock_out(jtag_info, pc, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); +} + +void arm7tdmi_branch_resume(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffa, 0), NULL, 0); + +} + +void arm7tdmi_branch_resume_thumb(target_t *target) +{ + DEBUG("-"); + + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + /* LDMIA r0, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ + arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* Branch and eXchange */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in DECODE stage */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in EXECUTE stage (1st cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* load r0 value */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + /* fetch NOP, LDR in Decode */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* fetch NOP, LDR in Execute */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ + arm7tdmi_clock_out(jtag_info, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); + +} + +void arm7tdmi_build_reg_cache(target_t *target) +{ + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +int arm7tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + + arm7tdmi_build_reg_cache(target); + + return ERROR_OK; + +} + +int arm7tdmi_quit() +{ + + return ERROR_OK; +} + +int arm7tdmi_init_arch_info(target_t *target, arm7tdmi_common_t *arm7tdmi, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + arm7_9 = &arm7tdmi->arm7_9_common; + armv4_5 = &arm7_9->armv4_5_common; + + /* prepare JTAG information for the new target */ + arm7_9->jtag_info.chain_pos = chain_pos; + arm7_9->jtag_info.scann_size = 4; + + /* register arch-specific functions */ + arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason; + arm7_9->change_to_arm = arm7tdmi_change_to_arm; + arm7_9->read_core_regs = arm7tdmi_read_core_regs; + arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; + arm7_9->read_xpsr = arm7tdmi_read_xpsr; + + arm7_9->write_xpsr = arm7tdmi_write_xpsr; + arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8; + arm7_9->write_core_regs = arm7tdmi_write_core_regs; + + arm7_9->load_word_regs = arm7tdmi_load_word_regs; + arm7_9->load_hword_reg = arm7tdmi_load_hword_reg; + arm7_9->load_byte_reg = arm7tdmi_load_byte_reg; + + arm7_9->store_word_regs = arm7tdmi_store_word_regs; + arm7_9->store_hword_reg = arm7tdmi_store_hword_reg; + arm7_9->store_byte_reg = arm7tdmi_store_byte_reg; + + arm7_9->write_pc = arm7tdmi_write_pc; + arm7_9->branch_resume = arm7tdmi_branch_resume; + arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb; + + arm7_9->enable_single_step = arm7_9_enable_eice_step; + arm7_9->disable_single_step = arm7_9_disable_eice_step; + + arm7_9->pre_debug_entry = NULL; + arm7_9->post_debug_entry = NULL; + + arm7_9->pre_restore_context = NULL; + arm7_9->post_restore_context = NULL; + + /* initialize arch-specific breakpoint handling */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 0xdeee; + + arm7_9->sw_bkpts_use_wp = 1; + arm7_9->sw_bkpts_enabled = 0; + arm7_9->dbgreq_adjust_pc = 2; + arm7_9->arch_info = arm7tdmi; + + arm7tdmi->arch_info = NULL; + arm7tdmi->common_magic = ARM7TDMI_COMMON_MAGIC; + + if (variant) + { + arm7tdmi->variant = strdup(variant); + } + else + { + arm7tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + return ERROR_OK; +} + +/* target arm7tdmi */ +int arm7tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm7tdmi_common_t *arm7tdmi = malloc(sizeof(arm7tdmi_common_t)); + + if (argc < 4) + { + ERROR("'target arm7tdmi' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + arm7tdmi_init_arch_info(target, arm7tdmi, chain_pos, variant); + + return ERROR_OK; +} + +int arm7tdmi_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + + retval = arm7_9_register_commands(cmd_ctx); + + return ERROR_OK; + +} + diff --git a/src/target/arm920t.c b/src/target/arm920t.c index bf159dbe..17c53973 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -1,1485 +1,1485 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm920t.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm920t_register_commands(struct command_context_s *cmd_ctx); - -int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* forward declarations */ -int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm920t_quit(); -int arm920t_arch_state(struct target_s *target); -int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm920t_soft_reset_halt(struct target_s *target); - -#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) - -target_type_t arm920t_target = -{ - .name = "arm920t", - - .poll = arm7_9_poll, - .arch_state = arm920t_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm920t_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm920t_read_memory, - .write_memory = arm920t_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm920t_register_commands, - .target_command = arm920t_target_command, - .init_target = arm920t_init_target, - .quit = arm920t_quit -}; - -int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[4]; - u8 access_type_buf = 1; - u8 reg_addr_buf = reg_addr & 0x3f; - u8 nr_w_buf = 0; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = &access_type_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 6; - fields[2].out_value = ®_addr_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - fields[3].device = jtag_info->chain_pos; - fields[3].num_bits = 1; - fields[3].out_value = &nr_w_buf; - fields[3].out_mask = NULL; - fields[3].in_value = NULL; - fields[3].in_check_value = NULL; - fields[3].in_check_mask = NULL; - fields[3].in_handler = NULL; - fields[3].in_handler_priv = NULL; - - jtag_add_dr_scan(4, fields, -1, NULL); - - fields[1].in_handler_priv = value; - fields[1].in_handler = arm_jtag_buf_to_u32; - - jtag_add_dr_scan(4, fields, -1, NULL); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - jtag_execute_queue(); - DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); -#endif - - return ERROR_OK; -} - -int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[4]; - u8 access_type_buf = 1; - u8 reg_addr_buf = reg_addr & 0x3f; - u8 nr_w_buf = 1; - u8 value_buf[4]; - - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = &access_type_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = value_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 6; - fields[2].out_value = ®_addr_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - fields[3].device = jtag_info->chain_pos; - fields[3].num_bits = 1; - fields[3].out_value = &nr_w_buf; - fields[3].out_mask = NULL; - fields[3].in_value = NULL; - fields[3].in_check_value = NULL; - fields[3].in_check_mask = NULL; - fields[3].in_handler = NULL; - fields[3].in_handler_priv = NULL; - - jtag_add_dr_scan(4, fields, -1, NULL); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); -#endif - - return ERROR_OK; -} - -int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[4]; - u8 access_type_buf = 0; /* interpreted access */ - u8 reg_addr_buf = 0x0; - u8 nr_w_buf = 0; - u8 cp15_opcode_buf[4]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 1; - fields[0].out_value = &access_type_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = cp15_opcode_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 6; - fields[2].out_value = ®_addr_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - fields[3].device = jtag_info->chain_pos; - fields[3].num_bits = 1; - fields[3].out_value = &nr_w_buf; - fields[3].out_mask = NULL; - fields[3].in_value = NULL; - fields[3].in_check_value = NULL; - fields[3].in_check_mask = NULL; - fields[3].in_handler = NULL; - fields[3].in_handler_priv = NULL; - - jtag_add_dr_scan(4, fields, -1, NULL); - - arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - arm7_9_execute_sys_speed(target); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("failed executing JTAG queue, exiting"); - exit(-1); - } - - return ERROR_OK; -} - -int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - u32* regs_p[1]; - u32 regs[2]; - u32 cp15c15 = 0x0; - - /* load address into R1 */ - regs[1] = address; - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* read-modify-write CP15 test state register - * to enable interpreted access mode */ - arm920t_read_cp15_physical(target, 0x1e, &cp15c15); - jtag_execute_queue(); - cp15c15 |= 1; /* set interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* execute CP15 instruction and ARM load (reading from coprocessor) */ - arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); - - /* disable interpreted access mode */ - cp15c15 &= ~1U; /* clear interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* retrieve value from R0 */ - regs_p[0] = value; - arm9tdmi_read_core_regs(target, 0x1, regs_p); - jtag_execute_queue(); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); -#endif - - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; - - return ERROR_OK; -} - -int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address) -{ - u32 cp15c15 = 0x0; - armv4_5_common_t *armv4_5 = target->arch_info; - u32 regs[2]; - - /* load value, address into R0, R1 */ - regs[0] = value; - regs[1] = address; - arm9tdmi_write_core_regs(target, 0x3, regs); - - /* read-modify-write CP15 test state register - * to enable interpreted access mode */ - arm920t_read_cp15_physical(target, 0x1e, &cp15c15); - jtag_execute_queue(); - cp15c15 |= 1; /* set interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* execute CP15 instruction and ARM store (writing to coprocessor) */ - arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); - - /* disable interpreted access mode */ - cp15c15 &= ~1U; /* set interpret mode */ - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); -#endif - - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; - - return ERROR_OK; -} - -u32 arm920t_get_ttb(target_t *target) -{ - int retval; - u32 ttb = 0x0; - - if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &ttb)) != ERROR_OK) - return retval; - - return ttb; -} - -void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - u32 cp15_control; - - /* read cp15 control register */ - arm920t_read_cp15_physical(target, 0x2, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control &= ~0x1U; - - if (d_u_cache) - cp15_control &= ~0x4U; - - if (i_cache) - cp15_control &= ~0x1000U; - - arm920t_write_cp15_physical(target, 0x2, cp15_control); -} - -void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - u32 cp15_control; - - /* read cp15 control register */ - arm920t_read_cp15_physical(target, 0x2, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache) - cp15_control |= 0x4U; - - if (i_cache) - cp15_control |= 0x1000U; - - arm920t_write_cp15_physical(target, 0x2, cp15_control); -} - -void arm920t_post_debug_entry(target_t *target) -{ - u32 cp15c15; - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm920t_common_t *arm920t = arm9tdmi->arch_info; - - /* examine cp15 control reg */ - arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg); - jtag_execute_queue(); - DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg); - - if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1) - { - u32 cache_type_reg; - /* identify caches */ - arm920t_read_cp15_physical(target, 0x1, &cache_type_reg); - jtag_execute_queue(); - armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache); - } - - arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; - arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; - arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; - - /* save i/d fault status and address register */ - arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr); - arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); - arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); - arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); - - DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x", - arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); - - if (arm920t->preserve_cache) - { - /* read-modify-write CP15 test state register - * to disable I/D-cache linefills */ - arm920t_read_cp15_physical(target, 0x1e, &cp15c15); - jtag_execute_queue(); - cp15c15 |= 0x600; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } -} - -void arm920t_pre_restore_context(target_t *target) -{ - u32 cp15c15; - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm920t_common_t *arm920t = arm9tdmi->arch_info; - - /* restore i/d fault status and address register */ - arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0); - arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0); - arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0); - arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0); - - /* read-modify-write CP15 test state register - * to reenable I/D-cache linefills */ - if (arm920t->preserve_cache) - { - arm920t_read_cp15_physical(target, 0x1e, &cp15c15); - jtag_execute_queue(); - cp15c15 &= ~0x600U; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } -} - -int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - return -1; - } - - arm7_9 = armv4_5->arch_info; - if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) - { - return -1; - } - - arm9tdmi = arm7_9->arch_info; - if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) - { - return -1; - } - - arm920t = arm9tdmi->arch_info; - if (arm920t->common_magic != ARM920T_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - *arm920t_p = arm920t; - - return ERROR_OK; -} - -int arm920t_arch_state(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm920t_common_t *arm920t = arm9tdmi->arch_info; - - char *state[] = - { - "disabled", "enabled" - }; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("BUG: called for a non-ARMv4/5 target"); - exit(-1); - } - - USER( "target halted in %s state due to %s, current mode: %s\n" - "cpsr: 0x%8.8x pc: 0x%8.8x\n" - "MMU: %s, D-Cache: %s, I-Cache: %s", - armv4_5_state_strings[armv4_5->core_state], - target_debug_reason_strings[target->debug_reason], - armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], - buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), - buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), - state[arm920t->armv4_5_mmu.mmu_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); - - return ERROR_OK; -} - -int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - int retval; - - retval = arm7_9_read_memory(target, address, size, count, buffer); - - return retval; -} - -int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - int retval; - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm920t_common_t *arm920t = arm9tdmi->arch_info; - - if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) - return retval; - - if (((size == 4) || (size == 2)) && (count == 1)) - { - if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) - { - DEBUG("D-Cache enabled, writing through to main memory"); - u32 pa, cb, ap; - int type, domain; - - pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap); - if (type == -1) - return ERROR_OK; - /* cacheable & bufferable means write-back region */ - if (cb == 3) - armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); - } - - if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) - { - DEBUG("I-Cache enabled, invalidating affected I-Cache line"); - arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address); - } - } - - return retval; -} - -int arm920t_soft_reset_halt(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm920t_common_t *arm920t = arm9tdmi->arch_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - - if (target->state == TARGET_RUNNING) - { - target->type->halt(target); - } - - while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) - { - embeddedice_read_reg(dbg_stat); - jtag_execute_queue(); - } - - target->state = TARGET_HALTED; - - /* SVC, ARM state, IRQ and FIQ disabled */ - buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; - - /* start fetching from 0x0 */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - - armv4_5->core_mode = ARMV4_5_MODE_SVC; - armv4_5->core_state = ARMV4_5_STATE_ARM; - - arm920t_disable_mmu_caches(target, 1, 1, 1); - arm920t->armv4_5_mmu.mmu_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; -} - -int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm9tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; - -} - -int arm920t_quit() -{ - - return ERROR_OK; -} - -int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant) -{ - arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common; - arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; - - /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) - */ - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - arm9tdmi->arch_info = arm920t; - arm920t->common_magic = ARM920T_COMMON_MAGIC; - - arm7_9->post_debug_entry = arm920t_post_debug_entry; - arm7_9->pre_restore_context = arm920t_pre_restore_context; - - arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; - arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; - arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; - arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; - arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; - arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; - arm920t->armv4_5_mmu.has_tiny_pages = 1; - arm920t->armv4_5_mmu.mmu_enabled = 0; - - /* disabling linefills leads to lockups, so keep them enabled for now - * this doesn't affect correctness, but might affect timing issues, if - * important data is evicted from the cache during the debug session - * */ - arm920t->preserve_cache = 0; - - /* override hw single-step capability from ARM9TDMI */ - arm7_9->has_single_step = 1; - - return ERROR_OK; -} - -int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t)); - - if (argc < 4) - { - ERROR("'target arm920t' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm920t_init_arch_info(target, arm920t, chain_pos, variant); - - return ERROR_OK; -} - -int arm920t_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm920t_cmd; - - - retval = arm9tdmi_register_commands(cmd_ctx); - - arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands"); - - register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) [value] [address]"); - register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); - register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); - - register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content"); - register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content"); - - return ERROR_OK; -} - -int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - u32 cp15c15; - u32 cp15_ctrl, cp15_ctrl_saved; - u32 regs[16]; - u32 *regs_p[16]; - u32 C15_C_D_Ind, C15_C_I_Ind; - int i; - FILE *output; - arm920t_cache_line_t d_cache[8][64], i_cache[8][64]; - int segment, index; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: arm920t read_cache "); - return ERROR_OK; - } - - if ((output = fopen(args[0], "w")) == NULL) - { - DEBUG("error opening cache content file"); - return ERROR_OK; - } - - for (i = 0; i < 16; i++) - regs_p[i] = ®s[i]; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - /* disable MMU and Caches */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); - jtag_execute_queue(); - cp15_ctrl_saved = cp15_ctrl; - cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); - - /* read CP15 test state register */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); - jtag_execute_queue(); - - /* read DCache content */ - fprintf(output, "DCache:\n"); - - /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ - for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) - { - fprintf(output, "\nsegment: %i\n----------", segment); - - /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* D CAM Read, loads current victim into C15.C.D.Ind */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0)); - - /* read current victim */ - arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - for (index = 0; index < 64; index++) - { - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (index << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write DCache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); - - /* Read D RAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); - - /* Read D CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D RAM and CAM content */ - arm9tdmi_read_core_regs(target, 0x3fe, regs_p); - jtag_execute_queue(); - - d_cache[segment][index].cam = regs[9]; - - /* mask LFSR[6] */ - regs[9] &= 0xfffffffe; - fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); - - for (i = 1; i < 9; i++) - { - d_cache[segment][index].data[i] = regs[i]; - fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); - } - - } - - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write DCache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } - - /* read ICache content */ - fprintf(output, "ICache:\n"); - - /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ - for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) - { - fprintf(output, "segment: %i\n----------", segment); - - /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* I CAM Read, loads current victim into C15.C.I.Ind */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0)); - - /* read current victim */ - arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - for (index = 0; index < 64; index++) - { - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (index << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write ICache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); - - /* Read I RAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); - - /* Read I CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I RAM and CAM content */ - arm9tdmi_read_core_regs(target, 0x3fe, regs_p); - jtag_execute_queue(); - - i_cache[segment][index].cam = regs[9]; - - /* mask LFSR[6] */ - regs[9] &= 0xfffffffe; - fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); - - for (i = 1; i < 9; i++) - { - i_cache[segment][index].data[i] = regs[i]; - fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); - } - - } - - - /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ - regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); - arm9tdmi_write_core_regs(target, 0x1, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write ICache victim */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - } - - /* restore CP15 MMU and Cache settings */ - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); - - command_print(cmd_ctx, "cache content successfully output to %s", args[0]); - - fclose(output); - - /* mark registers dirty. */ - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; - - return ERROR_OK; -} - -int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - u32 cp15c15; - u32 cp15_ctrl, cp15_ctrl_saved; - u32 regs[16]; - u32 *regs_p[16]; - int i; - FILE *output; - u32 Dlockdown, Ilockdown; - arm920t_tlb_entry_t d_tlb[64], i_tlb[64]; - int victim; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: arm920t read_mmu "); - return ERROR_OK; - } - - if ((output = fopen(args[0], "w")) == NULL) - { - DEBUG("error opening mmu content file"); - return ERROR_OK; - } - - for (i = 0; i < 16; i++) - regs_p[i] = ®s[i]; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - /* disable MMU and Caches */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); - jtag_execute_queue(); - cp15_ctrl_saved = cp15_ctrl; - cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); - - /* read CP15 test state register */ - arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); - jtag_execute_queue(); - - /* prepare reading D TLB content - * */ - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Read D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB lockdown stored to r1 */ - arm9tdmi_read_core_regs(target, 0x2, regs_p); - jtag_execute_queue(); - Dlockdown = regs[1]; - - for (victim = 0; victim < 64; victim += 8) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* Read D TLB CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB CAM content stored to r2-r9 */ - arm9tdmi_read_core_regs(target, 0x3fc, regs_p); - jtag_execute_queue(); - - for (i = 0; i < 8; i++) - d_tlb[victim + i].cam = regs[i + 2]; - } - - for (victim = 0; victim < 64; victim++) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* Read D TLB RAM1 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0)); - - /* Read D TLB RAM2 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read D TLB RAM content stored to r2 and r3 */ - arm9tdmi_read_core_regs(target, 0xc, regs_p); - jtag_execute_queue(); - - d_tlb[victim].ram1 = regs[2]; - d_tlb[victim].ram2 = regs[3]; - } - - /* restore D TLB lockdown */ - regs[1] = Dlockdown; - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* Write D TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); - - /* prepare reading I TLB content - * */ - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Read I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB lockdown stored to r1 */ - arm9tdmi_read_core_regs(target, 0x2, regs_p); - jtag_execute_queue(); - Ilockdown = regs[1]; - - for (victim = 0; victim < 64; victim += 8) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* Read I TLB CAM */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB CAM content stored to r2-r9 */ - arm9tdmi_read_core_regs(target, 0x3fc, regs_p); - jtag_execute_queue(); - - for (i = 0; i < 8; i++) - i_tlb[i + victim].cam = regs[i + 2]; - } - - for (victim = 0; victim < 64; victim++) - { - /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] - * base remains unchanged, victim goes through entries 0 to 63 */ - regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* set interpret mode */ - cp15c15 |= 0x1; - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* Read I TLB RAM1 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0)); - - /* Read I TLB RAM2 */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0)); - - /* clear interpret mode */ - cp15c15 &= ~0x1; - arm920t_write_cp15_physical(target, 0x1e, cp15c15); - - /* read I TLB RAM content stored to r2 and r3 */ - arm9tdmi_read_core_regs(target, 0xc, regs_p); - jtag_execute_queue(); - - i_tlb[victim].ram1 = regs[2]; - i_tlb[victim].ram2 = regs[3]; - } - - /* restore I TLB lockdown */ - regs[1] = Ilockdown; - arm9tdmi_write_core_regs(target, 0x2, regs); - - /* Write I TLB lockdown */ - arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); - - /* restore CP15 MMU and Cache settings */ - arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); - - /* output data to file */ - fprintf(output, "D TLB content:\n"); - for (i = 0; i < 64; i++) - { - fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); - } - - fprintf(output, "\n\nI TLB content:\n"); - for (i = 0; i < 64; i++) - { - fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); - } - - command_print(cmd_ctx, "mmu content successfully output to %s", args[0]); - - fclose(output); - - /* mark registers dirty */ - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; - - return ERROR_OK; -} -int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (argc >= 1) - { - int address = strtoul(args[0], NULL, 0); - - if (argc == 1) - { - u32 value; - if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access reg %i", address); - return ERROR_OK; - } - jtag_execute_queue(); - - command_print(cmd_ctx, "%i: %8.8x", address, value); - } - else if (argc == 2) - { - u32 value = strtoul(args[1], NULL, 0); - if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access reg %i", address); - return ERROR_OK; - } - command_print(cmd_ctx, "%i: %8.8x", address, value); - } - } - - return ERROR_OK; -} - -int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (argc >= 1) - { - u32 opcode = strtoul(args[0], NULL, 0); - - if (argc == 1) - { - u32 value; - if ((retval = arm920t_read_cp15_interpreted(target, opcode, 0x0, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't execute %8.8x", opcode); - return ERROR_OK; - } - - command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); - } - else if (argc == 2) - { - u32 value = strtoul(args[1], NULL, 0); - if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't execute %8.8x", opcode); - return ERROR_OK; - } - command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); - } - else if (argc == 3) - { - u32 value = strtoul(args[1], NULL, 0); - u32 address = strtoul(args[2], NULL, 0); - if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't execute %8.8x", opcode); - return ERROR_OK; - } - command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address); - } - } - else - { - command_print(cmd_ctx, "usage: arm920t cp15i [value] [address]"); - } - - return ERROR_OK; -} - -int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache); -} - -int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); -} - -int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); -} - -int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm920t_common_t *arm920t; - arm_jtag_t *jtag_info; - - if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM920t target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm920t.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm920t_register_commands(struct command_context_s *cmd_ctx); + +int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm920t_quit(); +int arm920t_arch_state(struct target_s *target); +int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm920t_soft_reset_halt(struct target_s *target); + +#define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) + +target_type_t arm920t_target = +{ + .name = "arm920t", + + .poll = arm7_9_poll, + .arch_state = arm920t_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm920t_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm920t_read_memory, + .write_memory = arm920t_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm920t_register_commands, + .target_command = arm920t_target_command, + .init_target = arm920t_init_target, + .quit = arm920t_quit +}; + +int arm920t_read_cp15_physical(target_t *target, int reg_addr, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 1; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 0; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + fields[1].in_handler_priv = value; + fields[1].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(4, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + return ERROR_OK; +} + +int arm920t_write_cp15_physical(target_t *target, int reg_addr, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 1; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 1; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = value_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm920t_execute_cp15(target_t *target, u32 cp15_opcode, u32 arm_opcode) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[4]; + u8 access_type_buf = 0; /* interpreted access */ + u8 reg_addr_buf = 0x0; + u8 nr_w_buf = 0; + u8 cp15_opcode_buf[4]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 1; + fields[0].out_value = &access_type_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = cp15_opcode_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 6; + fields[2].out_value = ®_addr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + arm7_9_execute_sys_speed(target); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("failed executing JTAG queue, exiting"); + exit(-1); + } + + return ERROR_OK; +} + +int arm920t_read_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 address, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + u32* regs_p[1]; + u32 regs[2]; + u32 cp15c15 = 0x0; + + /* load address into R1 */ + regs[1] = address; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* read-modify-write CP15 test state register + * to enable interpreted access mode */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 1; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* execute CP15 instruction and ARM load (reading from coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* clear interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* retrieve value from R0 */ + regs_p[0] = value; + arm9tdmi_read_core_regs(target, 0x1, regs_p); + jtag_execute_queue(); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); +#endif + + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; + + return ERROR_OK; +} + +int arm920t_write_cp15_interpreted(target_t *target, u32 cp15_opcode, u32 value, u32 address) +{ + u32 cp15c15 = 0x0; + armv4_5_common_t *armv4_5 = target->arch_info; + u32 regs[2]; + + /* load value, address into R0, R1 */ + regs[0] = value; + regs[1] = address; + arm9tdmi_write_core_regs(target, 0x3, regs); + + /* read-modify-write CP15 test state register + * to enable interpreted access mode */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 1; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* execute CP15 instruction and ARM store (writing to coprocessor) */ + arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); + + /* disable interpreted access mode */ + cp15c15 &= ~1U; /* set interpret mode */ + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); +#endif + + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = 1; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = 1; + + return ERROR_OK; +} + +u32 arm920t_get_ttb(target_t *target) +{ + int retval; + u32 ttb = 0x0; + + if ((retval = arm920t_read_cp15_interpreted(target, 0xeebf0f51, 0x0, &ttb)) != ERROR_OK) + return retval; + + return ttb; +} + +void arm920t_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm920t_read_cp15_physical(target, 0x2, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache) + cp15_control &= ~0x4U; + + if (i_cache) + cp15_control &= ~0x1000U; + + arm920t_write_cp15_physical(target, 0x2, cp15_control); +} + +void arm920t_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + u32 cp15_control; + + /* read cp15 control register */ + arm920t_read_cp15_physical(target, 0x2, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + arm920t_write_cp15_physical(target, 0x2, cp15_control); +} + +void arm920t_post_debug_entry(target_t *target) +{ + u32 cp15c15; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + /* examine cp15 control reg */ + arm920t_read_cp15_physical(target, 0x2, &arm920t->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm920t->cp15_control_reg); + + if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + /* identify caches */ + arm920t_read_cp15_physical(target, 0x1, &cache_type_reg); + jtag_execute_queue(); + armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache); + } + + arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* save i/d fault status and address register */ + arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr); + arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); + arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); + arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x, I FAR: 0x%8.8x", + arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); + + if (arm920t->preserve_cache) + { + /* read-modify-write CP15 test state register + * to disable I/D-cache linefills */ + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 |= 0x600; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } +} + +void arm920t_pre_restore_context(target_t *target) +{ + u32 cp15c15; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0); + arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0); + arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0); + arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0); + + /* read-modify-write CP15 test state register + * to reenable I/D-cache linefills */ + if (arm920t->preserve_cache) + { + arm920t_read_cp15_physical(target, 0x1e, &cp15c15); + jtag_execute_queue(); + cp15c15 &= ~0x600U; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } +} + +int arm920t_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm920t_common_t **arm920t_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm920t = arm9tdmi->arch_info; + if (arm920t->common_magic != ARM920T_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm920t_p = arm920t; + + return ERROR_OK; +} + +int arm920t_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER( "target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm920t->armv4_5_mmu.mmu_enabled], + state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + + return ERROR_OK; +} + +int arm920t_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + + retval = arm7_9_read_memory(target, address, size, count, buffer); + + return retval; +} + +int arm920t_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + if (((size == 4) || (size == 2)) && (count == 1)) + { + if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) + { + DEBUG("D-Cache enabled, writing through to main memory"); + u32 pa, cb, ap; + int type, domain; + + pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap); + if (type == -1) + return ERROR_OK; + /* cacheable & bufferable means write-back region */ + if (cb == 3) + armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); + } + + if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + DEBUG("I-Cache enabled, invalidating affected I-Cache line"); + arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address); + } + } + + return retval; +} + +int arm920t_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm920t_common_t *arm920t = arm9tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm920t_disable_mmu_caches(target, 1, 1, 1); + arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm920t_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm920t_quit() +{ + + return ERROR_OK; +} + +int arm920t_init_arch_info(target_t *target, arm920t_common_t *arm920t, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm920t->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm920t; + arm920t->common_magic = ARM920T_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm920t_post_debug_entry; + arm7_9->pre_restore_context = arm920t_pre_restore_context; + + arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; + arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; + arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; + arm920t->armv4_5_mmu.has_tiny_pages = 1; + arm920t->armv4_5_mmu.mmu_enabled = 0; + + /* disabling linefills leads to lockups, so keep them enabled for now + * this doesn't affect correctness, but might affect timing issues, if + * important data is evicted from the cache during the debug session + * */ + arm920t->preserve_cache = 0; + + /* override hw single-step capability from ARM9TDMI */ + arm7_9->has_single_step = 1; + + return ERROR_OK; +} + +int arm920t_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm920t_common_t *arm920t = malloc(sizeof(arm920t_common_t)); + + if (argc < 4) + { + ERROR("'target arm920t' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm920t_init_arch_info(target, arm920t, chain_pos, variant); + + return ERROR_OK; +} + +int arm920t_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm920t_cmd; + + + retval = arm9tdmi_register_commands(cmd_ctx); + + arm920t_cmd = register_command(cmd_ctx, NULL, "arm920t", NULL, COMMAND_ANY, "arm920t specific commands"); + + register_command(cmd_ctx, arm920t_cmd, "cp15", arm920t_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + register_command(cmd_ctx, arm920t_cmd, "cp15i", arm920t_handle_cp15i_command, COMMAND_EXEC, "display/modify cp15 (interpreted access) [value] [address]"); + register_command(cmd_ctx, arm920t_cmd, "cache_info", arm920t_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); + register_command(cmd_ctx, arm920t_cmd, "virt2phys", arm920t_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); + + register_command(cmd_ctx, arm920t_cmd, "mdw_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdh_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm920t_cmd, "mdb_phys", arm920t_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm920t_cmd, "mww_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm920t_cmd, "mwh_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm920t_cmd, "mwb_phys", arm920t_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + register_command(cmd_ctx, arm920t_cmd, "read_cache", arm920t_handle_read_cache_command, COMMAND_EXEC, "display I/D cache content"); + register_command(cmd_ctx, arm920t_cmd, "read_mmu", arm920t_handle_read_mmu_command, COMMAND_EXEC, "display I/D mmu content"); + + return ERROR_OK; +} + +int arm920t_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + u32 C15_C_D_Ind, C15_C_I_Ind; + int i; + FILE *output; + arm920t_cache_line_t d_cache[8][64], i_cache[8][64]; + int segment, index; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_cache "); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening cache content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* read DCache content */ + fprintf(output, "DCache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "\nsegment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* D CAM Read, loads current victim into C15.C.D.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3d, &C15_C_D_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* Read D RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,10,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read D CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,6,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + d_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + d_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write DCache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* read ICache content */ + fprintf(output, "ICache:\n"); + + /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ + for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) + { + fprintf(output, "segment: %i\n----------", segment); + + /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* I CAM Read, loads current victim into C15.C.I.Ind */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(1, 0)); + + /* read current victim */ + arm920t_read_cp15_physical(target, 0x3b, &C15_C_I_Ind); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + for (index = 0; index < 64; index++) + { + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (index << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* Read I RAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,9,2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); + + /* Read I CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,2,0,15,5,2), ARMV4_5_LDR(9, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I RAM and CAM content */ + arm9tdmi_read_core_regs(target, 0x3fe, regs_p); + jtag_execute_queue(); + + i_cache[segment][index].cam = regs[9]; + + /* mask LFSR[6] */ + regs[9] &= 0xfffffffe; + fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8x, content (%s):\n", segment, index, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); + + for (i = 1; i < 9; i++) + { + i_cache[segment][index].data[i] = regs[i]; + fprintf(output, "%i: 0x%8.8x\n", i-1, regs[i]); + } + + } + + + /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ + regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); + arm9tdmi_write_core_regs(target, 0x1, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write ICache victim */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,9,1,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + } + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + command_print(cmd_ctx, "cache content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty. */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + return ERROR_OK; +} + +int arm920t_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + u32 cp15c15; + u32 cp15_ctrl, cp15_ctrl_saved; + u32 regs[16]; + u32 *regs_p[16]; + int i; + FILE *output; + u32 Dlockdown, Ilockdown; + arm920t_tlb_entry_t d_tlb[64], i_tlb[64]; + int victim; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: arm920t read_mmu "); + return ERROR_OK; + } + + if ((output = fopen(args[0], "w")) == NULL) + { + DEBUG("error opening mmu content file"); + return ERROR_OK; + } + + for (i = 0; i < 16; i++) + regs_p[i] = ®s[i]; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + /* disable MMU and Caches */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), &cp15_ctrl); + jtag_execute_queue(); + cp15_ctrl_saved = cp15_ctrl; + cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl); + + /* read CP15 test state register */ + arm920t_read_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), &cp15c15); + jtag_execute_queue(); + + /* prepare reading D TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,0), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Dlockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,6,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + d_tlb[victim + i].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* Read D TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,10,4), ARMV4_5_LDR(2,0)); + + /* Read D TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,2,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read D TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + d_tlb[victim].ram1 = regs[2]; + d_tlb[victim].ram2 = regs[3]; + } + + /* restore D TLB lockdown */ + regs[1] = Dlockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write D TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,0), ARMV4_5_STR(1, 0)); + + /* prepare reading I TLB content + * */ + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Read I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MRC(15,0,0,10,0,1), ARMV4_5_LDR(1, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB lockdown stored to r1 */ + arm9tdmi_read_core_regs(target, 0x2, regs_p); + jtag_execute_queue(); + Ilockdown = regs[1]; + + for (victim = 0; victim < 64; victim += 8) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB CAM */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,5,4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB CAM content stored to r2-r9 */ + arm9tdmi_read_core_regs(target, 0x3fc, regs_p); + jtag_execute_queue(); + + for (i = 0; i < 8; i++) + i_tlb[i + victim].cam = regs[i + 2]; + } + + for (victim = 0; victim < 64; victim++) + { + /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] + * base remains unchanged, victim goes through entries 0 to 63 */ + regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* set interpret mode */ + cp15c15 |= 0x1; + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0xf, 0), cp15c15); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* Read I TLB RAM1 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,9,4), ARMV4_5_LDR(2,0)); + + /* Read I TLB RAM2 */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,4,0,15,1,5), ARMV4_5_LDR(3,0)); + + /* clear interpret mode */ + cp15c15 &= ~0x1; + arm920t_write_cp15_physical(target, 0x1e, cp15c15); + + /* read I TLB RAM content stored to r2 and r3 */ + arm9tdmi_read_core_regs(target, 0xc, regs_p); + jtag_execute_queue(); + + i_tlb[victim].ram1 = regs[2]; + i_tlb[victim].ram2 = regs[3]; + } + + /* restore I TLB lockdown */ + regs[1] = Ilockdown; + arm9tdmi_write_core_regs(target, 0x2, regs); + + /* Write I TLB lockdown */ + arm920t_execute_cp15(target, ARMV4_5_MCR(15,0,0,10,0,1), ARMV4_5_STR(1, 0)); + + /* restore CP15 MMU and Cache settings */ + arm920t_write_cp15_physical(target, ARM920T_CP15_PHYS_ADDR(0, 0x1, 0), cp15_ctrl_saved); + + /* output data to file */ + fprintf(output, "D TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + fprintf(output, "\n\nI TLB content:\n"); + for (i = 0; i < 64; i++) + { + fprintf(output, "%i: 0x%8.8x 0x%8.8x 0x%8.8x %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); + } + + command_print(cmd_ctx, "mmu content successfully output to %s", args[0]); + + fclose(output); + + /* mark registers dirty */ + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 1).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 2).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 3).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 4).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 5).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 6).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 7).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 8).valid; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 9).valid; + + return ERROR_OK; +} +int arm920t_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + int address = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm920t_read_cp15_physical(target, address, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm920t_write_cp15_physical(target, address, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + } + + return ERROR_OK; +} + +int arm920t_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + u32 opcode = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm920t_read_cp15_interpreted(target, opcode, 0x0, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + + command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, 0)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "%8.8x: %8.8x", opcode, value); + } + else if (argc == 3) + { + u32 value = strtoul(args[1], NULL, 0); + u32 address = strtoul(args[2], NULL, 0); + if ((retval = arm920t_write_cp15_interpreted(target, opcode, value, address)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't execute %8.8x", opcode); + return ERROR_OK; + } + command_print(cmd_ctx, "%8.8x: %8.8x %8.8x", opcode, value, address); + } + } + else + { + command_print(cmd_ctx, "usage: arm920t cp15i [value] [address]"); + } + + return ERROR_OK; +} + +int arm920t_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &arm920t->armv4_5_mmu.armv4_5_cache); +} + +int arm920t_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} + +int arm920t_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} + +int arm920t_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm920t_common_t *arm920t; + arm_jtag_t *jtag_info; + + if (arm920t_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm920t) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM920t target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm920t->armv4_5_mmu); +} diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index 75d43fd8..a02c27ae 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -1,944 +1,944 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm926ejs.h" -#include "jtag.h" -#include "log.h" - -#include -#include - -#if 1 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm926ejs_register_commands(struct command_context_s *cmd_ctx); - -int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* forward declarations */ -int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm926ejs_quit(); -int arm926ejs_arch_state(struct target_s *target); -int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int arm926ejs_soft_reset_halt(struct target_s *target); -static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical); -static int arm926ejs_mmu(struct target_s *target, int *enabled); - -target_type_t arm926ejs_target = -{ - .name = "arm926ejs", - - .poll = arm7_9_poll, - .arch_state = arm926ejs_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm926ejs_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm7_9_read_memory, - .write_memory = arm926ejs_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm926ejs_register_commands, - .target_command = arm926ejs_target_command, - .init_target = arm926ejs_init_target, - .quit = arm926ejs_quit, - .virt2phys = arm926ejs_virt2phys, - .mmu = arm926ejs_mmu -}; - - -int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field) -{ - /* The ARM926EJ-S' instruction register is 4 bits wide */ - u8 t = *captured & 0xf; - u8 t2 = *field->in_check_value & 0xf; - if (t == t2) - { - return ERROR_OK; - } - else if ((t == 0x0f) || (t == 0x00)) - { - DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access"); - return ERROR_OK; - } - return ERROR_JTAG_QUEUE_FAILED;; -} - -#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) - -int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 *value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); - scan_field_t fields[4]; - u8 address_buf[2]; - u8 nr_w_buf = 0; - u8 access = 1; - - buf_set_u32(address_buf, 0, 14, address); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 1; - fields[1].out_value = &access; - fields[1].out_mask = NULL; - fields[1].in_value = &access; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 14; - fields[2].out_value = address_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - fields[3].device = jtag_info->chain_pos; - fields[3].num_bits = 1; - fields[3].out_value = &nr_w_buf; - fields[3].out_mask = NULL; - fields[3].in_value = NULL; - fields[3].in_check_value = NULL; - fields[3].in_check_mask = NULL; - fields[3].in_handler = NULL; - fields[3].in_handler_priv = NULL; - - jtag_add_dr_scan(4, fields, -1, NULL); - - fields[0].in_handler_priv = value; - fields[0].in_handler = arm_jtag_buf_to_u32; - - do - { - /* rescan with NOP, to wait for the access to complete */ - access = 0; - nr_w_buf = 0; - jtag_add_dr_scan(4, fields, -1, NULL); - jtag_execute_queue(); - } while (buf_get_u32(&access, 0, 1) != 1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", address, *value); -#endif - - arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan); - - return ERROR_OK; -} - -int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); - scan_field_t fields[4]; - u8 value_buf[4]; - u8 address_buf[2]; - u8 nr_w_buf = 1; - u8 access = 1; - - buf_set_u32(address_buf, 0, 14, address); - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = value_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 1; - fields[1].out_value = &access; - fields[1].out_mask = NULL; - fields[1].in_value = &access; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 14; - fields[2].out_value = address_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - fields[3].device = jtag_info->chain_pos; - fields[3].num_bits = 1; - fields[3].out_value = &nr_w_buf; - fields[3].out_mask = NULL; - fields[3].in_value = NULL; - fields[3].in_check_value = NULL; - fields[3].in_check_mask = NULL; - fields[3].in_handler = NULL; - fields[3].in_handler_priv = NULL; - - jtag_add_dr_scan(4, fields, -1, NULL); - - do - { - /* rescan with NOP, to wait for the access to complete */ - access = 0; - nr_w_buf = 0; - jtag_add_dr_scan(4, fields, -1, NULL); - jtag_execute_queue(); - } while (buf_get_u32(&access, 0, 1) != 1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", address, value); -#endif - - arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan); - - return ERROR_OK; -} - -int arm926ejs_examine_debug_reason(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - int debug_reason; - int retval; - - embeddedice_read_reg(dbg_stat); - if ((retval = jtag_execute_queue()) != ERROR_OK) - return retval; - - debug_reason = buf_get_u32(dbg_stat->value, 6, 4); - - switch (debug_reason) - { - case 1: - DEBUG("breakpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 2: - DEBUG("breakpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 3: - DEBUG("soft breakpoint (BKPT instruction)"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 4: - DEBUG("vector catch breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 5: - DEBUG("external breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 6: - DEBUG("watchpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 7: - DEBUG("watchpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 8: - DEBUG("external watchpoint"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 9: - DEBUG("internal debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 10: - DEBUG("external debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 11: - ERROR("BUG: debug re-entry from system speed access shouldn't be handled here"); - break; - default: - ERROR("BUG: unknown debug reason: 0x%x", debug_reason); - target->debug_reason = DBG_REASON_DBGRQ; - } - - return ERROR_OK; -} - -u32 arm926ejs_get_ttb(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - int retval; - u32 ttb = 0x0; - - if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK) - return retval; - - return ttb; -} - -void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); - jtag_execute_queue(); - - if (mmu) - { - /* invalidate TLB */ - arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); - - cp15_control &= ~0x1U; - } - - if (d_u_cache) - { - u32 debug_override; - /* read-modify-write CP15 debug override register - * to enable "test and clean all" */ - arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); - debug_override |= 0x80000; - arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); - - /* clean and invalidate DCache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); - - /* write CP15 debug override register - * to disable "test and clean all" */ - debug_override &= ~0x80000; - arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); - - cp15_control &= ~0x4U; - } - - if (i_cache) - { - /* invalidate ICache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); - - cp15_control &= ~0x1000U; - } - - arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); -} - -void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); - jtag_execute_queue(); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache) - cp15_control |= 0x4U; - - if (i_cache) - cp15_control |= 0x1000U; - - arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); -} - -void arm926ejs_post_debug_entry(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - /* examine cp15 control reg */ - arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); - jtag_execute_queue(); - DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg); - - if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) - { - u32 cache_type_reg; - /* identify caches */ - arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); - jtag_execute_queue(); - armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); - } - - arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; - - /* save i/d fault status and address register */ - arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); - arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); - arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); - - DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x", - arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); - - - u32 cache_dbg_ctrl; - - /* read-modify-write CP15 cache debug control register - * to disable I/D-cache linefills and force WT */ - arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); - cache_dbg_ctrl |= 0x7; - arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); -} - -void arm926ejs_pre_restore_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - /* restore i/d fault status and address register */ - arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); - arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); - arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); - - u32 cache_dbg_ctrl; - - /* read-modify-write CP15 cache debug control register - * to reenable I/D-cache linefills and disable WT */ - arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); - cache_dbg_ctrl &= ~0x7; - arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); -} - -int arm926ejs_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm926ejs_common_t **arm926ejs_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - return -1; - } - - arm7_9 = armv4_5->arch_info; - if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) - { - return -1; - } - - arm9tdmi = arm7_9->arch_info; - if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) - { - return -1; - } - - arm926ejs = arm9tdmi->arch_info; - if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - *arm926ejs_p = arm926ejs; - - return ERROR_OK; -} - -int arm926ejs_arch_state(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - char *state[] = - { - "disabled", "enabled" - }; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("BUG: called for a non-ARMv4/5 target"); - exit(-1); - } - - USER( - "target halted in %s state due to %s, current mode: %s\n" - "cpsr: 0x%8.8x pc: 0x%8.8x\n" - "MMU: %s, D-Cache: %s, I-Cache: %s", - armv4_5_state_strings[armv4_5->core_state], - target_debug_reason_strings[target->debug_reason], - armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], - buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), - buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), - state[arm926ejs->armv4_5_mmu.mmu_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); - - return ERROR_OK; -} - -int arm926ejs_soft_reset_halt(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - - if (target->state == TARGET_RUNNING) - { - target->type->halt(target); - } - - while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) - { - embeddedice_read_reg(dbg_stat); - jtag_execute_queue(); - } - - target->state = TARGET_HALTED; - - /* SVC, ARM state, IRQ and FIQ disabled */ - buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; - - /* start fetching from 0x0 */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - - armv4_5->core_mode = ARMV4_5_MODE_SVC; - armv4_5->core_state = ARMV4_5_STATE_ARM; - - arm926ejs_disable_mmu_caches(target, 1, 1, 1); - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; -} - -int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - int retval; - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; - arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; - - if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) - return retval; - - /* If ICache is enabled, we have to invalidate affected ICache lines - * the DCache is forced to write-through, so we don't have to clean it here - */ - if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) - { - if (count <= 1) - { - /* invalidate ICache single entry with MVA */ - arm926ejs->write_cp15(target, 0, 1, 7, 5, address); - } - else - { - /* invalidate ICache */ - arm926ejs->write_cp15(target, 0, 0, 7, 5, address); - } - } - - return retval; -} - -int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm9tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; - -} - -int arm926ejs_quit() -{ - - return ERROR_OK; -} - -int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant) -{ - arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common; - arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; - - /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) - */ - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - arm9tdmi->arch_info = arm926ejs; - arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; - - arm7_9->post_debug_entry = arm926ejs_post_debug_entry; - arm7_9->pre_restore_context = arm926ejs_pre_restore_context; - - arm926ejs->read_cp15 = arm926ejs_cp15_read; - arm926ejs->write_cp15 = arm926ejs_cp15_write; - arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; - arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; - arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; - arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; - arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; - arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; - arm926ejs->armv4_5_mmu.has_tiny_pages = 1; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - - arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; - - /* The ARM926EJ-S implements the ARMv5TE architecture which - * has the BKPT instruction, so we don't have to use a watchpoint comparator - */ - arm7_9->arm_bkpt = ARMV5_BKPT(0x0); - arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - arm7_9->sw_bkpts_use_wp = 0; - arm7_9->sw_bkpts_enabled = 1; - - return ERROR_OK; -} - -int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t)); - - if (argc < 4) - { - ERROR("'target arm926ejs' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant); - - return ERROR_OK; -} - -int arm926ejs_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm926ejs_cmd; - - - retval = arm9tdmi_register_commands(cmd_ctx); - - arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands"); - - register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - - register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); - register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); - - register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); - - return ERROR_OK; -} - -int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - int opcode_1; - int opcode_2; - int CRn; - int CRm; - - if ((argc < 4) || (argc > 5)) - { - command_print(cmd_ctx, "usage: arm926ejs cp15 [value]"); - return ERROR_OK; - } - - opcode_1 = strtoul(args[0], NULL, 0); - opcode_2 = strtoul(args[1], NULL, 0); - CRn = strtoul(args[2], NULL, 0); - CRm = strtoul(args[3], NULL, 0); - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc == 4) - { - u32 value; - if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access register"); - return ERROR_OK; - } - jtag_execute_queue(); - - command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); - } - else - { - u32 value = strtoul(args[4], NULL, 0); - if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access register"); - return ERROR_OK; - } - command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); - } - - return ERROR_OK; -} - -int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache); -} - -int arm926ejs_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); -} - -int arm926ejs_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); -} - -int arm926ejs_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - arm_jtag_t *jtag_info; - - if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); -} -static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - int retval; - int type; - u32 cb; - int domain; - u32 ap; - - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm926ejs_common_t *arm926ejs; - retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs); - if (retval != ERROR_OK) - { - return retval; - } - u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); - if (type == -1) - { - return ret; - } - *physical = ret; - return ERROR_OK; -} - -static int arm926ejs_mmu(struct target_s *target, int *enabled) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm926ejs_common_t *arm926ejs = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_INVALID; - } - *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm926ejs.h" +#include "jtag.h" +#include "log.h" + +#include +#include + +#if 1 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm926ejs_register_commands(struct command_context_s *cmd_ctx); + +int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cp15i_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_virt2phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_md_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_mw_phys_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int arm926ejs_handle_read_cache_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int arm926ejs_handle_read_mmu_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm926ejs_quit(); +int arm926ejs_arch_state(struct target_s *target); +int arm926ejs_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int arm926ejs_soft_reset_halt(struct target_s *target); +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int arm926ejs_mmu(struct target_s *target, int *enabled); + +target_type_t arm926ejs_target = +{ + .name = "arm926ejs", + + .poll = arm7_9_poll, + .arch_state = arm926ejs_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm926ejs_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm926ejs_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm926ejs_register_commands, + .target_command = arm926ejs_target_command, + .init_target = arm926ejs_init_target, + .quit = arm926ejs_quit, + .virt2phys = arm926ejs_virt2phys, + .mmu = arm926ejs_mmu +}; + + +int arm926ejs_catch_broken_irscan(u8 *captured, void *priv, scan_field_t *field) +{ + /* The ARM926EJ-S' instruction register is 4 bits wide */ + u8 t = *captured & 0xf; + u8 t2 = *field->in_check_value & 0xf; + if (t == t2) + { + return ERROR_OK; + } + else if ((t == 0x0f) || (t == 0x00)) + { + DEBUG("caught ARM926EJ-S invalid Capture-IR result after CP15 access"); + return ERROR_OK; + } + return ERROR_JTAG_QUEUE_FAILED;; +} + +#define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) + +int arm926ejs_cp15_read(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 address_buf[2]; + u8 nr_w_buf = 0; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 14; + fields[2].out_value = address_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + fields[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, *value); +#endif + + arm_jtag_set_instr(jtag_info, 0xc, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_cp15_write(target_t *target, u32 op1, u32 op2, u32 CRn, u32 CRm, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + u32 address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); + scan_field_t fields[4]; + u8 value_buf[4]; + u8 address_buf[2]; + u8 nr_w_buf = 1; + u8 access = 1; + + buf_set_u32(address_buf, 0, 14, address); + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 1; + fields[1].out_value = &access; + fields[1].out_mask = NULL; + fields[1].in_value = &access; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 14; + fields[2].out_value = address_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + fields[3].device = jtag_info->chain_pos; + fields[3].num_bits = 1; + fields[3].out_value = &nr_w_buf; + fields[3].out_mask = NULL; + fields[3].in_value = NULL; + fields[3].in_check_value = NULL; + fields[3].in_check_mask = NULL; + fields[3].in_handler = NULL; + fields[3].in_handler_priv = NULL; + + jtag_add_dr_scan(4, fields, -1); + + do + { + /* rescan with NOP, to wait for the access to complete */ + access = 0; + nr_w_buf = 0; + jtag_add_dr_scan(4, fields, -1); + jtag_execute_queue(); + } while (buf_get_u32(&access, 0, 1) != 1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", address, value); +#endif + + arm_jtag_set_instr(jtag_info, 0xf, &arm926ejs_catch_broken_irscan); + + return ERROR_OK; +} + +int arm926ejs_examine_debug_reason(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + int debug_reason; + int retval; + + embeddedice_read_reg(dbg_stat); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + debug_reason = buf_get_u32(dbg_stat->value, 6, 4); + + switch (debug_reason) + { + case 1: + DEBUG("breakpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 2: + DEBUG("breakpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 3: + DEBUG("soft breakpoint (BKPT instruction)"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 4: + DEBUG("vector catch breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 5: + DEBUG("external breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 6: + DEBUG("watchpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 7: + DEBUG("watchpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 8: + DEBUG("external watchpoint"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 9: + DEBUG("internal debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 10: + DEBUG("external debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 11: + ERROR("BUG: debug re-entry from system speed access shouldn't be handled here"); + break; + default: + ERROR("BUG: unknown debug reason: 0x%x", debug_reason); + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +u32 arm926ejs_get_ttb(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + int retval; + u32 ttb = 0x0; + + if ((retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb)) != ERROR_OK) + return retval; + + return ttb; +} + +void arm926ejs_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + { + /* invalidate TLB */ + arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); + + cp15_control &= ~0x1U; + } + + if (d_u_cache) + { + u32 debug_override; + /* read-modify-write CP15 debug override register + * to enable "test and clean all" */ + arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); + debug_override |= 0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + /* clean and invalidate DCache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + /* write CP15 debug override register + * to disable "test and clean all" */ + debug_override &= ~0x80000; + arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); + + cp15_control &= ~0x1000U; + } + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); + jtag_execute_queue(); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); +} + +void arm926ejs_post_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* examine cp15 control reg */ + arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); + jtag_execute_queue(); + DEBUG("cp15_control_reg: %8.8x", arm926ejs->cp15_control_reg); + + if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + /* identify caches */ + arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); + jtag_execute_queue(); + armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); + } + + arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* save i/d fault status and address register */ + arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); + arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); + arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); + + DEBUG("D FSR: 0x%8.8x, D FAR: 0x%8.8x, I FSR: 0x%8.8x", + arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); + + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to disable I/D-cache linefills and force WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl |= 0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +void arm926ejs_pre_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + /* restore i/d fault status and address register */ + arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); + arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); + arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); + + u32 cache_dbg_ctrl; + + /* read-modify-write CP15 cache debug control register + * to reenable I/D-cache linefills and disable WT */ + arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); + cache_dbg_ctrl &= ~0x7; + arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); +} + +int arm926ejs_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm926ejs_common_t **arm926ejs_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm926ejs = arm9tdmi->arch_info; + if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm926ejs_p = arm926ejs; + + return ERROR_OK; +} + +int arm926ejs_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER( + "target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[arm926ejs->armv4_5_mmu.mmu_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + + return ERROR_OK; +} + +int arm926ejs_soft_reset_halt(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + if (target->state == TARGET_RUNNING) + { + target->type->halt(target); + } + + while (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) + { + embeddedice_read_reg(dbg_stat); + jtag_execute_queue(); + } + + target->state = TARGET_HALTED; + + /* SVC, ARM state, IRQ and FIQ disabled */ + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 8, 0xd3); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + + /* start fetching from 0x0 */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, 0x0); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + + armv4_5->core_mode = ARMV4_5_MODE_SVC; + armv4_5->core_state = ARMV4_5_STATE_ARM; + + arm926ejs_disable_mmu_caches(target, 1, 1, 1); + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +int arm926ejs_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + int retval; + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm9tdmi_common_t *arm9tdmi = arm7_9->arch_info; + arm926ejs_common_t *arm926ejs = arm9tdmi->arch_info; + + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + + /* If ICache is enabled, we have to invalidate affected ICache lines + * the DCache is forced to write-through, so we don't have to clean it here + */ + if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + if (count <= 1) + { + /* invalidate ICache single entry with MVA */ + arm926ejs->write_cp15(target, 0, 1, 7, 5, address); + } + else + { + /* invalidate ICache */ + arm926ejs->write_cp15(target, 0, 0, 7, 5, address); + } + } + + return retval; +} + +int arm926ejs_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; + +} + +int arm926ejs_quit() +{ + + return ERROR_OK; +} + +int arm926ejs_init_arch_info(target_t *target, arm926ejs_common_t *arm926ejs, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm926ejs->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + /* initialize arm9tdmi specific info (including arm7_9 and armv4_5) + */ + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm926ejs; + arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; + + arm7_9->post_debug_entry = arm926ejs_post_debug_entry; + arm7_9->pre_restore_context = arm926ejs_pre_restore_context; + + arm926ejs->read_cp15 = arm926ejs_cp15_read; + arm926ejs->write_cp15 = arm926ejs_cp15_write; + arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; + arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; + arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; + arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; + arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; + arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; + arm926ejs->armv4_5_mmu.has_tiny_pages = 1; + arm926ejs->armv4_5_mmu.mmu_enabled = 0; + + arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; + + /* The ARM926EJ-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm926ejs_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm926ejs_common_t *arm926ejs = malloc(sizeof(arm926ejs_common_t)); + + if (argc < 4) + { + ERROR("'target arm926ejs' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm926ejs_init_arch_info(target, arm926ejs, chain_pos, variant); + + return ERROR_OK; +} + +int arm926ejs_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm926ejs_cmd; + + + retval = arm9tdmi_register_commands(cmd_ctx); + + arm926ejs_cmd = register_command(cmd_ctx, NULL, "arm926ejs", NULL, COMMAND_ANY, "arm926ejs specific commands"); + + register_command(cmd_ctx, arm926ejs_cmd, "cp15", arm926ejs_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + + register_command(cmd_ctx, arm926ejs_cmd, "cache_info", arm926ejs_handle_cache_info_command, COMMAND_EXEC, "display information about target caches"); + register_command(cmd_ctx, arm926ejs_cmd, "virt2phys", arm926ejs_handle_virt2phys_command, COMMAND_EXEC, "translate va to pa "); + + register_command(cmd_ctx, arm926ejs_cmd, "mdw_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdh_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, arm926ejs_cmd, "mdb_phys", arm926ejs_handle_md_phys_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, arm926ejs_cmd, "mww_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, arm926ejs_cmd, "mwh_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, arm926ejs_cmd, "mwb_phys", arm926ejs_handle_mw_phys_command, COMMAND_EXEC, "write memory byte "); + + return ERROR_OK; +} + +int arm926ejs_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + int opcode_1; + int opcode_2; + int CRn; + int CRm; + + if ((argc < 4) || (argc > 5)) + { + command_print(cmd_ctx, "usage: arm926ejs cp15 [value]"); + return ERROR_OK; + } + + opcode_1 = strtoul(args[0], NULL, 0); + opcode_2 = strtoul(args[1], NULL, 0); + CRn = strtoul(args[2], NULL, 0); + CRm = strtoul(args[3], NULL, 0); + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc == 4) + { + u32 value; + if ((retval = arm926ejs->read_cp15(target, opcode_1, opcode_2, CRn, CRm, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + else + { + u32 value = strtoul(args[4], NULL, 0); + if ((retval = arm926ejs->write_cp15(target, opcode_1, opcode_2, CRn, CRm, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access register"); + return ERROR_OK; + } + command_print(cmd_ctx, "%i %i %i %i: %8.8x", opcode_1, opcode_2, CRn, CRm, value); + } + + return ERROR_OK; +} + +int arm926ejs_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &arm926ejs->armv4_5_mmu.armv4_5_cache); +} + +int arm926ejs_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_virt2phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_md_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} + +int arm926ejs_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + arm_jtag_t *jtag_info; + + if (arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM926EJ-S target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + return armv4_5_mmu_handle_mw_phys_command(cmd_ctx, cmd, args, argc, target, &arm926ejs->armv4_5_mmu); +} +static int arm926ejs_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm926ejs_common_t *arm926ejs; + retval= arm926ejs_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm926ejs); + if (retval != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + *physical = ret; + return ERROR_OK; +} + +static int arm926ejs_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm926ejs_common_t *arm926ejs = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 2885e3df..1ea2ce77 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -1,364 +1,364 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm966e.h" - -#include "arm7_9_common.h" -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "embeddedice.h" -#include "log.h" -#include "jtag.h" -#include "arm_jtag.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm966e_register_commands(struct command_context_s *cmd_ctx); - -/* forward declarations */ -int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm966e_quit(void); - -target_type_t arm966e_target = -{ - .name = "arm966e", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm7_9_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm7_9_read_memory, - .write_memory = arm7_9_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm966e_register_commands, - .target_command = arm966e_target_command, - .init_target = arm966e_init_target, - .quit = arm966e_quit, -}; - -int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - arm9tdmi_init_target(cmd_ctx, target); - - return ERROR_OK; -} - -int arm966e_quit(void) -{ - - return ERROR_OK; -} - -int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant) -{ - arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common; - arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; - - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - arm9tdmi->arch_info = arm966e; - arm966e->common_magic = ARM966E_COMMON_MAGIC; - - /* The ARM966E-S implements the ARMv5TE architecture which - * has the BKPT instruction, so we don't have to use a watchpoint comparator - */ - arm7_9->arm_bkpt = ARMV5_BKPT(0x0); - arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - arm7_9->sw_bkpts_use_wp = 0; - arm7_9->sw_bkpts_enabled = 1; - - return ERROR_OK; -} - -int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t)); - - if (argc < 4) - { - ERROR("'target arm966e' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); - - arm966e_init_arch_info(target, arm966e, chain_pos, variant); - - return ERROR_OK; -} - -int arm966e_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm966e_common_t **arm966e_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm966e_common_t *arm966e; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - return -1; - } - - arm7_9 = armv4_5->arch_info; - if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) - { - return -1; - } - - arm9tdmi = arm7_9->arch_info; - if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) - { - return -1; - } - - arm966e = arm9tdmi->arch_info; - if (arm966e->common_magic != ARM966E_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - *arm966e_p = arm966e; - - return ERROR_OK; -} - -int arm966e_read_cp15(target_t *target, int reg_addr, u32 *value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[3]; - u8 reg_addr_buf = reg_addr & 0x3f; - u8 nr_w_buf = 0; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 6; - fields[1].out_value = ®_addr_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &nr_w_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - fields[0].in_handler_priv = value; - fields[0].in_handler = arm_jtag_buf_to_u32; - - jtag_add_dr_scan(3, fields, -1, NULL); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - jtag_execute_queue(); - DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); -#endif - - return ERROR_OK; -} - -int arm966e_write_cp15(target_t *target, int reg_addr, u32 value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - scan_field_t fields[3]; - u8 reg_addr_buf = reg_addr & 0x3f; - u8 nr_w_buf = 1; - u8 value_buf[4]; - - buf_set_u32(value_buf, 0, 32, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0xf); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = value_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 6; - fields[1].out_value = ®_addr_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &nr_w_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); -#endif - - return ERROR_OK; -} - -int arm966e_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - arm966e_common_t *arm966e; - arm_jtag_t *jtag_info; - - if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM966e target"); - return ERROR_OK; - } - - jtag_info = &arm7_9->jtag_info; - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - /* one or more argument, access a single register (write if second argument is given */ - if (argc >= 1) - { - int address = strtoul(args[0], NULL, 0); - - if (argc == 1) - { - u32 value; - if ((retval = arm966e_read_cp15(target, address, &value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access reg %i", address); - return ERROR_OK; - } - jtag_execute_queue(); - - command_print(cmd_ctx, "%i: %8.8x", address, value); - } - else if (argc == 2) - { - u32 value = strtoul(args[1], NULL, 0); - if ((retval = arm966e_write_cp15(target, address, value)) != ERROR_OK) - { - command_print(cmd_ctx, "couldn't access reg %i", address); - return ERROR_OK; - } - command_print(cmd_ctx, "%i: %8.8x", address, value); - } - } - - return ERROR_OK; -} - -int arm966e_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *arm966e_cmd; - - retval = arm9tdmi_register_commands(cmd_ctx); - arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands"); - register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm966e.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm966e_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm966e_quit(void); + +target_type_t arm966e_target = +{ + .name = "arm966e", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm966e_register_commands, + .target_command = arm966e_target_command, + .init_target = arm966e_init_target, + .quit = arm966e_quit, +}; + +int arm966e_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + arm9tdmi_init_target(cmd_ctx, target); + + return ERROR_OK; +} + +int arm966e_quit(void) +{ + + return ERROR_OK; +} + +int arm966e_init_arch_info(target_t *target, arm966e_common_t *arm966e, int chain_pos, char *variant) +{ + arm9tdmi_common_t *arm9tdmi = &arm966e->arm9tdmi_common; + arm7_9_common_t *arm7_9 = &arm9tdmi->arm7_9_common; + + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + arm9tdmi->arch_info = arm966e; + arm966e->common_magic = ARM966E_COMMON_MAGIC; + + /* The ARM966E-S implements the ARMv5TE architecture which + * has the BKPT instruction, so we don't have to use a watchpoint comparator + */ + arm7_9->arm_bkpt = ARMV5_BKPT(0x0); + arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + arm7_9->sw_bkpts_use_wp = 0; + arm7_9->sw_bkpts_enabled = 1; + + return ERROR_OK; +} + +int arm966e_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm966e_common_t *arm966e = malloc(sizeof(arm966e_common_t)); + + if (argc < 4) + { + ERROR("'target arm966e' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + DEBUG("chain_pos: %i, variant: %s", chain_pos, variant); + + arm966e_init_arch_info(target, arm966e, chain_pos, variant); + + return ERROR_OK; +} + +int arm966e_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p, arm966e_common_t **arm966e_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm966e_common_t *arm966e; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + arm966e = arm9tdmi->arch_info; + if (arm966e->common_magic != ARM966E_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + *arm966e_p = arm966e; + + return ERROR_OK; +} + +int arm966e_read_cp15(target_t *target, int reg_addr, u32 *value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[3]; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 0; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 6; + fields[1].out_value = ®_addr_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &nr_w_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_handler_priv = value; + fields[0].in_handler = arm_jtag_buf_to_u32; + + jtag_add_dr_scan(3, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + jtag_execute_queue(); + DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); +#endif + + return ERROR_OK; +} + +int arm966e_write_cp15(target_t *target, int reg_addr, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + scan_field_t fields[3]; + u8 reg_addr_buf = reg_addr & 0x3f; + u8 nr_w_buf = 1; + u8 value_buf[4]; + + buf_set_u32(value_buf, 0, 32, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0xf); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = value_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 6; + fields[1].out_value = ®_addr_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &nr_w_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); +#endif + + return ERROR_OK; +} + +int arm966e_handle_cp15_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + arm966e_common_t *arm966e; + arm_jtag_t *jtag_info; + + if (arm966e_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi, &arm966e) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM966e target"); + return ERROR_OK; + } + + jtag_info = &arm7_9->jtag_info; + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + /* one or more argument, access a single register (write if second argument is given */ + if (argc >= 1) + { + int address = strtoul(args[0], NULL, 0); + + if (argc == 1) + { + u32 value; + if ((retval = arm966e_read_cp15(target, address, &value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + jtag_execute_queue(); + + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + else if (argc == 2) + { + u32 value = strtoul(args[1], NULL, 0); + if ((retval = arm966e_write_cp15(target, address, value)) != ERROR_OK) + { + command_print(cmd_ctx, "couldn't access reg %i", address); + return ERROR_OK; + } + command_print(cmd_ctx, "%i: %8.8x", address, value); + } + } + + return ERROR_OK; +} + +int arm966e_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + command_t *arm966e_cmd; + + retval = arm9tdmi_register_commands(cmd_ctx); + arm966e_cmd = register_command(cmd_ctx, NULL, "arm966e", NULL, COMMAND_ANY, "arm966e specific commands"); + register_command(cmd_ctx, arm966e_cmd, "cp15", arm966e_handle_cp15_command, COMMAND_EXEC, "display/modify cp15 register [value]"); + + return ERROR_OK; +} diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 5f808cdb..7170693d 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -1,1105 +1,1105 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm9tdmi.h" - -#include "arm7_9_common.h" -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "embeddedice.h" -#include "etm.h" -#include "etb.h" -#include "log.h" -#include "jtag.h" -#include "arm_jtag.h" - -#include -#include - -#if 0 -#define _DEBUG_INSTRUCTION_EXECUTION_ -#endif - -/* cli handling */ -int arm9tdmi_register_commands(struct command_context_s *cmd_ctx); -int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -/* forward declarations */ -int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int arm9tdmi_quit(); - -target_type_t arm9tdmi_target = -{ - .name = "arm9tdmi", - - .poll = arm7_9_poll, - .arch_state = armv4_5_arch_state, - - .target_request_data = arm7_9_target_request_data, - - .halt = arm7_9_halt, - .resume = arm7_9_resume, - .step = arm7_9_step, - - .assert_reset = arm7_9_assert_reset, - .deassert_reset = arm7_9_deassert_reset, - .soft_reset_halt = arm7_9_soft_reset_halt, - .prepare_reset_halt = arm7_9_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = arm7_9_read_memory, - .write_memory = arm7_9_write_memory, - .bulk_write_memory = arm7_9_bulk_write_memory, - .checksum_memory = arm7_9_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = arm7_9_add_breakpoint, - .remove_breakpoint = arm7_9_remove_breakpoint, - .add_watchpoint = arm7_9_add_watchpoint, - .remove_watchpoint = arm7_9_remove_watchpoint, - - .register_commands = arm9tdmi_register_commands, - .target_command = arm9tdmi_target_command, - .init_target = arm9tdmi_init_target, - .quit = arm9tdmi_quit -}; - -arm9tdmi_vector_t arm9tdmi_vectors[] = -{ - {"reset", ARM9TDMI_RESET_VECTOR}, - {"undef", ARM9TDMI_UNDEF_VECTOR}, - {"swi", ARM9TDMI_SWI_VECTOR}, - {"pabt", ARM9TDMI_PABT_VECTOR}, - {"dabt", ARM9TDMI_DABT_VECTOR}, - {"reserved", ARM9TDMI_RESERVED_VECTOR}, - {"irq", ARM9TDMI_IRQ_VECTOR}, - {"fiq", ARM9TDMI_FIQ_VECTOR}, - {0, 0}, -}; - -int arm9tdmi_examine_debug_reason(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - - /* only check the debug reason if we don't know it already */ - if ((target->debug_reason != DBG_REASON_DBGRQ) - && (target->debug_reason != DBG_REASON_SINGLESTEP)) - { - scan_field_t fields[3]; - u8 databus[4]; - u8 instructionbus[4]; - u8 debug_reason; - - jtag_add_end_state(TAP_PD); - - fields[0].device = arm7_9->jtag_info.chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = databus; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = arm7_9->jtag_info.chain_pos; - fields[1].num_bits = 3; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = &debug_reason; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = arm7_9->jtag_info.chain_pos; - fields[2].num_bits = 32; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = instructionbus; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - arm_jtag_scann(&arm7_9->jtag_info, 0x1); - arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); - - jtag_add_dr_scan(3, fields, TAP_PD, NULL); - jtag_execute_queue(); - - fields[0].in_value = NULL; - fields[0].out_value = databus; - fields[1].in_value = NULL; - fields[1].out_value = &debug_reason; - fields[2].in_value = NULL; - fields[2].out_value = instructionbus; - - jtag_add_dr_scan(3, fields, TAP_PD, NULL); - - if (debug_reason & 0x4) - if (debug_reason & 0x2) - target->debug_reason = DBG_REASON_WPTANDBKPT; - else - target->debug_reason = DBG_REASON_WATCHPOINT; - else - target->debug_reason = DBG_REASON_BREAKPOINT; - } - - return ERROR_OK; -} - -/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */ -int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed) -{ - scan_field_t fields[3]; - u8 out_buf[4]; - u8 instr_buf[4]; - u8 sysspeed_buf = 0x0; - - /* prepare buffer */ - buf_set_u32(out_buf, 0, 32, out); - - buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); - - if (sysspeed) - buf_set_u32(&sysspeed_buf, 2, 1, 1); - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = out_buf; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - if (in) - { - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = in; - } - else - { - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - } - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 3; - fields[1].out_value = &sysspeed_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 32; - fields[2].out_value = instr_buf; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); - } - else - DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out); - } -#endif - - return ERROR_OK; -} - -/* just read data (instruction and data-out = don't care) */ -int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) -{ - scan_field_t fields[3]; - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = in; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 3; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 32; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } - } -#endif - - return ERROR_OK; -} - -/* clock the target, and read the databus - * the *in pointer points to a buffer where elements of 'size' bytes - * are stored in big (be==1) or little (be==0) endianness - */ -int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) -{ - scan_field_t fields[3]; - - jtag_add_end_state(TAP_PD); - arm_jtag_scann(jtag_info, 0x1); - - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - switch (size) - { - case 4: - fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32; - break; - case 2: - fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16; - break; - case 1: - fields[0].in_handler = arm_jtag_buf_to_8; - break; - } - fields[0].in_handler_priv = in; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 3; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 32; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - jtag_add_runtest(0, -1); - -#ifdef _DEBUG_INSTRUCTION_EXECUTION_ - { - jtag_execute_queue(); - - if (in) - { - DEBUG("in: 0x%8.8x", *in); - } - else - { - ERROR("BUG: called with in == NULL"); - } - } -#endif - - return ERROR_OK; -} - -void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* save r0 before using it and put system in ARM state - * to allow common handling of ARM and THUMB debugging */ - - /* fetch STR r0, [r0] */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* STR r0, [r0] in Memory */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); - - /* MOV r0, r15 fetched, STR in Decode */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* nothing fetched, STR r0, [r0] in Memory */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); - - /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); - /* LDR in Decode */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* LDR in Execute */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* LDR in Memory (to account for interlock) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - - /* fetch BX */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); - /* NOP fetched, BX in Decode, MOV in Execute */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* NOP fetched, BX in Execute (1) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - - jtag_execute_queue(); - - /* fix program counter: - * MOV r0, r15 was the 5th instruction (+8) - * reading PC in Thumb state gives address of instruction + 4 - */ - *pc -= 0xc; -} - -void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* STMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); - - /* fetch NOP, STM in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - for (i = 0; i <= 15; i++) - { - if (mask & (1 << i)) - /* nothing fetched, STM in MEMORY (i'th cycle) */ - arm9tdmi_clock_data_in(jtag_info, core_regs[i]); - } - -} - -void arm9tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; - u32 *buf_u32 = buffer; - u16 *buf_u16 = buffer; - u8 *buf_u8 = buffer; - - /* STMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); - - /* fetch NOP, STM in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - for (i = 0; i <= 15; i++) - { - if (mask & (1 << i)) - /* nothing fetched, STM in MEMORY (i'th cycle) */ - switch (size) - { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; - } - } - -} - -void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* MRS r0, cpsr */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - /* STR r0, [r15] */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); - /* fetch NOP, STR in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, STR in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, STR in MEMORY */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); - -} - -void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); - - /* MSR1 fetched */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); - /* MSR2 fetched, MSR1 in DECODE */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); - /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); - /* nothing fetched, MSR1 in EXECUTE (2) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, MSR1 in EXECUTE (3) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); - /* nothing fetched, MSR2 in EXECUTE (2) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, MSR2 in EXECUTE (3) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, MSR3 in EXECUTE (2) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, MSR3 in EXECUTE (3) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* NOP fetched, MSR4 in EXECUTE (1) */ - /* last MSR writes flags, which takes only one cycle */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); -} - -void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); - - /* MSR fetched */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); - /* NOP fetched, MSR in DECODE */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* NOP fetched, MSR in EXECUTE (1) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - /* rot == 4 writes flags, which takes only one cycle */ - if (rot != 4) - { - /* nothing fetched, MSR in EXECUTE (2) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, MSR in EXECUTE (3) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - } -} - -void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) -{ - int i; - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* LDMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); - - /* fetch NOP, LDM in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - for (i = 0; i <= 15; i++) - { - if (mask & (1 << i)) - /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); - } - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - -} - -void arm9tdmi_load_word_regs(target_t *target, u32 mask) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load-multiple into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_load_hword_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load half-word into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); -} - -void arm9tdmi_load_byte_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed load byte into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_store_word_regs(target_t *target, u32 mask) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store-multiple into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_store_hword_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store half-word into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_store_byte_reg(target_t *target, int num) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* put system-speed store byte into the pipeline */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_write_pc(target_t *target, u32 pc) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - /* LDMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); - - /* fetch NOP, LDM in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - -} - -void arm9tdmi_branch_resume(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); - -} - -void arm9tdmi_branch_resume_thumb(target_t *target) -{ - DEBUG("-"); - - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; - - /* LDMIA r0-15, [r0] at debug speed - * register values will start to appear on 4th DCLK - */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0); - - /* fetch NOP, LDM in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); - /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - /* Branch and eXchange */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); - - embeddedice_read_reg(dbg_stat); - - /* fetch NOP, BX in DECODE stage */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - embeddedice_read_reg(dbg_stat); - - /* fetch NOP, BX in EXECUTE stage (1st cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); - - /* target is now in Thumb state */ - embeddedice_read_reg(dbg_stat); - - /* load r0 value, MOV_IM in Decode*/ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); - /* fetch NOP, LDR in Decode, MOV_IM in Execute */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* fetch NOP, LDR in Execute */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); - /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - - embeddedice_read_reg(dbg_stat); - - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1); - arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); - -} - -void arm9tdmi_enable_single_step(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - - if (arm7_9->has_single_step) - { - buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1); - embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); - } - else - { - arm7_9_enable_eice_step(target); - } -} - -void arm9tdmi_disable_single_step(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - - if (arm7_9->has_single_step) - { - buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0); - embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); - } - else - { - arm7_9_disable_eice_step(target); - } -} - -void arm9tdmi_build_reg_cache(target_t *target) -{ - reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9 = armv4_5->arch_info; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - /* one extra register (vector catch) */ - (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); - arm7_9->eice_cache = (*cache_p)->next; - - if (arm7_9->etm_ctx) - { - (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); - arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; - } -} - -int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - - arm9tdmi_build_reg_cache(target); - - return ERROR_OK; - -} - -int arm9tdmi_quit() -{ - - return ERROR_OK; -} - -int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant) -{ - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - arm7_9 = &arm9tdmi->arm7_9_common; - armv4_5 = &arm7_9->armv4_5_common; - - /* prepare JTAG information for the new target */ - arm7_9->jtag_info.chain_pos = chain_pos; - arm7_9->jtag_info.scann_size = 5; - - /* register arch-specific functions */ - arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; - arm7_9->change_to_arm = arm9tdmi_change_to_arm; - arm7_9->read_core_regs = arm9tdmi_read_core_regs; - arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; - arm7_9->read_xpsr = arm9tdmi_read_xpsr; - - arm7_9->write_xpsr = arm9tdmi_write_xpsr; - arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8; - arm7_9->write_core_regs = arm9tdmi_write_core_regs; - - arm7_9->load_word_regs = arm9tdmi_load_word_regs; - arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; - arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; - - arm7_9->store_word_regs = arm9tdmi_store_word_regs; - arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; - arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; - - arm7_9->write_pc = arm9tdmi_write_pc; - arm7_9->branch_resume = arm9tdmi_branch_resume; - arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb; - - arm7_9->enable_single_step = arm9tdmi_enable_single_step; - arm7_9->disable_single_step = arm9tdmi_disable_single_step; - - arm7_9->pre_debug_entry = NULL; - arm7_9->post_debug_entry = NULL; - - arm7_9->pre_restore_context = NULL; - arm7_9->post_restore_context = NULL; - - /* initialize arch-specific breakpoint handling */ - arm7_9->arm_bkpt = 0xdeeedeee; - arm7_9->thumb_bkpt = 0xdeee; - - arm7_9->sw_bkpts_use_wp = 1; - arm7_9->sw_bkpts_enabled = 0; - arm7_9->dbgreq_adjust_pc = 3; - arm7_9->arch_info = arm9tdmi; - - arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC; - arm9tdmi->arch_info = NULL; - - if (variant) - { - arm9tdmi->variant = strdup(variant); - } - else - { - arm9tdmi->variant = strdup(""); - } - - arm7_9_init_arch_info(target, arm7_9); - - /* override use of DBGRQ, this is safe on ARM9TDMI */ - arm7_9->use_dbgrq = 1; - - /* all ARM9s have the vector catch register */ - arm7_9->has_vector_catch = 1; - - return ERROR_OK; -} - -int arm9tdmi_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - return -1; - } - - arm7_9 = armv4_5->arch_info; - if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) - { - return -1; - } - - arm9tdmi = arm7_9->arch_info; - if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) - { - return -1; - } - - *armv4_5_p = armv4_5; - *arm7_9_p = arm7_9; - *arm9tdmi_p = arm9tdmi; - - return ERROR_OK; -} - - -/* target arm9tdmi */ -int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t)); - - if (argc < 4) - { - ERROR("'target arm9tdmi' requires at least one additional argument"); - exit(-1); - } - - chain_pos = strtoul(args[3], NULL, 0); - - if (argc >= 5) - variant = args[4]; - - arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); - - return ERROR_OK; -} - -int arm9tdmi_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - - command_t *arm9tdmi_cmd; - - - retval = arm7_9_register_commands(cmd_ctx); - - arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands"); - - register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'']"); - - - return ERROR_OK; - -} - -int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - arm9tdmi_common_t *arm9tdmi; - reg_t *vector_catch; - u32 vector_catch_value; - int i, j; - - if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM9TDMI based target"); - return ERROR_OK; - } - - vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; - - /* read the vector catch register if necessary */ - if (!vector_catch->valid) - embeddedice_read_reg(vector_catch); - - /* get the current setting */ - vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); - - if (argc > 0) - { - vector_catch_value = 0x0; - if (strcmp(args[0], "all") == 0) - { - vector_catch_value = 0xdf; - } - else if (strcmp(args[0], "none") == 0) - { - /* do nothing */ - } - else - { - for (i = 0; i < argc; i++) - { - /* go through list of vectors */ - for(j = 0; arm9tdmi_vectors[j].name; j++) - { - if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0) - { - vector_catch_value |= arm9tdmi_vectors[j].value; - break; - } - } - - /* complain if vector wasn't found */ - if (!arm9tdmi_vectors[j].name) - { - command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]); - - /* reread current setting */ - vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); - - break; - } - } - } - - /* store new settings */ - buf_set_u32(vector_catch->value, 0, 32, vector_catch_value); - embeddedice_store_reg(vector_catch); - } - - /* output current settings (skip RESERVED vector) */ - for (i = 0; i < 8; i++) - { - if (i != 5) - { - command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name, - (vector_catch_value & (1 << i)) ? "catch" : "don't catch"); - } - } - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm9tdmi.h" + +#include "arm7_9_common.h" +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "embeddedice.h" +#include "etm.h" +#include "etb.h" +#include "log.h" +#include "jtag.h" +#include "arm_jtag.h" + +#include +#include + +#if 0 +#define _DEBUG_INSTRUCTION_EXECUTION_ +#endif + +/* cli handling */ +int arm9tdmi_register_commands(struct command_context_s *cmd_ctx); +int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +/* forward declarations */ +int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int arm9tdmi_quit(); + +target_type_t arm9tdmi_target = +{ + .name = "arm9tdmi", + + .poll = arm7_9_poll, + .arch_state = armv4_5_arch_state, + + .target_request_data = arm7_9_target_request_data, + + .halt = arm7_9_halt, + .resume = arm7_9_resume, + .step = arm7_9_step, + + .assert_reset = arm7_9_assert_reset, + .deassert_reset = arm7_9_deassert_reset, + .soft_reset_halt = arm7_9_soft_reset_halt, + .prepare_reset_halt = arm7_9_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = arm7_9_read_memory, + .write_memory = arm7_9_write_memory, + .bulk_write_memory = arm7_9_bulk_write_memory, + .checksum_memory = arm7_9_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = arm7_9_add_breakpoint, + .remove_breakpoint = arm7_9_remove_breakpoint, + .add_watchpoint = arm7_9_add_watchpoint, + .remove_watchpoint = arm7_9_remove_watchpoint, + + .register_commands = arm9tdmi_register_commands, + .target_command = arm9tdmi_target_command, + .init_target = arm9tdmi_init_target, + .quit = arm9tdmi_quit +}; + +arm9tdmi_vector_t arm9tdmi_vectors[] = +{ + {"reset", ARM9TDMI_RESET_VECTOR}, + {"undef", ARM9TDMI_UNDEF_VECTOR}, + {"swi", ARM9TDMI_SWI_VECTOR}, + {"pabt", ARM9TDMI_PABT_VECTOR}, + {"dabt", ARM9TDMI_DABT_VECTOR}, + {"reserved", ARM9TDMI_RESERVED_VECTOR}, + {"irq", ARM9TDMI_IRQ_VECTOR}, + {"fiq", ARM9TDMI_FIQ_VECTOR}, + {0, 0}, +}; + +int arm9tdmi_examine_debug_reason(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + /* only check the debug reason if we don't know it already */ + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) + { + scan_field_t fields[3]; + u8 databus[4]; + u8 instructionbus[4]; + u8 debug_reason; + + jtag_add_end_state(TAP_PD); + + fields[0].device = arm7_9->jtag_info.chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = databus; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = arm7_9->jtag_info.chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = &debug_reason; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = arm7_9->jtag_info.chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = instructionbus; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + arm_jtag_scann(&arm7_9->jtag_info, 0x1); + arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL); + + jtag_add_dr_scan(3, fields, TAP_PD); + jtag_execute_queue(); + + fields[0].in_value = NULL; + fields[0].out_value = databus; + fields[1].in_value = NULL; + fields[1].out_value = &debug_reason; + fields[2].in_value = NULL; + fields[2].out_value = instructionbus; + + jtag_add_dr_scan(3, fields, TAP_PD); + + if (debug_reason & 0x4) + if (debug_reason & 0x2) + target->debug_reason = DBG_REASON_WPTANDBKPT; + else + target->debug_reason = DBG_REASON_WATCHPOINT; + else + target->debug_reason = DBG_REASON_BREAKPOINT; + } + + return ERROR_OK; +} + +/* put an instruction in the ARM9TDMI pipeline or write the data bus, and optionally read data */ +int arm9tdmi_clock_out(arm_jtag_t *jtag_info, u32 instr, u32 out, u32 *in, int sysspeed) +{ + scan_field_t fields[3]; + u8 out_buf[4]; + u8 instr_buf[4]; + u8 sysspeed_buf = 0x0; + + /* prepare buffer */ + buf_set_u32(out_buf, 0, 32, out); + + buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); + + if (sysspeed) + buf_set_u32(&sysspeed_buf, 2, 1, 1); + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = out_buf; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + if (in) + { + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + } + else + { + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + } + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = &sysspeed_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = instr_buf; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); + } + else + DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out); + } +#endif + + return ERROR_OK; +} + +/* just read data (instruction and data-out = don't care) */ +int arm9tdmi_clock_data_in(arm_jtag_t *jtag_info, u32 *in) +{ + scan_field_t fields[3]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#endif + + return ERROR_OK; +} + +/* clock the target, and read the databus + * the *in pointer points to a buffer where elements of 'size' bytes + * are stored in big (be==1) or little (be==0) endianness + */ +int arm9tdmi_clock_data_in_endianness(arm_jtag_t *jtag_info, void *in, int size, int be) +{ + scan_field_t fields[3]; + + jtag_add_end_state(TAP_PD); + arm_jtag_scann(jtag_info, 0x1); + + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + switch (size) + { + case 4: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be32 : arm_jtag_buf_to_le32; + break; + case 2: + fields[0].in_handler = (be) ? arm_jtag_buf_to_be16 : arm_jtag_buf_to_le16; + break; + case 1: + fields[0].in_handler = arm_jtag_buf_to_8; + break; + } + fields[0].in_handler_priv = in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 3; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 32; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + jtag_add_runtest(0, -1); + +#ifdef _DEBUG_INSTRUCTION_EXECUTION_ + { + jtag_execute_queue(); + + if (in) + { + DEBUG("in: 0x%8.8x", *in); + } + else + { + ERROR("BUG: called with in == NULL"); + } + } +#endif + + return ERROR_OK; +} + +void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* save r0 before using it and put system in ARM state + * to allow common handling of ARM and THUMB debugging */ + + /* fetch STR r0, [r0] */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* STR r0, [r0] in Memory */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); + + /* MOV r0, r15 fetched, STR in Decode */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* nothing fetched, STR r0, [r0] in Memory */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); + + /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); + /* LDR in Decode */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* LDR in Memory (to account for interlock) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + /* fetch BX */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); + /* NOP fetched, BX in Decode, MOV in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* NOP fetched, BX in Execute (1) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + jtag_execute_queue(); + + /* fix program counter: + * MOV r0, r15 was the 5th instruction (+8) + * reading PC in Thumb state gives address of instruction + 4 + */ + *pc -= 0xc; +} + +void arm9tdmi_read_core_regs(target_t *target, u32 mask, u32* core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM in MEMORY (i'th cycle) */ + arm9tdmi_clock_data_in(jtag_info, core_regs[i]); + } + +} + +void arm9tdmi_read_core_regs_target_buffer(target_t *target, u32 mask, void* buffer, int size) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; + u32 *buf_u32 = buffer; + u16 *buf_u16 = buffer; + u8 *buf_u8 = buffer; + + /* STMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, STM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, STM in MEMORY (i'th cycle) */ + switch (size) + { + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; + } + } + +} + +void arm9tdmi_read_xpsr(target_t *target, u32 *xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* MRS r0, cpsr */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* STR r0, [r15] */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); + /* fetch NOP, STR in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, STR in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, STR in MEMORY */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); + +} + +void arm9tdmi_write_xpsr(target_t *target, u32 xpsr, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr: %8.8x, spsr: %i", xpsr, spsr); + + /* MSR1 fetched */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); + /* MSR2 fetched, MSR1 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); + /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR1 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR2 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR3 in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR4 in EXECUTE (1) */ + /* last MSR writes flags, which takes only one cycle */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); +} + +void arm9tdmi_write_xpsr_im8(target_t *target, u8 xpsr_im, int rot, int spsr) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); + + /* MSR fetched */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); + /* NOP fetched, MSR in DECODE */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* NOP fetched, MSR in EXECUTE (1) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* rot == 4 writes flags, which takes only one cycle */ + if (rot != 4) + { + /* nothing fetched, MSR in EXECUTE (2) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, MSR in EXECUTE (3) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + } +} + +void arm9tdmi_write_core_regs(target_t *target, u32 mask, u32 core_regs[16]) +{ + int i; + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + for (i = 0; i <= 15; i++) + { + if (mask & (1 << i)) + /* nothing fetched, LDM still in EXECUTE (1+i cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); + } + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + +} + +void arm9tdmi_load_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load-multiple into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_load_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load half-word into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); +} + +void arm9tdmi_load_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed load byte into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_word_regs(target_t *target, u32 mask) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store-multiple into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_hword_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store half-word into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_store_byte_reg(target_t *target, int num) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* put system-speed store byte into the pipeline */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_write_pc(target_t *target, u32 pc) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + +} + +void arm9tdmi_branch_resume(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); + +} + +void arm9tdmi_branch_resume_thumb(target_t *target) +{ + DEBUG("-"); + + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + reg_t *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; + + /* LDMIA r0-15, [r0] at debug speed + * register values will start to appear on 4th DCLK + */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0); + + /* fetch NOP, LDM in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) | 1, NULL, 0); + /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* Branch and eXchange */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in DECODE stage */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + /* fetch NOP, BX in EXECUTE stage (1st cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); + + /* target is now in Thumb state */ + embeddedice_read_reg(dbg_stat); + + /* load r0 value, MOV_IM in Decode*/ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); + /* fetch NOP, LDR in Decode, MOV_IM in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* fetch NOP, LDR in Execute */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32), NULL, 0); + /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + + embeddedice_read_reg(dbg_stat); + + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1); + arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); + +} + +void arm9tdmi_enable_single_step(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + if (arm7_9->has_single_step) + { + buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1); + embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); + } + else + { + arm7_9_enable_eice_step(target); + } +} + +void arm9tdmi_disable_single_step(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + + if (arm7_9->has_single_step) + { + buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0); + embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); + } + else + { + arm7_9_disable_eice_step(target); + } +} + +void arm9tdmi_build_reg_cache(target_t *target) +{ + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9 = armv4_5->arch_info; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* one extra register (vector catch) */ + (*cache_p)->next = embeddedice_build_reg_cache(target, arm7_9); + arm7_9->eice_cache = (*cache_p)->next; + + if (arm7_9->etm_ctx) + { + (*cache_p)->next->next = etm_build_reg_cache(target, jtag_info, arm7_9->etm_ctx); + arm7_9->etm_ctx->reg_cache = (*cache_p)->next->next; + } +} + +int arm9tdmi_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + + arm9tdmi_build_reg_cache(target); + + return ERROR_OK; + +} + +int arm9tdmi_quit() +{ + + return ERROR_OK; +} + +int arm9tdmi_init_arch_info(target_t *target, arm9tdmi_common_t *arm9tdmi, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + arm7_9 = &arm9tdmi->arm7_9_common; + armv4_5 = &arm7_9->armv4_5_common; + + /* prepare JTAG information for the new target */ + arm7_9->jtag_info.chain_pos = chain_pos; + arm7_9->jtag_info.scann_size = 5; + + /* register arch-specific functions */ + arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; + arm7_9->change_to_arm = arm9tdmi_change_to_arm; + arm7_9->read_core_regs = arm9tdmi_read_core_regs; + arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; + arm7_9->read_xpsr = arm9tdmi_read_xpsr; + + arm7_9->write_xpsr = arm9tdmi_write_xpsr; + arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8; + arm7_9->write_core_regs = arm9tdmi_write_core_regs; + + arm7_9->load_word_regs = arm9tdmi_load_word_regs; + arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; + arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; + + arm7_9->store_word_regs = arm9tdmi_store_word_regs; + arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; + arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; + + arm7_9->write_pc = arm9tdmi_write_pc; + arm7_9->branch_resume = arm9tdmi_branch_resume; + arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb; + + arm7_9->enable_single_step = arm9tdmi_enable_single_step; + arm7_9->disable_single_step = arm9tdmi_disable_single_step; + + arm7_9->pre_debug_entry = NULL; + arm7_9->post_debug_entry = NULL; + + arm7_9->pre_restore_context = NULL; + arm7_9->post_restore_context = NULL; + + /* initialize arch-specific breakpoint handling */ + arm7_9->arm_bkpt = 0xdeeedeee; + arm7_9->thumb_bkpt = 0xdeee; + + arm7_9->sw_bkpts_use_wp = 1; + arm7_9->sw_bkpts_enabled = 0; + arm7_9->dbgreq_adjust_pc = 3; + arm7_9->arch_info = arm9tdmi; + + arm9tdmi->common_magic = ARM9TDMI_COMMON_MAGIC; + arm9tdmi->arch_info = NULL; + + if (variant) + { + arm9tdmi->variant = strdup(variant); + } + else + { + arm9tdmi->variant = strdup(""); + } + + arm7_9_init_arch_info(target, arm7_9); + + /* override use of DBGRQ, this is safe on ARM9TDMI */ + arm7_9->use_dbgrq = 1; + + /* all ARM9s have the vector catch register */ + arm7_9->has_vector_catch = 1; + + return ERROR_OK; +} + +int arm9tdmi_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, arm7_9_common_t **arm7_9_p, arm9tdmi_common_t **arm9tdmi_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + return -1; + } + + arm7_9 = armv4_5->arch_info; + if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC) + { + return -1; + } + + arm9tdmi = arm7_9->arch_info; + if (arm9tdmi->common_magic != ARM9TDMI_COMMON_MAGIC) + { + return -1; + } + + *armv4_5_p = armv4_5; + *arm7_9_p = arm7_9; + *arm9tdmi_p = arm9tdmi; + + return ERROR_OK; +} + + +/* target arm9tdmi */ +int arm9tdmi_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + arm9tdmi_common_t *arm9tdmi = malloc(sizeof(arm9tdmi_common_t)); + + if (argc < 4) + { + ERROR("'target arm9tdmi' requires at least one additional argument"); + exit(-1); + } + + chain_pos = strtoul(args[3], NULL, 0); + + if (argc >= 5) + variant = args[4]; + + arm9tdmi_init_arch_info(target, arm9tdmi, chain_pos, variant); + + return ERROR_OK; +} + +int arm9tdmi_register_commands(struct command_context_s *cmd_ctx) +{ + int retval; + + command_t *arm9tdmi_cmd; + + + retval = arm7_9_register_commands(cmd_ctx); + + arm9tdmi_cmd = register_command(cmd_ctx, NULL, "arm9tdmi", NULL, COMMAND_ANY, "arm9tdmi specific commands"); + + register_command(cmd_ctx, arm9tdmi_cmd, "vector_catch", handle_arm9tdmi_catch_vectors_command, COMMAND_EXEC, "catch arm920t vectors ['all'|'none'|'']"); + + + return ERROR_OK; + +} + +int handle_arm9tdmi_catch_vectors_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + arm9tdmi_common_t *arm9tdmi; + reg_t *vector_catch; + u32 vector_catch_value; + int i, j; + + if (arm9tdmi_get_arch_pointers(target, &armv4_5, &arm7_9, &arm9tdmi) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM9TDMI based target"); + return ERROR_OK; + } + + vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; + + /* read the vector catch register if necessary */ + if (!vector_catch->valid) + embeddedice_read_reg(vector_catch); + + /* get the current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + if (argc > 0) + { + vector_catch_value = 0x0; + if (strcmp(args[0], "all") == 0) + { + vector_catch_value = 0xdf; + } + else if (strcmp(args[0], "none") == 0) + { + /* do nothing */ + } + else + { + for (i = 0; i < argc; i++) + { + /* go through list of vectors */ + for(j = 0; arm9tdmi_vectors[j].name; j++) + { + if (strcmp(args[i], arm9tdmi_vectors[j].name) == 0) + { + vector_catch_value |= arm9tdmi_vectors[j].value; + break; + } + } + + /* complain if vector wasn't found */ + if (!arm9tdmi_vectors[j].name) + { + command_print(cmd_ctx, "vector '%s' not found, leaving current setting unchanged", args[i]); + + /* reread current setting */ + vector_catch_value = buf_get_u32(vector_catch->value, 0, 32); + + break; + } + } + } + + /* store new settings */ + buf_set_u32(vector_catch->value, 0, 32, vector_catch_value); + embeddedice_store_reg(vector_catch); + } + + /* output current settings (skip RESERVED vector) */ + for (i = 0; i < 8; i++) + { + if (i != 5) + { + command_print(cmd_ctx, "%s: %s", arm9tdmi_vectors[i].name, + (vector_catch_value & (1 << i)) ? "catch" : "don't catch"); + } + } + + return ERROR_OK; +} diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 070af213..08cf3462 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -1,207 +1,207 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "arm_jtag.h" - -#include "binarybuffer.h" -#include "log.h" -#include "jtag.h" - -#include - -#if 0 -#define _ARM_JTAG_SCAN_N_CHECK_ -#endif - -int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler) -{ - jtag_device_t *device = jtag_get_device(jtag_info->chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = jtag_info->chain_pos; - field.num_bits = device->ir_length; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_instr); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = handler; - field.in_handler_priv = NULL; - jtag_add_ir_scan(1, &field, -1, NULL); - - - free(field.out_value); - } - - return ERROR_OK; -} - -int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain) -{ - if(jtag_info->cur_scan_chain != new_scan_chain) - { -#ifdef _ARM_JTAG_SCAN_N_CHECK_ - u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1); -#endif - scan_field_t field; - - field.device = jtag_info->chain_pos; - field.num_bits = jtag_info->scann_size; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); - field.out_mask = NULL; - field.in_value = NULL; -#ifdef _ARM_JTAG_SCAN_N_CHECK_ - jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL); -#else - field.in_handler = NULL; - field.in_handler_priv = NULL; -#endif - - - arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL); - jtag_add_dr_scan(1, &field, -1, NULL); - - jtag_info->cur_scan_chain = new_scan_chain; - - free(field.out_value); - } - - return ERROR_OK; -} - -int arm_jtag_reset_callback(enum jtag_event event, void *priv) -{ - arm_jtag_t *jtag_info = priv; - - if (event == JTAG_TRST_ASSERTED) - { - jtag_info->cur_scan_chain = 0; - } - - return ERROR_OK; -} - -int arm_jtag_setup_connection(arm_jtag_t *jtag_info) -{ - jtag_info->scann_instr = 0x2; - jtag_info->cur_scan_chain = 0; - jtag_info->intest_instr = 0xc; - - jtag_register_event_callback(arm_jtag_reset_callback, jtag_info); - - return ERROR_OK; -} - -/* read JTAG buffer into host-endian u32, flipping bit-order */ -int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u32 *dest = priv; - *dest = flip_u32(le_to_h_u32(in_buf), 32); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u32, flipping bit-order */ -int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u16, flipping bit-order */ -int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u32, flipping bit-order */ -int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u16, flipping bit-order */ -int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into u8, flipping bit-order */ -int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u8 *dest = priv; - *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff; - return ERROR_OK; -} - -/* not-flipping variants */ -/* read JTAG buffer into host-endian u32 */ -int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u32 *dest = priv; - *dest = le_to_h_u32(in_buf); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u32 */ -int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf)); - return ERROR_OK; -} - -/* read JTAG buffer into little-endian u16 */ -int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u32 */ -int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf)); - return ERROR_OK; -} - -/* read JTAG buffer into big-endian u16 */ -int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); - return ERROR_OK; -} - -/* read JTAG buffer into u8 */ -int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field) -{ - u8 *dest = priv; - *dest = le_to_h_u32(in_buf) & 0xff; - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arm_jtag.h" + +#include "binarybuffer.h" +#include "log.h" +#include "jtag.h" + +#include + +#if 0 +#define _ARM_JTAG_SCAN_N_CHECK_ +#endif + +int arm_jtag_set_instr(arm_jtag_t *jtag_info, u32 new_instr, in_handler_t handler) +{ + jtag_device_t *device = jtag_get_device(jtag_info->chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = jtag_info->chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = handler; + field.in_handler_priv = NULL; + jtag_add_ir_scan(1, &field, -1); + + + free(field.out_value); + } + + return ERROR_OK; +} + +int arm_jtag_scann(arm_jtag_t *jtag_info, u32 new_scan_chain) +{ + if(jtag_info->cur_scan_chain != new_scan_chain) + { +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + u8 scan_n_check_value = 1 << (jtag_info->scann_size - 1); +#endif + scan_field_t field; + + field.device = jtag_info->chain_pos; + field.num_bits = jtag_info->scann_size; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); + field.out_mask = NULL; + field.in_value = NULL; +#ifdef _ARM_JTAG_SCAN_N_CHECK_ + jtag_set_check_value(&field, &scan_n_check_value, NULL, NULL, NULL); +#else + field.in_handler = NULL; + field.in_handler_priv = NULL; +#endif + + + arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL); + jtag_add_dr_scan(1, &field, -1); + + jtag_info->cur_scan_chain = new_scan_chain; + + free(field.out_value); + } + + return ERROR_OK; +} + +int arm_jtag_reset_callback(enum jtag_event event, void *priv) +{ + arm_jtag_t *jtag_info = priv; + + if (event == JTAG_TRST_ASSERTED) + { + jtag_info->cur_scan_chain = 0; + } + + return ERROR_OK; +} + +int arm_jtag_setup_connection(arm_jtag_t *jtag_info) +{ + jtag_info->scann_instr = 0x2; + jtag_info->cur_scan_chain = 0; + jtag_info->intest_instr = 0xc; + + jtag_register_event_callback(arm_jtag_reset_callback, jtag_info); + + return ERROR_OK; +} + +/* read JTAG buffer into host-endian u32, flipping bit-order */ +int arm_jtag_buf_to_u32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32, flipping bit-order */ +int arm_jtag_buf_to_le32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16, flipping bit-order */ +int arm_jtag_buf_to_le16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32, flipping bit-order */ +int arm_jtag_buf_to_be32_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16, flipping bit-order */ +int arm_jtag_buf_to_be16_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), flip_u32(le_to_h_u32(in_buf), 32) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8, flipping bit-order */ +int arm_jtag_buf_to_8_flip(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = flip_u32(le_to_h_u32(in_buf), 32) & 0xff; + return ERROR_OK; +} + +/* not-flipping variants */ +/* read JTAG buffer into host-endian u32 */ +int arm_jtag_buf_to_u32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u32 *dest = priv; + *dest = le_to_h_u32(in_buf); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u32 */ +int arm_jtag_buf_to_le32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_le(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into little-endian u16 */ +int arm_jtag_buf_to_le16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_le(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u32 */ +int arm_jtag_buf_to_be32(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u32_to_be(((u8*)priv), le_to_h_u32(in_buf)); + return ERROR_OK; +} + +/* read JTAG buffer into big-endian u16 */ +int arm_jtag_buf_to_be16(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + h_u16_to_be(((u8*)priv), le_to_h_u32(in_buf) & 0xffff); + return ERROR_OK; +} + +/* read JTAG buffer into u8 */ +int arm_jtag_buf_to_8(u8 *in_buf, void *priv, struct scan_field_s *field) +{ + u8 *dest = priv; + *dest = le_to_h_u32(in_buf) & 0xff; + return ERROR_OK; +} diff --git a/src/target/cortex_swjdp.c b/src/target/cortex_swjdp.c index 8cefcbfd..88b641e3 100644 --- a/src/target/cortex_swjdp.c +++ b/src/target/cortex_swjdp.c @@ -1,708 +1,708 @@ -/*************************************************************************** - * Copyright (C) 2006 by Magnus Lundin * - * lundin@mlu.mine.nu * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -/*************************************************************************** - * * - * CoreSight (Light?) SerialWireJtagDebugPort * - * * - * CoreSight™ DAP-Lite TRM, ARM DDI 0316A * - * Cortex-M3™ TRM, ARM DDI 0337C * - * * -***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "cortex_m3.h" -#include "cortex_swjdp.h" -#include "jtag.h" -#include "log.h" -#include - -/* - -Transaction Mode: -swjdp->trans_mode = TRANS_MODE_COMPOSITE; -Uses Overrun checking mode and does not do actual JTAG send/receive or transaction -result checking until swjdp_end_transaction() -This must be done before using or deallocating any return variables. - -swjdp->trans_mode == TRANS_MODE_ATOMIC -All reads and writes to the AHB bus are checked for valid completion, and return values -are immediatley available. - -*/ - -/*************************************************************************** - * * - * DPACC and APACC scanchain access through JTAG-DR * - * * -***************************************************************************/ - -/* Scan out and in from target ordered u8 buffers */ -int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack) -{ - scan_field_t fields[2]; - u8 out_addr_buf; - - jtag_add_end_state(TAP_RTI); - arm_jtag_set_instr(jtag_info, instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 3; - buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); - fields[0].out_value = &out_addr_buf; - fields[0].out_mask = NULL; - fields[0].in_value = ack; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = outvalue; - fields[1].out_mask = NULL; - fields[1].in_value = invalue; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - return ERROR_OK; -} - -/* Scan out and in from host ordered u32 variables */ -int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack) -{ - scan_field_t fields[2]; - u8 out_value_buf[4]; - u8 out_addr_buf; - - jtag_add_end_state(TAP_RTI); - arm_jtag_set_instr(jtag_info, instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 3; - buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); - fields[0].out_value = &out_addr_buf; - fields[0].out_mask = NULL; - fields[0].in_value = ack; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 32; - buf_set_u32(out_value_buf, 0, 32, outvalue); - fields[1].out_value = out_value_buf; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - if (invalue) - { - fields[1].in_handler = arm_jtag_buf_to_u32; - fields[1].in_handler_priv = invalue; - } - else - { - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - } - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - return ERROR_OK; -} - -/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ -int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue) -{ - swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); - if ((RnW == DPAP_READ) && (invalue != NULL)) - { - swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); - } - - /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */ - if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - { - return swjdp_transaction_endcheck(swjdp); - } - - return ERROR_OK; -} - -int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue) -{ - - swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); - if ((RnW==DPAP_READ) && (invalue != NULL)) - { - swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); - } - - /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */ - if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) - { - return swjdp_transaction_endcheck(swjdp); - } - - return ERROR_OK; -} - -int swjdp_transaction_endcheck(swjdp_common_t *swjdp) -{ - int waitcount = 0; - u32 ctrlstat; - - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - - swjdp->ack = swjdp->ack & 0x7; - - while (swjdp->ack != 2) - { - if (swjdp->ack == 1) - { - waitcount++; - if (waitcount > 100) - { - WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction"); - - return ERROR_JTAG_DEVICE_ERROR; - } - } - else - { - WARNING("Invalid ACK in SWJDP transaction"); - return ERROR_JTAG_DEVICE_ERROR; - } - - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - swjdp->ack = swjdp->ack & 0x7; - } - - /* Check for STICKYERR and STICKYORUN */ - if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) - { - DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat); - /* Check power to debug regions */ - if ((ctrlstat & 0xf0000000) != 0xf0000000) - { - ahbap_debugport_init(swjdp); - } - else - { - u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr; - - if (ctrlstat & SSTICKYORUN) - ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed"); - - if (ctrlstat & SSTICKYERR) - ERROR("SWJ-DP STICKY ERROR"); - - /* Clear Sticky Error Bits */ - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); - jtag_execute_queue(); - - DEBUG("swjdp: status 0x%x", ctrlstat); - - /* Can we find out the reason for the error ?? */ - ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr); - ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar); - ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar); - } - jtag_execute_queue(); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -/*************************************************************************** - * * - * DP and AHB-AP register access through APACC and DPACC * - * * -***************************************************************************/ - -int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr) -{ - u8 out_value_buf[4]; - - buf_set_u32(out_value_buf, 0, 32, value); - return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); -} - -int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr) -{ - scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value); - - return ERROR_OK; -} - -int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr) -{ - u32 select; - select = (reg_addr & 0xFF0000F0); - - if (select != swjdp->dp_select_value) - { - swjdp_write_dpacc(swjdp, select, DP_SELECT); - swjdp->dp_select_value = select; - } - - return ERROR_OK; -} - -int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); - - return ERROR_OK; -} - -int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf); - - return ERROR_OK; -} -int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value) -{ - u8 out_value_buf[4]; - - buf_set_u32(out_value_buf, 0, 32, value); - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); - - return ERROR_OK; -} - -int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value) -{ - swjdp_bankselect_apacc(swjdp, reg_addr); - scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value); - - return ERROR_OK; -} - -/*************************************************************************** - * * - * AHB-AP access to memory and system registers on AHB bus * - * * -***************************************************************************/ - -int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar) -{ - csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; - if (csw != swjdp->ap_csw_value) - { - //DEBUG("swjdp : Set CSW %x",csw); - ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw ); - swjdp->ap_csw_value = csw; - } - if (tar != swjdp->ap_tar_value) - { - //DEBUG("swjdp : Set TAR %x",tar); - ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar ); - swjdp->ap_tar_value = tar; - } - if (csw & CSW_ADDRINC_MASK) - { - /* Do not cache TAR value when autoincrementing */ - swjdp->ap_tar_value = -1; - } - return ERROR_OK; -} - -/***************************************************************************** -* * -* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) * -* * -* Read a u32 value from memory or system register * -* Functionally equivalent to target_read_u32(target, address, u32 *value), * -* but with less overhead * -*****************************************************************************/ -int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) -{ - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); - - return ERROR_OK; -} - -int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value) -{ - ahbap_read_system_u32(swjdp, address, value); - - return swjdp_transaction_endcheck(swjdp); -} - -/***************************************************************************** -* * -* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) * -* * -* Write a u32 value to memory or system register * -* * -*****************************************************************************/ -int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) -{ - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); - - return ERROR_OK; -} - -int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value) -{ - ahbap_write_system_u32(swjdp, address, value); - - return swjdp_transaction_endcheck(swjdp); -} - -/***************************************************************************** -* * -* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * -* * -* Write a buffer in target order (little endian) * -* * -*****************************************************************************/ -int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 outvalue; - int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while ((address & 0x3) && (count > 0)) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - outvalue = (*buffer++) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - swjdp_transaction_endcheck(swjdp); - count--; - address++; - } - wcount = count >> 2; - count = count - 4 * wcount; - while (wcount > 0) - { - /* Adjust to write blocks within 4K aligned boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (wcount < blocksize) - blocksize = wcount; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - for (writecount=0; writecount 1) - { - WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - outvalue = (*buffer++) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - retval = swjdp_transaction_endcheck(swjdp); - count--; - address++; - } - - return retval; -} - -int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 outvalue; - int retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); - outvalue = *((u16*)buffer) << 8 * (address & 0x3); - ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); - retval = swjdp_transaction_endcheck(swjdp); - count -= 2; - address += 2; - buffer += 2; - } - - return retval; -} - -/***************************************************************************** -* * -* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * -* * -* Read block fast in target order (little endian) into a buffer * -* * -*****************************************************************************/ -int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 invalue; - int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while ((address & 0x3) && (count > 0)) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue); - swjdp_transaction_endcheck(swjdp); - *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; - count--; - address++; - } - wcount = count >> 2; - count = count - 4 * wcount; - while (wcount > 0) - { - /* Adjust to read within 4K block boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (wcount < blocksize) - blocksize = wcount; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - /* Scan out first read */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL); - for (readcount = 0; readcount < blocksize - 1; readcount++) - { - /* Scan out read instruction and scan in previous value */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); - } - /* Scan in last value */ - swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); - if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) - { - wcount = wcount - blocksize; - address += 4 * blocksize; - buffer += 4 * blocksize; - } - else - { - errorcount++; - } - if (errorcount > 1) - { - WARNING("Block read error address 0x%x, count 0x%x", address, count); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); - retval = swjdp_transaction_endcheck(swjdp); - *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; - count--; - address++; - } - - return retval; -} - -int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) -{ - u32 invalue; - int retval = ERROR_OK; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); - ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); - retval = swjdp_transaction_endcheck(swjdp); - *((u16*)buffer) = (invalue >> 8 * (address & 0x3)); - count -= 2; - address += 2; - buffer += 2; - } - - return retval; -} - -int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address) -{ - int readcount, errorcount = 0; - u32 blocksize; - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - while (count > 0) - { - /* Adjust to read within 4K block boundaries */ - blocksize = (0x1000 - (0xFFF & address)) >> 2; - if (count < blocksize) - blocksize = count; - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); - for (readcount = 0; readcount < blocksize; readcount++) - { - ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount ); - } - if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) - { - count = count - blocksize; - address = address + 4 * blocksize; - buffer = buffer + blocksize; - } - else - { - errorcount++; - } - if (errorcount > 1) - { - WARNING("Block read error address 0x%x, count 0x%x", address, count); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - return ERROR_OK; -} - -int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum) -{ - int retval; - u32 dcrdr; - - ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum ); - - /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); - - retval = swjdp_transaction_endcheck(swjdp); - ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); - return retval; -} - -int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum) -{ - int retval; - u32 dcrdr; - - ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); - - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - - /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); - - /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */ - ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR ); - - retval = swjdp_transaction_endcheck(swjdp); - ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); - return retval; -} - -int ahbap_debugport_init(swjdp_common_t *swjdp) -{ - u32 idreg, romaddr, dummy; - u32 ctrlstat; - int cnt = 0; - - DEBUG(" "); - - swjdp->ap_csw_value = -1; - swjdp->ap_tar_value = -1; - swjdp->trans_mode = TRANS_MODE_ATOMIC; - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - - swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; - - swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - - /* Check that we have debug power domains activated */ - while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) - { - DEBUG("swjdp: wait CDBGPWRUPACK"); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - usleep(10000); - } - - while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) - { - DEBUG("swjdp: wait CSYSPWRUPACK"); - swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); - jtag_execute_queue(); - usleep(10000); - } - - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - /* With debug power on we can activate OVERRUN checking */ - swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; - swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT); - swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); - - ahbap_read_reg_u32(swjdp, 0xFC, &idreg); - ahbap_read_reg_u32(swjdp, 0xF8, &romaddr); - - DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2006 by Magnus Lundin * + * lundin@mlu.mine.nu * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/*************************************************************************** + * * + * CoreSight (Light?) SerialWireJtagDebugPort * + * * + * CoreSight™ DAP-Lite TRM, ARM DDI 0316A * + * Cortex-M3™ TRM, ARM DDI 0337C * + * * +***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "cortex_m3.h" +#include "cortex_swjdp.h" +#include "jtag.h" +#include "log.h" +#include + +/* + +Transaction Mode: +swjdp->trans_mode = TRANS_MODE_COMPOSITE; +Uses Overrun checking mode and does not do actual JTAG send/receive or transaction +result checking until swjdp_end_transaction() +This must be done before using or deallocating any return variables. + +swjdp->trans_mode == TRANS_MODE_ATOMIC +All reads and writes to the AHB bus are checked for valid completion, and return values +are immediatley available. + +*/ + +/*************************************************************************** + * * + * DPACC and APACC scanchain access through JTAG-DR * + * * +***************************************************************************/ + +/* Scan out and in from target ordered u8 buffers */ +int swjdp_scan(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = outvalue; + fields[1].out_mask = NULL; + fields[1].in_value = invalue; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +/* Scan out and in from host ordered u32 variables */ +int swjdp_scan_u32(arm_jtag_t *jtag_info, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue, u8 *ack) +{ + scan_field_t fields[2]; + u8 out_value_buf[4]; + u8 out_addr_buf; + + jtag_add_end_state(TAP_RTI); + arm_jtag_set_instr(jtag_info, instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 3; + buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); + fields[0].out_value = &out_addr_buf; + fields[0].out_mask = NULL; + fields[0].in_value = ack; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 32; + buf_set_u32(out_value_buf, 0, 32, outvalue); + fields[1].out_value = out_value_buf; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + if (invalue) + { + fields[1].in_handler = arm_jtag_buf_to_u32; + fields[1].in_handler_priv = invalue; + } + else + { + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + } + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +/* scan_inout_check adds one extra inscan for DPAP_READ commands to read variables */ +int scan_inout_check(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u8 *outvalue, u8 *invalue) +{ + swjdp_scan(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW == DPAP_READ) && (invalue != NULL)) + { + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and the check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int scan_inout_check_u32(swjdp_common_t *swjdp, u8 instr, u8 reg_addr, u8 RnW, u32 outvalue, u32 *invalue) +{ + + swjdp_scan_u32(swjdp->jtag_info, instr, reg_addr, RnW, outvalue, NULL, NULL); + if ((RnW==DPAP_READ) && (invalue != NULL)) + { + swjdp_scan_u32(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, invalue, &swjdp->ack); + } + + /* In TRANS_MODE_ATOMIC all SWJDP_IR_APACC transactions wait for ack=OK/FAULT and then check CTRL_STAT */ + if ((instr == SWJDP_IR_APACC) && (swjdp->trans_mode == TRANS_MODE_ATOMIC)) + { + return swjdp_transaction_endcheck(swjdp); + } + + return ERROR_OK; +} + +int swjdp_transaction_endcheck(swjdp_common_t *swjdp) +{ + int waitcount = 0; + u32 ctrlstat; + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + swjdp->ack = swjdp->ack & 0x7; + + while (swjdp->ack != 2) + { + if (swjdp->ack == 1) + { + waitcount++; + if (waitcount > 100) + { + WARNING("Timeout waiting for ACK = OK/FAULT in SWJDP transaction"); + + return ERROR_JTAG_DEVICE_ERROR; + } + } + else + { + WARNING("Invalid ACK in SWJDP transaction"); + return ERROR_JTAG_DEVICE_ERROR; + } + + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + swjdp->ack = swjdp->ack & 0x7; + } + + /* Check for STICKYERR and STICKYORUN */ + if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) + { + DEBUG("swjdp: CTRL/STAT error 0x%x", ctrlstat); + /* Check power to debug regions */ + if ((ctrlstat & 0xf0000000) != 0xf0000000) + { + ahbap_debugport_init(swjdp); + } + else + { + u32 dcb_dhcsr,nvic_shcsr, nvic_bfar, nvic_cfsr; + + if (ctrlstat & SSTICKYORUN) + ERROR("SWJ-DP OVERRUN - check clock or reduce jtag speed"); + + if (ctrlstat & SSTICKYERR) + ERROR("SWJ-DP STICKY ERROR"); + + /* Clear Sticky Error Bits */ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_WRITE, swjdp->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); + jtag_execute_queue(); + + DEBUG("swjdp: status 0x%x", ctrlstat); + + /* Can we find out the reason for the error ?? */ + ahbap_read_system_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_SHCSR, &nvic_shcsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_CFSR, &nvic_cfsr); + ahbap_read_system_atomic_u32(swjdp, NVIC_BFAR, &nvic_bfar); + ERROR("dcb_dhcsr 0x%x, nvic_shcsr 0x%x, nvic_cfsr 0x%x, nvic_bfar 0x%x", dcb_dhcsr, nvic_shcsr, nvic_cfsr, nvic_bfar); + } + jtag_execute_queue(); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +/*************************************************************************** + * * + * DP and AHB-AP register access through APACC and DPACC * + * * +***************************************************************************/ + +int swjdp_write_dpacc(swjdp_common_t *swjdp, u32 value, u8 reg_addr) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + return scan_inout_check(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); +} + +int swjdp_read_dpacc(swjdp_common_t *swjdp, u32 *value, u8 reg_addr) +{ + scan_inout_check_u32(swjdp, SWJDP_IR_DPACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +int swjdp_bankselect_apacc(swjdp_common_t *swjdp,u32 reg_addr) +{ + u32 select; + select = (reg_addr & 0xFF0000F0); + + if (select != swjdp->dp_select_value) + { + swjdp_write_dpacc(swjdp, select, DP_SELECT); + swjdp->dp_select_value = select; + } + + return ERROR_OK; +} + +int ahbap_write_reg(swjdp_common_t *swjdp, u32 reg_addr, u8* out_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg(swjdp_common_t *swjdp, u32 reg_addr, u8 *in_value_buf) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, in_value_buf); + + return ERROR_OK; +} +int ahbap_write_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 value) +{ + u8 out_value_buf[4]; + + buf_set_u32(out_value_buf, 0, 32, value); + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_WRITE, out_value_buf, NULL); + + return ERROR_OK; +} + +int ahbap_read_reg_u32(swjdp_common_t *swjdp, u32 reg_addr, u32 *value) +{ + swjdp_bankselect_apacc(swjdp, reg_addr); + scan_inout_check_u32(swjdp, SWJDP_IR_APACC, reg_addr, DPAP_READ, 0, value); + + return ERROR_OK; +} + +/*************************************************************************** + * * + * AHB-AP access to memory and system registers on AHB bus * + * * +***************************************************************************/ + +int ahbap_setup_accessport(swjdp_common_t *swjdp, u32 csw, u32 tar) +{ + csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT; + if (csw != swjdp->ap_csw_value) + { + //DEBUG("swjdp : Set CSW %x",csw); + ahbap_write_reg_u32(swjdp, AHBAP_CSW, csw ); + swjdp->ap_csw_value = csw; + } + if (tar != swjdp->ap_tar_value) + { + //DEBUG("swjdp : Set TAR %x",tar); + ahbap_write_reg_u32(swjdp, AHBAP_TAR, tar ); + swjdp->ap_tar_value = tar; + } + if (csw & CSW_ADDRINC_MASK) + { + /* Do not cache TAR value when autoincrementing */ + swjdp->ap_tar_value = -1; + } + return ERROR_OK; +} + +/***************************************************************************** +* * +* ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) * +* * +* Read a u32 value from memory or system register * +* Functionally equivalent to target_read_u32(target, address, u32 *value), * +* but with less overhead * +*****************************************************************************/ +int ahbap_read_system_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_read_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 *value) +{ + ahbap_read_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) * +* * +* Write a u32 value to memory or system register * +* * +*****************************************************************************/ +int ahbap_write_system_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (address & 0xC), value ); + + return ERROR_OK; +} + +int ahbap_write_system_atomic_u32(swjdp_common_t *swjdp, u32 address, u32 value) +{ + ahbap_write_system_u32(swjdp, address, value); + + return swjdp_transaction_endcheck(swjdp); +} + +/***************************************************************************** +* * +* ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Write a buffer in target order (little endian) * +* * +*****************************************************************************/ +int ahbap_write_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to write blocks within 4K aligned boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (writecount=0; writecount 1) + { + WARNING("Block write error address 0x%x, wcount 0x%x", address, wcount); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + outvalue = (*buffer++) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count--; + address++; + } + + return retval; +} + +int ahbap_write_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 outvalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + outvalue = *((u16*)buffer) << 8 * (address & 0x3); + ahbap_write_reg_u32(swjdp, AHBAP_DRW, outvalue ); + retval = swjdp_transaction_endcheck(swjdp); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +/***************************************************************************** +* * +* ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) * +* * +* Read block fast in target order (little endian) into a buffer * +* * +*****************************************************************************/ +int ahbap_read_buf(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while ((address & 0x3) && (count > 0)) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue); + swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + wcount = count >> 2; + count = count - 4 * wcount; + while (wcount > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (wcount < blocksize) + blocksize = wcount; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + /* Scan out first read */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, NULL, NULL); + for (readcount = 0; readcount < blocksize - 1; readcount++) + { + /* Scan out read instruction and scan in previous value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_APACC, AHBAP_DRW, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + } + /* Scan in last value */ + swjdp_scan(swjdp->jtag_info, SWJDP_IR_DPACC, 0xC, DPAP_READ, 0, buffer + 4 * readcount, &swjdp->ack); + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + wcount = wcount - blocksize; + address += 4 * blocksize; + buffer += 4 * blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_8BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *buffer++ = (invalue >> 8 * (address & 0x3)) & 0xFF; + count--; + address++; + } + + return retval; +} + +int ahbap_read_buf_u16(swjdp_common_t *swjdp, u8 *buffer, int count, u32 address) +{ + u32 invalue; + int retval = ERROR_OK; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + ahbap_setup_accessport(swjdp, CSW_16BIT | CSW_ADDRINC_SINGLE, address); + ahbap_read_reg_u32(swjdp, AHBAP_DRW, &invalue ); + retval = swjdp_transaction_endcheck(swjdp); + *((u16*)buffer) = (invalue >> 8 * (address & 0x3)); + count -= 2; + address += 2; + buffer += 2; + } + + return retval; +} + +int ahbap_block_read_u32(swjdp_common_t *swjdp, u32 *buffer, int count, u32 address) +{ + int readcount, errorcount = 0; + u32 blocksize; + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + while (count > 0) + { + /* Adjust to read within 4K block boundaries */ + blocksize = (0x1000 - (0xFFF & address)) >> 2; + if (count < blocksize) + blocksize = count; + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_SINGLE, address); + for (readcount = 0; readcount < blocksize; readcount++) + { + ahbap_read_reg_u32(swjdp, AHBAP_DRW, buffer + readcount ); + } + if (swjdp_transaction_endcheck(swjdp) == ERROR_OK) + { + count = count - blocksize; + address = address + 4 * blocksize; + buffer = buffer + blocksize; + } + else + { + errorcount++; + } + if (errorcount > 1) + { + WARNING("Block read error address 0x%x, count 0x%x", address, count); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + return ERROR_OK; +} + +int ahbap_read_coreregister_u32(swjdp_common_t *swjdp, u32 *value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, regnum); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum ); + + /* ahbap_read_system_u32(swjdp, DCB_DCRDR, value); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_read_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_write_coreregister_u32(swjdp_common_t *swjdp, u32 value, int regnum) +{ + int retval; + u32 dcrdr; + + ahbap_read_system_atomic_u32(swjdp, DCB_DCRDR, &dcrdr); + + swjdp->trans_mode = TRANS_MODE_COMPOSITE; + + /* ahbap_write_system_u32(swjdp, DCB_DCRDR, core_regs[i]); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRDR & 0xC), value ); + + /* ahbap_write_system_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR ); */ + ahbap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); + ahbap_write_reg_u32(swjdp, AHBAP_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR ); + + retval = swjdp_transaction_endcheck(swjdp); + ahbap_write_system_atomic_u32(swjdp, DCB_DCRDR, dcrdr); + return retval; +} + +int ahbap_debugport_init(swjdp_common_t *swjdp) +{ + u32 idreg, romaddr, dummy; + u32 ctrlstat; + int cnt = 0; + + DEBUG(" "); + + swjdp->ap_csw_value = -1; + swjdp->ap_tar_value = -1; + swjdp->trans_mode = TRANS_MODE_ATOMIC; + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + swjdp_write_dpacc(swjdp, SSTICKYERR, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat, DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + + /* Check that we have debug power domains activated */ + while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CDBGPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) + { + DEBUG("swjdp: wait CSYSPWRUPACK"); + swjdp_read_dpacc(swjdp, &ctrlstat, DP_CTRL_STAT); + jtag_execute_queue(); + usleep(10000); + } + + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + /* With debug power on we can activate OVERRUN checking */ + swjdp->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; + swjdp_write_dpacc(swjdp, swjdp->dp_ctrl_stat , DP_CTRL_STAT); + swjdp_read_dpacc(swjdp, &dummy, DP_CTRL_STAT); + + ahbap_read_reg_u32(swjdp, 0xFC, &idreg); + ahbap_read_reg_u32(swjdp, 0xF8, &romaddr); + + DEBUG("AHB-AP ID Register 0x%x, Debug ROM Address 0x%x", idreg, romaddr); + + return ERROR_OK; +} diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 3713fe95..07b965b0 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -1,565 +1,565 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "embeddedice.h" - -#include "armv4_5.h" -#include "arm7_9_common.h" - -#include "log.h" -#include "arm_jtag.h" -#include "types.h" -#include "binarybuffer.h" -#include "target.h" -#include "register.h" -#include "jtag.h" - -#include - -bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] = -{ - {"R", 1}, - {"W", 1}, - {"reserved", 26}, - {"version", 4} -}; - -int embeddedice_reg_arch_info[] = -{ - 0x0, 0x1, 0x4, 0x5, - 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x2 -}; - -char* embeddedice_reg_list[] = -{ - "debug_ctrl", - "debug_status", - - "comms_ctrl", - "comms_data", - - "watch 0 addr value", - "watch 0 addr mask", - "watch 0 data value", - "watch 0 data mask", - "watch 0 control value", - "watch 0 control mask", - - "watch 1 addr value", - "watch 1 addr mask", - "watch 1 data value", - "watch 1 data mask", - "watch 1 control value", - "watch 1 control mask", - - "vector catch" -}; - -int embeddedice_reg_arch_type = -1; - -int embeddedice_get_reg(reg_t *reg); -int embeddedice_set_reg(reg_t *reg, u32 value); -int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf); - -int embeddedice_write_reg(reg_t *reg, u32 value); -int embeddedice_read_reg(reg_t *reg); - -reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm7_9_common_t *arm7_9) -{ - reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); - reg_t *reg_list = NULL; - embeddedice_reg_t *arch_info = NULL; - arm_jtag_t *jtag_info = &arm7_9->jtag_info; - int num_regs; - int i; - int eice_version = 0; - - /* register a register arch-type for EmbeddedICE registers only once */ - if (embeddedice_reg_arch_type == -1) - embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec); - - if (arm7_9->has_vector_catch) - num_regs = 17; - else - num_regs = 16; - - /* the actual registers are kept in two arrays */ - reg_list = calloc(num_regs, sizeof(reg_t)); - arch_info = calloc(num_regs, sizeof(embeddedice_reg_t)); - - /* fill in values for the reg cache */ - reg_cache->name = "EmbeddedICE registers"; - reg_cache->next = NULL; - reg_cache->reg_list = reg_list; - reg_cache->num_regs = num_regs; - - /* set up registers */ - for (i = 0; i < num_regs; i++) - { - reg_list[i].name = embeddedice_reg_list[i]; - reg_list[i].size = 32; - reg_list[i].dirty = 0; - reg_list[i].valid = 0; - reg_list[i].bitfield_desc = NULL; - reg_list[i].num_bitfields = 0; - reg_list[i].value = calloc(1, 4); - reg_list[i].arch_info = &arch_info[i]; - reg_list[i].arch_type = embeddedice_reg_arch_type; - arch_info[i].addr = embeddedice_reg_arch_info[i]; - arch_info[i].jtag_info = jtag_info; - } - - /* identify EmbeddedICE version by reading DCC control register */ - embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); - jtag_execute_queue(); - - eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); - - switch (eice_version) - { - case 1: - reg_list[EICE_DBG_CTRL].size = 3; - reg_list[EICE_DBG_STAT].size = 5; - break; - case 2: - reg_list[EICE_DBG_CTRL].size = 4; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - break; - case 3: - ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken"); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 4: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - case 5: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 6: - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 10; - arm7_9->has_monitor_mode = 1; - break; - case 7: - WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken"); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - default: - ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); - } - - /* explicitly disable monitor mode */ - if (arm7_9->has_monitor_mode) - { - embeddedice_read_reg(®_list[EICE_DBG_CTRL]); - jtag_execute_queue(); - buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0); - embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value); - } - - return reg_cache; -} - -int embeddedice_get_reg(reg_t *reg) -{ - if (embeddedice_read_reg(reg) != ERROR_OK) - { - ERROR("BUG: error scheduling EmbeddedICE register read"); - exit(-1); - } - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register read failed"); - } - - return ERROR_OK; -} - -int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) -{ - embeddedice_reg_t *ice_reg = reg->arch_info; - u8 reg_addr = ice_reg->addr & 0x1f; - scan_field_t fields[3]; - u8 field1_out[1]; - u8 field2_out[1]; - - DEBUG("%i", ice_reg->addr); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(ice_reg->jtag_info, 0x2); - - arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); - - fields[0].device = ice_reg->jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = reg->value; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = ice_reg->jtag_info->chain_pos; - fields[1].num_bits = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = ice_reg->jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = field2_out; - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - fields[0].in_value = reg->value; - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - /* when reading the DCC data register, leaving the address field set to - * EICE_COMMS_DATA would read the register twice - * reading the control register is safe - */ - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); - - jtag_add_dr_scan(3, fields, -1, NULL); - - return ERROR_OK; -} - -/* receive words of 32 bit from the DCC - * we pretend the target is always going to be fast enough - * (relative to the JTAG clock), so we don't need to handshake - */ -int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size) -{ - scan_field_t fields[3]; - u8 field1_out[1]; - u8 field2_out[1]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = field2_out; - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - while (size > 0) - { - /* when reading the last item, set the register address to the DCC control reg, - * to avoid reading additional data from the DCC data reg - */ - if (size == 1) - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); - - fields[0].in_handler = arm_jtag_buf_to_u32; - fields[0].in_handler_priv = data; - jtag_add_dr_scan(3, fields, -1, NULL); - - data++; - size--; - } - - return jtag_execute_queue(); -} - -int embeddedice_read_reg(reg_t *reg) -{ - return embeddedice_read_reg_w_check(reg, NULL, NULL); -} - -int embeddedice_set_reg(reg_t *reg, u32 value) -{ - if (embeddedice_write_reg(reg, value) != ERROR_OK) - { - ERROR("BUG: error scheduling EmbeddedICE register write"); - exit(-1); - } - - buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; - - return ERROR_OK; -} - -int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf) -{ - embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register write failed"); - exit(-1); - } - return ERROR_OK; -} - -int embeddedice_write_reg(reg_t *reg, u32 value) -{ - embeddedice_reg_t *ice_reg = reg->arch_info; - u8 reg_addr = ice_reg->addr & 0x1f; - scan_field_t fields[3]; - u8 field0_out[4]; - u8 field1_out[1]; - u8 field2_out[1]; - - DEBUG("%i: 0x%8.8x", ice_reg->addr, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(ice_reg->jtag_info, 0x2); - - arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); - - fields[0].device = ice_reg->jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = field0_out; - buf_set_u32(fields[0].out_value, 0, 32, value); - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = ice_reg->jtag_info->chain_pos; - fields[1].num_bits = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = ice_reg->jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = field2_out; - buf_set_u32(fields[2].out_value, 0, 1, 1); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - return ERROR_OK; -} - -int embeddedice_store_reg(reg_t *reg) -{ - return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); -} - -/* send words of 32 bit to the DCC - * we pretend the target is always going to be fast enough - * (relative to the JTAG clock), so we don't need to handshake - */ -int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size) -{ - scan_field_t fields[3]; - u8 field0_out[4]; - u8 field1_out[1]; - u8 field2_out[1]; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = field0_out; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = field2_out; - buf_set_u32(fields[2].out_value, 0, 1, 1); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - while (size > 0) - { - buf_set_u32(fields[0].out_value, 0, 32, *data); - jtag_add_dr_scan(3, fields, -1, NULL); - - data++; - size--; - } - - /* call to jtag_execute_queue() intentionally omitted */ - return ERROR_OK; -} - -/* wait for DCC control register R/W handshake bit to become active - */ -int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout) -{ - scan_field_t fields[3]; - u8 field0_in[4]; - u8 field1_out[1]; - u8 field2_out[1]; - int retval; - int hsact; - struct timeval lap; - struct timeval now; - - if (hsbit == EICE_COMM_CTRL_WBIT) - hsact = 1; - else if (hsbit == EICE_COMM_CTRL_RBIT) - hsact = 0; - else - return ERROR_INVALID_ARGUMENTS; - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(jtag_info, 0x2); - arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); - - fields[0].device = jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = field0_in; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = jtag_info->chain_pos; - fields[1].num_bits = 5; - fields[1].out_value = field1_out; - buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = field2_out; - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - gettimeofday(&lap, NULL); - do - { - jtag_add_dr_scan(3, fields, -1, NULL); - if ((retval = jtag_execute_queue()) != ERROR_OK) - return retval; - - if (buf_get_u32(field0_in, hsbit, 1) == hsact) - return ERROR_OK; - - gettimeofday(&now, NULL); - } - while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout); - - return ERROR_TARGET_TIMEOUT; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "embeddedice.h" + +#include "armv4_5.h" +#include "arm7_9_common.h" + +#include "log.h" +#include "arm_jtag.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" + +#include + +bitfield_desc_t embeddedice_comms_ctrl_bitfield_desc[] = +{ + {"R", 1}, + {"W", 1}, + {"reserved", 26}, + {"version", 4} +}; + +int embeddedice_reg_arch_info[] = +{ + 0x0, 0x1, 0x4, 0x5, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x2 +}; + +char* embeddedice_reg_list[] = +{ + "debug_ctrl", + "debug_status", + + "comms_ctrl", + "comms_data", + + "watch 0 addr value", + "watch 0 addr mask", + "watch 0 data value", + "watch 0 data mask", + "watch 0 control value", + "watch 0 control mask", + + "watch 1 addr value", + "watch 1 addr mask", + "watch 1 data value", + "watch 1 data mask", + "watch 1 control value", + "watch 1 control mask", + + "vector catch" +}; + +int embeddedice_reg_arch_type = -1; + +int embeddedice_get_reg(reg_t *reg); +int embeddedice_set_reg(reg_t *reg, u32 value); +int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf); + +int embeddedice_write_reg(reg_t *reg, u32 value); +int embeddedice_read_reg(reg_t *reg); + +reg_cache_t* embeddedice_build_reg_cache(target_t *target, arm7_9_common_t *arm7_9) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + embeddedice_reg_t *arch_info = NULL; + arm_jtag_t *jtag_info = &arm7_9->jtag_info; + int num_regs; + int i; + int eice_version = 0; + + /* register a register arch-type for EmbeddedICE registers only once */ + if (embeddedice_reg_arch_type == -1) + embeddedice_reg_arch_type = register_reg_arch_type(embeddedice_get_reg, embeddedice_set_reg_w_exec); + + if (arm7_9->has_vector_catch) + num_regs = 17; + else + num_regs = 16; + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(embeddedice_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "EmbeddedICE registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = embeddedice_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = embeddedice_reg_arch_type; + arch_info[i].addr = embeddedice_reg_arch_info[i]; + arch_info[i].jtag_info = jtag_info; + } + + /* identify EmbeddedICE version by reading DCC control register */ + embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); + jtag_execute_queue(); + + eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); + + switch (eice_version) + { + case 1: + reg_list[EICE_DBG_CTRL].size = 3; + reg_list[EICE_DBG_STAT].size = 5; + break; + case 2: + reg_list[EICE_DBG_CTRL].size = 4; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + break; + case 3: + ERROR("EmbeddedICE version 3 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 4: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + case 5: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 6: + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 10; + arm7_9->has_monitor_mode = 1; + break; + case 7: + WARNING("EmbeddedICE version 7 detected, EmbeddedICE handling might be broken"); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + default: + ERROR("unknown EmbeddedICE version (comms ctrl: 0x%8.8x)", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); + } + + /* explicitly disable monitor mode */ + if (arm7_9->has_monitor_mode) + { + embeddedice_read_reg(®_list[EICE_DBG_CTRL]); + jtag_execute_queue(); + buf_set_u32(reg_list[EICE_DBG_CTRL].value, 4, 1, 0); + embeddedice_set_reg_w_exec(®_list[EICE_DBG_CTRL], reg_list[EICE_DBG_CTRL].value); + } + + return reg_cache; +} + +int embeddedice_get_reg(reg_t *reg) +{ + if (embeddedice_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling EmbeddedICE register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int embeddedice_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + embeddedice_reg_t *ice_reg = reg->arch_info; + u8 reg_addr = ice_reg->addr & 0x1f; + scan_field_t fields[3]; + u8 field1_out[1]; + u8 field2_out[1]; + + DEBUG("%i", ice_reg->addr); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(ice_reg->jtag_info, 0x2); + + arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); + + fields[0].device = ice_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = ice_reg->jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = ice_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_value = reg->value; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + /* when reading the DCC data register, leaving the address field set to + * EICE_COMMS_DATA would read the register twice + * reading the control register is safe + */ + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +/* receive words of 32 bit from the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_receive(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + while (size > 0) + { + /* when reading the last item, set the register address to the DCC control reg, + * to avoid reading additional data from the DCC data reg + */ + if (size == 1) + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + + fields[0].in_handler = arm_jtag_buf_to_u32; + fields[0].in_handler_priv = data; + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + return jtag_execute_queue(); +} + +int embeddedice_read_reg(reg_t *reg) +{ + return embeddedice_read_reg_w_check(reg, NULL, NULL); +} + +int embeddedice_set_reg(reg_t *reg, u32 value) +{ + if (embeddedice_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling EmbeddedICE register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int embeddedice_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int embeddedice_write_reg(reg_t *reg, u32 value) +{ + embeddedice_reg_t *ice_reg = reg->arch_info; + u8 reg_addr = ice_reg->addr & 0x1f; + scan_field_t fields[3]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + DEBUG("%i: 0x%8.8x", ice_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(ice_reg->jtag_info, 0x2); + + arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL); + + fields[0].device = ice_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = ice_reg->jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = ice_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +int embeddedice_store_reg(reg_t *reg) +{ + return embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +/* send words of 32 bit to the DCC + * we pretend the target is always going to be fast enough + * (relative to the JTAG clock), so we don't need to handshake + */ +int embeddedice_send(arm_jtag_t *jtag_info, u32 *data, u32 size) +{ + scan_field_t fields[3]; + u8 field0_out[4]; + u8 field1_out[1]; + u8 field2_out[1]; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = field0_out; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_DATA]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + while (size > 0) + { + buf_set_u32(fields[0].out_value, 0, 32, *data); + jtag_add_dr_scan(3, fields, -1); + + data++; + size--; + } + + /* call to jtag_execute_queue() intentionally omitted */ + return ERROR_OK; +} + +/* wait for DCC control register R/W handshake bit to become active + */ +int embeddedice_handshake(arm_jtag_t *jtag_info, int hsbit, u32 timeout) +{ + scan_field_t fields[3]; + u8 field0_in[4]; + u8 field1_out[1]; + u8 field2_out[1]; + int retval; + int hsact; + struct timeval lap; + struct timeval now; + + if (hsbit == EICE_COMM_CTRL_WBIT) + hsact = 1; + else if (hsbit == EICE_COMM_CTRL_RBIT) + hsact = 0; + else + return ERROR_INVALID_ARGUMENTS; + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(jtag_info, 0x2); + arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL); + + fields[0].device = jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = field0_in; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = jtag_info->chain_pos; + fields[1].num_bits = 5; + fields[1].out_value = field1_out; + buf_set_u32(fields[1].out_value, 0, 5, embeddedice_reg_arch_info[EICE_COMMS_CTRL]); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = field2_out; + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + gettimeofday(&lap, NULL); + do + { + jtag_add_dr_scan(3, fields, -1); + if ((retval = jtag_execute_queue()) != ERROR_OK) + return retval; + + if (buf_get_u32(field0_in, hsbit, 1) == hsact) + return ERROR_OK; + + gettimeofday(&now, NULL); + } + while ((now.tv_sec-lap.tv_sec)*1000 + (now.tv_usec-lap.tv_usec)/1000 <= timeout); + + return ERROR_TARGET_TIMEOUT; +} diff --git a/src/target/etb.c b/src/target/etb.c index 0c409fb0..6c9d3a0c 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -1,741 +1,741 @@ -/*************************************************************************** - * Copyright (C) 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "arm7_9_common.h" -#include "etb.h" -#include "etm.h" - -#include "log.h" -#include "types.h" -#include "binarybuffer.h" -#include "target.h" -#include "register.h" -#include "jtag.h" - -#include - -char* etb_reg_list[] = -{ - "ETB_identification", - "ETB_ram_depth", - "ETB_ram_width", - "ETB_status", - "ETB_ram_data", - "ETB_ram_read_pointer", - "ETB_ram_write_pointer", - "ETB_trigger_counter", - "ETB_control", -}; - -int etb_reg_arch_type = -1; - -int etb_get_reg(reg_t *reg); -int etb_set_reg(reg_t *reg, u32 value); -int etb_set_reg_w_exec(reg_t *reg, u8 *buf); - -int etb_write_reg(reg_t *reg, u32 value); -int etb_read_reg(reg_t *reg); - -int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int etb_set_instr(etb_t *etb, u32 new_instr) -{ - jtag_device_t *device = jtag_get_device(etb->chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = etb->chain_pos; - field.num_bits = device->ir_length; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_instr); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - jtag_add_ir_scan(1, &field, -1, NULL); - - free(field.out_value); - } - - return ERROR_OK; -} - -int etb_scann(etb_t *etb, u32 new_scan_chain) -{ - if(etb->cur_scan_chain != new_scan_chain) - { - scan_field_t field; - - field.device = etb->chain_pos; - field.num_bits = 5; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); - field.out_mask = NULL; - field.in_value = NULL; - field.in_check_value = NULL; - field.in_check_mask = NULL; - field.in_handler = NULL; - field.in_handler_priv = NULL; - - /* select INTEST instruction */ - etb_set_instr(etb, 0x2); - jtag_add_dr_scan(1, &field, -1, NULL); - - etb->cur_scan_chain = new_scan_chain; - - free(field.out_value); - } - - return ERROR_OK; -} - -reg_cache_t* etb_build_reg_cache(etb_t *etb) -{ - reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); - reg_t *reg_list = NULL; - etb_reg_t *arch_info = NULL; - int num_regs = 9; - int i; - - /* register a register arch-type for etm registers only once */ - if (etb_reg_arch_type == -1) - etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_set_reg_w_exec); - - /* the actual registers are kept in two arrays */ - reg_list = calloc(num_regs, sizeof(reg_t)); - arch_info = calloc(num_regs, sizeof(etb_reg_t)); - - /* fill in values for the reg cache */ - reg_cache->name = "etb registers"; - reg_cache->next = NULL; - reg_cache->reg_list = reg_list; - reg_cache->num_regs = num_regs; - - /* set up registers */ - for (i = 0; i < num_regs; i++) - { - reg_list[i].name = etb_reg_list[i]; - reg_list[i].size = 32; - reg_list[i].dirty = 0; - reg_list[i].valid = 0; - reg_list[i].bitfield_desc = NULL; - reg_list[i].num_bitfields = 0; - reg_list[i].value = calloc(1, 4); - reg_list[i].arch_info = &arch_info[i]; - reg_list[i].arch_type = etb_reg_arch_type; - reg_list[i].size = 32; - arch_info[i].addr = i; - arch_info[i].etb = etb; - } - - return reg_cache; -} - -int etb_get_reg(reg_t *reg) -{ - if (etb_read_reg(reg) != ERROR_OK) - { - ERROR("BUG: error scheduling etm register read"); - exit(-1); - } - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register read failed"); - } - - return ERROR_OK; -} - -int etb_read_ram(etb_t *etb, u32 *data, int num_frames) -{ - scan_field_t fields[3]; - int i; - - jtag_add_end_state(TAP_RTI); - etb_scann(etb, 0x0); - etb_set_instr(etb, 0xc); - - fields[0].device = etb->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = etb->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, 4); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = etb->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - fields[0].in_handler = buf_to_u32_handler; - - for (i = 0; i < num_frames; i++) - { - /* ensure nR/W reamins set to read */ - buf_set_u32(fields[2].out_value, 0, 1, 0); - - /* address remains set to 0x4 (RAM data) until we read the last frame */ - if (i < num_frames - 1) - buf_set_u32(fields[1].out_value, 0, 7, 4); - else - buf_set_u32(fields[1].out_value, 0, 7, 0); - - fields[0].in_handler_priv = &data[i]; - jtag_add_dr_scan(3, fields, -1, NULL); - } - - jtag_execute_queue(); - - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) -{ - etb_reg_t *etb_reg = reg->arch_info; - u8 reg_addr = etb_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i", etb_reg->addr); - - jtag_add_end_state(TAP_RTI); - etb_scann(etb_reg->etb, 0x0); - etb_set_instr(etb_reg->etb, 0xc); - - fields[0].device = etb_reg->etb->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = reg->value; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = etb_reg->etb->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = etb_reg->etb->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - /* read the identification register in the second run, to make sure we - * don't read the ETB data register twice, skipping every second entry - */ - buf_set_u32(fields[1].out_value, 0, 7, 0x0); - fields[0].in_value = reg->value; - - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1, NULL); - - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etb_read_reg(reg_t *reg) -{ - return etb_read_reg_w_check(reg, NULL, NULL); -} - -int etb_set_reg(reg_t *reg, u32 value) -{ - if (etb_write_reg(reg, value) != ERROR_OK) - { - ERROR("BUG: error scheduling etm register write"); - exit(-1); - } - - buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; - - return ERROR_OK; -} - -int etb_set_reg_w_exec(reg_t *reg, u8 *buf) -{ - etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register write failed"); - exit(-1); - } - return ERROR_OK; -} - -int etb_write_reg(reg_t *reg, u32 value) -{ - etb_reg_t *etb_reg = reg->arch_info; - u8 reg_addr = etb_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i: 0x%8.8x", etb_reg->addr, value); - - jtag_add_end_state(TAP_RTI); - etb_scann(etb_reg->etb, 0x0); - etb_set_instr(etb_reg->etb, 0xc); - - fields[0].device = etb_reg->etb->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = malloc(4); - buf_set_u32(fields[0].out_value, 0, 32, value); - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = etb_reg->etb->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = etb_reg->etb->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 1); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - free(fields[0].out_value); - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etb_store_reg(reg_t *reg) -{ - return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); -} - -int etb_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *etb_cmd; - - etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); - - register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); - - return ERROR_OK; -} - -int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - jtag_device_t *jtag_device; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - - if (argc != 2) - { - ERROR("incomplete 'etb config ' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); - - if (!jtag_device) - { - ERROR("jtag device number '%s' not defined", args[1]); - exit(-1); - } - - if (arm7_9->etm_ctx) - { - etb_t *etb = malloc(sizeof(etb_t)); - - arm7_9->etm_ctx->capture_driver_priv = etb; - - etb->chain_pos = strtoul(args[1], NULL, 0); - etb->cur_scan_chain = -1; - etb->reg_cache = NULL; - etb->ram_width = 0; - etb->ram_depth = 0; - } - else - { - ERROR("target has no ETM defined, ETB left unconfigured"); - } - - return ERROR_OK; -} - -int etb_init(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - - etb->etm_ctx = etm_ctx; - - /* identify ETB RAM depth and width */ - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); - jtag_execute_queue(); - - etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); - etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); - - return ERROR_OK; -} - -trace_status_t etb_status(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - - etb->etm_ctx = etm_ctx; - - /* if tracing is currently idle, return this information */ - if (etm_ctx->capture_status == TRACE_IDLE) - { - return etm_ctx->capture_status; - } - else if (etm_ctx->capture_status & TRACE_RUNNING) - { - reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; - int etb_timeout = 100; - - /* trace is running, check the ETB status flags */ - etb_get_reg(etb_status_reg); - - /* check Full bit to identify an overflow */ - if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) - etm_ctx->capture_status |= TRACE_OVERFLOWED; - - /* check Triggered bit to identify trigger condition */ - if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) - etm_ctx->capture_status |= TRACE_TRIGGERED; - - /* check AcqComp to identify trace completion */ - if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) - { - while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) - { - /* wait for data formatter idle */ - etb_get_reg(etb_status_reg); - } - - if (etb_timeout == 0) - { - ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", - buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); - } - - if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) - { - ERROR("trace completed, but no trigger condition detected"); - } - - etm_ctx->capture_status &= ~TRACE_RUNNING; - etm_ctx->capture_status |= TRACE_COMPLETED; - } - } - - return etm_ctx->capture_status; -} - -int etb_read_trace(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - int first_frame = 0; - int num_frames = etb->ram_depth; - u32 *trace_data = NULL; - int i, j; - - etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); - etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); - jtag_execute_queue(); - - /* check if we overflowed, and adjust first frame of the trace accordingly - * if we didn't overflow, read only up to the frame that would be written next, - * i.e. don't read invalid entries - */ - if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) - { - first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); - } - else - { - num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); - } - - etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); - - /* read data into temporary array for unpacking */ - trace_data = malloc(sizeof(u32) * num_frames); - etb_read_ram(etb, trace_data, num_frames); - - if (etm_ctx->trace_depth > 0) - { - free(etm_ctx->trace_data); - } - - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) - etm_ctx->trace_depth = num_frames * 3; - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - etm_ctx->trace_depth = num_frames * 2; - else - etm_ctx->trace_depth = num_frames; - - etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); - - for (i = 0, j = 0; i < num_frames; i++) - { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x80) >> 7) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+1 */ - etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8; - etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11; - etm_ctx->trace_data[j+1].flags = 0; - if ((trace_data[i] & 0x8000) >> 15) - { - etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; - etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+2 */ - etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16; - etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19; - etm_ctx->trace_data[j+2].flags = 0; - if ((trace_data[i] & 0x800000) >> 23) - { - etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+2].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7; - etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 3; - } - else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x800) >> 11) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - /* trace word j+1 */ - etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12; - etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15; - etm_ctx->trace_data[j+1].flags = 0; - if ((trace_data[i] & 0x800000) >> 23) - { - etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) - { - etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; - etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 2; - } - else - { - /* trace word j */ - etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; - etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; - etm_ctx->trace_data[j].flags = 0; - if ((trace_data[i] & 0x80000) >> 19) - { - etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; - } - if (etm_ctx->trace_data[j].pipestat == STAT_TR) - { - etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; - etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; - } - - j += 1; - } - } - - free(trace_data); - - return ERROR_OK; -} - -int etb_start_capture(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - u32 etb_ctrl_value = 0x1; - u32 trigger_count; - - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) - { - if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) - { - ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - } - etb_ctrl_value |= 0x2; - } - - if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) - return ERROR_ETM_PORTMODE_NOT_SUPPORTED; - - trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; - - etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); - etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); - etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); - jtag_execute_queue(); - - /* we're starting a new trace, initialize capture status */ - etm_ctx->capture_status = TRACE_RUNNING; - - return ERROR_OK; -} - -int etb_stop_capture(etm_context_t *etm_ctx) -{ - etb_t *etb = etm_ctx->capture_driver_priv; - reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; - - etb_write_reg(etb_ctrl_reg, 0x0); - jtag_execute_queue(); - - /* trace stopped, just clear running flag, but preserve others */ - etm_ctx->capture_status &= ~TRACE_RUNNING; - - return ERROR_OK; -} - -etm_capture_driver_t etb_capture_driver = -{ - .name = "etb", - .register_commands = etb_register_commands, - .init = etb_init, - .status = etb_status, - .start_capture = etb_start_capture, - .stop_capture = etb_stop_capture, - .read_trace = etb_read_trace, -}; +/*************************************************************************** + * Copyright (C) 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "arm7_9_common.h" +#include "etb.h" +#include "etm.h" + +#include "log.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" + +#include + +char* etb_reg_list[] = +{ + "ETB_identification", + "ETB_ram_depth", + "ETB_ram_width", + "ETB_status", + "ETB_ram_data", + "ETB_ram_read_pointer", + "ETB_ram_write_pointer", + "ETB_trigger_counter", + "ETB_control", +}; + +int etb_reg_arch_type = -1; + +int etb_get_reg(reg_t *reg); +int etb_set_reg(reg_t *reg, u32 value); +int etb_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etb_write_reg(reg_t *reg, u32 value); +int etb_read_reg(reg_t *reg); + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int etb_set_instr(etb_t *etb, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(etb->chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = etb->chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + jtag_add_ir_scan(1, &field, -1); + + free(field.out_value); + } + + return ERROR_OK; +} + +int etb_scann(etb_t *etb, u32 new_scan_chain) +{ + if(etb->cur_scan_chain != new_scan_chain) + { + scan_field_t field; + + field.device = etb->chain_pos; + field.num_bits = 5; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_scan_chain); + field.out_mask = NULL; + field.in_value = NULL; + field.in_check_value = NULL; + field.in_check_mask = NULL; + field.in_handler = NULL; + field.in_handler_priv = NULL; + + /* select INTEST instruction */ + etb_set_instr(etb, 0x2); + jtag_add_dr_scan(1, &field, -1); + + etb->cur_scan_chain = new_scan_chain; + + free(field.out_value); + } + + return ERROR_OK; +} + +reg_cache_t* etb_build_reg_cache(etb_t *etb) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + etb_reg_t *arch_info = NULL; + int num_regs = 9; + int i; + + /* register a register arch-type for etm registers only once */ + if (etb_reg_arch_type == -1) + etb_reg_arch_type = register_reg_arch_type(etb_get_reg, etb_set_reg_w_exec); + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(etb_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "etb registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = etb_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = etb_reg_arch_type; + reg_list[i].size = 32; + arch_info[i].addr = i; + arch_info[i].etb = etb; + } + + return reg_cache; +} + +int etb_get_reg(reg_t *reg) +{ + if (etb_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int etb_read_ram(etb_t *etb, u32 *data, int num_frames) +{ + scan_field_t fields[3]; + int i; + + jtag_add_end_state(TAP_RTI); + etb_scann(etb, 0x0); + etb_set_instr(etb, 0xc); + + fields[0].device = etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, 4); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_handler = buf_to_u32_handler; + + for (i = 0; i < num_frames; i++) + { + /* ensure nR/W reamins set to read */ + buf_set_u32(fields[2].out_value, 0, 1, 0); + + /* address remains set to 0x4 (RAM data) until we read the last frame */ + if (i < num_frames - 1) + buf_set_u32(fields[1].out_value, 0, 7, 4); + else + buf_set_u32(fields[1].out_value, 0, 7, 0); + + fields[0].in_handler_priv = &data[i]; + jtag_add_dr_scan(3, fields, -1); + } + + jtag_execute_queue(); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i", etb_reg->addr); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb_reg->etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb_reg->etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + /* read the identification register in the second run, to make sure we + * don't read the ETB data register twice, skipping every second entry + */ + buf_set_u32(fields[1].out_value, 0, 7, 0x0); + fields[0].in_value = reg->value; + + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_read_reg(reg_t *reg) +{ + return etb_read_reg_w_check(reg, NULL, NULL); +} + +int etb_set_reg(reg_t *reg, u32 value) +{ + if (etb_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int etb_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int etb_write_reg(reg_t *reg, u32 value) +{ + etb_reg_t *etb_reg = reg->arch_info; + u8 reg_addr = etb_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i: 0x%8.8x", etb_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + etb_scann(etb_reg->etb, 0x0); + etb_set_instr(etb_reg->etb, 0xc); + + fields[0].device = etb_reg->etb->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = malloc(4); + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etb_reg->etb->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etb_reg->etb->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + free(fields[0].out_value); + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etb_store_reg(reg_t *reg) +{ + return etb_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +int etb_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *etb_cmd; + + etb_cmd = register_command(cmd_ctx, NULL, "etb", NULL, COMMAND_ANY, "Embedded Trace Buffer"); + + register_command(cmd_ctx, etb_cmd, "config", handle_etb_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + jtag_device_t *jtag_device; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + + if (argc != 2) + { + ERROR("incomplete 'etb config ' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + jtag_device = jtag_get_device(strtoul(args[1], NULL, 0)); + + if (!jtag_device) + { + ERROR("jtag device number '%s' not defined", args[1]); + exit(-1); + } + + if (arm7_9->etm_ctx) + { + etb_t *etb = malloc(sizeof(etb_t)); + + arm7_9->etm_ctx->capture_driver_priv = etb; + + etb->chain_pos = strtoul(args[1], NULL, 0); + etb->cur_scan_chain = -1; + etb->reg_cache = NULL; + etb->ram_width = 0; + etb->ram_depth = 0; + } + else + { + ERROR("target has no ETM defined, ETB left unconfigured"); + } + + return ERROR_OK; +} + +int etb_init(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* identify ETB RAM depth and width */ + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); + jtag_execute_queue(); + + etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); + etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); + + return ERROR_OK; +} + +trace_status_t etb_status(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + + etb->etm_ctx = etm_ctx; + + /* if tracing is currently idle, return this information */ + if (etm_ctx->capture_status == TRACE_IDLE) + { + return etm_ctx->capture_status; + } + else if (etm_ctx->capture_status & TRACE_RUNNING) + { + reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS]; + int etb_timeout = 100; + + /* trace is running, check the ETB status flags */ + etb_get_reg(etb_status_reg); + + /* check Full bit to identify an overflow */ + if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) + etm_ctx->capture_status |= TRACE_OVERFLOWED; + + /* check Triggered bit to identify trigger condition */ + if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) + etm_ctx->capture_status |= TRACE_TRIGGERED; + + /* check AcqComp to identify trace completion */ + if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) + { + while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) + { + /* wait for data formatter idle */ + etb_get_reg(etb_status_reg); + } + + if (etb_timeout == 0) + { + ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%x", + buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size)); + } + + if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) + { + ERROR("trace completed, but no trigger condition detected"); + } + + etm_ctx->capture_status &= ~TRACE_RUNNING; + etm_ctx->capture_status |= TRACE_COMPLETED; + } + } + + return etm_ctx->capture_status; +} + +int etb_read_trace(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + int first_frame = 0; + int num_frames = etb->ram_depth; + u32 *trace_data = NULL; + int i, j; + + etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); + etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); + jtag_execute_queue(); + + /* check if we overflowed, and adjust first frame of the trace accordingly + * if we didn't overflow, read only up to the frame that would be written next, + * i.e. don't read invalid entries + */ + if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) + { + first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + else + { + num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); + } + + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); + + /* read data into temporary array for unpacking */ + trace_data = malloc(sizeof(u32) * num_frames); + etb_read_ram(etb, trace_data, num_frames); + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + etm_ctx->trace_depth = num_frames * 3; + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + etm_ctx->trace_depth = num_frames * 2; + else + etm_ctx->trace_depth = num_frames; + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0, j = 0; i < num_frames; i++) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80) >> 7) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x100) >> 8; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7800) >> 11; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x8000) >> 15) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+2 */ + etm_ctx->trace_data[j+2].pipestat = (trace_data[i] & 0x10000) >> 16; + etm_ctx->trace_data[j+2].packet = (trace_data[i] & 0x780000) >> 19; + etm_ctx->trace_data[j+2].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+2].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+2].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+2].pipestat = etm_ctx->trace_data[j+2].packet & 0x7; + etm_ctx->trace_data[j+2].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 3; + } + else if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x800) >> 11) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + /* trace word j+1 */ + etm_ctx->trace_data[j+1].pipestat = (trace_data[i] & 0x7000) >> 12; + etm_ctx->trace_data[j+1].packet = (trace_data[i] & 0x7f8000) >> 15; + etm_ctx->trace_data[j+1].flags = 0; + if ((trace_data[i] & 0x800000) >> 23) + { + etm_ctx->trace_data[j+1].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j+1].pipestat == STAT_TR) + { + etm_ctx->trace_data[j+1].pipestat = etm_ctx->trace_data[j+1].packet & 0x7; + etm_ctx->trace_data[j+1].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 2; + } + else + { + /* trace word j */ + etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; + etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; + etm_ctx->trace_data[j].flags = 0; + if ((trace_data[i] & 0x80000) >> 19) + { + etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; + } + if (etm_ctx->trace_data[j].pipestat == STAT_TR) + { + etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; + etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; + } + + j += 1; + } + } + + free(trace_data); + + return ERROR_OK; +} + +int etb_start_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + u32 etb_ctrl_value = 0x1; + u32 trigger_count; + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) + { + if ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) + { + ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + } + etb_ctrl_value |= 0x2; + } + + if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) + return ERROR_ETM_PORTMODE_NOT_SUPPORTED; + + trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; + + etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); + etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); + etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); + jtag_execute_queue(); + + /* we're starting a new trace, initialize capture status */ + etm_ctx->capture_status = TRACE_RUNNING; + + return ERROR_OK; +} + +int etb_stop_capture(etm_context_t *etm_ctx) +{ + etb_t *etb = etm_ctx->capture_driver_priv; + reg_t *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; + + etb_write_reg(etb_ctrl_reg, 0x0); + jtag_execute_queue(); + + /* trace stopped, just clear running flag, but preserve others */ + etm_ctx->capture_status &= ~TRACE_RUNNING; + + return ERROR_OK; +} + +etm_capture_driver_t etb_capture_driver = +{ + .name = "etb", + .register_commands = etb_register_commands, + .init = etb_init, + .status = etb_status, + .start_capture = etb_start_capture, + .stop_capture = etb_stop_capture, + .read_trace = etb_read_trace, +}; diff --git a/src/target/etm.c b/src/target/etm.c index 0d20b0d5..fe4ac77f 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1,1863 +1,1863 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "etm.h" -#include "etb.h" - -#include "armv4_5.h" -#include "arm7_9_common.h" -#include "arm_disassembler.h" -#include "arm_simulator.h" - -#include "log.h" -#include "arm_jtag.h" -#include "types.h" -#include "binarybuffer.h" -#include "target.h" -#include "register.h" -#include "jtag.h" -#include "fileio.h" - -#include - -/* ETM register access functionality - * - */ - -bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = -{ - {"R", 1}, - {"W", 1}, - {"reserved", 26}, - {"version", 4} -}; - -int etm_reg_arch_info[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, -}; - -int etm_reg_arch_size_info[] = -{ - 32, 32, 17, 8, 3, 9, 32, 16, - 17, 26, 25, 8, 17, 32, 32, 17, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 16, 16, 16, 16, 18, 18, 18, 18, - 17, 17, 17, 17, 16, 16, 16, 16, - 17, 17, 17, 17, 17, 17, 2, - 17, 17, 17, 17, 32, 32, 32, 32 -}; - -char* etm_reg_list[] = -{ - "ETM_CTRL", - "ETM_CONFIG", - "ETM_TRIG_EVENT", - "ETM_MMD_CTRL", - "ETM_STATUS", - "ETM_SYS_CONFIG", - "ETM_TRACE_RESOURCE_CTRL", - "ETM_TRACE_EN_CTRL2", - "ETM_TRACE_EN_EVENT", - "ETM_TRACE_EN_CTRL1", - "ETM_FIFOFULL_REGION", - "ETM_FIFOFULL_LEVEL", - "ETM_VIEWDATA_EVENT", - "ETM_VIEWDATA_CTRL1", - "ETM_VIEWDATA_CTRL2", - "ETM_VIEWDATA_CTRL3", - "ETM_ADDR_COMPARATOR_VALUE1", - "ETM_ADDR_COMPARATOR_VALUE2", - "ETM_ADDR_COMPARATOR_VALUE3", - "ETM_ADDR_COMPARATOR_VALUE4", - "ETM_ADDR_COMPARATOR_VALUE5", - "ETM_ADDR_COMPARATOR_VALUE6", - "ETM_ADDR_COMPARATOR_VALUE7", - "ETM_ADDR_COMPARATOR_VALUE8", - "ETM_ADDR_COMPARATOR_VALUE9", - "ETM_ADDR_COMPARATOR_VALUE10", - "ETM_ADDR_COMPARATOR_VALUE11", - "ETM_ADDR_COMPARATOR_VALUE12", - "ETM_ADDR_COMPARATOR_VALUE13", - "ETM_ADDR_COMPARATOR_VALUE14", - "ETM_ADDR_COMPARATOR_VALUE15", - "ETM_ADDR_COMPARATOR_VALUE16", - "ETM_ADDR_ACCESS_TYPE1", - "ETM_ADDR_ACCESS_TYPE2", - "ETM_ADDR_ACCESS_TYPE3", - "ETM_ADDR_ACCESS_TYPE4", - "ETM_ADDR_ACCESS_TYPE5", - "ETM_ADDR_ACCESS_TYPE6", - "ETM_ADDR_ACCESS_TYPE7", - "ETM_ADDR_ACCESS_TYPE8", - "ETM_ADDR_ACCESS_TYPE9", - "ETM_ADDR_ACCESS_TYPE10", - "ETM_ADDR_ACCESS_TYPE11", - "ETM_ADDR_ACCESS_TYPE12", - "ETM_ADDR_ACCESS_TYPE13", - "ETM_ADDR_ACCESS_TYPE14", - "ETM_ADDR_ACCESS_TYPE15", - "ETM_ADDR_ACCESS_TYPE16", - "ETM_DATA_COMPARATOR_VALUE1", - "ETM_DATA_COMPARATOR_VALUE2", - "ETM_DATA_COMPARATOR_VALUE3", - "ETM_DATA_COMPARATOR_VALUE4", - "ETM_DATA_COMPARATOR_VALUE5", - "ETM_DATA_COMPARATOR_VALUE6", - "ETM_DATA_COMPARATOR_VALUE7", - "ETM_DATA_COMPARATOR_VALUE8", - "ETM_DATA_COMPARATOR_VALUE9", - "ETM_DATA_COMPARATOR_VALUE10", - "ETM_DATA_COMPARATOR_VALUE11", - "ETM_DATA_COMPARATOR_VALUE12", - "ETM_DATA_COMPARATOR_VALUE13", - "ETM_DATA_COMPARATOR_VALUE14", - "ETM_DATA_COMPARATOR_VALUE15", - "ETM_DATA_COMPARATOR_VALUE16", - "ETM_DATA_COMPARATOR_MASK1", - "ETM_DATA_COMPARATOR_MASK2", - "ETM_DATA_COMPARATOR_MASK3", - "ETM_DATA_COMPARATOR_MASK4", - "ETM_DATA_COMPARATOR_MASK5", - "ETM_DATA_COMPARATOR_MASK6", - "ETM_DATA_COMPARATOR_MASK7", - "ETM_DATA_COMPARATOR_MASK8", - "ETM_DATA_COMPARATOR_MASK9", - "ETM_DATA_COMPARATOR_MASK10", - "ETM_DATA_COMPARATOR_MASK11", - "ETM_DATA_COMPARATOR_MASK12", - "ETM_DATA_COMPARATOR_MASK13", - "ETM_DATA_COMPARATOR_MASK14", - "ETM_DATA_COMPARATOR_MASK15", - "ETM_DATA_COMPARATOR_MASK16", - "ETM_COUNTER_INITAL_VALUE1", - "ETM_COUNTER_INITAL_VALUE2", - "ETM_COUNTER_INITAL_VALUE3", - "ETM_COUNTER_INITAL_VALUE4", - "ETM_COUNTER_ENABLE1", - "ETM_COUNTER_ENABLE2", - "ETM_COUNTER_ENABLE3", - "ETM_COUNTER_ENABLE4", - "ETM_COUNTER_RELOAD_VALUE1", - "ETM_COUNTER_RELOAD_VALUE2", - "ETM_COUNTER_RELOAD_VALUE3", - "ETM_COUNTER_RELOAD_VALUE4", - "ETM_COUNTER_VALUE1", - "ETM_COUNTER_VALUE2", - "ETM_COUNTER_VALUE3", - "ETM_COUNTER_VALUE4", - "ETM_SEQUENCER_CTRL1", - "ETM_SEQUENCER_CTRL2", - "ETM_SEQUENCER_CTRL3", - "ETM_SEQUENCER_CTRL4", - "ETM_SEQUENCER_CTRL5", - "ETM_SEQUENCER_CTRL6", - "ETM_SEQUENCER_STATE", - "ETM_EXTERNAL_OUTPUT1", - "ETM_EXTERNAL_OUTPUT2", - "ETM_EXTERNAL_OUTPUT3", - "ETM_EXTERNAL_OUTPUT4", - "ETM_CONTEXTID_COMPARATOR_VALUE1", - "ETM_CONTEXTID_COMPARATOR_VALUE2", - "ETM_CONTEXTID_COMPARATOR_VALUE3", - "ETM_CONTEXTID_COMPARATOR_MASK" -}; - -int etm_reg_arch_type = -1; - -int etm_get_reg(reg_t *reg); -int etm_set_reg(reg_t *reg, u32 value); -int etm_set_reg_w_exec(reg_t *reg, u8 *buf); - -int etm_write_reg(reg_t *reg, u32 value); -int etm_read_reg(reg_t *reg); - -command_t *etm_cmd = NULL; - -reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) -{ - reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); - reg_t *reg_list = NULL; - etm_reg_t *arch_info = NULL; - int num_regs = sizeof(etm_reg_arch_info)/sizeof(int); - int i; - u32 etm_ctrl_value; - - /* register a register arch-type for etm registers only once */ - if (etm_reg_arch_type == -1) - etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec); - - /* the actual registers are kept in two arrays */ - reg_list = calloc(num_regs, sizeof(reg_t)); - arch_info = calloc(num_regs, sizeof(etm_reg_t)); - - /* fill in values for the reg cache */ - reg_cache->name = "etm registers"; - reg_cache->next = NULL; - reg_cache->reg_list = reg_list; - reg_cache->num_regs = num_regs; - - /* set up registers */ - for (i = 0; i < num_regs; i++) - { - reg_list[i].name = etm_reg_list[i]; - reg_list[i].size = 32; - reg_list[i].dirty = 0; - reg_list[i].valid = 0; - reg_list[i].bitfield_desc = NULL; - reg_list[i].num_bitfields = 0; - reg_list[i].value = calloc(1, 4); - reg_list[i].arch_info = &arch_info[i]; - reg_list[i].arch_type = etm_reg_arch_type; - reg_list[i].size = etm_reg_arch_size_info[i]; - arch_info[i].addr = etm_reg_arch_info[i]; - arch_info[i].jtag_info = jtag_info; - } - - /* initialize some ETM control register settings */ - etm_get_reg(®_list[ETM_CTRL]); - etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); - - /* clear the ETM powerdown bit (0) */ - etm_ctrl_value &= ~0x1; - - /* configure port width (6:4), mode (17:16) and clocking (13) */ - etm_ctrl_value = (etm_ctrl_value & - ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) - | etm_ctx->portmode; - - buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); - etm_store_reg(®_list[ETM_CTRL]); - - /* the ETM might have an ETB connected */ - if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) - { - etb_t *etb = etm_ctx->capture_driver_priv; - - if (!etb) - { - ERROR("etb selected as etm capture driver, but no ETB configured"); - return ERROR_OK; - } - - reg_cache->next = etb_build_reg_cache(etb); - - etb->reg_cache = reg_cache->next; - } - - if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) - { - ERROR("ETM capture driver initialization failed"); - exit(-1); - } - - return reg_cache; -} - -int etm_get_reg(reg_t *reg) -{ - if (etm_read_reg(reg) != ERROR_OK) - { - ERROR("BUG: error scheduling etm register read"); - exit(-1); - } - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register read failed"); - } - - return ERROR_OK; -} - -int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) -{ - etm_reg_t *etm_reg = reg->arch_info; - u8 reg_addr = etm_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i", etm_reg->addr); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(etm_reg->jtag_info, 0x6); - arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); - - fields[0].device = etm_reg->jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = reg->value; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = etm_reg->jtag_info->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = etm_reg->jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 0); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - fields[0].in_value = reg->value; - jtag_set_check_value(fields+0, check_value, check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1, NULL); - - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etm_read_reg(reg_t *reg) -{ - return etm_read_reg_w_check(reg, NULL, NULL); -} - -int etm_set_reg(reg_t *reg, u32 value) -{ - if (etm_write_reg(reg, value) != ERROR_OK) - { - ERROR("BUG: error scheduling etm register write"); - exit(-1); - } - - buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; - - return ERROR_OK; -} - -int etm_set_reg_w_exec(reg_t *reg, u8 *buf) -{ - etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); - - if (jtag_execute_queue() != ERROR_OK) - { - ERROR("register write failed"); - exit(-1); - } - return ERROR_OK; -} - -int etm_write_reg(reg_t *reg, u32 value) -{ - etm_reg_t *etm_reg = reg->arch_info; - u8 reg_addr = etm_reg->addr & 0x7f; - scan_field_t fields[3]; - - DEBUG("%i: 0x%8.8x", etm_reg->addr, value); - - jtag_add_end_state(TAP_RTI); - arm_jtag_scann(etm_reg->jtag_info, 0x6); - arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); - - fields[0].device = etm_reg->jtag_info->chain_pos; - fields[0].num_bits = 32; - fields[0].out_value = malloc(4); - buf_set_u32(fields[0].out_value, 0, 32, value); - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = etm_reg->jtag_info->chain_pos; - fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - fields[2].device = etm_reg->jtag_info->chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 1); - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_check_value = NULL; - fields[2].in_check_mask = NULL; - fields[2].in_handler = NULL; - fields[2].in_handler_priv = NULL; - - jtag_add_dr_scan(3, fields, -1, NULL); - - free(fields[0].out_value); - free(fields[1].out_value); - free(fields[2].out_value); - - return ERROR_OK; -} - -int etm_store_reg(reg_t *reg) -{ - return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); -} - -/* ETM trace analysis functionality - * - */ -extern etm_capture_driver_t etb_capture_driver; -extern etm_capture_driver_t etm_dummy_capture_driver; -#if BUILD_OOCD_TRACE == 1 -extern etm_capture_driver_t oocd_trace_capture_driver; -#endif - -etm_capture_driver_t *etm_capture_drivers[] = -{ - &etb_capture_driver, - &etm_dummy_capture_driver, -#if BUILD_OOCD_TRACE == 1 - &oocd_trace_capture_driver, -#endif - NULL -}; - -char *etmv1v1_branch_reason_strings[] = -{ - "normal PC change", - "tracing enabled", - "trace restarted after overflow", - "exit from debug", - "periodic synchronization", - "reserved", - "reserved", - "reserved", -}; - -int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) -{ - int i; - int section = -1; - u32 size_read; - u32 opcode; - int retval; - - if (!ctx->image) - return ERROR_TRACE_IMAGE_UNAVAILABLE; - - /* search for the section the current instruction belongs to */ - for (i = 0; i < ctx->image->num_sections; i++) - { - if ((ctx->image->sections[i].base_address <= ctx->current_pc) && - (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) - { - section = i; - break; - } - } - - if (section == -1) - { - /* current instruction couldn't be found in the image */ - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - - if (ctx->core_state == ARMV4_5_STATE_ARM) - { - u8 buf[4]; - if ((retval = image_read_section(ctx->image, section, - ctx->current_pc - ctx->image->sections[section].base_address, - 4, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u32(ctx->target, buf); - arm_evaluate_opcode(opcode, ctx->current_pc, instruction); - } - else if (ctx->core_state == ARMV4_5_STATE_THUMB) - { - u8 buf[2]; - if ((retval = image_read_section(ctx->image, section, - ctx->current_pc - ctx->image->sections[section].base_address, - 2, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u16(ctx->target, buf); - thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); - } - else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) - { - ERROR("BUG: tracing of jazelle code not supported"); - exit(-1); - } - else - { - ERROR("BUG: unknown core state encountered"); - exit(-1); - } - - return ERROR_OK; -} - -int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo) -{ - while (ctx->data_index < ctx->trace_depth) - { - /* if the caller specified an address packet offset, skip until the - * we reach the n-th cycle marked with tracesync */ - if (apo > 0) - { - if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) - apo--; - - if (apo > 0) - { - ctx->data_index++; - ctx->data_half = 0; - } - continue; - } - - /* no tracedata output during a TD cycle - * or in a trigger cycle */ - if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) - || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) - { - ctx->data_index++; - ctx->data_half = 0; - continue; - } - - if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) - { - if (ctx->data_half == 0) - { - *packet = ctx->trace_data[ctx->data_index].packet & 0xff; - ctx->data_half = 1; - } - else - { - *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; - ctx->data_half = 0; - ctx->data_index++; - } - } - else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) - { - *packet = ctx->trace_data[ctx->data_index].packet & 0xff; - ctx->data_index++; - } - else - { - /* on a 4-bit port, a packet will be output during two consecutive cycles */ - if (ctx->data_index > (ctx->trace_depth - 2)) - return -1; - - *packet = ctx->trace_data[ctx->data_index].packet & 0xf; - *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; - ctx->data_index += 2; - } - - return 0; - } - - return -1; -} - -int etmv1_branch_address(etm_context_t *ctx) -{ - int retval; - u8 packet; - int shift = 0; - int apo; - int i; - - /* quit analysis if less than two cycles are left in the trace - * because we can't extract the APO */ - if (ctx->data_index > (ctx->trace_depth - 2)) - return -1; - - /* a BE could be output during an APO cycle, skip the current - * and continue with the new one */ - if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) - return 1; - if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) - return 2; - - /* address packet offset encoded in the next two cycles' pipestat bits */ - apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; - apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; - - /* count number of tracesync cycles between current pipe_index and data_index - * i.e. the number of tracesyncs that data_index already passed by - * to subtract them from the APO */ - for (i = ctx->pipe_index; i < ctx->data_index; i++) - { - if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) - apo--; - } - - /* extract up to four 7-bit packets */ - do { - if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0) - return -1; - ctx->last_branch &= ~(0x7f << shift); - ctx->last_branch |= (packet & 0x7f) << shift; - shift += 7; - } while ((packet & 0x80) && (shift < 28)); - - /* one last packet holding 4 bits of the address, plus the branch reason code */ - if ((shift == 28) && (packet & 0x80)) - { - if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) - return -1; - ctx->last_branch &= 0x0fffffff; - ctx->last_branch |= (packet & 0x0f) << 28; - ctx->last_branch_reason = (packet & 0x70) >> 4; - shift += 4; - } - else - { - ctx->last_branch_reason = 0; - } - - if (shift == 32) - { - ctx->pc_ok = 1; - } - - /* if a full address was output, we might have branched into Jazelle state */ - if ((shift == 32) && (packet & 0x80)) - { - ctx->core_state = ARMV4_5_STATE_JAZELLE; - } - else - { - /* if we didn't branch into Jazelle state, the current processor state is - * encoded in bit 0 of the branch target address */ - if (ctx->last_branch & 0x1) - { - ctx->core_state = ARMV4_5_STATE_THUMB; - ctx->last_branch &= ~0x1; - } - else - { - ctx->core_state = ARMV4_5_STATE_ARM; - ctx->last_branch &= ~0x3; - } - } - - return 0; -} - -int etmv1_data(etm_context_t *ctx, int size, u32 *data) -{ - int j; - u8 buf[4]; - int retval; - - for (j = 0; j < size; j++) - { - if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0) - return -1; - } - - if (size == 8) - ERROR("TODO: add support for 64-bit values"); - else if (size == 4) - *data = target_buffer_get_u32(ctx->target, buf); - else if (size == 2) - *data = target_buffer_get_u16(ctx->target, buf); - else if (size == 1) - *data = buf[0]; - - return 0; -} - -int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) -{ - int retval; - arm_instruction_t instruction; - - /* read the trace data if it wasn't read already */ - if (ctx->trace_depth == 0) - ctx->capture_driver->read_trace(ctx); - - /* start at the beginning of the captured trace */ - ctx->pipe_index = 0; - ctx->data_index = 0; - ctx->data_half = 0; - - /* neither the PC nor the data pointer are valid */ - ctx->pc_ok = 0; - ctx->ptr_ok = 0; - - while (ctx->pipe_index < ctx->trace_depth) - { - u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat; - u32 next_pc = ctx->current_pc; - u32 old_data_index = ctx->data_index; - u32 old_data_half = ctx->data_half; - u32 old_index = ctx->pipe_index; - u32 last_instruction = ctx->last_instruction; - u32 cycles = 0; - int current_pc_ok = ctx->pc_ok; - - if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) - { - command_print(cmd_ctx, "--- trigger ---"); - } - - /* instructions execute in IE/D or BE/D cycles */ - if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) - ctx->last_instruction = ctx->pipe_index; - - /* if we don't have a valid pc skip until we reach an indirect branch */ - if ((!ctx->pc_ok) && (pipestat != STAT_BE)) - { - ctx->pipe_index++; - continue; - } - - /* any indirect branch could have interrupted instruction flow - * - the branch reason code could indicate a trace discontinuity - * - a branch to the exception vectors indicates an exception - */ - if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) - { - /* backup current data index, to be able to consume the branch address - * before examining data address and values - */ - old_data_index = ctx->data_index; - old_data_half = ctx->data_half; - - ctx->last_instruction = ctx->pipe_index; - - if ((retval = etmv1_branch_address(ctx)) != 0) - { - /* negative return value from etmv1_branch_address means we ran out of packets, - * quit analysing the trace */ - if (retval < 0) - break; - - /* a positive return values means the current branch was abandoned, - * and a new branch was encountered in cycle ctx->pipe_index + retval; - */ - WARNING("abandoned branch encountered, correctnes of analysis uncertain"); - ctx->pipe_index += retval; - continue; - } - - /* skip over APO cycles */ - ctx->pipe_index += 2; - - switch (ctx->last_branch_reason) - { - case 0x0: /* normal PC change */ - next_pc = ctx->last_branch; - break; - case 0x1: /* tracing enabled */ - command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x2: /* trace restarted after FIFO overflow */ - command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x3: /* exit from debug state */ - command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x4: /* periodic synchronization point */ - next_pc = ctx->last_branch; - /* if we had no valid PC prior to this synchronization point, - * we have to move on with the next trace cycle - */ - if (!current_pc_ok) - { - command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); - ctx->current_pc = next_pc; - ctx->pipe_index++; - continue; - } - break; - default: /* reserved */ - ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); - exit(-1); - break; - } - - /* if we got here the branch was a normal PC change - * (or a periodic synchronization point, which means the same for that matter) - * if we didn't accquire a complete PC continue with the next cycle - */ - if (!ctx->pc_ok) - continue; - - /* indirect branch to the exception vector means an exception occured */ - if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20)) - || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) - { - if ((ctx->last_branch & 0xff) == 0x10) - { - command_print(cmd_ctx, "data abort"); - } - else - { - command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - } - } - } - - /* an instruction was executed (or not, depending on the condition flags) - * retrieve it from the image for displaying */ - if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && - !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && - ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) - { - if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images - * for now we just quit the analsysis*/ - return retval; - } - } - - cycles = old_index - last_instruction; - } - - if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) - { - u32 new_data_index = ctx->data_index; - u32 new_data_half = ctx->data_half; - - /* in case of a branch with data, the branch target address was consumed before - * we temporarily go back to the saved data index */ - if (pipestat == STAT_BD) - { - ctx->data_index = old_data_index; - ctx->data_half = old_data_half; - } - - if (ctx->tracemode & ETMV1_TRACE_ADDR) - { - u8 packet; - int shift = 0; - - do { - if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - ctx->last_ptr &= ~(0x7f << shift); - ctx->last_ptr |= (packet & 0x7f) << shift; - shift += 7; - } while ((packet & 0x80) && (shift < 32)); - - if (shift >= 32) - ctx->ptr_ok = 1; - - if (ctx->ptr_ok) - { - command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr); - } - } - - if (ctx->tracemode & ETMV1_TRACE_DATA) - { - if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) - { - int i; - for (i = 0; i < 16; i++) - { - if (instruction.info.load_store_multiple.register_list & (1 << i)) - { - u32 data; - if (etmv1_data(ctx, 4, &data) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd_ctx, "data: 0x%8.8x", data); - } - } - } - else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) - { - u32 data; - if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) - return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd_ctx, "data: 0x%8.8x", data); - } - } - - /* restore data index after consuming BD address and data */ - if (pipestat == STAT_BD) - { - ctx->data_index = new_data_index; - ctx->data_half = new_data_half; - } - } - - /* adjust PC */ - if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) - { - if (((instruction.type == ARM_B) || - (instruction.type == ARM_BL) || - (instruction.type == ARM_BLX)) && - (instruction.info.b_bl_bx_blx.target_address != -1)) - { - next_pc = instruction.info.b_bl_bx_blx.target_address; - } - else - { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - } - else if (pipestat == STAT_IN) - { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - - if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) - { - char cycles_text[32] = ""; - - /* if the trace was captured with cycle accurate tracing enabled, - * output the number of cycles since the last executed instruction - */ - if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) - { - snprintf(cycles_text, 32, " (%i %s)", - cycles, - (cycles == 1) ? "cycle" : "cycles"); - } - - command_print(cmd_ctx, "%s%s%s", - instruction.text, - (pipestat == STAT_IN) ? " (not executed)" : "", - cycles_text); - - ctx->current_pc = next_pc; - - /* packets for an instruction don't start on or before the preceding - * functional pipestat (i.e. other than WT or TD) - */ - if (ctx->data_index <= ctx->pipe_index) - { - ctx->data_index = ctx->pipe_index + 1; - ctx->data_half = 0; - } - } - - ctx->pipe_index += 1; - } - - return ERROR_OK; -} - -int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etmv1_tracemode_t tracemode; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - tracemode = arm7_9->etm_ctx->tracemode; - - if (argc == 4) - { - if (strcmp(args[0], "none") == 0) - { - tracemode = ETMV1_TRACE_NONE; - } - else if (strcmp(args[0], "data") == 0) - { - tracemode = ETMV1_TRACE_DATA; - } - else if (strcmp(args[0], "address") == 0) - { - tracemode = ETMV1_TRACE_ADDR; - } - else if (strcmp(args[0], "all") == 0) - { - tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[0]); - return ERROR_OK; - } - - switch (strtol(args[1], NULL, 0)) - { - case 0: - tracemode |= ETMV1_CONTEXTID_NONE; - break; - case 8: - tracemode |= ETMV1_CONTEXTID_8; - break; - case 16: - tracemode |= ETMV1_CONTEXTID_16; - break; - case 32: - tracemode |= ETMV1_CONTEXTID_32; - break; - default: - command_print(cmd_ctx, "invalid option '%s'", args[1]); - return ERROR_OK; - } - - if (strcmp(args[2], "enable") == 0) - { - tracemode |= ETMV1_CYCLE_ACCURATE; - } - else if (strcmp(args[2], "disable") == 0) - { - tracemode |= 0; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[2]); - return ERROR_OK; - } - - if (strcmp(args[3], "enable") == 0) - { - tracemode |= ETMV1_BRANCH_OUTPUT; - } - else if (strcmp(args[3], "disable") == 0) - { - tracemode |= 0; - } - else - { - command_print(cmd_ctx, "invalid option '%s'", args[2]); - return ERROR_OK; - } - } - else if (argc != 0) - { - command_print(cmd_ctx, "usage: configure trace mode "); - return ERROR_OK; - } - - command_print(cmd_ctx, "current tracemode configuration:"); - - switch (tracemode & ETMV1_TRACE_MASK) - { - case ETMV1_TRACE_NONE: - command_print(cmd_ctx, "data tracing: none"); - break; - case ETMV1_TRACE_DATA: - command_print(cmd_ctx, "data tracing: data only"); - break; - case ETMV1_TRACE_ADDR: - command_print(cmd_ctx, "data tracing: address only"); - break; - case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: - command_print(cmd_ctx, "data tracing: address and data"); - break; - } - - switch (tracemode & ETMV1_CONTEXTID_MASK) - { - case ETMV1_CONTEXTID_NONE: - command_print(cmd_ctx, "contextid tracing: none"); - break; - case ETMV1_CONTEXTID_8: - command_print(cmd_ctx, "contextid tracing: 8 bit"); - break; - case ETMV1_CONTEXTID_16: - command_print(cmd_ctx, "contextid tracing: 16 bit"); - break; - case ETMV1_CONTEXTID_32: - command_print(cmd_ctx, "contextid tracing: 32 bit"); - break; - } - - if (tracemode & ETMV1_CYCLE_ACCURATE) - { - command_print(cmd_ctx, "cycle-accurate tracing enabled"); - } - else - { - command_print(cmd_ctx, "cycle-accurate tracing disabled"); - } - - if (tracemode & ETMV1_BRANCH_OUTPUT) - { - command_print(cmd_ctx, "full branch address output enabled"); - } - else - { - command_print(cmd_ctx, "full branch address output disabled"); - } - - /* only update ETM_CTRL register if tracemode changed */ - if (arm7_9->etm_ctx->tracemode != tracemode) - { - reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - - etm_get_reg(etm_ctrl_reg); - - buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); - buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); - buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); - buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); - etm_store_reg(etm_ctrl_reg); - - arm7_9->etm_ctx->tracemode = tracemode; - - /* invalidate old trace data */ - arm7_9->etm_ctx->capture_status = TRACE_IDLE; - if (arm7_9->etm_ctx->trace_depth > 0) - { - free(arm7_9->etm_ctx->trace_data); - arm7_9->etm_ctx->trace_data = NULL; - } - arm7_9->etm_ctx->trace_depth = 0; - } - - return ERROR_OK; -} - -int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_portmode_t portmode = 0x0; - etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); - int i; - - if (argc != 5) - { - ERROR("incomplete 'etm config ' command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - switch (strtoul(args[1], NULL, 0)) - { - case 4: - portmode |= ETM_PORT_4BIT; - break; - case 8: - portmode |= ETM_PORT_8BIT; - break; - case 16: - portmode |= ETM_PORT_16BIT; - break; - default: - command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); - return ERROR_OK; - } - - if (strcmp("normal", args[2]) == 0) - { - portmode |= ETM_PORT_NORMAL; - } - else if (strcmp("multiplexed", args[2]) == 0) - { - portmode |= ETM_PORT_MUXED; - } - else if (strcmp("demultiplexed", args[2]) == 0) - { - portmode |= ETM_PORT_DEMUXED; - } - else - { - command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); - return ERROR_OK; - } - - if (strcmp("half", args[3]) == 0) - { - portmode |= ETM_PORT_HALF_CLOCK; - } - else if (strcmp("full", args[3]) == 0) - { - portmode |= ETM_PORT_FULL_CLOCK; - } - else - { - command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); - return ERROR_OK; - } - - for (i=0; etm_capture_drivers[i]; i++) - { - if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) - { - if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) - { - free(etm_ctx); - exit(-1); - } - - etm_ctx->capture_driver = etm_capture_drivers[i]; - - break; - } - } - - if (!etm_capture_drivers[i]) - { - /* no supported capture driver found, don't register an ETM */ - free(etm_ctx); - ERROR("trace capture driver '%s' not found", args[4]); - return ERROR_OK; - } - - etm_ctx->target = target; - etm_ctx->trigger_percent = 50; - etm_ctx->trace_data = NULL; - etm_ctx->trace_depth = 0; - etm_ctx->portmode = portmode; - etm_ctx->tracemode = 0x0; - etm_ctx->core_state = ARMV4_5_STATE_ARM; - etm_ctx->image = NULL; - etm_ctx->pipe_index = 0; - etm_ctx->data_index = 0; - etm_ctx->current_pc = 0x0; - etm_ctx->pc_ok = 0; - etm_ctx->last_branch = 0x0; - etm_ctx->last_branch_reason = 0x0; - etm_ctx->last_ptr = 0x0; - etm_ctx->ptr_ok = 0x0; - etm_ctx->context_id = 0x0; - etm_ctx->last_instruction = 0; - - arm7_9->etm_ctx = etm_ctx; - - etm_register_user_commands(cmd_ctx); - - return ERROR_OK; -} - -int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - reg_t *etm_config_reg; - reg_t *etm_sys_config_reg; - - int max_port_size; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; - etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; - - etm_get_reg(etm_config_reg); - command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); - command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); - command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); - command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); - command_print(cmd_ctx, "sequencer %spresent", - (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); - command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); - command_print(cmd_ctx, "FIFO full %spresent", - (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); - - etm_get_reg(etm_sys_config_reg); - - switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) - { - case 0: - max_port_size = 4; - break; - case 1: - max_port_size = 8; - break; - case 2: - max_port_size = 16; - break; - } - command_print(cmd_ctx, "max. port size: %i", max_port_size); - - command_print(cmd_ctx, "half-rate clocking %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "full-rate clocking %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "normal trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "multiplex trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "demultiplex trace format %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); - command_print(cmd_ctx, "FIFO full %ssupported", - (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); - - return ERROR_OK; -} - -int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - trace_status_t trace_status; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!arm7_9->etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); - - if (trace_status == TRACE_IDLE) - { - command_print(cmd_ctx, "tracing is idle"); - } - else - { - static char *completed = " completed"; - static char *running = " is running"; - static char *overflowed = ", trace overflowed"; - static char *triggered = ", trace triggered"; - - command_print(cmd_ctx, "trace collection%s%s%s", - (trace_status & TRACE_RUNNING) ? running : completed, - (trace_status & TRACE_OVERFLOWED) ? overflowed : "", - (trace_status & TRACE_TRIGGERED) ? triggered : ""); - - if (arm7_9->etm_ctx->trace_depth > 0) - { - command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); - } - } - - return ERROR_OK; -} - -int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - - if (argc < 1) - { - command_print(cmd_ctx, "usage: etm image [base address] [type]"); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->image) - { - image_close(etm_ctx->image); - free(etm_ctx->image); - command_print(cmd_ctx, "previously loaded image found and closed"); - } - - etm_ctx->image = malloc(sizeof(image_t)); - etm_ctx->image->base_address_set = 0; - etm_ctx->image->start_address_set = 0; - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - etm_ctx->image->base_address_set = 1; - etm_ctx->image->base_address = strtoul(args[1], NULL, 0); - } - else - { - etm_ctx->image->base_address_set = 0; - } - - if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); - free(etm_ctx->image); - etm_ctx->image = NULL; - return ERROR_OK; - } - - return ERROR_OK; -} - -int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t file; - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int i; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: etm dump "); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status == TRACE_IDLE) - { - command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) - { - /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ - command_print(cmd_ctx, "trace capture not completed"); - return ERROR_OK; - } - - /* read the trace data if it wasn't read already */ - if (etm_ctx->trace_depth == 0) - etm_ctx->capture_driver->read_trace(etm_ctx); - - if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - fileio_write_u32(&file, etm_ctx->capture_status); - fileio_write_u32(&file, etm_ctx->portmode); - fileio_write_u32(&file, etm_ctx->tracemode); - fileio_write_u32(&file, etm_ctx->trace_depth); - - for (i = 0; i < etm_ctx->trace_depth; i++) - { - fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); - fileio_write_u32(&file, etm_ctx->trace_data[i].packet); - fileio_write_u32(&file, etm_ctx->trace_data[i].flags); - } - - fileio_close(&file); - - return ERROR_OK; -} - -int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t file; - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int i; - - if (argc != 1) - { - command_print(cmd_ctx, "usage: etm load "); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) - { - command_print(cmd_ctx, "trace capture running, stop first"); - return ERROR_OK; - } - - if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - if (file.size % 4) - { - command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); - return ERROR_OK; - } - - if (etm_ctx->trace_depth > 0) - { - free(etm_ctx->trace_data); - } - - fileio_read_u32(&file, &etm_ctx->capture_status); - fileio_read_u32(&file, &etm_ctx->portmode); - fileio_read_u32(&file, &etm_ctx->tracemode); - fileio_read_u32(&file, &etm_ctx->trace_depth); - - etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); - - for (i = 0; i < etm_ctx->trace_depth; i++) - { - u32 pipestat, packet, flags; - fileio_read_u32(&file, &pipestat); - fileio_read_u32(&file, &packet); - fileio_read_u32(&file, &flags); - etm_ctx->trace_data[i].pipestat = pipestat & 0xff; - etm_ctx->trace_data[i].packet = packet & 0xffff; - etm_ctx->trace_data[i].flags = flags; - } - - fileio_close(&file); - - return ERROR_OK; -} - -int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if (argc > 0) - { - u32 new_value = strtoul(args[0], NULL, 0); - - if ((new_value < 2) || (new_value > 100)) - { - command_print(cmd_ctx, "valid settings are 2% to 100%"); - } - else - { - etm_ctx->trigger_percent = new_value; - } - } - - command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); - - return ERROR_OK; -} - -int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - reg_t *etm_ctrl_reg; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - /* invalidate old tracing data */ - arm7_9->etm_ctx->capture_status = TRACE_IDLE; - if (arm7_9->etm_ctx->trace_depth > 0) - { - free(arm7_9->etm_ctx->trace_data); - arm7_9->etm_ctx->trace_data = NULL; - } - arm7_9->etm_ctx->trace_depth = 0; - - etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - etm_get_reg(etm_ctrl_reg); - - /* Clear programming bit (10), set port selection bit (11) */ - buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); - - etm_store_reg(etm_ctrl_reg); - jtag_execute_queue(); - - etm_ctx->capture_driver->start_capture(etm_ctx); - - return ERROR_OK; -} - -int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - reg_t *etm_ctrl_reg; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; - etm_get_reg(etm_ctrl_reg); - - /* Set programming bit (10), clear port selection bit (11) */ - buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); - - etm_store_reg(etm_ctrl_reg); - jtag_execute_queue(); - - etm_ctx->capture_driver->stop_capture(etm_ctx); - - return ERROR_OK; -} - -int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - arm7_9_common_t *arm7_9; - etm_context_t *etm_ctx; - int retval; - - target = get_current_target(cmd_ctx); - - if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) - { - command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); - return ERROR_OK; - } - - if (!(etm_ctx = arm7_9->etm_ctx)) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_OK; - } - - if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) - { - switch(retval) - { - case ERROR_ETM_ANALYSIS_FAILED: - command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); - break; - case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: - command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); - break; - case ERROR_TRACE_IMAGE_UNAVAILABLE: - command_print(cmd_ctx, "no image available for trace analysis"); - break; - default: - command_print(cmd_ctx, "unknown error: %i", retval); - } - } - - return ERROR_OK; -} - -int etm_register_commands(struct command_context_s *cmd_ctx) -{ - etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); - - register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); - - return ERROR_OK; -} - -int etm_register_user_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, - COMMAND_EXEC, "configure trace mode ", handle_etm_trigger_percent_command, - COMMAND_EXEC, "amount () of trace buffer to be filled after the trigger occured"); - register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, - COMMAND_EXEC, "display current target's ETM status"); - register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, - COMMAND_EXEC, "start ETM trace collection"); - register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, - COMMAND_EXEC, "stop ETM trace collection"); - - register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command, - COMMAND_EXEC, "anaylze collected ETM trace"); - - register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command, - COMMAND_EXEC, "load image from [base address]"); - - register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, - COMMAND_EXEC, "dump captured trace data "); - register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, - COMMAND_EXEC, "load trace data for analysis "); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "etm.h" +#include "etb.h" + +#include "armv4_5.h" +#include "arm7_9_common.h" +#include "arm_disassembler.h" +#include "arm_simulator.h" + +#include "log.h" +#include "arm_jtag.h" +#include "types.h" +#include "binarybuffer.h" +#include "target.h" +#include "register.h" +#include "jtag.h" +#include "fileio.h" + +#include + +/* ETM register access functionality + * + */ + +bitfield_desc_t etm_comms_ctrl_bitfield_desc[] = +{ + {"R", 1}, + {"W", 1}, + {"reserved", 26}, + {"version", 4} +}; + +int etm_reg_arch_info[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, +}; + +int etm_reg_arch_size_info[] = +{ + 32, 32, 17, 8, 3, 9, 32, 16, + 17, 26, 25, 8, 17, 32, 32, 17, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 16, 16, 16, 18, 18, 18, 18, + 17, 17, 17, 17, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 2, + 17, 17, 17, 17, 32, 32, 32, 32 +}; + +char* etm_reg_list[] = +{ + "ETM_CTRL", + "ETM_CONFIG", + "ETM_TRIG_EVENT", + "ETM_MMD_CTRL", + "ETM_STATUS", + "ETM_SYS_CONFIG", + "ETM_TRACE_RESOURCE_CTRL", + "ETM_TRACE_EN_CTRL2", + "ETM_TRACE_EN_EVENT", + "ETM_TRACE_EN_CTRL1", + "ETM_FIFOFULL_REGION", + "ETM_FIFOFULL_LEVEL", + "ETM_VIEWDATA_EVENT", + "ETM_VIEWDATA_CTRL1", + "ETM_VIEWDATA_CTRL2", + "ETM_VIEWDATA_CTRL3", + "ETM_ADDR_COMPARATOR_VALUE1", + "ETM_ADDR_COMPARATOR_VALUE2", + "ETM_ADDR_COMPARATOR_VALUE3", + "ETM_ADDR_COMPARATOR_VALUE4", + "ETM_ADDR_COMPARATOR_VALUE5", + "ETM_ADDR_COMPARATOR_VALUE6", + "ETM_ADDR_COMPARATOR_VALUE7", + "ETM_ADDR_COMPARATOR_VALUE8", + "ETM_ADDR_COMPARATOR_VALUE9", + "ETM_ADDR_COMPARATOR_VALUE10", + "ETM_ADDR_COMPARATOR_VALUE11", + "ETM_ADDR_COMPARATOR_VALUE12", + "ETM_ADDR_COMPARATOR_VALUE13", + "ETM_ADDR_COMPARATOR_VALUE14", + "ETM_ADDR_COMPARATOR_VALUE15", + "ETM_ADDR_COMPARATOR_VALUE16", + "ETM_ADDR_ACCESS_TYPE1", + "ETM_ADDR_ACCESS_TYPE2", + "ETM_ADDR_ACCESS_TYPE3", + "ETM_ADDR_ACCESS_TYPE4", + "ETM_ADDR_ACCESS_TYPE5", + "ETM_ADDR_ACCESS_TYPE6", + "ETM_ADDR_ACCESS_TYPE7", + "ETM_ADDR_ACCESS_TYPE8", + "ETM_ADDR_ACCESS_TYPE9", + "ETM_ADDR_ACCESS_TYPE10", + "ETM_ADDR_ACCESS_TYPE11", + "ETM_ADDR_ACCESS_TYPE12", + "ETM_ADDR_ACCESS_TYPE13", + "ETM_ADDR_ACCESS_TYPE14", + "ETM_ADDR_ACCESS_TYPE15", + "ETM_ADDR_ACCESS_TYPE16", + "ETM_DATA_COMPARATOR_VALUE1", + "ETM_DATA_COMPARATOR_VALUE2", + "ETM_DATA_COMPARATOR_VALUE3", + "ETM_DATA_COMPARATOR_VALUE4", + "ETM_DATA_COMPARATOR_VALUE5", + "ETM_DATA_COMPARATOR_VALUE6", + "ETM_DATA_COMPARATOR_VALUE7", + "ETM_DATA_COMPARATOR_VALUE8", + "ETM_DATA_COMPARATOR_VALUE9", + "ETM_DATA_COMPARATOR_VALUE10", + "ETM_DATA_COMPARATOR_VALUE11", + "ETM_DATA_COMPARATOR_VALUE12", + "ETM_DATA_COMPARATOR_VALUE13", + "ETM_DATA_COMPARATOR_VALUE14", + "ETM_DATA_COMPARATOR_VALUE15", + "ETM_DATA_COMPARATOR_VALUE16", + "ETM_DATA_COMPARATOR_MASK1", + "ETM_DATA_COMPARATOR_MASK2", + "ETM_DATA_COMPARATOR_MASK3", + "ETM_DATA_COMPARATOR_MASK4", + "ETM_DATA_COMPARATOR_MASK5", + "ETM_DATA_COMPARATOR_MASK6", + "ETM_DATA_COMPARATOR_MASK7", + "ETM_DATA_COMPARATOR_MASK8", + "ETM_DATA_COMPARATOR_MASK9", + "ETM_DATA_COMPARATOR_MASK10", + "ETM_DATA_COMPARATOR_MASK11", + "ETM_DATA_COMPARATOR_MASK12", + "ETM_DATA_COMPARATOR_MASK13", + "ETM_DATA_COMPARATOR_MASK14", + "ETM_DATA_COMPARATOR_MASK15", + "ETM_DATA_COMPARATOR_MASK16", + "ETM_COUNTER_INITAL_VALUE1", + "ETM_COUNTER_INITAL_VALUE2", + "ETM_COUNTER_INITAL_VALUE3", + "ETM_COUNTER_INITAL_VALUE4", + "ETM_COUNTER_ENABLE1", + "ETM_COUNTER_ENABLE2", + "ETM_COUNTER_ENABLE3", + "ETM_COUNTER_ENABLE4", + "ETM_COUNTER_RELOAD_VALUE1", + "ETM_COUNTER_RELOAD_VALUE2", + "ETM_COUNTER_RELOAD_VALUE3", + "ETM_COUNTER_RELOAD_VALUE4", + "ETM_COUNTER_VALUE1", + "ETM_COUNTER_VALUE2", + "ETM_COUNTER_VALUE3", + "ETM_COUNTER_VALUE4", + "ETM_SEQUENCER_CTRL1", + "ETM_SEQUENCER_CTRL2", + "ETM_SEQUENCER_CTRL3", + "ETM_SEQUENCER_CTRL4", + "ETM_SEQUENCER_CTRL5", + "ETM_SEQUENCER_CTRL6", + "ETM_SEQUENCER_STATE", + "ETM_EXTERNAL_OUTPUT1", + "ETM_EXTERNAL_OUTPUT2", + "ETM_EXTERNAL_OUTPUT3", + "ETM_EXTERNAL_OUTPUT4", + "ETM_CONTEXTID_COMPARATOR_VALUE1", + "ETM_CONTEXTID_COMPARATOR_VALUE2", + "ETM_CONTEXTID_COMPARATOR_VALUE3", + "ETM_CONTEXTID_COMPARATOR_MASK" +}; + +int etm_reg_arch_type = -1; + +int etm_get_reg(reg_t *reg); +int etm_set_reg(reg_t *reg, u32 value); +int etm_set_reg_w_exec(reg_t *reg, u8 *buf); + +int etm_write_reg(reg_t *reg, u32 value); +int etm_read_reg(reg_t *reg); + +command_t *etm_cmd = NULL; + +reg_cache_t* etm_build_reg_cache(target_t *target, arm_jtag_t *jtag_info, etm_context_t *etm_ctx) +{ + reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t)); + reg_t *reg_list = NULL; + etm_reg_t *arch_info = NULL; + int num_regs = sizeof(etm_reg_arch_info)/sizeof(int); + int i; + u32 etm_ctrl_value; + + /* register a register arch-type for etm registers only once */ + if (etm_reg_arch_type == -1) + etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec); + + /* the actual registers are kept in two arrays */ + reg_list = calloc(num_regs, sizeof(reg_t)); + arch_info = calloc(num_regs, sizeof(etm_reg_t)); + + /* fill in values for the reg cache */ + reg_cache->name = "etm registers"; + reg_cache->next = NULL; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = num_regs; + + /* set up registers */ + for (i = 0; i < num_regs; i++) + { + reg_list[i].name = etm_reg_list[i]; + reg_list[i].size = 32; + reg_list[i].dirty = 0; + reg_list[i].valid = 0; + reg_list[i].bitfield_desc = NULL; + reg_list[i].num_bitfields = 0; + reg_list[i].value = calloc(1, 4); + reg_list[i].arch_info = &arch_info[i]; + reg_list[i].arch_type = etm_reg_arch_type; + reg_list[i].size = etm_reg_arch_size_info[i]; + arch_info[i].addr = etm_reg_arch_info[i]; + arch_info[i].jtag_info = jtag_info; + } + + /* initialize some ETM control register settings */ + etm_get_reg(®_list[ETM_CTRL]); + etm_ctrl_value = buf_get_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size); + + /* clear the ETM powerdown bit (0) */ + etm_ctrl_value &= ~0x1; + + /* configure port width (6:4), mode (17:16) and clocking (13) */ + etm_ctrl_value = (etm_ctrl_value & + ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_PORT_CLOCK_MASK) + | etm_ctx->portmode; + + buf_set_u32(reg_list[ETM_CTRL].value, 0, reg_list[ETM_CTRL].size, etm_ctrl_value); + etm_store_reg(®_list[ETM_CTRL]); + + /* the ETM might have an ETB connected */ + if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) + { + etb_t *etb = etm_ctx->capture_driver_priv; + + if (!etb) + { + ERROR("etb selected as etm capture driver, but no ETB configured"); + return ERROR_OK; + } + + reg_cache->next = etb_build_reg_cache(etb); + + etb->reg_cache = reg_cache->next; + } + + if (etm_ctx->capture_driver->init(etm_ctx) != ERROR_OK) + { + ERROR("ETM capture driver initialization failed"); + exit(-1); + } + + return reg_cache; +} + +int etm_get_reg(reg_t *reg) +{ + if (etm_read_reg(reg) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register read"); + exit(-1); + } + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register read failed"); + } + + return ERROR_OK; +} + +int etm_read_reg_w_check(reg_t *reg, u8* check_value, u8* check_mask) +{ + etm_reg_t *etm_reg = reg->arch_info; + u8 reg_addr = etm_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i", etm_reg->addr); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(etm_reg->jtag_info, 0x6); + arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + + fields[0].device = etm_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = reg->value; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etm_reg->jtag_info->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etm_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 0); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + fields[0].in_value = reg->value; + jtag_set_check_value(fields+0, check_value, check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etm_read_reg(reg_t *reg) +{ + return etm_read_reg_w_check(reg, NULL, NULL); +} + +int etm_set_reg(reg_t *reg, u32 value) +{ + if (etm_write_reg(reg, value) != ERROR_OK) + { + ERROR("BUG: error scheduling etm register write"); + exit(-1); + } + + buf_set_u32(reg->value, 0, reg->size, value); + reg->valid = 1; + reg->dirty = 0; + + return ERROR_OK; +} + +int etm_set_reg_w_exec(reg_t *reg, u8 *buf) +{ + etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); + + if (jtag_execute_queue() != ERROR_OK) + { + ERROR("register write failed"); + exit(-1); + } + return ERROR_OK; +} + +int etm_write_reg(reg_t *reg, u32 value) +{ + etm_reg_t *etm_reg = reg->arch_info; + u8 reg_addr = etm_reg->addr & 0x7f; + scan_field_t fields[3]; + + DEBUG("%i: 0x%8.8x", etm_reg->addr, value); + + jtag_add_end_state(TAP_RTI); + arm_jtag_scann(etm_reg->jtag_info, 0x6); + arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + + fields[0].device = etm_reg->jtag_info->chain_pos; + fields[0].num_bits = 32; + fields[0].out_value = malloc(4); + buf_set_u32(fields[0].out_value, 0, 32, value); + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = etm_reg->jtag_info->chain_pos; + fields[1].num_bits = 7; + fields[1].out_value = malloc(1); + buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + fields[2].device = etm_reg->jtag_info->chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = malloc(1); + buf_set_u32(fields[2].out_value, 0, 1, 1); + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_check_value = NULL; + fields[2].in_check_mask = NULL; + fields[2].in_handler = NULL; + fields[2].in_handler_priv = NULL; + + jtag_add_dr_scan(3, fields, -1); + + free(fields[0].out_value); + free(fields[1].out_value); + free(fields[2].out_value); + + return ERROR_OK; +} + +int etm_store_reg(reg_t *reg) +{ + return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); +} + +/* ETM trace analysis functionality + * + */ +extern etm_capture_driver_t etb_capture_driver; +extern etm_capture_driver_t etm_dummy_capture_driver; +#if BUILD_OOCD_TRACE == 1 +extern etm_capture_driver_t oocd_trace_capture_driver; +#endif + +etm_capture_driver_t *etm_capture_drivers[] = +{ + &etb_capture_driver, + &etm_dummy_capture_driver, +#if BUILD_OOCD_TRACE == 1 + &oocd_trace_capture_driver, +#endif + NULL +}; + +char *etmv1v1_branch_reason_strings[] = +{ + "normal PC change", + "tracing enabled", + "trace restarted after overflow", + "exit from debug", + "periodic synchronization", + "reserved", + "reserved", + "reserved", +}; + +int etm_read_instruction(etm_context_t *ctx, arm_instruction_t *instruction) +{ + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!ctx->image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < ctx->image->num_sections; i++) + { + if ((ctx->image->sections[i].base_address <= ctx->current_pc) && + (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (ctx->core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(ctx->target, buf); + arm_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(ctx->image, section, + ctx->current_pc - ctx->image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(ctx->target, buf); + thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); + } + else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) + { + ERROR("BUG: tracing of jazelle code not supported"); + exit(-1); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int etmv1_next_packet(etm_context_t *ctx, u8 *packet, int apo) +{ + while (ctx->data_index < ctx->trace_depth) + { + /* if the caller specified an address packet offset, skip until the + * we reach the n-th cycle marked with tracesync */ + if (apo > 0) + { + if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) + apo--; + + if (apo > 0) + { + ctx->data_index++; + ctx->data_half = 0; + } + continue; + } + + /* no tracedata output during a TD cycle + * or in a trigger cycle */ + if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) + || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) + { + ctx->data_index++; + ctx->data_half = 0; + continue; + } + + if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) + { + if (ctx->data_half == 0) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_half = 1; + } + else + { + *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; + ctx->data_half = 0; + ctx->data_index++; + } + } + else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + { + *packet = ctx->trace_data[ctx->data_index].packet & 0xff; + ctx->data_index++; + } + else + { + /* on a 4-bit port, a packet will be output during two consecutive cycles */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + *packet = ctx->trace_data[ctx->data_index].packet & 0xf; + *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; + ctx->data_index += 2; + } + + return 0; + } + + return -1; +} + +int etmv1_branch_address(etm_context_t *ctx) +{ + int retval; + u8 packet; + int shift = 0; + int apo; + int i; + + /* quit analysis if less than two cycles are left in the trace + * because we can't extract the APO */ + if (ctx->data_index > (ctx->trace_depth - 2)) + return -1; + + /* a BE could be output during an APO cycle, skip the current + * and continue with the new one */ + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) + return 1; + if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) + return 2; + + /* address packet offset encoded in the next two cycles' pipestat bits */ + apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; + apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; + + /* count number of tracesync cycles between current pipe_index and data_index + * i.e. the number of tracesyncs that data_index already passed by + * to subtract them from the APO */ + for (i = ctx->pipe_index; i < ctx->data_index; i++) + { + if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) + apo--; + } + + /* extract up to four 7-bit packets */ + do { + if ((retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0)) != 0) + return -1; + ctx->last_branch &= ~(0x7f << shift); + ctx->last_branch |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 28)); + + /* one last packet holding 4 bits of the address, plus the branch reason code */ + if ((shift == 28) && (packet & 0x80)) + { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return -1; + ctx->last_branch &= 0x0fffffff; + ctx->last_branch |= (packet & 0x0f) << 28; + ctx->last_branch_reason = (packet & 0x70) >> 4; + shift += 4; + } + else + { + ctx->last_branch_reason = 0; + } + + if (shift == 32) + { + ctx->pc_ok = 1; + } + + /* if a full address was output, we might have branched into Jazelle state */ + if ((shift == 32) && (packet & 0x80)) + { + ctx->core_state = ARMV4_5_STATE_JAZELLE; + } + else + { + /* if we didn't branch into Jazelle state, the current processor state is + * encoded in bit 0 of the branch target address */ + if (ctx->last_branch & 0x1) + { + ctx->core_state = ARMV4_5_STATE_THUMB; + ctx->last_branch &= ~0x1; + } + else + { + ctx->core_state = ARMV4_5_STATE_ARM; + ctx->last_branch &= ~0x3; + } + } + + return 0; +} + +int etmv1_data(etm_context_t *ctx, int size, u32 *data) +{ + int j; + u8 buf[4]; + int retval; + + for (j = 0; j < size; j++) + { + if ((retval = etmv1_next_packet(ctx, &buf[j], 0)) != 0) + return -1; + } + + if (size == 8) + ERROR("TODO: add support for 64-bit values"); + else if (size == 4) + *data = target_buffer_get_u32(ctx->target, buf); + else if (size == 2) + *data = target_buffer_get_u16(ctx->target, buf); + else if (size == 1) + *data = buf[0]; + + return 0; +} + +int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd_ctx) +{ + int retval; + arm_instruction_t instruction; + + /* read the trace data if it wasn't read already */ + if (ctx->trace_depth == 0) + ctx->capture_driver->read_trace(ctx); + + /* start at the beginning of the captured trace */ + ctx->pipe_index = 0; + ctx->data_index = 0; + ctx->data_half = 0; + + /* neither the PC nor the data pointer are valid */ + ctx->pc_ok = 0; + ctx->ptr_ok = 0; + + while (ctx->pipe_index < ctx->trace_depth) + { + u8 pipestat = ctx->trace_data[ctx->pipe_index].pipestat; + u32 next_pc = ctx->current_pc; + u32 old_data_index = ctx->data_index; + u32 old_data_half = ctx->data_half; + u32 old_index = ctx->pipe_index; + u32 last_instruction = ctx->last_instruction; + u32 cycles = 0; + int current_pc_ok = ctx->pc_ok; + + if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) + { + command_print(cmd_ctx, "--- trigger ---"); + } + + /* instructions execute in IE/D or BE/D cycles */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + ctx->last_instruction = ctx->pipe_index; + + /* if we don't have a valid pc skip until we reach an indirect branch */ + if ((!ctx->pc_ok) && (pipestat != STAT_BE)) + { + ctx->pipe_index++; + continue; + } + + /* any indirect branch could have interrupted instruction flow + * - the branch reason code could indicate a trace discontinuity + * - a branch to the exception vectors indicates an exception + */ + if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) + { + /* backup current data index, to be able to consume the branch address + * before examining data address and values + */ + old_data_index = ctx->data_index; + old_data_half = ctx->data_half; + + ctx->last_instruction = ctx->pipe_index; + + if ((retval = etmv1_branch_address(ctx)) != 0) + { + /* negative return value from etmv1_branch_address means we ran out of packets, + * quit analysing the trace */ + if (retval < 0) + break; + + /* a positive return values means the current branch was abandoned, + * and a new branch was encountered in cycle ctx->pipe_index + retval; + */ + WARNING("abandoned branch encountered, correctnes of analysis uncertain"); + ctx->pipe_index += retval; + continue; + } + + /* skip over APO cycles */ + ctx->pipe_index += 2; + + switch (ctx->last_branch_reason) + { + case 0x0: /* normal PC change */ + next_pc = ctx->last_branch; + break; + case 0x1: /* tracing enabled */ + command_print(cmd_ctx, "--- tracing enabled at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x2: /* trace restarted after FIFO overflow */ + command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x3: /* exit from debug state */ + command_print(cmd_ctx, "--- exit from debug state at 0x%8.8x ---", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + break; + case 0x4: /* periodic synchronization point */ + next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) + { + command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8x ---", next_pc); + ctx->current_pc = next_pc; + ctx->pipe_index++; + continue; + } + break; + default: /* reserved */ + ERROR("BUG: branch reason code 0x%x is reserved", ctx->last_branch_reason); + exit(-1); + break; + } + + /* if we got here the branch was a normal PC change + * (or a periodic synchronization point, which means the same for that matter) + * if we didn't accquire a complete PC continue with the next cycle + */ + if (!ctx->pc_ok) + continue; + + /* indirect branch to the exception vector means an exception occured */ + if (((ctx->last_branch >= 0x0) && (ctx->last_branch <= 0x20)) + || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) + { + if ((ctx->last_branch & 0xff) == 0x10) + { + command_print(cmd_ctx, "data abort"); + } + else + { + command_print(cmd_ctx, "exception vector 0x%2.2x", ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + } + } + } + + /* an instruction was executed (or not, depending on the condition flags) + * retrieve it from the image for displaying */ + if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && + !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && + ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) + { + if ((retval = etm_read_instruction(ctx, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images + * for now we just quit the analsysis*/ + return retval; + } + } + + cycles = old_index - last_instruction; + } + + if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) + { + u32 new_data_index = ctx->data_index; + u32 new_data_half = ctx->data_half; + + /* in case of a branch with data, the branch target address was consumed before + * we temporarily go back to the saved data index */ + if (pipestat == STAT_BD) + { + ctx->data_index = old_data_index; + ctx->data_half = old_data_half; + } + + if (ctx->tracemode & ETMV1_TRACE_ADDR) + { + u8 packet; + int shift = 0; + + do { + if ((retval = etmv1_next_packet(ctx, &packet, 0)) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + ctx->last_ptr &= ~(0x7f << shift); + ctx->last_ptr |= (packet & 0x7f) << shift; + shift += 7; + } while ((packet & 0x80) && (shift < 32)); + + if (shift >= 32) + ctx->ptr_ok = 1; + + if (ctx->ptr_ok) + { + command_print(cmd_ctx, "address: 0x%8.8x", ctx->last_ptr); + } + } + + if (ctx->tracemode & ETMV1_TRACE_DATA) + { + if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) + { + int i; + for (i = 0; i < 16; i++) + { + if (instruction.info.load_store_multiple.register_list & (1 << i)) + { + u32 data; + if (etmv1_data(ctx, 4, &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + } + else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) + { + u32 data; + if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) + return ERROR_ETM_ANALYSIS_FAILED; + command_print(cmd_ctx, "data: 0x%8.8x", data); + } + } + + /* restore data index after consuming BD address and data */ + if (pipestat == STAT_BD) + { + ctx->data_index = new_data_index; + ctx->data_half = new_data_half; + } + } + + /* adjust PC */ + if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) + { + if (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1)) + { + next_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + } + else if (pipestat == STAT_IN) + { + next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + + if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) + { + char cycles_text[32] = ""; + + /* if the trace was captured with cycle accurate tracing enabled, + * output the number of cycles since the last executed instruction + */ + if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + { + snprintf(cycles_text, 32, " (%i %s)", + cycles, + (cycles == 1) ? "cycle" : "cycles"); + } + + command_print(cmd_ctx, "%s%s%s", + instruction.text, + (pipestat == STAT_IN) ? " (not executed)" : "", + cycles_text); + + ctx->current_pc = next_pc; + + /* packets for an instruction don't start on or before the preceding + * functional pipestat (i.e. other than WT or TD) + */ + if (ctx->data_index <= ctx->pipe_index) + { + ctx->data_index = ctx->pipe_index + 1; + ctx->data_half = 0; + } + } + + ctx->pipe_index += 1; + } + + return ERROR_OK; +} + +int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etmv1_tracemode_t tracemode; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + tracemode = arm7_9->etm_ctx->tracemode; + + if (argc == 4) + { + if (strcmp(args[0], "none") == 0) + { + tracemode = ETMV1_TRACE_NONE; + } + else if (strcmp(args[0], "data") == 0) + { + tracemode = ETMV1_TRACE_DATA; + } + else if (strcmp(args[0], "address") == 0) + { + tracemode = ETMV1_TRACE_ADDR; + } + else if (strcmp(args[0], "all") == 0) + { + tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[0]); + return ERROR_OK; + } + + switch (strtol(args[1], NULL, 0)) + { + case 0: + tracemode |= ETMV1_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETMV1_CONTEXTID_8; + break; + case 16: + tracemode |= ETMV1_CONTEXTID_16; + break; + case 32: + tracemode |= ETMV1_CONTEXTID_32; + break; + default: + command_print(cmd_ctx, "invalid option '%s'", args[1]); + return ERROR_OK; + } + + if (strcmp(args[2], "enable") == 0) + { + tracemode |= ETMV1_CYCLE_ACCURATE; + } + else if (strcmp(args[2], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + + if (strcmp(args[3], "enable") == 0) + { + tracemode |= ETMV1_BRANCH_OUTPUT; + } + else if (strcmp(args[3], "disable") == 0) + { + tracemode |= 0; + } + else + { + command_print(cmd_ctx, "invalid option '%s'", args[2]); + return ERROR_OK; + } + } + else if (argc != 0) + { + command_print(cmd_ctx, "usage: configure trace mode "); + return ERROR_OK; + } + + command_print(cmd_ctx, "current tracemode configuration:"); + + switch (tracemode & ETMV1_TRACE_MASK) + { + case ETMV1_TRACE_NONE: + command_print(cmd_ctx, "data tracing: none"); + break; + case ETMV1_TRACE_DATA: + command_print(cmd_ctx, "data tracing: data only"); + break; + case ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address only"); + break; + case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR: + command_print(cmd_ctx, "data tracing: address and data"); + break; + } + + switch (tracemode & ETMV1_CONTEXTID_MASK) + { + case ETMV1_CONTEXTID_NONE: + command_print(cmd_ctx, "contextid tracing: none"); + break; + case ETMV1_CONTEXTID_8: + command_print(cmd_ctx, "contextid tracing: 8 bit"); + break; + case ETMV1_CONTEXTID_16: + command_print(cmd_ctx, "contextid tracing: 16 bit"); + break; + case ETMV1_CONTEXTID_32: + command_print(cmd_ctx, "contextid tracing: 32 bit"); + break; + } + + if (tracemode & ETMV1_CYCLE_ACCURATE) + { + command_print(cmd_ctx, "cycle-accurate tracing enabled"); + } + else + { + command_print(cmd_ctx, "cycle-accurate tracing disabled"); + } + + if (tracemode & ETMV1_BRANCH_OUTPUT) + { + command_print(cmd_ctx, "full branch address output enabled"); + } + else + { + command_print(cmd_ctx, "full branch address output disabled"); + } + + /* only update ETM_CTRL register if tracemode changed */ + if (arm7_9->etm_ctx->tracemode != tracemode) + { + reg_t *etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + + etm_get_reg(etm_ctrl_reg); + + buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK); + buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4); + buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8); + buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9); + etm_store_reg(etm_ctrl_reg); + + arm7_9->etm_ctx->tracemode = tracemode; + + /* invalidate old trace data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + } + + return ERROR_OK; +} + +int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_portmode_t portmode = 0x0; + etm_context_t *etm_ctx = malloc(sizeof(etm_context_t)); + int i; + + if (argc != 5) + { + ERROR("incomplete 'etm config ' command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + switch (strtoul(args[1], NULL, 0)) + { + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + default: + command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]); + return ERROR_OK; + } + + if (strcmp("normal", args[2]) == 0) + { + portmode |= ETM_PORT_NORMAL; + } + else if (strcmp("multiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_MUXED; + } + else if (strcmp("demultiplexed", args[2]) == 0) + { + portmode |= ETM_PORT_DEMUXED; + } + else + { + command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]); + return ERROR_OK; + } + + if (strcmp("half", args[3]) == 0) + { + portmode |= ETM_PORT_HALF_CLOCK; + } + else if (strcmp("full", args[3]) == 0) + { + portmode |= ETM_PORT_FULL_CLOCK; + } + else + { + command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]); + return ERROR_OK; + } + + for (i=0; etm_capture_drivers[i]; i++) + { + if (strcmp(args[4], etm_capture_drivers[i]->name) == 0) + { + if (etm_capture_drivers[i]->register_commands(cmd_ctx) != ERROR_OK) + { + free(etm_ctx); + exit(-1); + } + + etm_ctx->capture_driver = etm_capture_drivers[i]; + + break; + } + } + + if (!etm_capture_drivers[i]) + { + /* no supported capture driver found, don't register an ETM */ + free(etm_ctx); + ERROR("trace capture driver '%s' not found", args[4]); + return ERROR_OK; + } + + etm_ctx->target = target; + etm_ctx->trigger_percent = 50; + etm_ctx->trace_data = NULL; + etm_ctx->trace_depth = 0; + etm_ctx->portmode = portmode; + etm_ctx->tracemode = 0x0; + etm_ctx->core_state = ARMV4_5_STATE_ARM; + etm_ctx->image = NULL; + etm_ctx->pipe_index = 0; + etm_ctx->data_index = 0; + etm_ctx->current_pc = 0x0; + etm_ctx->pc_ok = 0; + etm_ctx->last_branch = 0x0; + etm_ctx->last_branch_reason = 0x0; + etm_ctx->last_ptr = 0x0; + etm_ctx->ptr_ok = 0x0; + etm_ctx->context_id = 0x0; + etm_ctx->last_instruction = 0; + + arm7_9->etm_ctx = etm_ctx; + + etm_register_user_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_etm_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + reg_t *etm_config_reg; + reg_t *etm_sys_config_reg; + + int max_port_size; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CONFIG]; + etm_sys_config_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_SYS_CONFIG]; + + etm_get_reg(etm_config_reg); + command_print(cmd_ctx, "pairs of address comparators: %i", buf_get_u32(etm_config_reg->value, 0, 4)); + command_print(cmd_ctx, "pairs of data comparators: %i", buf_get_u32(etm_config_reg->value, 4, 4)); + command_print(cmd_ctx, "memory map decoders: %i", buf_get_u32(etm_config_reg->value, 8, 5)); + command_print(cmd_ctx, "number of counters: %i", buf_get_u32(etm_config_reg->value, 13, 3)); + command_print(cmd_ctx, "sequencer %spresent", + (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "number of ext. inputs: %i", buf_get_u32(etm_config_reg->value, 17, 3)); + command_print(cmd_ctx, "number of ext. outputs: %i", buf_get_u32(etm_config_reg->value, 20, 3)); + command_print(cmd_ctx, "FIFO full %spresent", + (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "protocol version: %i", buf_get_u32(etm_config_reg->value, 28, 3)); + + etm_get_reg(etm_sys_config_reg); + + switch (buf_get_u32(etm_sys_config_reg->value, 0, 3)) + { + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + } + command_print(cmd_ctx, "max. port size: %i", max_port_size); + + command_print(cmd_ctx, "half-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "full-rate clocking %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "normal trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "multiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "demultiplex trace format %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not "); + command_print(cmd_ctx, "FIFO full %ssupported", + (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not "); + + return ERROR_OK; +} + +int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + trace_status_t trace_status; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!arm7_9->etm_ctx) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + trace_status = arm7_9->etm_ctx->capture_driver->status(arm7_9->etm_ctx); + + if (trace_status == TRACE_IDLE) + { + command_print(cmd_ctx, "tracing is idle"); + } + else + { + static char *completed = " completed"; + static char *running = " is running"; + static char *overflowed = ", trace overflowed"; + static char *triggered = ", trace triggered"; + + command_print(cmd_ctx, "trace collection%s%s%s", + (trace_status & TRACE_RUNNING) ? running : completed, + (trace_status & TRACE_OVERFLOWED) ? overflowed : "", + (trace_status & TRACE_TRIGGERED) ? triggered : ""); + + if (arm7_9->etm_ctx->trace_depth > 0) + { + command_print(cmd_ctx, "%i frames of trace data read", arm7_9->etm_ctx->trace_depth); + } + } + + return ERROR_OK; +} + +int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: etm image [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->image) + { + image_close(etm_ctx->image); + free(etm_ctx->image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + etm_ctx->image = malloc(sizeof(image_t)); + etm_ctx->image->base_address_set = 0; + etm_ctx->image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + etm_ctx->image->base_address_set = 1; + etm_ctx->image->base_address = strtoul(args[1], NULL, 0); + } + else + { + etm_ctx->image->base_address_set = 0; + } + + if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", etm_ctx->image->error_str); + free(etm_ctx->image); + etm_ctx->image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm dump "); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status == TRACE_IDLE) + { + command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ + command_print(cmd_ctx, "trace capture not completed"); + return ERROR_OK; + } + + /* read the trace data if it wasn't read already */ + if (etm_ctx->trace_depth == 0) + etm_ctx->capture_driver->read_trace(etm_ctx); + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + fileio_write_u32(&file, etm_ctx->capture_status); + fileio_write_u32(&file, etm_ctx->portmode); + fileio_write_u32(&file, etm_ctx->tracemode); + fileio_write_u32(&file, etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); + fileio_write_u32(&file, etm_ctx->trace_data[i].packet); + fileio_write_u32(&file, etm_ctx->trace_data[i].flags); + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t file; + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int i; + + if (argc != 1) + { + command_print(cmd_ctx, "usage: etm load "); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) + { + command_print(cmd_ctx, "trace capture running, stop first"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + if (file.size % 4) + { + command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + return ERROR_OK; + } + + if (etm_ctx->trace_depth > 0) + { + free(etm_ctx->trace_data); + } + + fileio_read_u32(&file, &etm_ctx->capture_status); + fileio_read_u32(&file, &etm_ctx->portmode); + fileio_read_u32(&file, &etm_ctx->tracemode); + fileio_read_u32(&file, &etm_ctx->trace_depth); + + etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth); + + for (i = 0; i < etm_ctx->trace_depth; i++) + { + u32 pipestat, packet, flags; + fileio_read_u32(&file, &pipestat); + fileio_read_u32(&file, &packet); + fileio_read_u32(&file, &flags); + etm_ctx->trace_data[i].pipestat = pipestat & 0xff; + etm_ctx->trace_data[i].packet = packet & 0xffff; + etm_ctx->trace_data[i].flags = flags; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if (argc > 0) + { + u32 new_value = strtoul(args[0], NULL, 0); + + if ((new_value < 2) || (new_value > 100)) + { + command_print(cmd_ctx, "valid settings are 2% to 100%"); + } + else + { + etm_ctx->trigger_percent = new_value; + } + } + + command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", etm_ctx->trigger_percent); + + return ERROR_OK; +} + +int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + /* invalidate old tracing data */ + arm7_9->etm_ctx->capture_status = TRACE_IDLE; + if (arm7_9->etm_ctx->trace_depth > 0) + { + free(arm7_9->etm_ctx->trace_data); + arm7_9->etm_ctx->trace_data = NULL; + } + arm7_9->etm_ctx->trace_depth = 0; + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Clear programming bit (10), set port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->start_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + reg_t *etm_ctrl_reg; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + etm_ctrl_reg = &arm7_9->etm_ctx->reg_cache->reg_list[ETM_CTRL]; + etm_get_reg(etm_ctrl_reg); + + /* Set programming bit (10), clear port selection bit (11) */ + buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); + + etm_store_reg(etm_ctrl_reg); + jtag_execute_queue(); + + etm_ctx->capture_driver->stop_capture(etm_ctx); + + return ERROR_OK; +} + +int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + arm7_9_common_t *arm7_9; + etm_context_t *etm_ctx; + int retval; + + target = get_current_target(cmd_ctx); + + if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) + { + command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target"); + return ERROR_OK; + } + + if (!(etm_ctx = arm7_9->etm_ctx)) + { + command_print(cmd_ctx, "current target doesn't have an ETM configured"); + return ERROR_OK; + } + + if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK) + { + switch(retval) + { + case ERROR_ETM_ANALYSIS_FAILED: + command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(cmd_ctx, "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(cmd_ctx, "no image available for trace analysis"); + break; + default: + command_print(cmd_ctx, "unknown error: %i", retval); + } + } + + return ERROR_OK; +} + +int etm_register_commands(struct command_context_s *cmd_ctx) +{ + etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell"); + + register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command, COMMAND_CONFIG, NULL); + + return ERROR_OK; +} + +int etm_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, + COMMAND_EXEC, "configure trace mode ", handle_etm_trigger_percent_command, + COMMAND_EXEC, "amount () of trace buffer to be filled after the trigger occured"); + register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command, + COMMAND_EXEC, "display current target's ETM status"); + register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command, + COMMAND_EXEC, "start ETM trace collection"); + register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command, + COMMAND_EXEC, "stop ETM trace collection"); + + register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command, + COMMAND_EXEC, "anaylze collected ETM trace"); + + register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command, + COMMAND_EXEC, "load image from [base address]"); + + register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, + COMMAND_EXEC, "dump captured trace data "); + register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, + COMMAND_EXEC, "load trace data for analysis "); + + return ERROR_OK; +} diff --git a/src/target/target.c b/src/target/target.c index 27df12fc..a9f7c103 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1,2332 +1,2332 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" -#include "target.h" -#include "target_request.h" - -#include "log.h" -#include "configuration.h" -#include "binarybuffer.h" -#include "jtag.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); - - -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); - -int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); -int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc); - -/* targets - */ -extern target_type_t arm7tdmi_target; -extern target_type_t arm720t_target; -extern target_type_t arm9tdmi_target; -extern target_type_t arm920t_target; -extern target_type_t arm966e_target; -extern target_type_t arm926ejs_target; -extern target_type_t feroceon_target; -extern target_type_t xscale_target; -extern target_type_t cortexm3_target; - -target_type_t *target_types[] = -{ - &arm7tdmi_target, - &arm9tdmi_target, - &arm920t_target, - &arm720t_target, - &arm966e_target, - &arm926ejs_target, - &feroceon_target, - &xscale_target, - &cortexm3_target, - NULL, -}; - -target_t *targets = NULL; -target_event_callback_t *target_event_callbacks = NULL; -target_timer_callback_t *target_timer_callbacks = NULL; - -char *target_state_strings[] = -{ - "unknown", - "running", - "halted", - "reset", - "debug_running", -}; - -char *target_debug_reason_strings[] = -{ - "debug request", "breakpoint", "watchpoint", - "watchpoint and breakpoint", "single step", - "target not halted" -}; - -char *target_endianess_strings[] = -{ - "big endian", - "little endian", -}; - -enum daemon_startup_mode startup_mode = DAEMON_ATTACH; - -static int target_continous_poll = 1; - -/* read a u32 from a buffer in target memory endianness */ -u32 target_buffer_get_u32(target_t *target, u8 *buffer) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - return le_to_h_u32(buffer); - else - return be_to_h_u32(buffer); -} - -/* read a u16 from a buffer in target memory endianness */ -u16 target_buffer_get_u16(target_t *target, u8 *buffer) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - return le_to_h_u16(buffer); - else - return be_to_h_u16(buffer); -} - -/* write a u32 to a buffer in target memory endianness */ -void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - h_u32_to_le(buffer, value); - else - h_u32_to_be(buffer, value); -} - -/* write a u16 to a buffer in target memory endianness */ -void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value) -{ - if (target->endianness == TARGET_LITTLE_ENDIAN) - h_u16_to_le(buffer, value); - else - h_u16_to_be(buffer, value); -} - -/* returns a pointer to the n-th configured target */ -target_t* get_target_by_num(int num) -{ - target_t *target = targets; - int i = 0; - - while (target) - { - if (num == i) - return target; - target = target->next; - i++; - } - - return NULL; -} - -int get_num_by_target(target_t *query_target) -{ - target_t *target = targets; - int i = 0; - - while (target) - { - if (target == query_target) - return i; - target = target->next; - i++; - } - - return -1; -} - -target_t* get_current_target(command_context_t *cmd_ctx) -{ - target_t *target = get_target_by_num(cmd_ctx->current_target); - - if (target == NULL) - { - ERROR("BUG: current_target out of bounds"); - exit(-1); - } - - return target; -} - -/* Process target initialization, when target entered debug out of reset - * the handler is unregistered at the end of this function, so it's only called once - */ -int target_init_handler(struct target_s *target, enum target_event event, void *priv) -{ - FILE *script; - struct command_context_s *cmd_ctx = priv; - - if ((event == TARGET_EVENT_HALTED) && (target->reset_script)) - { - target_unregister_event_callback(target_init_handler, priv); - - script = open_file_from_path(cmd_ctx, target->reset_script, "r"); - if (!script) - { - ERROR("couldn't open script file %s", target->reset_script); - return ERROR_OK; - } - - INFO("executing reset script '%s'", target->reset_script); - command_run_file(cmd_ctx, script, COMMAND_EXEC); - fclose(script); - - jtag_execute_queue(); - } - - return ERROR_OK; -} - -int target_run_and_halt_handler(void *priv) -{ - target_t *target = priv; - - target->type->halt(target); - - return ERROR_OK; -} - -int target_process_reset(struct command_context_s *cmd_ctx) -{ - int retval = ERROR_OK; - target_t *target; - struct timeval timeout, now; - - /* prepare reset_halt where necessary */ - target = targets; - while (target) - { - if (jtag_reset_config & RESET_SRST_PULLS_TRST) - { - switch (target->reset_mode) - { - case RESET_HALT: - command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT"); - target->reset_mode = RESET_RUN_AND_HALT; - break; - case RESET_INIT: - command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT"); - target->reset_mode = RESET_RUN_AND_INIT; - break; - default: - break; - } - } - switch (target->reset_mode) - { - case RESET_HALT: - case RESET_INIT: - target->type->prepare_reset_halt(target); - break; - default: - break; - } - target = target->next; - } - - target = targets; - while (target) - { - target->type->assert_reset(target); - target = target->next; - } - jtag_execute_queue(); - - /* request target halt if necessary, and schedule further action */ - target = targets; - while (target) - { - switch (target->reset_mode) - { - case RESET_RUN: - /* nothing to do if target just wants to be run */ - break; - case RESET_RUN_AND_HALT: - /* schedule halt */ - target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); - break; - case RESET_RUN_AND_INIT: - /* schedule halt */ - target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); - target_register_event_callback(target_init_handler, cmd_ctx); - break; - case RESET_HALT: - target->type->halt(target); - break; - case RESET_INIT: - target->type->halt(target); - target_register_event_callback(target_init_handler, cmd_ctx); - break; - default: - ERROR("BUG: unknown target->reset_mode"); - } - target = target->next; - } - - target = targets; - while (target) - { - target->type->deassert_reset(target); - target = target->next; - } - jtag_execute_queue(); - - /* Wait for reset to complete, maximum 5 seconds. */ - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - for(;;) - { - gettimeofday(&now, NULL); - - target_call_timer_callbacks(); - - target = targets; - while (target) - { - target->type->poll(target); - if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT)) - { - if (target->state != TARGET_HALTED) - { - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) - { - command_print(cmd_ctx, "Timed out waiting for reset"); - goto done; - } - usleep(100*1000); /* Do not eat all cpu */ - goto again; - } - } - target = target->next; - } - /* All targets we're waiting for are halted */ - break; - - again:; - } - done: - - - /* We want any events to be processed before the prompt */ - target_call_timer_callbacks(); - - return retval; -} - -static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - *physical = virtual; - return ERROR_OK; -} - -static int default_mmu(struct target_s *target, int *enabled) -{ - *enabled = 0; - return ERROR_OK; -} - -int target_init(struct command_context_s *cmd_ctx) -{ - target_t *target = targets; - - while (target) - { - if (target->type->init_target(cmd_ctx, target) != ERROR_OK) - { - ERROR("target '%s' init failed", target->type->name); - exit(-1); - } - - /* Set up default functions if none are provided by target */ - if (target->type->virt2phys == NULL) - { - target->type->virt2phys = default_virt2phys; - } - if (target->type->mmu == NULL) - { - target->type->mmu = default_mmu; - } - target = target->next; - } - - if (targets) - { - target_register_user_commands(cmd_ctx); - target_register_timer_callback(handle_target, 100, 1, NULL); - } - - return ERROR_OK; -} - -int target_init_reset(struct command_context_s *cmd_ctx) -{ - if (startup_mode == DAEMON_RESET) - target_process_reset(cmd_ctx); - - return ERROR_OK; -} - -int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) -{ - target_event_callback_t **callbacks_p = &target_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - if (*callbacks_p) - { - while ((*callbacks_p)->next) - callbacks_p = &((*callbacks_p)->next); - callbacks_p = &((*callbacks_p)->next); - } - - (*callbacks_p) = malloc(sizeof(target_event_callback_t)); - (*callbacks_p)->callback = callback; - (*callbacks_p)->priv = priv; - (*callbacks_p)->next = NULL; - - return ERROR_OK; -} - -int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) -{ - target_timer_callback_t **callbacks_p = &target_timer_callbacks; - struct timeval now; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - if (*callbacks_p) - { - while ((*callbacks_p)->next) - callbacks_p = &((*callbacks_p)->next); - callbacks_p = &((*callbacks_p)->next); - } - - (*callbacks_p) = malloc(sizeof(target_timer_callback_t)); - (*callbacks_p)->callback = callback; - (*callbacks_p)->periodic = periodic; - (*callbacks_p)->time_ms = time_ms; - - gettimeofday(&now, NULL); - (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; - time_ms -= (time_ms % 1000); - (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); - if ((*callbacks_p)->when.tv_usec > 1000000) - { - (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; - (*callbacks_p)->when.tv_sec += 1; - } - - (*callbacks_p)->priv = priv; - (*callbacks_p)->next = NULL; - - return ERROR_OK; -} - -int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) -{ - target_event_callback_t **p = &target_event_callbacks; - target_event_callback_t *c = target_event_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - while (c) - { - target_event_callback_t *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { - *p = next; - free(c); - return ERROR_OK; - } - else - p = &(c->next); - c = next; - } - - return ERROR_OK; -} - -int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) -{ - target_timer_callback_t **p = &target_timer_callbacks; - target_timer_callback_t *c = target_timer_callbacks; - - if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } - - while (c) - { - target_timer_callback_t *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { - *p = next; - free(c); - return ERROR_OK; - } - else - p = &(c->next); - c = next; - } - - return ERROR_OK; -} - -int target_call_event_callbacks(target_t *target, enum target_event event) -{ - target_event_callback_t *callback = target_event_callbacks; - target_event_callback_t *next_callback; - - DEBUG("target event %i", event); - - while (callback) - { - next_callback = callback->next; - callback->callback(target, event, callback->priv); - callback = next_callback; - } - - return ERROR_OK; -} - -int target_call_timer_callbacks() -{ - target_timer_callback_t *callback = target_timer_callbacks; - target_timer_callback_t *next_callback; - struct timeval now; - - gettimeofday(&now, NULL); - - while (callback) - { - next_callback = callback->next; - - if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec)) - || (now.tv_sec > callback->when.tv_sec)) - { - callback->callback(callback->priv); - if (callback->periodic) - { - int time_ms = callback->time_ms; - callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; - time_ms -= (time_ms % 1000); - callback->when.tv_sec = now.tv_sec + time_ms / 1000; - if (callback->when.tv_usec > 1000000) - { - callback->when.tv_usec = callback->when.tv_usec - 1000000; - callback->when.tv_sec += 1; - } - } - else - target_unregister_timer_callback(callback->callback, callback->priv); - } - - callback = next_callback; - } - - return ERROR_OK; -} - -int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) -{ - working_area_t *c = target->working_areas; - working_area_t *new_wa = NULL; - - /* Reevaluate working area address based on MMU state*/ - if (target->working_areas == NULL) - { - int retval; - int enabled; - retval = target->type->mmu(target, &enabled); - if (retval != ERROR_OK) - { - return retval; - } - if (enabled) - { - target->working_area = target->working_area_virt; - } - else - { - target->working_area = target->working_area_phys; - } - } - - /* only allocate multiples of 4 byte */ - if (size % 4) - { - ERROR("BUG: code tried to allocate unaligned number of bytes, padding"); - size = CEIL(size, 4); - } - - /* see if there's already a matching working area */ - while (c) - { - if ((c->free) && (c->size == size)) - { - new_wa = c; - break; - } - c = c->next; - } - - /* if not, allocate a new one */ - if (!new_wa) - { - working_area_t **p = &target->working_areas; - u32 first_free = target->working_area; - u32 free_size = target->working_area_size; - - DEBUG("allocating new working area"); - - c = target->working_areas; - while (c) - { - first_free += c->size; - free_size -= c->size; - p = &c->next; - c = c->next; - } - - if (free_size < size) - { - WARNING("not enough working area available(requested %d, free %d)", size, free_size); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - new_wa = malloc(sizeof(working_area_t)); - new_wa->next = NULL; - new_wa->size = size; - new_wa->address = first_free; - - if (target->backup_working_area) - { - new_wa->backup = malloc(new_wa->size); - target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); - } - else - { - new_wa->backup = NULL; - } - - /* put new entry in list */ - *p = new_wa; - } - - /* mark as used, and return the new (reused) area */ - new_wa->free = 0; - *area = new_wa; - - /* user pointer */ - new_wa->user = area; - - return ERROR_OK; -} - -int target_free_working_area(struct target_s *target, working_area_t *area) -{ - if (area->free) - return ERROR_OK; - - if (target->backup_working_area) - target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); - - area->free = 1; - - /* mark user pointer invalid */ - *area->user = NULL; - area->user = NULL; - - return ERROR_OK; -} - -int target_free_all_working_areas(struct target_s *target) -{ - working_area_t *c = target->working_areas; - - while (c) - { - working_area_t *next = c->next; - target_free_working_area(target, c); - - if (c->backup) - free(c->backup); - - free(c); - - c = next; - } - - target->working_areas = NULL; - - return ERROR_OK; -} - -int target_register_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL); - register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area
<'backup'|'nobackup'> [virtual address]"); - register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys "); - - return ERROR_OK; -} - -int target_arch_state(struct target_s *target) -{ - int retval; - if (target==NULL) - { - USER("No target has been configured"); - return ERROR_OK; - } - - USER("target state: %s", target_state_strings[target->state]); - - if (target->state!=TARGET_HALTED) - return ERROR_OK; - - retval=target->type->arch_state(target); - return retval; -} - -/* Single aligned words are guaranteed to use 16 or 32 bit access - * mode respectively, otherwise data is handled as quickly as - * possible - */ -int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) -{ - int retval; - - DEBUG("writing buffer of %i byte at 0x%8.8x", size, address); - - if (((address % 2) == 0) && (size == 2)) - { - return target->type->write_memory(target, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) - { - int unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - /* use bulk writes above a certain limit. This may have to be changed */ - if (aligned > 128) - { - if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) - return retval; - } - else - { - if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) - return retval; - } - - buffer += aligned; - address += aligned; - size -= aligned; - } - - /* handle tail writes of less than 4 bytes */ - if (size > 0) - { - if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - - -/* Single aligned words are guaranteed to use 16 or 32 bit access - * mode respectively, otherwise data is handled as quickly as - * possible - */ -int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) -{ - int retval; - - DEBUG("reading buffer of %i byte at 0x%8.8x", size, address); - - if (((address % 2) == 0) && (size == 2)) - { - return target->type->read_memory(target, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) - { - int unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) - return retval; - - buffer += aligned; - address += aligned; - size -= aligned; - } - - /* handle tail writes of less than 4 bytes */ - if (size > 0) - { - if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - -int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc) -{ - u8 *buffer; - int retval; - int i; - u32 checksum = 0; - - if ((retval = target->type->checksum_memory(target, address, - size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - buffer = malloc(size); - if (buffer == NULL) - { - ERROR("error allocating buffer for section (%d bytes)", size); - return ERROR_INVALID_ARGUMENTS; - } - retval = target_read_buffer(target, address, size, buffer); - if (retval != ERROR_OK) - { - free(buffer); - return retval; - } - - /* convert to target endianess */ - for (i = 0; i < (size/sizeof(u32)); i++) - { - u32 target_data; - target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]); - target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data); - } - - retval = image_calculate_checksum( buffer, size, &checksum ); - free(buffer); - } - - *crc = checksum; - - return retval; -} - -int target_read_u32(struct target_s *target, u32 address, u32 *value) -{ - u8 value_buf[4]; - - int retval = target->type->read_memory(target, address, 4, 1, value_buf); - - if (retval == ERROR_OK) - { - *value = target_buffer_get_u32(target, value_buf); - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_read_u16(struct target_s *target, u32 address, u16 *value) -{ - u8 value_buf[2]; - - int retval = target->type->read_memory(target, address, 2, 1, value_buf); - - if (retval == ERROR_OK) - { - *value = target_buffer_get_u16(target, value_buf); - DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_read_u8(struct target_s *target, u32 address, u8 *value) -{ - int retval = target->type->read_memory(target, address, 1, 1, value); - - if (retval == ERROR_OK) - { - DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value); - } - else - { - *value = 0x0; - DEBUG("address: 0x%8.8x failed", address); - } - - return retval; -} - -int target_write_u32(struct target_s *target, u32 address, u32 value) -{ - int retval; - u8 value_buf[4]; - - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); - - target_buffer_set_u32(target, value_buf, value); - if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_write_u16(struct target_s *target, u32 address, u16 value) -{ - int retval; - u8 value_buf[2]; - - DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); - - target_buffer_set_u16(target, value_buf, value); - if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_write_u8(struct target_s *target, u32 address, u8 value) -{ - int retval; - - DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); - - if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) - { - DEBUG("failed: %i", retval); - } - - return retval; -} - -int target_register_user_commands(struct command_context_s *cmd_ctx) -{ - register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); - register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); - register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); - register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]"); - register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]"); - register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]"); - register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset"); - - register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words [count]"); - register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words [count]"); - register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes [count]"); - - register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word "); - register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word "); - register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte "); - - register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint
[hw]"); - register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint "); - register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint
[value] [mask]"); - register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint "); - - register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image
['bin'|'ihex'|'elf'|'s19']"); - register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image
"); - register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image [offset] [type]"); - register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary
"); - register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary
"); - - target_request_register_commands(cmd_ctx); - trace_register_commands(cmd_ctx); - - return ERROR_OK; -} - -int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = targets; - int count = 0; - - if (argc == 1) - { - int num = strtoul(args[0], NULL, 0); - - while (target) - { - count++; - target = target->next; - } - - if (num < count) - cmd_ctx->current_target = num; - else - command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count); - - return ERROR_OK; - } - - while (target) - { - command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]); - target = target->next; - } - - return ERROR_OK; -} - -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int i; - int found = 0; - - if (argc < 3) - { - ERROR("target command requires at least three arguments: "); - exit(-1); - } - - /* search for the specified target */ - if (args[0] && (args[0][0] != 0)) - { - for (i = 0; target_types[i]; i++) - { - if (strcmp(args[0], target_types[i]->name) == 0) - { - target_t **last_target_p = &targets; - - /* register target specific commands */ - if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) - { - ERROR("couldn't register '%s' commands", args[0]); - exit(-1); - } - - if (*last_target_p) - { - while ((*last_target_p)->next) - last_target_p = &((*last_target_p)->next); - last_target_p = &((*last_target_p)->next); - } - - *last_target_p = malloc(sizeof(target_t)); - - (*last_target_p)->type = target_types[i]; - - if (strcmp(args[1], "big") == 0) - (*last_target_p)->endianness = TARGET_BIG_ENDIAN; - else if (strcmp(args[1], "little") == 0) - (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; - else - { - ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); - exit(-1); - } - - /* what to do on a target reset */ - if (strcmp(args[2], "reset_halt") == 0) - (*last_target_p)->reset_mode = RESET_HALT; - else if (strcmp(args[2], "reset_run") == 0) - (*last_target_p)->reset_mode = RESET_RUN; - else if (strcmp(args[2], "reset_init") == 0) - (*last_target_p)->reset_mode = RESET_INIT; - else if (strcmp(args[2], "run_and_halt") == 0) - (*last_target_p)->reset_mode = RESET_RUN_AND_HALT; - else if (strcmp(args[2], "run_and_init") == 0) - (*last_target_p)->reset_mode = RESET_RUN_AND_INIT; - else - { - ERROR("unknown target startup mode %s", args[2]); - exit(-1); - } - (*last_target_p)->run_and_halt_time = 1000; /* default 1s */ - - (*last_target_p)->reset_script = NULL; - (*last_target_p)->post_halt_script = NULL; - (*last_target_p)->pre_resume_script = NULL; - (*last_target_p)->gdb_program_script = NULL; - - (*last_target_p)->working_area = 0x0; - (*last_target_p)->working_area_size = 0x0; - (*last_target_p)->working_areas = NULL; - (*last_target_p)->backup_working_area = 0; - - (*last_target_p)->state = TARGET_UNKNOWN; - (*last_target_p)->reg_cache = NULL; - (*last_target_p)->breakpoints = NULL; - (*last_target_p)->watchpoints = NULL; - (*last_target_p)->next = NULL; - (*last_target_p)->arch_info = NULL; - - /* initialize trace information */ - (*last_target_p)->trace_info = malloc(sizeof(trace_t)); - (*last_target_p)->trace_info->num_trace_points = 0; - (*last_target_p)->trace_info->trace_points_size = 0; - (*last_target_p)->trace_info->trace_points = NULL; - (*last_target_p)->trace_info->trace_history_size = 0; - (*last_target_p)->trace_info->trace_history = NULL; - (*last_target_p)->trace_info->trace_history_pos = 0; - (*last_target_p)->trace_info->trace_history_overflowed = 0; - - (*last_target_p)->dbgmsg = NULL; - (*last_target_p)->dbg_msg_enabled = 0; - - (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); - - found = 1; - break; - } - } - } - - /* no matching target found */ - if (!found) - { - ERROR("target '%s' not found", args[0]); - exit(-1); - } - - return ERROR_OK; -} - -/* usage: target_script */ -int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if (argc < 3) - { - ERROR("incomplete target_script command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - if (strcmp(args[1], "reset") == 0) - { - if (target->reset_script) - free(target->reset_script); - target->reset_script = strdup(args[2]); - } - else if (strcmp(args[1], "post_halt") == 0) - { - if (target->post_halt_script) - free(target->post_halt_script); - target->post_halt_script = strdup(args[2]); - } - else if (strcmp(args[1], "pre_resume") == 0) - { - if (target->pre_resume_script) - free(target->pre_resume_script); - target->pre_resume_script = strdup(args[2]); - } - else if (strcmp(args[1], "gdb_program_config") == 0) - { - if (target->gdb_program_script) - free(target->gdb_program_script); - target->gdb_program_script = strdup(args[2]); - } - else - { - ERROR("unknown event type: '%s", args[1]); - exit(-1); - } - - return ERROR_OK; -} - -int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if (argc < 2) - { - ERROR("incomplete run_and_halt_time command"); - exit(-1); - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - - target->run_and_halt_time = strtoul(args[1], NULL, 0); - - return ERROR_OK; -} - -int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - - if ((argc < 4) || (argc > 5)) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - target = get_target_by_num(strtoul(args[0], NULL, 0)); - - if (!target) - { - ERROR("target number '%s' not defined", args[0]); - exit(-1); - } - target_free_all_working_areas(target); - - target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0); - if (argc == 5) - { - target->working_area_virt = strtoul(args[4], NULL, 0); - } - target->working_area_size = strtoul(args[2], NULL, 0); - - if (strcmp(args[3], "backup") == 0) - { - target->backup_working_area = 1; - } - else if (strcmp(args[3], "nobackup") == 0) - { - target->backup_working_area = 0; - } - else - { - ERROR("unrecognized argument (%s)", args[3]); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - - -/* process target state changes */ -int handle_target(void *priv) -{ - int retval; - target_t *target = targets; - - while (target) - { - /* only poll if target isn't already halted */ - if (target->state != TARGET_HALTED) - { - if (target_continous_poll) - if ((retval = target->type->poll(target)) != ERROR_OK) - { - ERROR("couldn't poll target(%d). It's due for a reset.", retval); - } - } - - target = target->next; - } - - return ERROR_OK; -} - -int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - reg_t *reg = NULL; - int count = 0; - char *value; - - DEBUG("-"); - - target = get_current_target(cmd_ctx); - - /* list all available registers for the current target */ - if (argc == 0) - { - reg_cache_t *cache = target->reg_cache; - - count = 0; - while(cache) - { - int i; - for (i = 0; i < cache->num_regs; i++) - { - value = buf_to_str(cache->reg_list[i].value, cache->reg_list[i].size, 16); - command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid); - free(value); - } - cache = cache->next; - } - - return ERROR_OK; - } - - /* access a single register by its ordinal number */ - if ((args[0][0] >= '0') && (args[0][0] <= '9')) - { - int num = strtoul(args[0], NULL, 0); - reg_cache_t *cache = target->reg_cache; - - count = 0; - while(cache) - { - int i; - for (i = 0; i < cache->num_regs; i++) - { - if (count++ == num) - { - reg = &cache->reg_list[i]; - break; - } - } - if (reg) - break; - cache = cache->next; - } - - if (!reg) - { - command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; - } - } else /* access a single register by its name */ - { - reg = register_get_by_name(target->reg_cache, args[0], 1); - - if (!reg) - { - command_print(cmd_ctx, "register %s not found in current target", args[0]); - return ERROR_OK; - } - } - - /* display a register */ - if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9')))) - { - if ((argc == 2) && (strcmp(args[1], "force") == 0)) - reg->valid = 0; - - if (reg->valid == 0) - { - reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } - arch_type->get(reg); - } - value = buf_to_str(reg->value, reg->size, 16); - command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); - free(value); - return ERROR_OK; - } - - /* set register value */ - if (argc == 2) - { - u8 *buf = malloc(CEIL(reg->size, 8)); - str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0); - - reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } - - arch_type->set(reg, buf); - - value = buf_to_str(reg->value, reg->size, 16); - command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); - free(value); - - free(buf); - - return ERROR_OK; - } - - command_print(cmd_ctx, "usage: reg <#|name> [value]"); - - return ERROR_OK; -} - -static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms); - -int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - { - target->type->poll(target); - target_arch_state(target); - } - else - { - if (strcmp(args[0], "on") == 0) - { - target_continous_poll = 1; - } - else if (strcmp(args[0], "off") == 0) - { - target_continous_poll = 0; - } - else - { - command_print(cmd_ctx, "arg is \"on\" or \"off\""); - } - } - - - return ERROR_OK; -} - -int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int ms = 5000; - - if (argc > 0) - { - char *end; - - ms = strtoul(args[0], &end, 0) * 1000; - if (*end) - { - command_print(cmd_ctx, "usage: %s [seconds]", cmd); - return ERROR_OK; - } - } - - return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms); -} - -static void target_process_events(struct command_context_s *cmd_ctx) -{ - target_t *target = get_current_target(cmd_ctx); - target->type->poll(target); - target_call_timer_callbacks(); -} - -static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms) -{ - int retval; - struct timeval timeout, now; - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 0, ms * 1000); - - target_t *target = get_current_target(cmd_ctx); - for (;;) - { - if ((retval=target->type->poll(target))!=ERROR_OK) - return retval; - target_call_timer_callbacks(); - if (target->state == state) - { - break; - } - command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]); - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) - { - command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]); - ERROR("timed out while waiting for target %s", target_state_strings[state]); - break; - } - } - - return ERROR_OK; -} - -int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - DEBUG("-"); - - command_print(cmd_ctx, "requesting target halt..."); - - if ((retval = target->type->halt(target)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_ALREADY_HALTED: - command_print(cmd_ctx, "target already halted"); - break; - case ERROR_TARGET_TIMEOUT: - command_print(cmd_ctx, "target timed out... shutting down"); - return retval; - default: - command_print(cmd_ctx, "unknown error... shutting down"); - return retval; - } - } - - return handle_wait_halt_command(cmd_ctx, cmd, args, argc); -} - -/* what to do on daemon startup */ -int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - if (argc == 1) - { - if (strcmp(args[0], "attach") == 0) - { - startup_mode = DAEMON_ATTACH; - return ERROR_OK; - } - else if (strcmp(args[0], "reset") == 0) - { - startup_mode = DAEMON_RESET; - return ERROR_OK; - } - } - - WARNING("invalid daemon_startup configuration directive: %s", args[0]); - return ERROR_OK; - -} - -int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - int retval; - - command_print(cmd_ctx, "requesting target halt and executing a soft reset"); - - if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_TIMEOUT: - command_print(cmd_ctx, "target timed out... shutting down"); - exit(-1); - default: - command_print(cmd_ctx, "unknown error... shutting down"); - exit(-1); - } - } - - return ERROR_OK; -} - -int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - enum target_reset_mode reset_mode = target->reset_mode; - enum target_reset_mode save = target->reset_mode; - - DEBUG("-"); - - if (argc >= 1) - { - if (strcmp("run", args[0]) == 0) - reset_mode = RESET_RUN; - else if (strcmp("halt", args[0]) == 0) - reset_mode = RESET_HALT; - else if (strcmp("init", args[0]) == 0) - reset_mode = RESET_INIT; - else if (strcmp("run_and_halt", args[0]) == 0) - { - reset_mode = RESET_RUN_AND_HALT; - if (argc >= 2) - { - target->run_and_halt_time = strtoul(args[1], NULL, 0); - } - } - else if (strcmp("run_and_init", args[0]) == 0) - { - reset_mode = RESET_RUN_AND_INIT; - if (argc >= 2) - { - target->run_and_halt_time = strtoul(args[1], NULL, 0); - } - } - else - { - command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]"); - return ERROR_OK; - } - } - - /* temporarily modify mode of current reset target */ - target->reset_mode = reset_mode; - - /* reset *all* targets */ - target_process_reset(cmd_ctx); - - /* Restore default reset mode for this target */ - target->reset_mode = save; - - return ERROR_OK; -} - -int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ - else if (argc == 1) - retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ - else - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - target_process_events(cmd_ctx); - - target_arch_state(target); - - return retval; -} - -int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - DEBUG("-"); - - if (argc == 0) - target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */ - - if (argc == 1) - target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */ - - return ERROR_OK; -} - -int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - const int line_bytecnt = 32; - int count = 1; - int size = 4; - u32 address = 0; - int line_modulo; - int i; - - char output[128]; - int output_len; - - int retval; - - u8 *buffer; - target_t *target = get_current_target(cmd_ctx); - - if (argc < 1) - return ERROR_OK; - - if (argc == 2) - count = strtoul(args[1], NULL, 0); - - address = strtoul(args[0], NULL, 0); - - - switch (cmd[2]) - { - case 'w': - size = 4; line_modulo = line_bytecnt / 4; - break; - case 'h': - size = 2; line_modulo = line_bytecnt / 2; - break; - case 'b': - size = 1; line_modulo = line_bytecnt / 1; - break; - default: - return ERROR_OK; - } - - buffer = calloc(count, size); - retval = target->type->read_memory(target, address, size, count, buffer); - if (retval != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_UNALIGNED_ACCESS: - command_print(cmd_ctx, "error: address not aligned"); - break; - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "error: target must be halted for memory accesses"); - break; - case ERROR_TARGET_DATA_ABORT: - command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); - break; - default: - command_print(cmd_ctx, "error: unknown error"); - break; - } - return ERROR_OK; - } - - output_len = 0; - - for (i = 0; i < count; i++) - { - if (i%line_modulo == 0) - output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size)); - - switch (size) - { - case 4: - output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", target_buffer_get_u32(target, &buffer[i*4])); - break; - case 2: - output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2])); - break; - case 1: - output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]); - break; - } - - if ((i%line_modulo == line_modulo-1) || (i == count - 1)) - { - command_print(cmd_ctx, output); - output_len = 0; - } - } - - free(buffer); - - return ERROR_OK; -} - -int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u32 address = 0; - u32 value = 0; - int retval; - target_t *target = get_current_target(cmd_ctx); - u8 value_buf[4]; - - if (argc < 2) - return ERROR_OK; - - address = strtoul(args[0], NULL, 0); - value = strtoul(args[1], NULL, 0); - - switch (cmd[2]) - { - case 'w': - target_buffer_set_u32(target, value_buf, value); - retval = target->type->write_memory(target, address, 4, 1, value_buf); - break; - case 'h': - target_buffer_set_u16(target, value_buf, value); - retval = target->type->write_memory(target, address, 2, 1, value_buf); - break; - case 'b': - value_buf[0] = value; - retval = target->type->write_memory(target, address, 1, 1, value_buf); - break; - default: - return ERROR_OK; - } - - switch (retval) - { - case ERROR_TARGET_UNALIGNED_ACCESS: - command_print(cmd_ctx, "error: address not aligned"); - break; - case ERROR_TARGET_DATA_ABORT: - command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); - break; - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "error: target must be halted for memory accesses"); - break; - case ERROR_OK: - break; - default: - command_print(cmd_ctx, "error: unknown error"); - break; - } - - return ERROR_OK; - -} - -int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 *buffer; - u32 buf_cnt; - u32 image_size; - int i; - int retval; - - image_t image; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc < 1) - { - command_print(cmd_ctx, "usage: load_image [address] [type]"); - return ERROR_OK; - } - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - image.base_address_set = 1; - image.base_address = strtoul(args[1], NULL, 0); - } - else - { - image.base_address_set = 0; - } - - image.start_address_set = 0; - - duration_start_measure(&duration); - - if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "load_image error: %s", image.error_str); - return ERROR_OK; - } - - image_size = 0x0; - for (i = 0; i < image.num_sections; i++) - { - buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { - command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); - break; - } - - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("image_read_section failed with error code: %i", retval); - command_print(cmd_ctx, "image reading failed, download aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); - image_size += buf_cnt; - command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address); - - free(buffer); - } - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); - free(duration_text); - - image_close(&image); - - return ERROR_OK; - -} - -int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - fileio_t fileio; - - u32 address; - u32 size; - u8 buffer[560]; - int retval; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc != 3) - { - command_print(cmd_ctx, "usage: dump_image
"); - return ERROR_OK; - } - - address = strtoul(args[1], NULL, 0); - size = strtoul(args[2], NULL, 0); - - if ((address & 3) || (size & 3)) - { - command_print(cmd_ctx, "only 32-bit aligned address and size are supported"); - return ERROR_OK; - } - - if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); - return ERROR_OK; - } - - duration_start_measure(&duration); - - while (size > 0) - { - u32 size_written; - u32 this_run_size = (size > 560) ? 560 : size; - - retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer); - if (retval != ERROR_OK) - { - command_print(cmd_ctx, "Reading memory failed %d", retval); - break; - } - - fileio_write(&fileio, this_run_size, buffer, &size_written); - - size -= this_run_size; - address += this_run_size; - } - - fileio_close(&fileio); - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); - free(duration_text); - - return ERROR_OK; -} - -int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - u8 *buffer; - u32 buf_cnt; - u32 image_size; - int i; - int retval; - u32 checksum = 0; - u32 mem_checksum = 0; - - image_t image; - - duration_t duration; - char *duration_text; - - target_t *target = get_current_target(cmd_ctx); - - if (argc < 1) - { - command_print(cmd_ctx, "usage: verify_image [offset] [type]"); - return ERROR_OK; - } - - if (!target) - { - ERROR("no target selected"); - return ERROR_OK; - } - - duration_start_measure(&duration); - - if (argc >= 2) - { - image.base_address_set = 1; - image.base_address = strtoul(args[1], NULL, 0); - } - else - { - image.base_address_set = 0; - image.base_address = 0x0; - } - - image.start_address_set = 0; - - if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "verify_image error: %s", image.error_str); - return ERROR_OK; - } - - image_size = 0x0; - for (i = 0; i < image.num_sections; i++) - { - buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { - command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); - break; - } - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("image_read_section failed with error code: %i", retval); - command_print(cmd_ctx, "image reading failed, verify aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - - /* calculate checksum of image */ - image_calculate_checksum( buffer, buf_cnt, &checksum ); - - retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); - - if( retval != ERROR_OK ) - { - command_print(cmd_ctx, "could not calculate checksum, verify aborted"); - free(buffer); - image_close(&image); - return ERROR_OK; - } - - if( checksum != mem_checksum ) - { - /* failed crc checksum, fall back to a binary compare */ - u8 *data; - - command_print(cmd_ctx, "checksum mismatch - attempting binary compare"); - - data = (u8*)malloc(buf_cnt); - - /* Can we use 32bit word accesses? */ - int size = 1; - int count = buf_cnt; - if ((count % 4) == 0) - { - size *= 4; - count /= 4; - } - retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data); - - if (retval == ERROR_OK) - { - int t; - for (t = 0; t < buf_cnt; t++) - { - if (data[t] != buffer[t]) - { - command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]); - free(data); - free(buffer); - image_close(&image); - return ERROR_OK; - } - } - } - - free(data); - } - - free(buffer); - image_size += buf_cnt; - } - - duration_stop_measure(&duration, &duration_text); - command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); - free(duration_text); - - image_close(&image); - - return ERROR_OK; -} - -int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - - if (argc == 0) - { - breakpoint_t *breakpoint = target->breakpoints; - - while (breakpoint) - { - if (breakpoint->type == BKPT_SOFT) - { - char* buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); - command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); - free(buf); - } - else - { - command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); - } - breakpoint = breakpoint->next; - } - } - else if (argc >= 2) - { - int hw = BKPT_SOFT; - u32 length = 0; - - length = strtoul(args[1], NULL, 0); - - if (argc >= 3) - if (strcmp(args[2], "hw") == 0) - hw = BKPT_HARD; - - if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "target must be halted to set breakpoints"); - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - command_print(cmd_ctx, "no more breakpoints available"); - break; - default: - command_print(cmd_ctx, "unknown error, breakpoint not set"); - break; - } - } - else - { - command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0)); - } - } - else - { - command_print(cmd_ctx, "usage: bp
['hw']"); - } - - return ERROR_OK; -} - -int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc > 0) - breakpoint_remove(target, strtoul(args[0], NULL, 0)); - - return ERROR_OK; -} - -int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - int retval; - - if (argc == 0) - { - watchpoint_t *watchpoint = target->watchpoints; - - while (watchpoint) - { - command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); - watchpoint = watchpoint->next; - } - } - else if (argc >= 2) - { - enum watchpoint_rw type = WPT_ACCESS; - u32 data_value = 0x0; - u32 data_mask = 0xffffffff; - - if (argc >= 3) - { - switch(args[2][0]) - { - case 'r': - type = WPT_READ; - break; - case 'w': - type = WPT_WRITE; - break; - case 'a': - type = WPT_ACCESS; - break; - default: - command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); - return ERROR_OK; - } - } - if (argc >= 4) - { - data_value = strtoul(args[3], NULL, 0); - } - if (argc >= 5) - { - data_mask = strtoul(args[4], NULL, 0); - } - - if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0), - strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK) - { - switch (retval) - { - case ERROR_TARGET_NOT_HALTED: - command_print(cmd_ctx, "target must be halted to set watchpoints"); - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - command_print(cmd_ctx, "no more watchpoints available"); - break; - default: - command_print(cmd_ctx, "unknown error, watchpoint not set"); - break; - } - } - } - else - { - command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); - } - - return ERROR_OK; -} - -int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - - if (argc > 0) - watchpoint_remove(target, strtoul(args[0], NULL, 0)); - - return ERROR_OK; -} - -int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - int retval; - target_t *target = get_current_target(cmd_ctx); - u32 va; - u32 pa; - - if (argc != 1) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - va = strtoul(args[0], NULL, 0); - - retval = target->type->virt2phys(target, va, &pa); - if (retval == ERROR_OK) - { - command_print(cmd_ctx, "Physical address 0x%08x", pa); - } - else - { - /* lower levels will have logged a detailed error which is - * forwarded to telnet/GDB session. - */ - } - return retval; -} +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" +#include "target.h" +#include "target_request.h" + +#include "log.h" +#include "configuration.h" +#include "binarybuffer.h" +#include "jtag.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); + + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc); + +/* targets + */ +extern target_type_t arm7tdmi_target; +extern target_type_t arm720t_target; +extern target_type_t arm9tdmi_target; +extern target_type_t arm920t_target; +extern target_type_t arm966e_target; +extern target_type_t arm926ejs_target; +extern target_type_t feroceon_target; +extern target_type_t xscale_target; +extern target_type_t cortexm3_target; + +target_type_t *target_types[] = +{ + &arm7tdmi_target, + &arm9tdmi_target, + &arm920t_target, + &arm720t_target, + &arm966e_target, + &arm926ejs_target, + &feroceon_target, + &xscale_target, + &cortexm3_target, + NULL, +}; + +target_t *targets = NULL; +target_event_callback_t *target_event_callbacks = NULL; +target_timer_callback_t *target_timer_callbacks = NULL; + +char *target_state_strings[] = +{ + "unknown", + "running", + "halted", + "reset", + "debug_running", +}; + +char *target_debug_reason_strings[] = +{ + "debug request", "breakpoint", "watchpoint", + "watchpoint and breakpoint", "single step", + "target not halted" +}; + +char *target_endianess_strings[] = +{ + "big endian", + "little endian", +}; + +enum daemon_startup_mode startup_mode = DAEMON_ATTACH; + +static int target_continous_poll = 1; + +/* read a u32 from a buffer in target memory endianness */ +u32 target_buffer_get_u32(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u32(buffer); + else + return be_to_h_u32(buffer); +} + +/* read a u16 from a buffer in target memory endianness */ +u16 target_buffer_get_u16(target_t *target, u8 *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u16(buffer); + else + return be_to_h_u16(buffer); +} + +/* write a u32 to a buffer in target memory endianness */ +void target_buffer_set_u32(target_t *target, u8 *buffer, u32 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u32_to_le(buffer, value); + else + h_u32_to_be(buffer, value); +} + +/* write a u16 to a buffer in target memory endianness */ +void target_buffer_set_u16(target_t *target, u8 *buffer, u16 value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u16_to_le(buffer, value); + else + h_u16_to_be(buffer, value); +} + +/* returns a pointer to the n-th configured target */ +target_t* get_target_by_num(int num) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (num == i) + return target; + target = target->next; + i++; + } + + return NULL; +} + +int get_num_by_target(target_t *query_target) +{ + target_t *target = targets; + int i = 0; + + while (target) + { + if (target == query_target) + return i; + target = target->next; + i++; + } + + return -1; +} + +target_t* get_current_target(command_context_t *cmd_ctx) +{ + target_t *target = get_target_by_num(cmd_ctx->current_target); + + if (target == NULL) + { + ERROR("BUG: current_target out of bounds"); + exit(-1); + } + + return target; +} + +/* Process target initialization, when target entered debug out of reset + * the handler is unregistered at the end of this function, so it's only called once + */ +int target_init_handler(struct target_s *target, enum target_event event, void *priv) +{ + FILE *script; + struct command_context_s *cmd_ctx = priv; + + if ((event == TARGET_EVENT_HALTED) && (target->reset_script)) + { + target_unregister_event_callback(target_init_handler, priv); + + script = open_file_from_path(cmd_ctx, target->reset_script, "r"); + if (!script) + { + ERROR("couldn't open script file %s", target->reset_script); + return ERROR_OK; + } + + INFO("executing reset script '%s'", target->reset_script); + command_run_file(cmd_ctx, script, COMMAND_EXEC); + fclose(script); + + jtag_execute_queue(); + } + + return ERROR_OK; +} + +int target_run_and_halt_handler(void *priv) +{ + target_t *target = priv; + + target->type->halt(target); + + return ERROR_OK; +} + +int target_process_reset(struct command_context_s *cmd_ctx) +{ + int retval = ERROR_OK; + target_t *target; + struct timeval timeout, now; + + /* prepare reset_halt where necessary */ + target = targets; + while (target) + { + if (jtag_reset_config & RESET_SRST_PULLS_TRST) + { + switch (target->reset_mode) + { + case RESET_HALT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_HALT"); + target->reset_mode = RESET_RUN_AND_HALT; + break; + case RESET_INIT: + command_print(cmd_ctx, "nSRST pulls nTRST, falling back to RESET_RUN_AND_INIT"); + target->reset_mode = RESET_RUN_AND_INIT; + break; + default: + break; + } + } + switch (target->reset_mode) + { + case RESET_HALT: + case RESET_INIT: + target->type->prepare_reset_halt(target); + break; + default: + break; + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->assert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* request target halt if necessary, and schedule further action */ + target = targets; + while (target) + { + switch (target->reset_mode) + { + case RESET_RUN: + /* nothing to do if target just wants to be run */ + break; + case RESET_RUN_AND_HALT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + break; + case RESET_RUN_AND_INIT: + /* schedule halt */ + target_register_timer_callback(target_run_and_halt_handler, target->run_and_halt_time, 0, target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + case RESET_HALT: + target->type->halt(target); + break; + case RESET_INIT: + target->type->halt(target); + target_register_event_callback(target_init_handler, cmd_ctx); + break; + default: + ERROR("BUG: unknown target->reset_mode"); + } + target = target->next; + } + + target = targets; + while (target) + { + target->type->deassert_reset(target); + target = target->next; + } + jtag_execute_queue(); + + /* Wait for reset to complete, maximum 5 seconds. */ + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + for(;;) + { + gettimeofday(&now, NULL); + + target_call_timer_callbacks(); + + target = targets; + while (target) + { + target->type->poll(target); + if ((target->reset_mode == RESET_RUN_AND_INIT) || (target->reset_mode == RESET_RUN_AND_HALT)) + { + if (target->state != TARGET_HALTED) + { + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "Timed out waiting for reset"); + goto done; + } + usleep(100*1000); /* Do not eat all cpu */ + goto again; + } + } + target = target->next; + } + /* All targets we're waiting for are halted */ + break; + + again:; + } + done: + + + /* We want any events to be processed before the prompt */ + target_call_timer_callbacks(); + + return retval; +} + +static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + *physical = virtual; + return ERROR_OK; +} + +static int default_mmu(struct target_s *target, int *enabled) +{ + *enabled = 0; + return ERROR_OK; +} + +int target_init(struct command_context_s *cmd_ctx) +{ + target_t *target = targets; + + while (target) + { + if (target->type->init_target(cmd_ctx, target) != ERROR_OK) + { + ERROR("target '%s' init failed", target->type->name); + exit(-1); + } + + /* Set up default functions if none are provided by target */ + if (target->type->virt2phys == NULL) + { + target->type->virt2phys = default_virt2phys; + } + if (target->type->mmu == NULL) + { + target->type->mmu = default_mmu; + } + target = target->next; + } + + if (targets) + { + target_register_user_commands(cmd_ctx); + target_register_timer_callback(handle_target, 100, 1, NULL); + } + + return ERROR_OK; +} + +int target_init_reset(struct command_context_s *cmd_ctx) +{ + if (startup_mode == DAEMON_RESET) + target_process_reset(cmd_ctx); + + return ERROR_OK; +} + +int target_register_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **callbacks_p = &target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_event_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) +{ + target_timer_callback_t **callbacks_p = &target_timer_callbacks; + struct timeval now; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + if (*callbacks_p) + { + while ((*callbacks_p)->next) + callbacks_p = &((*callbacks_p)->next); + callbacks_p = &((*callbacks_p)->next); + } + + (*callbacks_p) = malloc(sizeof(target_timer_callback_t)); + (*callbacks_p)->callback = callback; + (*callbacks_p)->periodic = periodic; + (*callbacks_p)->time_ms = time_ms; + + gettimeofday(&now, NULL); + (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); + if ((*callbacks_p)->when.tv_usec > 1000000) + { + (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; + (*callbacks_p)->when.tv_sec += 1; + } + + (*callbacks_p)->priv = priv; + (*callbacks_p)->next = NULL; + + return ERROR_OK; +} + +int target_unregister_event_callback(int (*callback)(struct target_s *target, enum target_event event, void *priv), void *priv) +{ + target_event_callback_t **p = &target_event_callbacks; + target_event_callback_t *c = target_event_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_event_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + target_timer_callback_t **p = &target_timer_callbacks; + target_timer_callback_t *c = target_timer_callbacks; + + if (callback == NULL) + { + return ERROR_INVALID_ARGUMENTS; + } + + while (c) + { + target_timer_callback_t *next = c->next; + if ((c->callback == callback) && (c->priv == priv)) + { + *p = next; + free(c); + return ERROR_OK; + } + else + p = &(c->next); + c = next; + } + + return ERROR_OK; +} + +int target_call_event_callbacks(target_t *target, enum target_event event) +{ + target_event_callback_t *callback = target_event_callbacks; + target_event_callback_t *next_callback; + + DEBUG("target event %i", event); + + while (callback) + { + next_callback = callback->next; + callback->callback(target, event, callback->priv); + callback = next_callback; + } + + return ERROR_OK; +} + +int target_call_timer_callbacks() +{ + target_timer_callback_t *callback = target_timer_callbacks; + target_timer_callback_t *next_callback; + struct timeval now; + + gettimeofday(&now, NULL); + + while (callback) + { + next_callback = callback->next; + + if (((now.tv_sec >= callback->when.tv_sec) && (now.tv_usec >= callback->when.tv_usec)) + || (now.tv_sec > callback->when.tv_sec)) + { + callback->callback(callback->priv); + if (callback->periodic) + { + int time_ms = callback->time_ms; + callback->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; + time_ms -= (time_ms % 1000); + callback->when.tv_sec = now.tv_sec + time_ms / 1000; + if (callback->when.tv_usec > 1000000) + { + callback->when.tv_usec = callback->when.tv_usec - 1000000; + callback->when.tv_sec += 1; + } + } + else + target_unregister_timer_callback(callback->callback, callback->priv); + } + + callback = next_callback; + } + + return ERROR_OK; +} + +int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) +{ + working_area_t *c = target->working_areas; + working_area_t *new_wa = NULL; + + /* Reevaluate working area address based on MMU state*/ + if (target->working_areas == NULL) + { + int retval; + int enabled; + retval = target->type->mmu(target, &enabled); + if (retval != ERROR_OK) + { + return retval; + } + if (enabled) + { + target->working_area = target->working_area_virt; + } + else + { + target->working_area = target->working_area_phys; + } + } + + /* only allocate multiples of 4 byte */ + if (size % 4) + { + ERROR("BUG: code tried to allocate unaligned number of bytes, padding"); + size = CEIL(size, 4); + } + + /* see if there's already a matching working area */ + while (c) + { + if ((c->free) && (c->size == size)) + { + new_wa = c; + break; + } + c = c->next; + } + + /* if not, allocate a new one */ + if (!new_wa) + { + working_area_t **p = &target->working_areas; + u32 first_free = target->working_area; + u32 free_size = target->working_area_size; + + DEBUG("allocating new working area"); + + c = target->working_areas; + while (c) + { + first_free += c->size; + free_size -= c->size; + p = &c->next; + c = c->next; + } + + if (free_size < size) + { + WARNING("not enough working area available(requested %d, free %d)", size, free_size); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + new_wa = malloc(sizeof(working_area_t)); + new_wa->next = NULL; + new_wa->size = size; + new_wa->address = first_free; + + if (target->backup_working_area) + { + new_wa->backup = malloc(new_wa->size); + target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); + } + else + { + new_wa->backup = NULL; + } + + /* put new entry in list */ + *p = new_wa; + } + + /* mark as used, and return the new (reused) area */ + new_wa->free = 0; + *area = new_wa; + + /* user pointer */ + new_wa->user = area; + + return ERROR_OK; +} + +int target_free_working_area(struct target_s *target, working_area_t *area) +{ + if (area->free) + return ERROR_OK; + + if (target->backup_working_area) + target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); + + area->free = 1; + + /* mark user pointer invalid */ + *area->user = NULL; + area->user = NULL; + + return ERROR_OK; +} + +int target_free_all_working_areas(struct target_s *target) +{ + working_area_t *c = target->working_areas; + + while (c) + { + working_area_t *next = c->next; + target_free_working_area(target, c); + + if (c->backup) + free(c->backup); + + free(c); + + c = next; + } + + target->working_areas = NULL; + + return ERROR_OK; +} + +int target_register_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "target_script", handle_target_script_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "run_and_halt_time", handle_run_and_halt_time_command, COMMAND_CONFIG, NULL); + register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area
<'backup'|'nobackup'> [virtual address]"); + register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys "); + + return ERROR_OK; +} + +int target_arch_state(struct target_s *target) +{ + int retval; + if (target==NULL) + { + USER("No target has been configured"); + return ERROR_OK; + } + + USER("target state: %s", target_state_strings[target->state]); + + if (target->state!=TARGET_HALTED) + return ERROR_OK; + + retval=target->type->arch_state(target); + return retval; +} + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_write_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("writing buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->write_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + /* use bulk writes above a certain limit. This may have to be changed */ + if (aligned > 128) + { + if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + else + { + if ((retval = target->type->write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + } + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->write_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + + +/* Single aligned words are guaranteed to use 16 or 32 bit access + * mode respectively, otherwise data is handled as quickly as + * possible + */ +int target_read_buffer(struct target_s *target, u32 address, u32 size, u8 *buffer) +{ + int retval; + + DEBUG("reading buffer of %i byte at 0x%8.8x", size, address); + + if (((address % 2) == 0) && (size == 2)) + { + return target->type->read_memory(target, address, 2, 1, buffer); + } + + /* handle unaligned head bytes */ + if (address % 4) + { + int unaligned = 4 - (address % 4); + + if (unaligned > size) + unaligned = size; + + if ((retval = target->type->read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) + return retval; + + buffer += unaligned; + address += unaligned; + size -= unaligned; + } + + /* handle aligned words */ + if (size >= 4) + { + int aligned = size - (size % 4); + + if ((retval = target->type->read_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + return retval; + + buffer += aligned; + address += aligned; + size -= aligned; + } + + /* handle tail writes of less than 4 bytes */ + if (size > 0) + { + if ((retval = target->type->read_memory(target, address, 1, size, buffer)) != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* crc) +{ + u8 *buffer; + int retval; + int i; + u32 checksum = 0; + + if ((retval = target->type->checksum_memory(target, address, + size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + buffer = malloc(size); + if (buffer == NULL) + { + ERROR("error allocating buffer for section (%d bytes)", size); + return ERROR_INVALID_ARGUMENTS; + } + retval = target_read_buffer(target, address, size, buffer); + if (retval != ERROR_OK) + { + free(buffer); + return retval; + } + + /* convert to target endianess */ + for (i = 0; i < (size/sizeof(u32)); i++) + { + u32 target_data; + target_data = target_buffer_get_u32(target, &buffer[i*sizeof(u32)]); + target_buffer_set_u32(target, &buffer[i*sizeof(u32)], target_data); + } + + retval = image_calculate_checksum( buffer, size, &checksum ); + free(buffer); + } + + *crc = checksum; + + return retval; +} + +int target_read_u32(struct target_s *target, u32 address, u32 *value) +{ + u8 value_buf[4]; + + int retval = target->type->read_memory(target, address, 4, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u32(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u16(struct target_s *target, u32 address, u16 *value) +{ + u8 value_buf[2]; + + int retval = target->type->read_memory(target, address, 2, 1, value_buf); + + if (retval == ERROR_OK) + { + *value = target_buffer_get_u16(target, value_buf); + DEBUG("address: 0x%8.8x, value: 0x%4.4x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_read_u8(struct target_s *target, u32 address, u8 *value) +{ + int retval = target->type->read_memory(target, address, 1, 1, value); + + if (retval == ERROR_OK) + { + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, *value); + } + else + { + *value = 0x0; + DEBUG("address: 0x%8.8x failed", address); + } + + return retval; +} + +int target_write_u32(struct target_s *target, u32 address, u32 value) +{ + int retval; + u8 value_buf[4]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u32(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u16(struct target_s *target, u32 address, u16 value) +{ + int retval; + u8 value_buf[2]; + + DEBUG("address: 0x%8.8x, value: 0x%8.8x", address, value); + + target_buffer_set_u16(target, value_buf, value); + if ((retval = target->type->write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_write_u8(struct target_s *target, u32 address, u8 value) +{ + int retval; + + DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); + + if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) + { + DEBUG("failed: %i", retval); + } + + return retval; +} + +int target_register_user_commands(struct command_context_s *cmd_ctx) +{ + register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); + register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); + register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); + register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]"); + register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]"); + register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run|halt|init|run_and_halt|run_and_init]"); + register_command(cmd_ctx, NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset"); + + register_command(cmd_ctx, NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words [count]"); + register_command(cmd_ctx, NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words [count]"); + register_command(cmd_ctx, NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes [count]"); + + register_command(cmd_ctx, NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word "); + register_command(cmd_ctx, NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word "); + register_command(cmd_ctx, NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte "); + + register_command(cmd_ctx, NULL, "bp", handle_bp_command, COMMAND_EXEC, "set breakpoint
[hw]"); + register_command(cmd_ctx, NULL, "rbp", handle_rbp_command, COMMAND_EXEC, "remove breakpoint "); + register_command(cmd_ctx, NULL, "wp", handle_wp_command, COMMAND_EXEC, "set watchpoint
[value] [mask]"); + register_command(cmd_ctx, NULL, "rwp", handle_rwp_command, COMMAND_EXEC, "remove watchpoint "); + + register_command(cmd_ctx, NULL, "load_image", handle_load_image_command, COMMAND_EXEC, "load_image
['bin'|'ihex'|'elf'|'s19']"); + register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image
"); + register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image [offset] [type]"); + register_command(cmd_ctx, NULL, "load_binary", handle_load_image_command, COMMAND_EXEC, "[DEPRECATED] load_binary
"); + register_command(cmd_ctx, NULL, "dump_binary", handle_dump_image_command, COMMAND_EXEC, "[DEPRECATED] dump_binary
"); + + target_request_register_commands(cmd_ctx); + trace_register_commands(cmd_ctx); + + return ERROR_OK; +} + +int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = targets; + int count = 0; + + if (argc == 1) + { + int num = strtoul(args[0], NULL, 0); + + while (target) + { + count++; + target = target->next; + } + + if (num < count) + cmd_ctx->current_target = num; + else + command_print(cmd_ctx, "%i is out of bounds, only %i targets are configured", num, count); + + return ERROR_OK; + } + + while (target) + { + command_print(cmd_ctx, "%i: %s (%s), state: %s", count++, target->type->name, target_endianess_strings[target->endianness], target_state_strings[target->state]); + target = target->next; + } + + return ERROR_OK; +} + +int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int i; + int found = 0; + + if (argc < 3) + { + ERROR("target command requires at least three arguments: "); + exit(-1); + } + + /* search for the specified target */ + if (args[0] && (args[0][0] != 0)) + { + for (i = 0; target_types[i]; i++) + { + if (strcmp(args[0], target_types[i]->name) == 0) + { + target_t **last_target_p = &targets; + + /* register target specific commands */ + if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) + { + ERROR("couldn't register '%s' commands", args[0]); + exit(-1); + } + + if (*last_target_p) + { + while ((*last_target_p)->next) + last_target_p = &((*last_target_p)->next); + last_target_p = &((*last_target_p)->next); + } + + *last_target_p = malloc(sizeof(target_t)); + + (*last_target_p)->type = target_types[i]; + + if (strcmp(args[1], "big") == 0) + (*last_target_p)->endianness = TARGET_BIG_ENDIAN; + else if (strcmp(args[1], "little") == 0) + (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; + else + { + ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); + exit(-1); + } + + /* what to do on a target reset */ + if (strcmp(args[2], "reset_halt") == 0) + (*last_target_p)->reset_mode = RESET_HALT; + else if (strcmp(args[2], "reset_run") == 0) + (*last_target_p)->reset_mode = RESET_RUN; + else if (strcmp(args[2], "reset_init") == 0) + (*last_target_p)->reset_mode = RESET_INIT; + else if (strcmp(args[2], "run_and_halt") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_HALT; + else if (strcmp(args[2], "run_and_init") == 0) + (*last_target_p)->reset_mode = RESET_RUN_AND_INIT; + else + { + ERROR("unknown target startup mode %s", args[2]); + exit(-1); + } + (*last_target_p)->run_and_halt_time = 1000; /* default 1s */ + + (*last_target_p)->reset_script = NULL; + (*last_target_p)->post_halt_script = NULL; + (*last_target_p)->pre_resume_script = NULL; + (*last_target_p)->gdb_program_script = NULL; + + (*last_target_p)->working_area = 0x0; + (*last_target_p)->working_area_size = 0x0; + (*last_target_p)->working_areas = NULL; + (*last_target_p)->backup_working_area = 0; + + (*last_target_p)->state = TARGET_UNKNOWN; + (*last_target_p)->reg_cache = NULL; + (*last_target_p)->breakpoints = NULL; + (*last_target_p)->watchpoints = NULL; + (*last_target_p)->next = NULL; + (*last_target_p)->arch_info = NULL; + + /* initialize trace information */ + (*last_target_p)->trace_info = malloc(sizeof(trace_t)); + (*last_target_p)->trace_info->num_trace_points = 0; + (*last_target_p)->trace_info->trace_points_size = 0; + (*last_target_p)->trace_info->trace_points = NULL; + (*last_target_p)->trace_info->trace_history_size = 0; + (*last_target_p)->trace_info->trace_history = NULL; + (*last_target_p)->trace_info->trace_history_pos = 0; + (*last_target_p)->trace_info->trace_history_overflowed = 0; + + (*last_target_p)->dbgmsg = NULL; + (*last_target_p)->dbg_msg_enabled = 0; + + (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); + + found = 1; + break; + } + } + } + + /* no matching target found */ + if (!found) + { + ERROR("target '%s' not found", args[0]); + exit(-1); + } + + return ERROR_OK; +} + +/* usage: target_script */ +int handle_target_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 3) + { + ERROR("incomplete target_script command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + if (strcmp(args[1], "reset") == 0) + { + if (target->reset_script) + free(target->reset_script); + target->reset_script = strdup(args[2]); + } + else if (strcmp(args[1], "post_halt") == 0) + { + if (target->post_halt_script) + free(target->post_halt_script); + target->post_halt_script = strdup(args[2]); + } + else if (strcmp(args[1], "pre_resume") == 0) + { + if (target->pre_resume_script) + free(target->pre_resume_script); + target->pre_resume_script = strdup(args[2]); + } + else if (strcmp(args[1], "gdb_program_config") == 0) + { + if (target->gdb_program_script) + free(target->gdb_program_script); + target->gdb_program_script = strdup(args[2]); + } + else + { + ERROR("unknown event type: '%s", args[1]); + exit(-1); + } + + return ERROR_OK; +} + +int handle_run_and_halt_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if (argc < 2) + { + ERROR("incomplete run_and_halt_time command"); + exit(-1); + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + + target->run_and_halt_time = strtoul(args[1], NULL, 0); + + return ERROR_OK; +} + +int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + + if ((argc < 4) || (argc > 5)) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target = get_target_by_num(strtoul(args[0], NULL, 0)); + + if (!target) + { + ERROR("target number '%s' not defined", args[0]); + exit(-1); + } + target_free_all_working_areas(target); + + target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0); + if (argc == 5) + { + target->working_area_virt = strtoul(args[4], NULL, 0); + } + target->working_area_size = strtoul(args[2], NULL, 0); + + if (strcmp(args[3], "backup") == 0) + { + target->backup_working_area = 1; + } + else if (strcmp(args[3], "nobackup") == 0) + { + target->backup_working_area = 0; + } + else + { + ERROR("unrecognized argument (%s)", args[3]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + + +/* process target state changes */ +int handle_target(void *priv) +{ + int retval; + target_t *target = targets; + + while (target) + { + /* only poll if target isn't already halted */ + if (target->state != TARGET_HALTED) + { + if (target_continous_poll) + if ((retval = target->type->poll(target)) != ERROR_OK) + { + ERROR("couldn't poll target(%d). It's due for a reset.", retval); + } + } + + target = target->next; + } + + return ERROR_OK; +} + +int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + reg_t *reg = NULL; + int count = 0; + char *value; + + DEBUG("-"); + + target = get_current_target(cmd_ctx); + + /* list all available registers for the current target */ + if (argc == 0) + { + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + value = buf_to_str(cache->reg_list[i].value, cache->reg_list[i].size, 16); + command_print(cmd_ctx, "(%i) %s (/%i): 0x%s (dirty: %i, valid: %i)", count++, cache->reg_list[i].name, cache->reg_list[i].size, value, cache->reg_list[i].dirty, cache->reg_list[i].valid); + free(value); + } + cache = cache->next; + } + + return ERROR_OK; + } + + /* access a single register by its ordinal number */ + if ((args[0][0] >= '0') && (args[0][0] <= '9')) + { + int num = strtoul(args[0], NULL, 0); + reg_cache_t *cache = target->reg_cache; + + count = 0; + while(cache) + { + int i; + for (i = 0; i < cache->num_regs; i++) + { + if (count++ == num) + { + reg = &cache->reg_list[i]; + break; + } + } + if (reg) + break; + cache = cache->next; + } + + if (!reg) + { + command_print(cmd_ctx, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); + return ERROR_OK; + } + } else /* access a single register by its name */ + { + reg = register_get_by_name(target->reg_cache, args[0], 1); + + if (!reg) + { + command_print(cmd_ctx, "register %s not found in current target", args[0]); + return ERROR_OK; + } + } + + /* display a register */ + if ((argc == 1) || ((argc == 2) && !((args[1][0] >= '0') && (args[1][0] <= '9')))) + { + if ((argc == 2) && (strcmp(args[1], "force") == 0)) + reg->valid = 0; + + if (reg->valid == 0) + { + reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + arch_type->get(reg); + } + value = buf_to_str(reg->value, reg->size, 16); + command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); + free(value); + return ERROR_OK; + } + + /* set register value */ + if (argc == 2) + { + u8 *buf = malloc(CEIL(reg->size, 8)); + str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0); + + reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); + if (arch_type == NULL) + { + ERROR("BUG: encountered unregistered arch type"); + return ERROR_OK; + } + + arch_type->set(reg, buf); + + value = buf_to_str(reg->value, reg->size, 16); + command_print(cmd_ctx, "%s (/%i): 0x%s", reg->name, reg->size, value); + free(value); + + free(buf); + + return ERROR_OK; + } + + command_print(cmd_ctx, "usage: reg <#|name> [value]"); + + return ERROR_OK; +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms); + +int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + target->type->poll(target); + target_arch_state(target); + } + else + { + if (strcmp(args[0], "on") == 0) + { + target_continous_poll = 1; + } + else if (strcmp(args[0], "off") == 0) + { + target_continous_poll = 0; + } + else + { + command_print(cmd_ctx, "arg is \"on\" or \"off\""); + } + } + + + return ERROR_OK; +} + +int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int ms = 5000; + + if (argc > 0) + { + char *end; + + ms = strtoul(args[0], &end, 0) * 1000; + if (*end) + { + command_print(cmd_ctx, "usage: %s [seconds]", cmd); + return ERROR_OK; + } + } + + return wait_state(cmd_ctx, cmd, TARGET_HALTED, ms); +} + +static void target_process_events(struct command_context_s *cmd_ctx) +{ + target_t *target = get_current_target(cmd_ctx); + target->type->poll(target); + target_call_timer_callbacks(); +} + +static int wait_state(struct command_context_s *cmd_ctx, char *cmd, enum target_state state, int ms) +{ + int retval; + struct timeval timeout, now; + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 0, ms * 1000); + + target_t *target = get_current_target(cmd_ctx); + for (;;) + { + if ((retval=target->type->poll(target))!=ERROR_OK) + return retval; + target_call_timer_callbacks(); + if (target->state == state) + { + break; + } + command_print(cmd_ctx, "waiting for target %s...", target_state_strings[state]); + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) + { + command_print(cmd_ctx, "timed out while waiting for target %s", target_state_strings[state]); + ERROR("timed out while waiting for target %s", target_state_strings[state]); + break; + } + } + + return ERROR_OK; +} + +int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + command_print(cmd_ctx, "requesting target halt..."); + + if ((retval = target->type->halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_ALREADY_HALTED: + command_print(cmd_ctx, "target already halted"); + break; + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + return retval; + default: + command_print(cmd_ctx, "unknown error... shutting down"); + return retval; + } + } + + return handle_wait_halt_command(cmd_ctx, cmd, args, argc); +} + +/* what to do on daemon startup */ +int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + if (argc == 1) + { + if (strcmp(args[0], "attach") == 0) + { + startup_mode = DAEMON_ATTACH; + return ERROR_OK; + } + else if (strcmp(args[0], "reset") == 0) + { + startup_mode = DAEMON_RESET; + return ERROR_OK; + } + } + + WARNING("invalid daemon_startup configuration directive: %s", args[0]); + return ERROR_OK; + +} + +int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + command_print(cmd_ctx, "requesting target halt and executing a soft reset"); + + if ((retval = target->type->soft_reset_halt(target)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_TIMEOUT: + command_print(cmd_ctx, "target timed out... shutting down"); + exit(-1); + default: + command_print(cmd_ctx, "unknown error... shutting down"); + exit(-1); + } + } + + return ERROR_OK; +} + +int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + enum target_reset_mode reset_mode = target->reset_mode; + enum target_reset_mode save = target->reset_mode; + + DEBUG("-"); + + if (argc >= 1) + { + if (strcmp("run", args[0]) == 0) + reset_mode = RESET_RUN; + else if (strcmp("halt", args[0]) == 0) + reset_mode = RESET_HALT; + else if (strcmp("init", args[0]) == 0) + reset_mode = RESET_INIT; + else if (strcmp("run_and_halt", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_HALT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else if (strcmp("run_and_init", args[0]) == 0) + { + reset_mode = RESET_RUN_AND_INIT; + if (argc >= 2) + { + target->run_and_halt_time = strtoul(args[1], NULL, 0); + } + } + else + { + command_print(cmd_ctx, "usage: reset ['run', 'halt', 'init', 'run_and_halt', 'run_and_init]"); + return ERROR_OK; + } + } + + /* temporarily modify mode of current reset target */ + target->reset_mode = reset_mode; + + /* reset *all* targets */ + target_process_reset(cmd_ctx); + + /* Restore default reset mode for this target */ + target->reset_mode = save; + + return ERROR_OK; +} + +int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + retval = target->type->resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ + else if (argc == 1) + retval = target->type->resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + target_process_events(cmd_ctx); + + target_arch_state(target); + + return retval; +} + +int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + DEBUG("-"); + + if (argc == 0) + target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */ + + if (argc == 1) + target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */ + + return ERROR_OK; +} + +int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + const int line_bytecnt = 32; + int count = 1; + int size = 4; + u32 address = 0; + int line_modulo; + int i; + + char output[128]; + int output_len; + + int retval; + + u8 *buffer; + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + return ERROR_OK; + + if (argc == 2) + count = strtoul(args[1], NULL, 0); + + address = strtoul(args[0], NULL, 0); + + + switch (cmd[2]) + { + case 'w': + size = 4; line_modulo = line_bytecnt / 4; + break; + case 'h': + size = 2; line_modulo = line_bytecnt / 2; + break; + case 'b': + size = 1; line_modulo = line_bytecnt / 1; + break; + default: + return ERROR_OK; + } + + buffer = calloc(count, size); + retval = target->type->read_memory(target, address, size, count, buffer); + if (retval != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_UNALIGNED_ACCESS: + command_print(cmd_ctx, "error: address not aligned"); + break; + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "error: target must be halted for memory accesses"); + break; + case ERROR_TARGET_DATA_ABORT: + command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); + break; + default: + command_print(cmd_ctx, "error: unknown error"); + break; + } + return ERROR_OK; + } + + output_len = 0; + + for (i = 0; i < count; i++) + { + if (i%line_modulo == 0) + output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size)); + + switch (size) + { + case 4: + output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", target_buffer_get_u32(target, &buffer[i*4])); + break; + case 2: + output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2])); + break; + case 1: + output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]); + break; + } + + if ((i%line_modulo == line_modulo-1) || (i == count - 1)) + { + command_print(cmd_ctx, output); + output_len = 0; + } + } + + free(buffer); + + return ERROR_OK; +} + +int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u32 address = 0; + u32 value = 0; + int retval; + target_t *target = get_current_target(cmd_ctx); + u8 value_buf[4]; + + if (argc < 2) + return ERROR_OK; + + address = strtoul(args[0], NULL, 0); + value = strtoul(args[1], NULL, 0); + + switch (cmd[2]) + { + case 'w': + target_buffer_set_u32(target, value_buf, value); + retval = target->type->write_memory(target, address, 4, 1, value_buf); + break; + case 'h': + target_buffer_set_u16(target, value_buf, value); + retval = target->type->write_memory(target, address, 2, 1, value_buf); + break; + case 'b': + value_buf[0] = value; + retval = target->type->write_memory(target, address, 1, 1, value_buf); + break; + default: + return ERROR_OK; + } + + switch (retval) + { + case ERROR_TARGET_UNALIGNED_ACCESS: + command_print(cmd_ctx, "error: address not aligned"); + break; + case ERROR_TARGET_DATA_ABORT: + command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted"); + break; + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "error: target must be halted for memory accesses"); + break; + case ERROR_OK: + break; + default: + command_print(cmd_ctx, "error: unknown error"); + break; + } + + return ERROR_OK; + +} + +int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: load_image [address] [type]"); + return ERROR_OK; + } + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + } + + image.start_address_set = 0; + + duration_start_measure(&duration); + + if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "load_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, download aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); + image_size += buf_cnt; + command_print(cmd_ctx, "%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address); + + free(buffer); + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; + +} + +int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + fileio_t fileio; + + u32 address; + u32 size; + u8 buffer[560]; + int retval; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc != 3) + { + command_print(cmd_ctx, "usage: dump_image
"); + return ERROR_OK; + } + + address = strtoul(args[1], NULL, 0); + size = strtoul(args[2], NULL, 0); + + if ((address & 3) || (size & 3)) + { + command_print(cmd_ctx, "only 32-bit aligned address and size are supported"); + return ERROR_OK; + } + + if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "dump_image error: %s", fileio.error_str); + return ERROR_OK; + } + + duration_start_measure(&duration); + + while (size > 0) + { + u32 size_written; + u32 this_run_size = (size > 560) ? 560 : size; + + retval = target->type->read_memory(target, address, 4, this_run_size / 4, buffer); + if (retval != ERROR_OK) + { + command_print(cmd_ctx, "Reading memory failed %d", retval); + break; + } + + fileio_write(&fileio, this_run_size, buffer, &size_written); + + size -= this_run_size; + address += this_run_size; + } + + fileio_close(&fileio); + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); + free(duration_text); + + return ERROR_OK; +} + +int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + u8 *buffer; + u32 buf_cnt; + u32 image_size; + int i; + int retval; + u32 checksum = 0; + u32 mem_checksum = 0; + + image_t image; + + duration_t duration; + char *duration_text; + + target_t *target = get_current_target(cmd_ctx); + + if (argc < 1) + { + command_print(cmd_ctx, "usage: verify_image [offset] [type]"); + return ERROR_OK; + } + + if (!target) + { + ERROR("no target selected"); + return ERROR_OK; + } + + duration_start_measure(&duration); + + if (argc >= 2) + { + image.base_address_set = 1; + image.base_address = strtoul(args[1], NULL, 0); + } + else + { + image.base_address_set = 0; + image.base_address = 0x0; + } + + image.start_address_set = 0; + + if (image_open(&image, args[0], (argc == 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "verify_image error: %s", image.error_str); + return ERROR_OK; + } + + image_size = 0x0; + for (i = 0; i < image.num_sections; i++) + { + buffer = malloc(image.sections[i].size); + if (buffer == NULL) + { + command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size); + break; + } + if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("image_read_section failed with error code: %i", retval); + command_print(cmd_ctx, "image reading failed, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + /* calculate checksum of image */ + image_calculate_checksum( buffer, buf_cnt, &checksum ); + + retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); + + if( retval != ERROR_OK ) + { + command_print(cmd_ctx, "could not calculate checksum, verify aborted"); + free(buffer); + image_close(&image); + return ERROR_OK; + } + + if( checksum != mem_checksum ) + { + /* failed crc checksum, fall back to a binary compare */ + u8 *data; + + command_print(cmd_ctx, "checksum mismatch - attempting binary compare"); + + data = (u8*)malloc(buf_cnt); + + /* Can we use 32bit word accesses? */ + int size = 1; + int count = buf_cnt; + if ((count % 4) == 0) + { + size *= 4; + count /= 4; + } + retval = target->type->read_memory(target, image.sections[i].base_address, size, count, data); + + if (retval == ERROR_OK) + { + int t; + for (t = 0; t < buf_cnt; t++) + { + if (data[t] != buffer[t]) + { + command_print(cmd_ctx, "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n", t + image.sections[i].base_address, data[t], buffer[t]); + free(data); + free(buffer); + image_close(&image); + return ERROR_OK; + } + } + } + + free(data); + } + + free(buffer); + image_size += buf_cnt; + } + + duration_stop_measure(&duration, &duration_text); + command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); + free(duration_text); + + image_close(&image); + + return ERROR_OK; +} + +int handle_bp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + + if (argc == 0) + { + breakpoint_t *breakpoint = target->breakpoints; + + while (breakpoint) + { + if (breakpoint->type == BKPT_SOFT) + { + char* buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); + command_print(cmd_ctx, "0x%8.8x, 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); + free(buf); + } + else + { + command_print(cmd_ctx, "0x%8.8x, 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); + } + breakpoint = breakpoint->next; + } + } + else if (argc >= 2) + { + int hw = BKPT_SOFT; + u32 length = 0; + + length = strtoul(args[1], NULL, 0); + + if (argc >= 3) + if (strcmp(args[2], "hw") == 0) + hw = BKPT_HARD; + + if ((retval = breakpoint_add(target, strtoul(args[0], NULL, 0), length, hw)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set breakpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more breakpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, breakpoint not set"); + break; + } + } + else + { + command_print(cmd_ctx, "breakpoint added at address 0x%8.8x", strtoul(args[0], NULL, 0)); + } + } + else + { + command_print(cmd_ctx, "usage: bp
['hw']"); + } + + return ERROR_OK; +} + +int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + breakpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + int retval; + + if (argc == 0) + { + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + command_print(cmd_ctx, "address: 0x%8.8x, mask: 0x%8.8x, r/w/a: %i, value: 0x%8.8x, mask: 0x%8.8x", watchpoint->address, watchpoint->length, watchpoint->rw, watchpoint->value, watchpoint->mask); + watchpoint = watchpoint->next; + } + } + else if (argc >= 2) + { + enum watchpoint_rw type = WPT_ACCESS; + u32 data_value = 0x0; + u32 data_mask = 0xffffffff; + + if (argc >= 3) + { + switch(args[2][0]) + { + case 'r': + type = WPT_READ; + break; + case 'w': + type = WPT_WRITE; + break; + case 'a': + type = WPT_ACCESS; + break; + default: + command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); + return ERROR_OK; + } + } + if (argc >= 4) + { + data_value = strtoul(args[3], NULL, 0); + } + if (argc >= 5) + { + data_mask = strtoul(args[4], NULL, 0); + } + + if ((retval = watchpoint_add(target, strtoul(args[0], NULL, 0), + strtoul(args[1], NULL, 0), type, data_value, data_mask)) != ERROR_OK) + { + switch (retval) + { + case ERROR_TARGET_NOT_HALTED: + command_print(cmd_ctx, "target must be halted to set watchpoints"); + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + command_print(cmd_ctx, "no more watchpoints available"); + break; + default: + command_print(cmd_ctx, "unknown error, watchpoint not set"); + break; + } + } + } + else + { + command_print(cmd_ctx, "usage: wp
[r/w/a] [value] [mask]"); + } + + return ERROR_OK; +} + +int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + + if (argc > 0) + watchpoint_remove(target, strtoul(args[0], NULL, 0)); + + return ERROR_OK; +} + +int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + int retval; + target_t *target = get_current_target(cmd_ctx); + u32 va; + u32 pa; + + if (argc != 1) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + va = strtoul(args[0], NULL, 0); + + retval = target->type->virt2phys(target, va, &pa); + if (retval == ERROR_OK) + { + command_print(cmd_ctx, "Physical address 0x%08x", pa); + } + else + { + /* lower levels will have logged a detailed error which is + * forwarded to telnet/GDB session. + */ + } + return retval; +} diff --git a/src/target/xscale.c b/src/target/xscale.c index bfa0f9f9..11ae5eed 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1,3799 +1,3799 @@ -/*************************************************************************** - * Copyright (C) 2006, 2007 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "replacements.h" - -#include "xscale.h" - -#include "register.h" -#include "target.h" -#include "armv4_5.h" -#include "arm_simulator.h" -#include "arm_disassembler.h" -#include "log.h" -#include "jtag.h" -#include "binarybuffer.h" -#include "time_support.h" -#include "breakpoints.h" -#include "fileio.h" - -#include -#include - -#include -#include -#include - - -/* cli handling */ -int xscale_register_commands(struct command_context_s *cmd_ctx); - -/* forward declarations */ -int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); -int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target); -int xscale_quit(); - -int xscale_arch_state(struct target_s *target); -int xscale_poll(target_t *target); -int xscale_halt(target_t *target); -int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); -int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints); -int xscale_debug_entry(target_t *target); -int xscale_restore_context(target_t *target); - -int xscale_assert_reset(target_t *target); -int xscale_deassert_reset(target_t *target); -int xscale_soft_reset_halt(struct target_s *target); -int xscale_prepare_reset_halt(struct target_s *target); - -int xscale_set_reg_u32(reg_t *reg, u32 value); - -int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode); -int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value); - -int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); -int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer); -int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); - -int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); -int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); -void xscale_enable_watchpoints(struct target_s *target); -void xscale_enable_breakpoints(struct target_s *target); -static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical); -static int xscale_mmu(struct target_s *target, int *enabled); - -int xscale_read_trace(target_t *target); - -target_type_t xscale_target = -{ - .name = "xscale", - - .poll = xscale_poll, - .arch_state = xscale_arch_state, - - .target_request_data = NULL, - - .halt = xscale_halt, - .resume = xscale_resume, - .step = xscale_step, - - .assert_reset = xscale_assert_reset, - .deassert_reset = xscale_deassert_reset, - .soft_reset_halt = xscale_soft_reset_halt, - .prepare_reset_halt = xscale_prepare_reset_halt, - - .get_gdb_reg_list = armv4_5_get_gdb_reg_list, - - .read_memory = xscale_read_memory, - .write_memory = xscale_write_memory, - .bulk_write_memory = xscale_bulk_write_memory, - .checksum_memory = xscale_checksum_memory, - - .run_algorithm = armv4_5_run_algorithm, - - .add_breakpoint = xscale_add_breakpoint, - .remove_breakpoint = xscale_remove_breakpoint, - .add_watchpoint = xscale_add_watchpoint, - .remove_watchpoint = xscale_remove_watchpoint, - - .register_commands = xscale_register_commands, - .target_command = xscale_target_command, - .init_target = xscale_init_target, - .quit = xscale_quit, - - .virt2phys = xscale_virt2phys, - .mmu = xscale_mmu -}; - -char* xscale_reg_list[] = -{ - "XSCALE_MAINID", /* 0 */ - "XSCALE_CACHETYPE", - "XSCALE_CTRL", - "XSCALE_AUXCTRL", - "XSCALE_TTB", - "XSCALE_DAC", - "XSCALE_FSR", - "XSCALE_FAR", - "XSCALE_PID", - "XSCALE_CPACCESS", - "XSCALE_IBCR0", /* 10 */ - "XSCALE_IBCR1", - "XSCALE_DBR0", - "XSCALE_DBR1", - "XSCALE_DBCON", - "XSCALE_TBREG", - "XSCALE_CHKPT0", - "XSCALE_CHKPT1", - "XSCALE_DCSR", - "XSCALE_TX", - "XSCALE_RX", /* 20 */ - "XSCALE_TXRXCTRL", -}; - -xscale_reg_t xscale_reg_arch_info[] = -{ - {XSCALE_MAINID, NULL}, - {XSCALE_CACHETYPE, NULL}, - {XSCALE_CTRL, NULL}, - {XSCALE_AUXCTRL, NULL}, - {XSCALE_TTB, NULL}, - {XSCALE_DAC, NULL}, - {XSCALE_FSR, NULL}, - {XSCALE_FAR, NULL}, - {XSCALE_PID, NULL}, - {XSCALE_CPACCESS, NULL}, - {XSCALE_IBCR0, NULL}, - {XSCALE_IBCR1, NULL}, - {XSCALE_DBR0, NULL}, - {XSCALE_DBR1, NULL}, - {XSCALE_DBCON, NULL}, - {XSCALE_TBREG, NULL}, - {XSCALE_CHKPT0, NULL}, - {XSCALE_CHKPT1, NULL}, - {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ - {-1, NULL}, /* TX accessed via JTAG */ - {-1, NULL}, /* RX accessed via JTAG */ - {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ -}; - -int xscale_reg_arch_type = -1; - -int xscale_get_reg(reg_t *reg); -int xscale_set_reg(reg_t *reg, u8 *buf); - -int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("target isn't an XScale target"); - return -1; - } - - if (xscale->common_magic != XSCALE_COMMON_MAGIC) - { - ERROR("target isn't an XScale target"); - return -1; - } - - *armv4_5_p = armv4_5; - *xscale_p = xscale; - - return ERROR_OK; -} - -int xscale_jtag_set_instr(int chain_pos, u32 new_instr) -{ - jtag_device_t *device = jtag_get_device(chain_pos); - - if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) - { - scan_field_t field; - - field.device = chain_pos; - field.num_bits = device->ir_length; - field.out_value = calloc(CEIL(field.num_bits, 8), 1); - buf_set_u32(field.out_value, 0, field.num_bits, new_instr); - field.out_mask = NULL; - field.in_value = NULL; - jtag_set_check_value(&field, device->expected, device->expected_mask, NULL); - - jtag_add_ir_scan(1, &field, -1, NULL); - - free(field.out_value); - } - - return ERROR_OK; -} - -int xscale_jtag_callback(enum jtag_event event, void *priv) -{ - switch (event) - { - case JTAG_TRST_ASSERTED: - break; - case JTAG_TRST_RELEASED: - break; - case JTAG_SRST_ASSERTED: - break; - case JTAG_SRST_RELEASED: - break; - default: - WARNING("unhandled JTAG event"); - } - - return ERROR_OK; -} - -int xscale_read_dcsr(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - scan_field_t fields[3]; - u8 field0 = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x7; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_PD); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - buf_set_u32(&field0, 1, 1, xscale->hold_rst); - buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1, NULL); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while reading DCSR"); - return retval; - } - - xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; - xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; - - /* write the register with the value we just read - * on this second pass, only the first bit of field0 is guaranteed to be 0) - */ - field0_check_mask = 0x1; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - fields[1].in_value = NULL; - - jtag_add_end_state(TAP_RTI); - - jtag_add_dr_scan(3, fields, -1, NULL); - - return ERROR_OK; -} - -int xscale_receive(target_t *target, u32 *buffer, int num_words) -{ - int retval = ERROR_OK; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - enum tap_state path[3]; - scan_field_t fields[3]; - - u8 *field0 = malloc(num_words * 1); - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u32 *field1 = malloc(num_words * 4); - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - int words_done = 0; - int words_scheduled = 0; - - int i; - - path[0] = TAP_SDS; - path[1] = TAP_CD; - path[2] = TAP_SD; - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - /* fields[0].in_value = field0; */ - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); - jtag_add_runtest(1, -1); - - /* repeat until all words have been collected */ - int attempts = 0; - while (words_done < num_words) - { - /* schedule reads */ - words_scheduled = 0; - for (i = words_done; i < num_words; i++) - { - fields[0].in_value = &field0[i]; - fields[1].in_handler = buf_to_u32_handler; - fields[1].in_handler_priv = (u8*)&field1[i]; - - jtag_add_pathmove(3, path); - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - words_scheduled++; - } - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while receiving data from debug handler"); - break; - } - - /* examine results */ - for (i = words_done; i < num_words; i++) - { - if (!(field0[0] & 1)) - { - /* move backwards if necessary */ - int j; - for (j = i; j < num_words - 1; j++) - { - field0[j] = field0[j+1]; - field1[j] = field1[j+1]; - } - words_scheduled--; - } - } - if (words_scheduled == 0) - { - if (attempts++ == 1000) - { - ERROR("Failed to receiving data from debug handler after 1000 attempts"); - retval = ERROR_JTAG_QUEUE_FAILED; - break; - } - } - - words_done += words_scheduled; - } - - for (i = 0; i < num_words; i++) - *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32); - - free(field1); - - return retval; -} - -int xscale_read_tx(target_t *target, int consume) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - enum tap_state path[3]; - enum tap_state noconsume_path[9]; - - int retval; - struct timeval timeout, now; - - scan_field_t fields[3]; - u8 field0_in = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); - - path[0] = TAP_SDS; - path[1] = TAP_CD; - path[2] = TAP_SD; - - noconsume_path[0] = TAP_SDS; - noconsume_path[1] = TAP_CD; - noconsume_path[2] = TAP_E1D; - noconsume_path[3] = TAP_PD; - noconsume_path[4] = TAP_E2D; - noconsume_path[5] = TAP_UD; - noconsume_path[6] = TAP_SDS; - noconsume_path[7] = TAP_CD; - noconsume_path[8] = TAP_SD; - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = NULL; - fields[0].out_mask = NULL; - fields[0].in_value = &field0_in; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = NULL; - fields[1].out_mask = NULL; - fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = NULL; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - - do - { - /* if we want to consume the register content (i.e. clear TX_READY), - * we have to go straight from Capture-DR to Shift-DR - * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR - */ - if (consume) - jtag_add_pathmove(3, path); - else - jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path); - - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while reading TX"); - return ERROR_TARGET_TIMEOUT; - } - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) - { - ERROR("time out reading TX register"); - return ERROR_TARGET_TIMEOUT; - } - } while ((!(field0_in & 1)) && consume); - - if (!(field0_in & 1)) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - - return ERROR_OK; -} - -int xscale_write_rx(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - struct timeval timeout, now; - - scan_field_t fields[3]; - u8 field0_out = 0x0; - u8 field0_in = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0_out; - fields[0].out_mask = NULL; - fields[0].in_value = &field0_in; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, 5, 0); - - /* poll until rx_read is low */ - DEBUG("polling RX"); - do - { - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing RX"); - return retval; - } - - gettimeofday(&now, NULL); - if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) - { - ERROR("time out writing RX register"); - return ERROR_TARGET_TIMEOUT; - } - } while (field0_in & 1); - - /* set rx_valid */ - field2 = 0x1; - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing RX"); - return retval; - } - - return ERROR_OK; -} - -/* send count elements of size byte to the debug handler */ -int xscale_send(target_t *target, u8 *buffer, int count, int size) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - int done_count = 0; - u8 output[4] = {0, 0, 0, 0}; - - scan_field_t fields[3]; - u8 field0_out = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x6; - u8 field2 = 0x1; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - jtag_add_end_state(TAP_RTI); - - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0_out; - fields[0].out_mask = NULL; - fields[0].in_handler = NULL; - if (!xscale->fast_memory_access) - { - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - } - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = output; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - fields[2].in_handler = NULL; - if (!xscale->fast_memory_access) - { - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - } - - if (size==4) - { - int endianness = target->endianness; - while (done_count++ < count) - { - if (endianness == TARGET_LITTLE_ENDIAN) - { - output[0]=buffer[0]; - output[1]=buffer[1]; - output[2]=buffer[2]; - output[3]=buffer[3]; - } else - { - output[0]=buffer[3]; - output[1]=buffer[2]; - output[2]=buffer[1]; - output[3]=buffer[0]; - } - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - buffer += size; - } - - } else - { - while (done_count++ < count) - { - /* extract sized element from target-endian buffer, and put it - * into little-endian output buffer - */ - switch (size) - { - case 2: - buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer)); - break; - case 1: - output[0] = *buffer; - break; - default: - ERROR("BUG: size neither 4, 2 nor 1"); - exit(-1); - } - - jtag_add_dr_scan(3, fields, TAP_RTI, NULL); - buffer += size; - } - - } - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while sending data to debug handler"); - return retval; - } - - return ERROR_OK; -} - -int xscale_send_u32(target_t *target, u32 value) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); - return xscale_write_rx(target); -} - -int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - int retval; - - scan_field_t fields[3]; - u8 field0 = 0x0; - u8 field0_check_value = 0x2; - u8 field0_check_mask = 0x7; - u8 field2 = 0x0; - u8 field2_check_value = 0x0; - u8 field2_check_mask = 0x1; - - if (hold_rst != -1) - xscale->hold_rst = hold_rst; - - if (ext_dbg_brk != -1) - xscale->external_debug_break = ext_dbg_brk; - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - buf_set_u32(&field0, 1, 1, xscale->hold_rst); - buf_set_u32(&field0, 2, 1, xscale->external_debug_break); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 3; - fields[0].out_value = &field0; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 32; - fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - - - - fields[2].device = xscale->jtag_info.chain_pos; - fields[2].num_bits = 1; - fields[2].out_value = &field2; - fields[2].out_mask = NULL; - fields[2].in_value = NULL; - jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); - - jtag_add_dr_scan(3, fields, -1, NULL); - - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - ERROR("JTAG error while writing DCSR"); - return retval; - } - - xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; - xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; - - return ERROR_OK; -} - -/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ -unsigned int parity (unsigned int v) -{ - unsigned int ov = v; - v ^= v >> 16; - v ^= v >> 8; - v ^= v >> 4; - v &= 0xf; - DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); - return (0x6996 >> v) & 1; -} - -int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8]) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 packet[4]; - u8 cmd; - int word; - - scan_field_t fields[2]; - - DEBUG("loading miniIC at 0x%8.8x", va); - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ - - /* CMD is b010 for Main IC and b011 for Mini IC */ - if (mini) - buf_set_u32(&cmd, 0, 3, 0x3); - else - buf_set_u32(&cmd, 0, 3, 0x2); - - buf_set_u32(&cmd, 3, 3, 0x0); - - /* virtual address of desired cache line */ - buf_set_u32(packet, 0, 27, va >> 5); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 6; - fields[0].out_value = &cmd; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 27; - fields[1].out_value = packet; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - fields[0].num_bits = 32; - fields[0].out_value = packet; - - fields[1].num_bits = 1; - fields[1].out_value = &cmd; - - for (word = 0; word < 8; word++) - { - buf_set_u32(packet, 0, 32, buffer[word]); - cmd = parity(*((u32*)packet)); - jtag_add_dr_scan(2, fields, -1, NULL); - } - - jtag_execute_queue(); - - return ERROR_OK; -} - -int xscale_invalidate_ic_line(target_t *target, u32 va) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 packet[4]; - u8 cmd; - - scan_field_t fields[2]; - - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ - - /* CMD for invalidate IC line b000, bits [6:4] b000 */ - buf_set_u32(&cmd, 0, 6, 0x0); - - /* virtual address of desired cache line */ - buf_set_u32(packet, 0, 27, va >> 5); - - fields[0].device = xscale->jtag_info.chain_pos; - fields[0].num_bits = 6; - fields[0].out_value = &cmd; - fields[0].out_mask = NULL; - fields[0].in_value = NULL; - fields[0].in_check_value = NULL; - fields[0].in_check_mask = NULL; - fields[0].in_handler = NULL; - fields[0].in_handler_priv = NULL; - - fields[1].device = xscale->jtag_info.chain_pos; - fields[1].num_bits = 27; - fields[1].out_value = packet; - fields[1].out_mask = NULL; - fields[1].in_value = NULL; - fields[1].in_check_value = NULL; - fields[1].in_check_mask = NULL; - fields[1].in_handler = NULL; - fields[1].in_handler_priv = NULL; - - jtag_add_dr_scan(2, fields, -1, NULL); - - return ERROR_OK; -} - -int xscale_update_vectors(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int i; - - u32 low_reset_branch, high_reset_branch; - - for (i = 1; i < 8; i++) - { - /* if there's a static vector specified for this exception, override */ - if (xscale->static_high_vectors_set & (1 << i)) - { - xscale->high_vectors[i] = xscale->static_high_vectors[i]; - } - else - { - if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK) - { - xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - } - } - - for (i = 1; i < 8; i++) - { - if (xscale->static_low_vectors_set & (1 << i)) - { - xscale->low_vectors[i] = xscale->static_low_vectors[i]; - } - else - { - if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK) - { - xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - } - } - - /* calculate branches to debug handler */ - low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; - high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; - - xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); - xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); - - /* invalidate and load exception vectors in mini i-cache */ - xscale_invalidate_ic_line(target, 0x0); - xscale_invalidate_ic_line(target, 0xffff0000); - - xscale_load_ic(target, 1, 0x0, xscale->low_vectors); - xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); - - return ERROR_OK; -} - -int xscale_arch_state(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - char *state[] = - { - "disabled", "enabled" - }; - - char *arch_dbg_reason[] = - { - "", "\n(processor reset)", "\n(trace buffer full)" - }; - - if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) - { - ERROR("BUG: called for a non-ARMv4/5 target"); - exit(-1); - } - - USER("target halted in %s state due to %s, current mode: %s\n" - "cpsr: 0x%8.8x pc: 0x%8.8x\n" - "MMU: %s, D-Cache: %s, I-Cache: %s" - "%s", - armv4_5_state_strings[armv4_5->core_state], - target_debug_reason_strings[target->debug_reason], - armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], - buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), - buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), - state[xscale->armv4_5_mmu.mmu_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], - arch_dbg_reason[xscale->arch_debug_reason]); - - return ERROR_OK; -} - -int xscale_poll(target_t *target) -{ - int retval=ERROR_OK; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) - { - enum target_state previous_state = target->state; - if ((retval = xscale_read_tx(target, 0)) == ERROR_OK) - { - - /* there's data to read from the tx register, we entered debug state */ - xscale->handler_running = 1; - - target->state = TARGET_HALTED; - - /* process debug entry, fetching current mode regs */ - retval = xscale_debug_entry(target); - } - else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - USER("error while polling TX register, reset CPU"); - /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ - target->state = TARGET_HALTED; - } - - /* debug_entry could have overwritten target state (i.e. immediate resume) - * don't signal event handlers in that case - */ - if (target->state != TARGET_HALTED) - return ERROR_OK; - - /* if target was running, signal that we halted - * otherwise we reentered from debug execution */ - if (previous_state == TARGET_RUNNING) - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - else - target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); - } - return retval; -} - -int xscale_debug_entry(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 pc; - u32 buffer[10]; - int i; - - u32 moe; - - /* clear external dbg break (will be written on next DCSR read) */ - xscale->external_debug_break = 0; - xscale_read_dcsr(target); - - /* get r0, pc, r1 to r7 and cpsr */ - xscale_receive(target, buffer, 10); - - /* move r0 from buffer to register cache */ - buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - DEBUG("r0: 0x%8.8x", buffer[0]); - - /* move pc from buffer to register cache */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]); - armv4_5->core_cache->reg_list[15].dirty = 1; - armv4_5->core_cache->reg_list[15].valid = 1; - DEBUG("pc: 0x%8.8x", buffer[1]); - - /* move data from buffer to register cache */ - for (i = 1; i <= 7; i++) - { - buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); - armv4_5->core_cache->reg_list[i].dirty = 1; - armv4_5->core_cache->reg_list[i].valid = 1; - DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]); - } - - buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]); - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; - armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; - DEBUG("cpsr: 0x%8.8x", buffer[9]); - - armv4_5->core_mode = buffer[9] & 0x1f; - if (armv4_5_mode_to_number(armv4_5->core_mode) == -1) - { - target->state = TARGET_UNKNOWN; - ERROR("cpsr contains invalid mode value - communication failure"); - return ERROR_TARGET_FAILURE; - } - DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]); - - if (buffer[9] & 0x20) - armv4_5->core_state = ARMV4_5_STATE_THUMB; - else - armv4_5->core_state = ARMV4_5_STATE_ARM; - - /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS)) - { - xscale_receive(target, buffer, 8); - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1; - } - else - { - /* r8 to r14, but no spsr */ - xscale_receive(target, buffer, 7); - } - - /* move data from buffer to register cache */ - for (i = 8; i <= 14; i++) - { - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1; - } - - /* examine debug reason */ - xscale_read_dcsr(target); - moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); - - /* stored PC (for calculating fixup) */ - pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - switch (moe) - { - case 0x0: /* Processor reset */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; - pc -= 4; - break; - case 0x1: /* Instruction breakpoint hit */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x2: /* Data breakpoint hit */ - target->debug_reason = DBG_REASON_WATCHPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x3: /* BKPT instruction executed */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x4: /* Ext. debug event */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x5: /* Vector trap occured */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x6: /* Trace buffer full break */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; - pc -= 4; - break; - case 0x7: /* Reserved */ - default: - ERROR("Method of Entry is 'Reserved'"); - exit(-1); - break; - } - - /* apply PC fixup */ - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); - - /* on the first debug entry, identify cache type */ - if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) - { - u32 cache_type_reg; - - /* read cp15 cache type register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); - cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); - - armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); - } - - /* examine MMU and Cache settings */ - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; - - /* tracing enabled, read collected trace data */ - if (xscale->trace.buffer_enabled) - { - xscale_read_trace(target); - xscale->trace.buffer_fill--; - - /* resume if we're still collecting trace data */ - if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) - && (xscale->trace.buffer_fill > 0)) - { - xscale_resume(target, 1, 0x0, 1, 0); - } - else - { - xscale->trace.buffer_enabled = 0; - } - } - - return ERROR_OK; -} - -int xscale_halt(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - if (target->state == TARGET_HALTED) - { - WARNING("target was already halted"); - return ERROR_TARGET_ALREADY_HALTED; - } - else if (target->state == TARGET_UNKNOWN) - { - /* this must not happen for a xscale target */ - ERROR("target was in unknown state when halt was requested"); - return ERROR_TARGET_INVALID; - } - else if (target->state == TARGET_RESET) - { - DEBUG("target->state == TARGET_RESET"); - } - else - { - /* assert external dbg break */ - xscale->external_debug_break = 1; - xscale_read_dcsr(target); - - target->debug_reason = DBG_REASON_DBGRQ; - } - - return ERROR_OK; -} - -int xscale_enable_single_step(struct target_s *target, u32 next_pc) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; - - if (xscale->ibcr0_used) - { - breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); - - if (ibcr0_bp) - { - xscale_unset_breakpoint(target, ibcr0_bp); - } - else - { - ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); - exit(-1); - } - } - - xscale_set_reg_u32(ibcr0, next_pc | 0x1); - - return ERROR_OK; -} - -int xscale_disable_single_step(struct target_s *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; - - xscale_set_reg_u32(ibcr0, 0x0); - - return ERROR_OK; -} - -int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale= armv4_5->arch_info; - breakpoint_t *breakpoint = target->breakpoints; - - u32 current_pc; - - int retval; - int i; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!debug_execution) - { - target_free_all_working_areas(target); - } - - /* update vector tables */ - xscale_update_vectors(target); - - /* current = 1: continue on current pc, otherwise continue at
*/ - if (!current) - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); - - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - /* if we're at the reset vector, we have to simulate the branch */ - if (current_pc == 0x0) - { - arm_simulate_step(target, NULL); - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - } - - /* the front-end may request us not to handle breakpoints */ - if (handle_breakpoints) - { - if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) - { - u32 next_pc; - - /* there's a breakpoint at the current PC, we have to step over it */ - DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); - xscale_unset_breakpoint(target, breakpoint); - - /* calculate PC of next instruction */ - if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) - { - u32 current_opcode; - target_read_u32(target, current_pc, ¤t_opcode); - ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); - } - - DEBUG("enable single-step"); - xscale_enable_single_step(target, next_pc); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - /* wait for and process debug entry */ - xscale_debug_entry(target); - - DEBUG("disable single-step"); - xscale_disable_single_step(target); - - DEBUG("set breakpoint at 0x%8.8x", breakpoint->address); - xscale_set_breakpoint(target, breakpoint); - } - } - - /* enable any pending breakpoints and watchpoints */ - xscale_enable_breakpoints(target); - xscale_enable_watchpoints(target); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - target->debug_reason = DBG_REASON_NOTHALTED; - - if (!debug_execution) - { - /* registers are now invalid */ - armv4_5_invalidate_core_regs(target); - target->state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - } - else - { - target->state = TARGET_DEBUG_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - } - - DEBUG("target resumed"); - - xscale->handler_running = 1; - - return ERROR_OK; -} - -int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - breakpoint_t *breakpoint = target->breakpoints; - - u32 current_pc, next_pc; - int i; - int retval; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* current = 1: continue on current pc, otherwise continue at
*/ - if (!current) - buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); - - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - /* if we're at the reset vector, we have to simulate the step */ - if (current_pc == 0x0) - { - arm_simulate_step(target, NULL); - current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - - target->debug_reason = DBG_REASON_SINGLESTEP; - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - return ERROR_OK; - } - - /* the front-end may request us not to handle breakpoints */ - if (handle_breakpoints) - if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) - { - xscale_unset_breakpoint(target, breakpoint); - } - - target->debug_reason = DBG_REASON_SINGLESTEP; - - /* calculate PC of next instruction */ - if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) - { - u32 current_opcode; - target_read_u32(target, current_pc, ¤t_opcode); - ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); - } - - DEBUG("enable single-step"); - xscale_enable_single_step(target, next_pc); - - /* restore banked registers */ - xscale_restore_context(target); - - /* send resume request (command 0x30 or 0x31) - * clean the trace buffer if it is to be enabled (0x62) */ - if (xscale->trace.buffer_enabled) - { - xscale_send_u32(target, 0x62); - xscale_send_u32(target, 0x31); - } - else - xscale_send_u32(target, 0x30); - - /* send CPSR */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); - - for (i = 7; i >= 0; i--) - { - /* send register */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); - } - - /* send PC */ - xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); - - target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - - /* registers are now invalid */ - armv4_5_invalidate_core_regs(target); - - /* wait for and process debug entry */ - xscale_debug_entry(target); - - DEBUG("disable single-step"); - xscale_disable_single_step(target); - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - - if (breakpoint) - { - xscale_set_breakpoint(target, breakpoint); - } - - DEBUG("target stepped"); - - return ERROR_OK; - -} - -int xscale_assert_reset(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("target->state: %s", target_state_strings[target->state]); - - /* select DCSR instruction (set endstate to R-T-I to ensure we don't - * end up in T-L-R, which would reset JTAG - */ - jtag_add_end_state(TAP_RTI); - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ - xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f); - jtag_execute_queue(); - - /* assert reset */ - jtag_add_reset(0, 1); - - /* sleep 1ms, to be sure we fulfill any requirements */ - jtag_add_sleep(1000); - jtag_execute_queue(); - - target->state = TARGET_RESET; - - return ERROR_OK; -} - -int xscale_deassert_reset(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - fileio_t debug_handler; - u32 address; - u32 binary_size; - - u32 buf_cnt; - int i; - int retval; - - breakpoint_t *breakpoint = target->breakpoints; - - DEBUG("-"); - - xscale->ibcr_available = 2; - xscale->ibcr0_used = 0; - xscale->ibcr1_used = 0; - - xscale->dbr_available = 2; - xscale->dbr0_used = 0; - xscale->dbr1_used = 0; - - /* mark all hardware breakpoints as unset */ - while (breakpoint) - { - if (breakpoint->type == BKPT_HARD) - { - breakpoint->set = 0; - } - breakpoint = breakpoint->next; - } - - if (!xscale->handler_installed) - { - /* release SRST */ - jtag_add_reset(0, 0); - - /* wait 300ms; 150 and 100ms were not enough */ - jtag_add_sleep(300*1000); - - jtag_add_runtest(2030, TAP_RTI); - jtag_execute_queue(); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* Load debug handler */ - if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK) - { - ERROR("file open error: %s", debug_handler.error_str); - return ERROR_OK; - } - - if ((binary_size = debug_handler.size) % 4) - { - ERROR("debug_handler.bin: size not a multiple of 4"); - exit(-1); - } - - if (binary_size > 0x800) - { - ERROR("debug_handler.bin: larger than 2kb"); - exit(-1); - } - - binary_size = CEIL(binary_size, 32) * 32; - - address = xscale->handler_address; - while (binary_size > 0) - { - u32 cache_line[8]; - u8 buffer[32]; - - if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK) - { - ERROR("reading debug handler failed: %s", debug_handler.error_str); - } - - for (i = 0; i < buf_cnt; i += 4) - { - /* convert LE buffer to host-endian u32 */ - cache_line[i / 4] = le_to_h_u32(&buffer[i]); - } - - for (; buf_cnt < 32; buf_cnt += 4) - { - cache_line[buf_cnt / 4] = 0xe1a08008; - } - - /* only load addresses other than the reset vectors */ - if ((address % 0x400) != 0x0) - { - xscale_load_ic(target, 1, address, cache_line); - } - - address += buf_cnt; - binary_size -= buf_cnt; - }; - - xscale_load_ic(target, 1, 0x0, xscale->low_vectors); - xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); - - jtag_add_runtest(30, TAP_RTI); - - jtag_add_sleep(100000); - - /* set Hold reset, Halt mode and Trap Reset */ - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); - xscale_write_dcsr(target, 1, 0); - - /* clear Hold reset to let the target run (should enter debug handler) */ - xscale_write_dcsr(target, 0, 1); - target->state = TARGET_RUNNING; - - if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT)) - { - jtag_add_sleep(10000); - - /* we should have entered debug now */ - xscale_debug_entry(target); - target->state = TARGET_HALTED; - - /* resume the target */ - xscale_resume(target, 1, 0x0, 1, 0); - } - - fileio_close(&debug_handler); - } - else - { - jtag_add_reset(0, 0); - } - - - return ERROR_OK; -} - -int xscale_soft_reset_halt(struct target_s *target) -{ - - return ERROR_OK; -} - -int xscale_prepare_reset_halt(struct target_s *target) -{ - /* nothing to be done for reset_halt on XScale targets - * we always halt after a reset to upload the debug handler - */ - return ERROR_OK; -} - -int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode) -{ - - return ERROR_OK; -} - -int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value) -{ - - return ERROR_OK; -} - -int xscale_full_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - - u32 *buffer; - - int i, j; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - buffer = malloc(4 * 8); - - /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) - * we can't enter User mode on an XScale (unpredictable), - * but User shares registers with SYS - */ - for(i = 1; i < 7; i++) - { - int valid = 1; - - /* check if there are invalid registers in the current mode - */ - for (j = 0; j <= 16; j++) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0) - valid = 0; - } - - if (!valid) - { - u32 tmp_cpsr; - - /* request banked registers */ - xscale_send_u32(target, 0x0); - - tmp_cpsr = 0x0; - tmp_cpsr |= armv4_5_number_to_mode(i); - tmp_cpsr |= 0xc0; /* I/F bits */ - - /* send CPSR for desired mode */ - xscale_send_u32(target, tmp_cpsr); - - /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - xscale_receive(target, buffer, 8); - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; - } - else - { - xscale_receive(target, buffer, 7); - } - - /* move data from buffer to register cache */ - for (j = 8; j <= 14; j++) - { - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1; - } - } - } - - free(buffer); - - return ERROR_OK; -} - -int xscale_restore_context(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - - int i, j; - - DEBUG("-"); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) - * we can't enter User mode on an XScale (unpredictable), - * but User shares registers with SYS - */ - for(i = 1; i < 7; i++) - { - int dirty = 0; - - /* check if there are invalid registers in the current mode - */ - for (j = 8; j <= 14; j++) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1) - dirty = 1; - } - - /* if not USR/SYS, check if the SPSR needs to be written */ - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1) - dirty = 1; - } - - if (dirty) - { - u32 tmp_cpsr; - - /* send banked registers */ - xscale_send_u32(target, 0x1); - - tmp_cpsr = 0x0; - tmp_cpsr |= armv4_5_number_to_mode(i); - tmp_cpsr |= 0xc0; /* I/F bits */ - - /* send CPSR for desired mode */ - xscale_send_u32(target, tmp_cpsr); - - /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */ - for (j = 8; j <= 14; j++) - { - xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32)); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; - } - - if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) - { - xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32)); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; - } - } - } - - return ERROR_OK; -} - -int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 *buf32; - int i; - - DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; - - if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) - return ERROR_TARGET_UNALIGNED_ACCESS; - - /* send memory read request (command 0x1n, n: access size) */ - xscale_send_u32(target, 0x10 | size); - - /* send base address for read request */ - xscale_send_u32(target, address); - - /* send number of requested data words */ - xscale_send_u32(target, count); - - /* receive data from target (count times 32-bit words in host endianness) */ - buf32 = malloc(4 * count); - xscale_receive(target, buf32, count); - - /* extract data from host-endian buffer into byte stream */ - for (i = 0; i < count; i++) - { - switch (size) - { - case 4: - target_buffer_set_u32(target, buffer, buf32[i]); - buffer += 4; - break; - case 2: - target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); - buffer += 2; - break; - case 1: - *buffer++ = buf32[i] & 0xff; - break; - default: - ERROR("should never get here"); - exit(-1); - } - } - - free(buf32); - - /* examine DCSR, to see if Sticky Abort (SA) got set */ - xscale_read_dcsr(target); - if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) - { - /* clear SA bit */ - xscale_send_u32(target, 0x60); - - return ERROR_TARGET_DATA_ABORT; - } - - return ERROR_OK; -} - -int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; - - if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) - return ERROR_TARGET_UNALIGNED_ACCESS; - - /* send memory write request (command 0x2n, n: access size) */ - xscale_send_u32(target, 0x20 | size); - - /* send base address for read request */ - xscale_send_u32(target, address); - - /* send number of requested data words to be written*/ - xscale_send_u32(target, count); - - /* extract data from host-endian buffer into byte stream */ -#if 0 - for (i = 0; i < count; i++) - { - switch (size) - { - case 4: - value = target_buffer_get_u32(target, buffer); - xscale_send_u32(target, value); - buffer += 4; - break; - case 2: - value = target_buffer_get_u16(target, buffer); - xscale_send_u32(target, value); - buffer += 2; - break; - case 1: - value = *buffer; - xscale_send_u32(target, value); - buffer += 1; - break; - default: - ERROR("should never get here"); - exit(-1); - } - } -#endif - xscale_send(target, buffer, count, size); - - /* examine DCSR, to see if Sticky Abort (SA) got set */ - xscale_read_dcsr(target); - if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) - { - /* clear SA bit */ - xscale_send_u32(target, 0x60); - - return ERROR_TARGET_DATA_ABORT; - } - - return ERROR_OK; -} - -int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer) -{ - return xscale_write_memory(target, address, 4, count, buffer); -} - -int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) -{ - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; -} - -u32 xscale_get_ttb(target_t *target) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 ttb; - - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); - ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); - - return ttb; -} - -void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - - if (mmu) - cp15_control &= ~0x1U; - - if (d_u_cache) - { - /* clean DCache */ - xscale_send_u32(target, 0x50); - xscale_send_u32(target, xscale->cache_clean_address); - - /* invalidate DCache */ - xscale_send_u32(target, 0x51); - - cp15_control &= ~0x4U; - } - - if (i_cache) - { - /* invalidate ICache */ - xscale_send_u32(target, 0x52); - cp15_control &= ~0x1000U; - } - - /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); -} - -void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 cp15_control; - - /* read cp15 control register */ - xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); - cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - - if (mmu) - cp15_control |= 0x1U; - - if (d_u_cache) - cp15_control |= 0x4U; - - if (i_cache) - cp15_control |= 0x1000U; - - /* write new cp15 control register */ - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); -} - -int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->force_hw_bkpts) - breakpoint->type = BKPT_HARD; - - if (breakpoint->set) - { - WARNING("breakpoint already set"); - return ERROR_OK; - } - - if (breakpoint->type == BKPT_HARD) - { - u32 value = breakpoint->address | 1; - if (!xscale->ibcr0_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); - xscale->ibcr0_used = 1; - breakpoint->set = 1; /* breakpoint set on first breakpoint register */ - } - else if (!xscale->ibcr1_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); - xscale->ibcr1_used = 1; - breakpoint->set = 2; /* breakpoint set on second breakpoint register */ - } - else - { - ERROR("BUG: no hardware comparator available"); - return ERROR_OK; - } - } - else if (breakpoint->type == BKPT_SOFT) - { - if (breakpoint->length == 4) - { - /* keep the original instruction in target endianness */ - target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); - /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ - target_write_u32(target, breakpoint->address, xscale->arm_bkpt); - } - else - { - /* keep the original instruction in target endianness */ - target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); - /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ - target_write_u32(target, breakpoint->address, xscale->thumb_bkpt); - } - breakpoint->set = 1; - } - - return ERROR_OK; - -} - -int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->force_hw_bkpts) - { - DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address); - breakpoint->type = BKPT_HARD; - } - - if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) - { - INFO("no breakpoint unit available for hardware breakpoint"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - else - { - xscale->ibcr_available--; - } - - if ((breakpoint->length != 2) && (breakpoint->length != 4)) - { - INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - return ERROR_OK; -} - -int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!breakpoint->set) - { - WARNING("breakpoint not set"); - return ERROR_OK; - } - - if (breakpoint->type == BKPT_HARD) - { - if (breakpoint->set == 1) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); - xscale->ibcr0_used = 0; - } - else if (breakpoint->set == 2) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); - xscale->ibcr1_used = 0; - } - breakpoint->set = 0; - } - else - { - /* restore original instruction (kept in target endianness) */ - if (breakpoint->length == 4) - { - target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); - } - else - { - target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); - } - breakpoint->set = 0; - } - - return ERROR_OK; -} - -int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (breakpoint->set) - { - xscale_unset_breakpoint(target, breakpoint); - } - - if (breakpoint->type == BKPT_HARD) - xscale->ibcr_available++; - - return ERROR_OK; -} - -int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u8 enable = 0; - reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; - u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - xscale_get_reg(dbcon); - - switch (watchpoint->rw) - { - case WPT_READ: - enable = 0x3; - break; - case WPT_ACCESS: - enable = 0x2; - break; - case WPT_WRITE: - enable = 0x1; - break; - default: - ERROR("BUG: watchpoint->rw neither read, write nor access"); - } - - if (!xscale->dbr0_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); - dbcon_value |= enable; - xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 1; - xscale->dbr0_used = 1; - } - else if (!xscale->dbr1_used) - { - xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); - dbcon_value |= enable << 2; - xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 2; - xscale->dbr1_used = 1; - } - else - { - ERROR("BUG: no hardware comparator available"); - return ERROR_OK; - } - - return ERROR_OK; -} - -int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (xscale->dbr_available < 1) - { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) - { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - xscale->dbr_available--; - - return ERROR_OK; -} - -int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; - u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (!watchpoint->set) - { - WARNING("breakpoint not set"); - return ERROR_OK; - } - - if (watchpoint->set == 1) - { - dbcon_value &= ~0x3; - xscale_set_reg_u32(dbcon, dbcon_value); - xscale->dbr0_used = 0; - } - else if (watchpoint->set == 2) - { - dbcon_value &= ~0xc; - xscale_set_reg_u32(dbcon, dbcon_value); - xscale->dbr1_used = 0; - } - watchpoint->set = 0; - - return ERROR_OK; -} - -int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (watchpoint->set) - { - xscale_unset_watchpoint(target, watchpoint); - } - - xscale->dbr_available++; - - return ERROR_OK; -} - -void xscale_enable_watchpoints(struct target_s *target) -{ - watchpoint_t *watchpoint = target->watchpoints; - - while (watchpoint) - { - if (watchpoint->set == 0) - xscale_set_watchpoint(target, watchpoint); - watchpoint = watchpoint->next; - } -} - -void xscale_enable_breakpoints(struct target_s *target) -{ - breakpoint_t *breakpoint = target->breakpoints; - - /* set any pending breakpoints */ - while (breakpoint) - { - if (breakpoint->set == 0) - xscale_set_breakpoint(target, breakpoint); - breakpoint = breakpoint->next; - } -} - -int xscale_get_reg(reg_t *reg) -{ - xscale_reg_t *arch_info = reg->arch_info; - target_t *target = arch_info->target; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - /* DCSR, TX and RX are accessible via JTAG */ - if (strcmp(reg->name, "XSCALE_DCSR") == 0) - { - return xscale_read_dcsr(arch_info->target); - } - else if (strcmp(reg->name, "XSCALE_TX") == 0) - { - /* 1 = consume register content */ - return xscale_read_tx(arch_info->target, 1); - } - else if (strcmp(reg->name, "XSCALE_RX") == 0) - { - /* can't read from RX register (host -> debug handler) */ - return ERROR_OK; - } - else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) - { - /* can't (explicitly) read from TXRXCTRL register */ - return ERROR_OK; - } - else /* Other DBG registers have to be transfered by the debug handler */ - { - /* send CP read request (command 0x40) */ - xscale_send_u32(target, 0x40); - - /* send CP register number */ - xscale_send_u32(target, arch_info->dbg_handler_number); - - /* read register value */ - xscale_read_tx(target, 1); - buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); - - reg->dirty = 0; - reg->valid = 1; - } - - return ERROR_OK; -} - -int xscale_set_reg(reg_t *reg, u8* buf) -{ - xscale_reg_t *arch_info = reg->arch_info; - target_t *target = arch_info->target; - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - u32 value = buf_get_u32(buf, 0, 32); - - /* DCSR, TX and RX are accessible via JTAG */ - if (strcmp(reg->name, "XSCALE_DCSR") == 0) - { - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); - return xscale_write_dcsr(arch_info->target, -1, -1); - } - else if (strcmp(reg->name, "XSCALE_RX") == 0) - { - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); - return xscale_write_rx(arch_info->target); - } - else if (strcmp(reg->name, "XSCALE_TX") == 0) - { - /* can't write to TX register (debug-handler -> host) */ - return ERROR_OK; - } - else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) - { - /* can't (explicitly) write to TXRXCTRL register */ - return ERROR_OK; - } - else /* Other DBG registers have to be transfered by the debug handler */ - { - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, arch_info->dbg_handler_number); - - /* send CP register value */ - xscale_send_u32(target, value); - buf_set_u32(reg->value, 0, 32, value); - } - - return ERROR_OK; -} - -/* convenience wrapper to access XScale specific registers */ -int xscale_set_reg_u32(reg_t *reg, u32 value) -{ - u8 buf[4]; - - buf_set_u32(buf, 0, 32, value); - - return xscale_set_reg(reg, buf); -} - -int xscale_write_dcsr_sw(target_t *target, u32 value) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; - xscale_reg_t *dcsr_arch_info = dcsr->arch_info; - - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); - - /* send CP register value */ - xscale_send_u32(target, value); - buf_set_u32(dcsr->value, 0, 32, value); - - return ERROR_OK; -} - -int xscale_read_trace(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - xscale_trace_data_t **trace_data_p; - - /* 258 words from debug handler - * 256 trace buffer entries - * 2 checkpoint addresses - */ - u32 trace_buffer[258]; - int is_address[256]; - int i, j; - - if (target->state != TARGET_HALTED) - { - WARNING("target must be stopped to read trace data"); - return ERROR_TARGET_NOT_HALTED; - } - - /* send read trace buffer command (command 0x61) */ - xscale_send_u32(target, 0x61); - - /* receive trace buffer content */ - xscale_receive(target, trace_buffer, 258); - - /* parse buffer backwards to identify address entries */ - for (i = 255; i >= 0; i--) - { - is_address[i] = 0; - if (((trace_buffer[i] & 0xf0) == 0x90) || - ((trace_buffer[i] & 0xf0) == 0xd0)) - { - if (i >= 3) - is_address[--i] = 1; - if (i >= 2) - is_address[--i] = 1; - if (i >= 1) - is_address[--i] = 1; - if (i >= 0) - is_address[--i] = 1; - } - } - - - /* search first non-zero entry */ - for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) - ; - - if (j == 256) - { - DEBUG("no trace data collected"); - return ERROR_XSCALE_NO_TRACE_DATA; - } - - for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) - ; - - *trace_data_p = malloc(sizeof(xscale_trace_data_t)); - (*trace_data_p)->next = NULL; - (*trace_data_p)->chkpt0 = trace_buffer[256]; - (*trace_data_p)->chkpt1 = trace_buffer[257]; - (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j)); - (*trace_data_p)->depth = 256 - j; - - for (i = j; i < 256; i++) - { - (*trace_data_p)->entries[i - j].data = trace_buffer[i]; - if (is_address[i]) - (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; - else - (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; - } - - return ERROR_OK; -} - -int xscale_read_instruction(target_t *target, arm_instruction_t *instruction) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int i; - int section = -1; - u32 size_read; - u32 opcode; - int retval; - - if (!xscale->trace.image) - return ERROR_TRACE_IMAGE_UNAVAILABLE; - - /* search for the section the current instruction belongs to */ - for (i = 0; i < xscale->trace.image->num_sections; i++) - { - if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) && - (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc)) - { - section = i; - break; - } - } - - if (section == -1) - { - /* current instruction couldn't be found in the image */ - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - - if (xscale->trace.core_state == ARMV4_5_STATE_ARM) - { - u8 buf[4]; - if ((retval = image_read_section(xscale->trace.image, section, - xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, - 4, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u32(target, buf); - arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); - } - else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB) - { - u8 buf[2]; - if ((retval = image_read_section(xscale->trace.image, section, - xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, - 2, buf, &size_read)) != ERROR_OK) - { - ERROR("error while reading instruction: %i", retval); - return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; - } - opcode = target_buffer_get_u16(target, buf); - thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); - } - else - { - ERROR("BUG: unknown core state encountered"); - exit(-1); - } - - return ERROR_OK; -} - -int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target) -{ - /* if there are less than four entries prior to the indirect branch message - * we can't extract the address */ - if (i < 4) - { - return -1; - } - - *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | - (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); - - return 0; -} - -int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - int next_pc_ok = 0; - u32 next_pc = 0x0; - xscale_trace_data_t *trace_data = xscale->trace.data; - int retval; - - while (trace_data) - { - int i, chkpt; - int rollover; - int branch; - int exception; - xscale->trace.core_state = ARMV4_5_STATE_ARM; - - chkpt = 0; - rollover = 0; - - for (i = 0; i < trace_data->depth; i++) - { - next_pc_ok = 0; - branch = 0; - exception = 0; - - if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) - continue; - - switch ((trace_data->entries[i].data & 0xf0) >> 4) - { - case 0: /* Exceptions */ - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - exception = (trace_data->entries[i].data & 0x70) >> 4; - next_pc_ok = 1; - next_pc = (trace_data->entries[i].data & 0xf0) >> 2; - command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4); - break; - case 8: /* Direct Branch */ - branch = 1; - break; - case 9: /* Indirect Branch */ - branch = 1; - if (xscale_branch_address(trace_data, i, &next_pc) == 0) - { - next_pc_ok = 1; - } - break; - case 13: /* Checkpointed Indirect Branch */ - if (xscale_branch_address(trace_data, i, &next_pc) == 0) - { - next_pc_ok = 1; - if (((chkpt == 0) && (next_pc != trace_data->chkpt0)) - || ((chkpt == 1) && (next_pc != trace_data->chkpt1))) - WARNING("checkpointed indirect branch target address doesn't match checkpoint"); - } - /* explicit fall-through */ - case 12: /* Checkpointed Direct Branch */ - branch = 1; - if (chkpt == 0) - { - next_pc_ok = 1; - next_pc = trace_data->chkpt0; - chkpt++; - } - else if (chkpt == 1) - { - next_pc_ok = 1; - next_pc = trace_data->chkpt0; - chkpt++; - } - else - { - WARNING("more than two checkpointed branches encountered"); - } - break; - case 15: /* Roll-over */ - rollover++; - continue; - default: /* Reserved */ - command_print(cmd_ctx, "--- reserved trace message ---"); - ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4); - return ERROR_OK; - } - - if (xscale->trace.pc_ok) - { - int executed = (trace_data->entries[i].data & 0xf) + rollover * 16; - arm_instruction_t instruction; - - if ((exception == 6) || (exception == 7)) - { - /* IRQ or FIQ exception, no instruction executed */ - executed -= 1; - } - - while (executed-- >= 0) - { - if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images */ - } - } - - /* a precise abort on a load to the PC is included in the incremental - * word count, other instructions causing data aborts are not included - */ - if ((executed == 0) && (exception == 4) - && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM))) - { - if ((instruction.type == ARM_LDM) - && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0)) - { - executed--; - } - else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) - && (instruction.info.load_store.Rd != 15)) - { - executed--; - } - } - - /* only the last instruction executed - * (the one that caused the control flow change) - * could be a taken branch - */ - if (((executed == -1) && (branch == 1)) && - (((instruction.type == ARM_B) || - (instruction.type == ARM_BL) || - (instruction.type == ARM_BLX)) && - (instruction.info.b_bl_bx_blx.target_address != -1))) - { - xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address; - } - else - { - xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2; - } - command_print(cmd_ctx, "%s", instruction.text); - } - - rollover = 0; - } - - if (next_pc_ok) - { - xscale->trace.current_pc = next_pc; - xscale->trace.pc_ok = 1; - } - } - - for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2) - { - arm_instruction_t instruction; - if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) - { - /* can't continue tracing with no image available */ - if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) - { - return retval; - } - else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) - { - /* TODO: handle incomplete images */ - } - } - command_print(cmd_ctx, "%s", instruction.text); - } - - trace_data = trace_data->next; - } - - return ERROR_OK; -} - -void xscale_build_reg_cache(target_t *target) -{ - /* get pointers to arch-specific information */ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); - xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info)); - int i; - int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t); - - (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); - - /* register a register arch-type for XScale dbg registers only once */ - if (xscale_reg_arch_type == -1) - xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg); - - (*cache_p)->next = malloc(sizeof(reg_cache_t)); - cache_p = &(*cache_p)->next; - - /* fill in values for the xscale reg cache */ - (*cache_p)->name = "XScale registers"; - (*cache_p)->next = NULL; - (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t)); - (*cache_p)->num_regs = num_regs; - - for (i = 0; i < num_regs; i++) - { - (*cache_p)->reg_list[i].name = xscale_reg_list[i]; - (*cache_p)->reg_list[i].value = calloc(4, 1); - (*cache_p)->reg_list[i].dirty = 0; - (*cache_p)->reg_list[i].valid = 0; - (*cache_p)->reg_list[i].size = 32; - (*cache_p)->reg_list[i].bitfield_desc = NULL; - (*cache_p)->reg_list[i].num_bitfields = 0; - (*cache_p)->reg_list[i].arch_info = &arch_info[i]; - (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type; - arch_info[i] = xscale_reg_arch_info[i]; - arch_info[i].target = target; - } - - xscale->reg_cache = (*cache_p); -} - -int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target) -{ - if (startup_mode != DAEMON_RESET) - { - ERROR("XScale target requires a reset"); - ERROR("Reset target to enable debug"); - } - - /* assert TRST once during startup */ - jtag_add_reset(1, 0); - jtag_add_sleep(5000); - jtag_add_reset(0, 0); - jtag_execute_queue(); - - return ERROR_OK; -} - -int xscale_quit() -{ - - return ERROR_OK; -} - -int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant) -{ - armv4_5_common_t *armv4_5; - u32 high_reset_branch, low_reset_branch; - int i; - - armv4_5 = &xscale->armv4_5_common; - - /* store architecture specfic data (none so far) */ - xscale->arch_info = NULL; - xscale->common_magic = XSCALE_COMMON_MAGIC; - - /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */ - xscale->variant = strdup(variant); - - /* prepare JTAG information for the new target */ - xscale->jtag_info.chain_pos = chain_pos; - jtag_register_event_callback(xscale_jtag_callback, target); - - xscale->jtag_info.dbgrx = 0x02; - xscale->jtag_info.dbgtx = 0x10; - xscale->jtag_info.dcsr = 0x09; - xscale->jtag_info.ldic = 0x07; - - if ((strcmp(xscale->variant, "pxa250") == 0) || - (strcmp(xscale->variant, "pxa255") == 0) || - (strcmp(xscale->variant, "pxa26x") == 0)) - { - xscale->jtag_info.ir_length = 5; - } - else if ((strcmp(xscale->variant, "pxa27x") == 0) || - (strcmp(xscale->variant, "ixp42x") == 0) || - (strcmp(xscale->variant, "ixp45x") == 0) || - (strcmp(xscale->variant, "ixp46x") == 0)) - { - xscale->jtag_info.ir_length = 7; - } - - /* the debug handler isn't installed (and thus not running) at this time */ - xscale->handler_installed = 0; - xscale->handler_running = 0; - xscale->handler_address = 0xfe000800; - - /* clear the vectors we keep locally for reference */ - memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); - memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); - - /* no user-specified vectors have been configured yet */ - xscale->static_low_vectors_set = 0x0; - xscale->static_high_vectors_set = 0x0; - - /* calculate branches to debug handler */ - low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; - high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; - - xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); - xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); - - for (i = 1; i <= 7; i++) - { - xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); - xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); - } - - /* 64kB aligned region used for DCache cleaning */ - xscale->cache_clean_address = 0xfffe0000; - - xscale->hold_rst = 0; - xscale->external_debug_break = 0; - - xscale->force_hw_bkpts = 1; - - xscale->ibcr_available = 2; - xscale->ibcr0_used = 0; - xscale->ibcr1_used = 0; - - xscale->dbr_available = 2; - xscale->dbr0_used = 0; - xscale->dbr1_used = 0; - - xscale->arm_bkpt = ARMV5_BKPT(0x0); - xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; - - xscale->vector_catch = 0x1; - - xscale->trace.capture_status = TRACE_IDLE; - xscale->trace.data = NULL; - xscale->trace.image = NULL; - xscale->trace.buffer_enabled = 0; - xscale->trace.buffer_fill = 0; - - /* prepare ARMv4/5 specific information */ - armv4_5->arch_info = xscale; - armv4_5->read_core_reg = xscale_read_core_reg; - armv4_5->write_core_reg = xscale_write_core_reg; - armv4_5->full_context = xscale_full_context; - - armv4_5_init_arch_info(target, armv4_5); - - xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; - xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; - xscale->armv4_5_mmu.read_memory = xscale_read_memory; - xscale->armv4_5_mmu.write_memory = xscale_write_memory; - xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; - xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; - xscale->armv4_5_mmu.has_tiny_pages = 1; - xscale->armv4_5_mmu.mmu_enabled = 0; - - xscale->fast_memory_access = 0; - - return ERROR_OK; -} - -/* target xscale */ -int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) -{ - int chain_pos; - char *variant = NULL; - xscale_common_t *xscale = malloc(sizeof(xscale_common_t)); - - if (argc < 5) - { - ERROR("'target xscale' requires four arguments: "); - return ERROR_OK; - } - - chain_pos = strtoul(args[3], NULL, 0); - - variant = args[4]; - - xscale_init_arch_info(target, xscale, chain_pos, variant); - xscale_build_reg_cache(target); - - return ERROR_OK; -} - -int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - u32 handler_address; - - if (argc < 2) - { - ERROR("'xscale debug_handler
' command takes two required operands"); - return ERROR_OK; - } - - if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) - { - ERROR("no target '%s' configured", args[0]); - return ERROR_OK; - } - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - handler_address = strtoul(args[1], NULL, 0); - - if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || - ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) - { - xscale->handler_address = handler_address; - } - else - { - ERROR("xscale debug_handler
must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); - } - - return ERROR_OK; -} - -int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = NULL; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - u32 cache_clean_address; - - if (argc < 2) - { - ERROR("'xscale cache_clean_address
' command takes two required operands"); - return ERROR_OK; - } - - if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) - { - ERROR("no target '%s' configured", args[0]); - return ERROR_OK; - } - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - cache_clean_address = strtoul(args[1], NULL, 0); - - if (cache_clean_address & 0xffff) - { - ERROR("xscale cache_clean_address
must be 64kb aligned"); - } - else - { - xscale->cache_clean_address = cache_clean_address; - } - - return ERROR_OK; -} - -int xscale_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache); -} - -static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical) -{ - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - int retval; - int type; - u32 cb; - int domain; - u32 ap; - - if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK) - { - return retval; - } - u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); - if (type == -1) - { - return ret; - } - - *physical = ret; - return ERROR_OK; -} - -static int xscale_mmu(struct target_s *target, int *enabled) -{ - armv4_5_common_t *armv4_5 = target->arch_info; - xscale_common_t *xscale = armv4_5->arch_info; - - if (target->state != TARGET_HALTED) - { - ERROR("Target not halted"); - return ERROR_TARGET_INVALID; - } - - *enabled = xscale->armv4_5_mmu.mmu_enabled; - return ERROR_OK; -} - -int xscale_handle_mmu_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc >= 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale_enable_mmu_caches(target, 1, 0, 0); - xscale->armv4_5_mmu.mmu_enabled = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale_disable_mmu_caches(target, 1, 0, 0); - xscale->armv4_5_mmu.mmu_enabled = 0; - } - } - - command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_idcache_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - int icache = 0, dcache = 0; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (strcmp(cmd, "icache") == 0) - icache = 1; - else if (strcmp(cmd, "dcache") == 0) - dcache = 1; - - if (argc >= 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale_enable_mmu_caches(target, 0, dcache, icache); - - if (icache) - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1; - else if (dcache) - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale_disable_mmu_caches(target, 0, dcache, icache); - - if (icache) - xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; - else if (dcache) - xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - } - } - - if (icache) - command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled"); - - if (dcache) - command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_vector_catch_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale vector_catch [mask]"); - } - else - { - xscale->vector_catch = strtoul(args[0], NULL, 0); - buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); - xscale_write_dcsr(target, -1, -1); - } - - command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch); - - return ERROR_OK; -} - -int xscale_handle_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) - { - xscale->force_hw_bkpts = 1; - } - else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) - { - xscale->force_hw_bkpts = 0; - } - else - { - command_print(cmd_ctx, "usage: xscale force_hw_bkpts "); - } - - command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - u32 dcsr_value; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) - { - xscale_trace_data_t *td, *next_td; - xscale->trace.buffer_enabled = 1; - - /* free old trace data */ - td = xscale->trace.data; - while (td) - { - next_td = td->next; - - if (td->entries) - free(td->entries); - free(td); - td = next_td; - } - xscale->trace.data = NULL; - } - else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) - { - xscale->trace.buffer_enabled = 0; - } - - if ((argc >= 2) && (strcmp("fill", args[1]) == 0)) - { - if (argc >= 3) - xscale->trace.buffer_fill = strtoul(args[2], NULL, 0); - else - xscale->trace.buffer_fill = 1; - } - else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0)) - { - xscale->trace.buffer_fill = -1; - } - - if (xscale->trace.buffer_enabled) - { - /* if we enable the trace buffer in fill-once - * mode we know the address of the first instruction */ - xscale->trace.pc_ok = 1; - xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); - } - else - { - /* otherwise the address is unknown, and we have no known good PC */ - xscale->trace.pc_ok = 0; - } - - command_print(cmd_ctx, "trace buffer %s (%s)", - (xscale->trace.buffer_enabled) ? "enabled" : "disabled", - (xscale->trace.buffer_fill > 0) ? "fill" : "wrap"); - - dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); - if (xscale->trace.buffer_fill >= 0) - xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); - else - xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); - - return ERROR_OK; -} - -int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target; - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale trace_image [base address] [type]"); - return ERROR_OK; - } - - target = get_current_target(cmd_ctx); - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (xscale->trace.image) - { - image_close(xscale->trace.image); - free(xscale->trace.image); - command_print(cmd_ctx, "previously loaded image found and closed"); - } - - xscale->trace.image = malloc(sizeof(image_t)); - xscale->trace.image->base_address_set = 0; - xscale->trace.image->start_address_set = 0; - - /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ - if (argc >= 2) - { - xscale->trace.image->base_address_set = 1; - xscale->trace.image->base_address = strtoul(args[1], NULL, 0); - } - else - { - xscale->trace.image->base_address_set = 0; - } - - if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) - { - command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str); - free(xscale->trace.image); - xscale->trace.image = NULL; - return ERROR_OK; - } - - return ERROR_OK; -} - -int xscale_handle_dump_trace_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - xscale_trace_data_t *trace_data; - fileio_t file; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - - if (argc < 1) - { - command_print(cmd_ctx, "usage: xscale dump_trace "); - return ERROR_OK; - } - - trace_data = xscale->trace.data; - - if (!trace_data) - { - command_print(cmd_ctx, "no trace data collected"); - return ERROR_OK; - } - - if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) - { - command_print(cmd_ctx, "file open error: %s", file.error_str); - return ERROR_OK; - } - - while (trace_data) - { - int i; - - fileio_write_u32(&file, trace_data->chkpt0); - fileio_write_u32(&file, trace_data->chkpt1); - fileio_write_u32(&file, trace_data->last_instruction); - fileio_write_u32(&file, trace_data->depth); - - for (i = 0; i < trace_data->depth; i++) - fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); - - trace_data = trace_data->next; - } - - fileio_close(&file); - - return ERROR_OK; -} - -int xscale_handle_analyze_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - xscale_analyze_trace(target, cmd_ctx); - - return ERROR_OK; -} - -int xscale_handle_cp15(command_context_t *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (target->state != TARGET_HALTED) - { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); - return ERROR_OK; - } - u32 reg_no = 0; - reg_t *reg = NULL; - if(argc > 0) - { - reg_no = strtoul(args[0], NULL, 0); - /*translate from xscale cp15 register no to openocd register*/ - switch(reg_no) - { - case 0: - reg_no = XSCALE_MAINID; - break; - case 1: - reg_no = XSCALE_CTRL; - break; - case 2: - reg_no = XSCALE_TTB; - break; - case 3: - reg_no = XSCALE_DAC; - break; - case 5: - reg_no = XSCALE_FSR; - break; - case 6: - reg_no = XSCALE_FAR; - break; - case 13: - reg_no = XSCALE_PID; - break; - case 15: - reg_no = XSCALE_CPACCESS; - break; - default: - command_print(cmd_ctx, "invalid register number"); - return ERROR_INVALID_ARGUMENTS; - } - reg = &xscale->reg_cache->reg_list[reg_no]; - - } - if(argc == 1) - { - u32 value; - - /* read cp15 control register */ - xscale_get_reg(reg); - value = buf_get_u32(reg->value, 0, 32); - command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value); - } - else if(argc == 2) - { - - u32 value = strtoul(args[1], NULL, 0); - - /* send CP write request (command 0x41) */ - xscale_send_u32(target, 0x41); - - /* send CP register number */ - xscale_send_u32(target, reg_no); - - /* send CP register value */ - xscale_send_u32(target, value); - - /* execute cpwait to ensure outstanding operations complete */ - xscale_send_u32(target, 0x53); - } - else - { - command_print(cmd_ctx, "usage: cp15 [register]<, [value]>"); - } - - return ERROR_OK; -} - -int handle_xscale_fast_memory_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - target_t *target = get_current_target(cmd_ctx); - armv4_5_common_t *armv4_5; - xscale_common_t *xscale; - - if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) - { - return ERROR_OK; - } - - if (argc == 1) - { - if (strcmp("enable", args[0]) == 0) - { - xscale->fast_memory_access = 1; - } - else if (strcmp("disable", args[0]) == 0) - { - xscale->fast_memory_access = 0; - } - else - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - } else if (argc!=0) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled"); - - return ERROR_OK; -} - -int xscale_register_commands(struct command_context_s *cmd_ctx) -{ - command_t *xscale_cmd; - - xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands"); - - register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler
' command takes two required operands"); - register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL); - - register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU"); - register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache"); - register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache"); - - register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, " of vectors that should be catched"); - - register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, " ['fill' [n]|'wrap']"); - - register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to "); - register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer"); - register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command, - COMMAND_EXEC, "load image from [base address]"); - - register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 [value]"); - register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command, - COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses "); - - armv4_5_register_commands(cmd_ctx); - - return ERROR_OK; -} +/*************************************************************************** + * Copyright (C) 2006, 2007 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "replacements.h" + +#include "xscale.h" + +#include "register.h" +#include "target.h" +#include "armv4_5.h" +#include "arm_simulator.h" +#include "arm_disassembler.h" +#include "log.h" +#include "jtag.h" +#include "binarybuffer.h" +#include "time_support.h" +#include "breakpoints.h" +#include "fileio.h" + +#include +#include + +#include +#include +#include + + +/* cli handling */ +int xscale_register_commands(struct command_context_s *cmd_ctx); + +/* forward declarations */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target); +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target); +int xscale_quit(); + +int xscale_arch_state(struct target_s *target); +int xscale_poll(target_t *target); +int xscale_halt(target_t *target); +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution); +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints); +int xscale_debug_entry(target_t *target); +int xscale_restore_context(target_t *target); + +int xscale_assert_reset(target_t *target); +int xscale_deassert_reset(target_t *target); +int xscale_soft_reset_halt(struct target_s *target); +int xscale_prepare_reset_halt(struct target_s *target); + +int xscale_set_reg_u32(reg_t *reg, u32 value); + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode); +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value); + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer); +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer); +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum); + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint); +void xscale_enable_watchpoints(struct target_s *target); +void xscale_enable_breakpoints(struct target_s *target); +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical); +static int xscale_mmu(struct target_s *target, int *enabled); + +int xscale_read_trace(target_t *target); + +target_type_t xscale_target = +{ + .name = "xscale", + + .poll = xscale_poll, + .arch_state = xscale_arch_state, + + .target_request_data = NULL, + + .halt = xscale_halt, + .resume = xscale_resume, + .step = xscale_step, + + .assert_reset = xscale_assert_reset, + .deassert_reset = xscale_deassert_reset, + .soft_reset_halt = xscale_soft_reset_halt, + .prepare_reset_halt = xscale_prepare_reset_halt, + + .get_gdb_reg_list = armv4_5_get_gdb_reg_list, + + .read_memory = xscale_read_memory, + .write_memory = xscale_write_memory, + .bulk_write_memory = xscale_bulk_write_memory, + .checksum_memory = xscale_checksum_memory, + + .run_algorithm = armv4_5_run_algorithm, + + .add_breakpoint = xscale_add_breakpoint, + .remove_breakpoint = xscale_remove_breakpoint, + .add_watchpoint = xscale_add_watchpoint, + .remove_watchpoint = xscale_remove_watchpoint, + + .register_commands = xscale_register_commands, + .target_command = xscale_target_command, + .init_target = xscale_init_target, + .quit = xscale_quit, + + .virt2phys = xscale_virt2phys, + .mmu = xscale_mmu +}; + +char* xscale_reg_list[] = +{ + "XSCALE_MAINID", /* 0 */ + "XSCALE_CACHETYPE", + "XSCALE_CTRL", + "XSCALE_AUXCTRL", + "XSCALE_TTB", + "XSCALE_DAC", + "XSCALE_FSR", + "XSCALE_FAR", + "XSCALE_PID", + "XSCALE_CPACCESS", + "XSCALE_IBCR0", /* 10 */ + "XSCALE_IBCR1", + "XSCALE_DBR0", + "XSCALE_DBR1", + "XSCALE_DBCON", + "XSCALE_TBREG", + "XSCALE_CHKPT0", + "XSCALE_CHKPT1", + "XSCALE_DCSR", + "XSCALE_TX", + "XSCALE_RX", /* 20 */ + "XSCALE_TXRXCTRL", +}; + +xscale_reg_t xscale_reg_arch_info[] = +{ + {XSCALE_MAINID, NULL}, + {XSCALE_CACHETYPE, NULL}, + {XSCALE_CTRL, NULL}, + {XSCALE_AUXCTRL, NULL}, + {XSCALE_TTB, NULL}, + {XSCALE_DAC, NULL}, + {XSCALE_FSR, NULL}, + {XSCALE_FAR, NULL}, + {XSCALE_PID, NULL}, + {XSCALE_CPACCESS, NULL}, + {XSCALE_IBCR0, NULL}, + {XSCALE_IBCR1, NULL}, + {XSCALE_DBR0, NULL}, + {XSCALE_DBR1, NULL}, + {XSCALE_DBCON, NULL}, + {XSCALE_TBREG, NULL}, + {XSCALE_CHKPT0, NULL}, + {XSCALE_CHKPT1, NULL}, + {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ + {-1, NULL}, /* TX accessed via JTAG */ + {-1, NULL}, /* RX accessed via JTAG */ + {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ +}; + +int xscale_reg_arch_type = -1; + +int xscale_get_reg(reg_t *reg); +int xscale_set_reg(reg_t *reg, u8 *buf); + +int xscale_get_arch_pointers(target_t *target, armv4_5_common_t **armv4_5_p, xscale_common_t **xscale_p) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + if (xscale->common_magic != XSCALE_COMMON_MAGIC) + { + ERROR("target isn't an XScale target"); + return -1; + } + + *armv4_5_p = armv4_5; + *xscale_p = xscale; + + return ERROR_OK; +} + +int xscale_jtag_set_instr(int chain_pos, u32 new_instr) +{ + jtag_device_t *device = jtag_get_device(chain_pos); + + if (buf_get_u32(device->cur_instr, 0, device->ir_length) != new_instr) + { + scan_field_t field; + + field.device = chain_pos; + field.num_bits = device->ir_length; + field.out_value = calloc(CEIL(field.num_bits, 8), 1); + buf_set_u32(field.out_value, 0, field.num_bits, new_instr); + field.out_mask = NULL; + field.in_value = NULL; + jtag_set_check_value(&field, device->expected, device->expected_mask, NULL); + + jtag_add_ir_scan(1, &field, -1); + + free(field.out_value); + } + + return ERROR_OK; +} + +int xscale_jtag_callback(enum jtag_event event, void *priv) +{ + switch (event) + { + case JTAG_TRST_ASSERTED: + break; + case JTAG_TRST_RELEASED: + break; + case JTAG_SRST_ASSERTED: + break; + case JTAG_SRST_RELEASED: + break; + default: + WARNING("unhandled JTAG event"); + } + + return ERROR_OK; +} + +int xscale_read_dcsr(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_PD); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + /* write the register with the value we just read + * on this second pass, only the first bit of field0 is guaranteed to be 0) + */ + field0_check_mask = 0x1; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].in_value = NULL; + + jtag_add_end_state(TAP_RTI); + + jtag_add_dr_scan(3, fields, -1); + + return ERROR_OK; +} + +int xscale_receive(target_t *target, u32 *buffer, int num_words) +{ + int retval = ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + enum tap_state path[3]; + scan_field_t fields[3]; + + u8 *field0 = malloc(num_words * 1); + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u32 *field1 = malloc(num_words * 4); + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + int words_done = 0; + int words_scheduled = 0; + + int i; + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + /* fields[0].in_value = field0; */ + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + jtag_add_runtest(1, -1); + + /* repeat until all words have been collected */ + int attempts = 0; + while (words_done < num_words) + { + /* schedule reads */ + words_scheduled = 0; + for (i = words_done; i < num_words; i++) + { + fields[0].in_value = &field0[i]; + fields[1].in_handler = buf_to_u32_handler; + fields[1].in_handler_priv = (u8*)&field1[i]; + + jtag_add_pathmove(3, path); + jtag_add_dr_scan(3, fields, TAP_RTI); + words_scheduled++; + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while receiving data from debug handler"); + break; + } + + /* examine results */ + for (i = words_done; i < num_words; i++) + { + if (!(field0[0] & 1)) + { + /* move backwards if necessary */ + int j; + for (j = i; j < num_words - 1; j++) + { + field0[j] = field0[j+1]; + field1[j] = field1[j+1]; + } + words_scheduled--; + } + } + if (words_scheduled == 0) + { + if (attempts++ == 1000) + { + ERROR("Failed to receiving data from debug handler after 1000 attempts"); + retval = ERROR_JTAG_QUEUE_FAILED; + break; + } + } + + words_done += words_scheduled; + } + + for (i = 0; i < num_words; i++) + *(buffer++) = buf_get_u32((u8*)&field1[i], 0, 32); + + free(field1); + + return retval; +} + +int xscale_read_tx(target_t *target, int consume) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + enum tap_state path[3]; + enum tap_state noconsume_path[9]; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgtx); + + path[0] = TAP_SDS; + path[1] = TAP_CD; + path[2] = TAP_SD; + + noconsume_path[0] = TAP_SDS; + noconsume_path[1] = TAP_CD; + noconsume_path[2] = TAP_E1D; + noconsume_path[3] = TAP_PD; + noconsume_path[4] = TAP_E2D; + noconsume_path[5] = TAP_UD; + noconsume_path[6] = TAP_SDS; + noconsume_path[7] = TAP_CD; + noconsume_path[8] = TAP_SD; + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = NULL; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = NULL; + fields[1].out_mask = NULL; + fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = NULL; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + do + { + /* if we want to consume the register content (i.e. clear TX_READY), + * we have to go straight from Capture-DR to Shift-DR + * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR + */ + if (consume) + jtag_add_pathmove(3, path); + else + jtag_add_pathmove(sizeof(noconsume_path)/sizeof(*noconsume_path), noconsume_path); + + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while reading TX"); + return ERROR_TARGET_TIMEOUT; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out reading TX register"); + return ERROR_TARGET_TIMEOUT; + } + } while ((!(field0_in & 1)) && consume); + + if (!(field0_in & 1)) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + return ERROR_OK; +} + +int xscale_write_rx(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + struct timeval timeout, now; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_in = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_value = &field0_in; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, 5, 0); + + /* poll until rx_read is low */ + DEBUG("polling RX"); + do + { + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + gettimeofday(&now, NULL); + if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec)&& (now.tv_usec > timeout.tv_usec))) + { + ERROR("time out writing RX register"); + return ERROR_TARGET_TIMEOUT; + } + } while (field0_in & 1); + + /* set rx_valid */ + field2 = 0x1; + jtag_add_dr_scan(3, fields, TAP_RTI); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing RX"); + return retval; + } + + return ERROR_OK; +} + +/* send count elements of size byte to the debug handler */ +int xscale_send(target_t *target, u8 *buffer, int count, int size) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + int done_count = 0; + u8 output[4] = {0, 0, 0, 0}; + + scan_field_t fields[3]; + u8 field0_out = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x6; + u8 field2 = 0x1; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + jtag_add_end_state(TAP_RTI); + + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dbgrx); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0_out; + fields[0].out_mask = NULL; + fields[0].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + } + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = output; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + fields[2].in_handler = NULL; + if (!xscale->fast_memory_access) + { + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + } + + if (size==4) + { + int endianness = target->endianness; + while (done_count++ < count) + { + if (endianness == TARGET_LITTLE_ENDIAN) + { + output[0]=buffer[0]; + output[1]=buffer[1]; + output[2]=buffer[2]; + output[3]=buffer[3]; + } else + { + output[0]=buffer[3]; + output[1]=buffer[2]; + output[2]=buffer[1]; + output[3]=buffer[0]; + } + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } else + { + while (done_count++ < count) + { + /* extract sized element from target-endian buffer, and put it + * into little-endian output buffer + */ + switch (size) + { + case 2: + buf_set_u32(output, 0, 32, target_buffer_get_u16(target, buffer)); + break; + case 1: + output[0] = *buffer; + break; + default: + ERROR("BUG: size neither 4, 2 nor 1"); + exit(-1); + } + + jtag_add_dr_scan(3, fields, TAP_RTI); + buffer += size; + } + + } + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while sending data to debug handler"); + return retval; + } + + return ERROR_OK; +} + +int xscale_send_u32(target_t *target, u32 value) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(target); +} + +int xscale_write_dcsr(target_t *target, int hold_rst, int ext_dbg_brk) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + int retval; + + scan_field_t fields[3]; + u8 field0 = 0x0; + u8 field0_check_value = 0x2; + u8 field0_check_mask = 0x7; + u8 field2 = 0x0; + u8 field2_check_value = 0x0; + u8 field2_check_mask = 0x1; + + if (hold_rst != -1) + xscale->hold_rst = hold_rst; + + if (ext_dbg_brk != -1) + xscale->external_debug_break = ext_dbg_brk; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + buf_set_u32(&field0, 1, 1, xscale->hold_rst); + buf_set_u32(&field0, 2, 1, xscale->external_debug_break); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 3; + fields[0].out_value = &field0; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + jtag_set_check_value(fields+0, &field0_check_value, &field0_check_mask, NULL); + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 32; + fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + + + + fields[2].device = xscale->jtag_info.chain_pos; + fields[2].num_bits = 1; + fields[2].out_value = &field2; + fields[2].out_mask = NULL; + fields[2].in_value = NULL; + jtag_set_check_value(fields+2, &field2_check_value, &field2_check_mask, NULL); + + jtag_add_dr_scan(3, fields, -1); + + if ((retval = jtag_execute_queue()) != ERROR_OK) + { + ERROR("JTAG error while writing DCSR"); + return retval; + } + + xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; + xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; + + return ERROR_OK; +} + +/* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ +unsigned int parity (unsigned int v) +{ + unsigned int ov = v; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v &= 0xf; + DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); + return (0x6996 >> v) & 1; +} + +int xscale_load_ic(target_t *target, int mini, u32 va, u32 buffer[8]) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + int word; + + scan_field_t fields[2]; + + DEBUG("loading miniIC at 0x%8.8x", va); + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD is b010 for Main IC and b011 for Mini IC */ + if (mini) + buf_set_u32(&cmd, 0, 3, 0x3); + else + buf_set_u32(&cmd, 0, 3, 0x2); + + buf_set_u32(&cmd, 3, 3, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + jtag_add_dr_scan(2, fields, -1); + + fields[0].num_bits = 32; + fields[0].out_value = packet; + + fields[1].num_bits = 1; + fields[1].out_value = &cmd; + + for (word = 0; word < 8; word++) + { + buf_set_u32(packet, 0, 32, buffer[word]); + cmd = parity(*((u32*)packet)); + jtag_add_dr_scan(2, fields, -1); + } + + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_invalidate_ic_line(target_t *target, u32 va) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 packet[4]; + u8 cmd; + + scan_field_t fields[2]; + + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.ldic); /* LDIC */ + + /* CMD for invalidate IC line b000, bits [6:4] b000 */ + buf_set_u32(&cmd, 0, 6, 0x0); + + /* virtual address of desired cache line */ + buf_set_u32(packet, 0, 27, va >> 5); + + fields[0].device = xscale->jtag_info.chain_pos; + fields[0].num_bits = 6; + fields[0].out_value = &cmd; + fields[0].out_mask = NULL; + fields[0].in_value = NULL; + fields[0].in_check_value = NULL; + fields[0].in_check_mask = NULL; + fields[0].in_handler = NULL; + fields[0].in_handler_priv = NULL; + + fields[1].device = xscale->jtag_info.chain_pos; + fields[1].num_bits = 27; + fields[1].out_value = packet; + fields[1].out_mask = NULL; + fields[1].in_value = NULL; + fields[1].in_check_value = NULL; + fields[1].in_check_mask = NULL; + fields[1].in_handler = NULL; + fields[1].in_handler_priv = NULL; + + jtag_add_dr_scan(2, fields, -1); + + return ERROR_OK; +} + +int xscale_update_vectors(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + + u32 low_reset_branch, high_reset_branch; + + for (i = 1; i < 8; i++) + { + /* if there's a static vector specified for this exception, override */ + if (xscale->static_high_vectors_set & (1 << i)) + { + xscale->high_vectors[i] = xscale->static_high_vectors[i]; + } + else + { + if (target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]) != ERROR_OK) + { + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + for (i = 1; i < 8; i++) + { + if (xscale->static_low_vectors_set & (1 << i)) + { + xscale->low_vectors[i] = xscale->static_low_vectors[i]; + } + else + { + if (target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]) != ERROR_OK) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + } + } + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + /* invalidate and load exception vectors in mini i-cache */ + xscale_invalidate_ic_line(target, 0x0); + xscale_invalidate_ic_line(target, 0xffff0000); + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + return ERROR_OK; +} + +int xscale_arch_state(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + char *state[] = + { + "disabled", "enabled" + }; + + char *arch_dbg_reason[] = + { + "", "\n(processor reset)", "\n(trace buffer full)" + }; + + if (armv4_5->common_magic != ARMV4_5_COMMON_MAGIC) + { + ERROR("BUG: called for a non-ARMv4/5 target"); + exit(-1); + } + + USER("target halted in %s state due to %s, current mode: %s\n" + "cpsr: 0x%8.8x pc: 0x%8.8x\n" + "MMU: %s, D-Cache: %s, I-Cache: %s" + "%s", + armv4_5_state_strings[armv4_5->core_state], + target_debug_reason_strings[target->debug_reason], + armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)], + buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32), + buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32), + state[xscale->armv4_5_mmu.mmu_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], + state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], + arch_dbg_reason[xscale->arch_debug_reason]); + + return ERROR_OK; +} + +int xscale_poll(target_t *target) +{ + int retval=ERROR_OK; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) + { + enum target_state previous_state = target->state; + if ((retval = xscale_read_tx(target, 0)) == ERROR_OK) + { + + /* there's data to read from the tx register, we entered debug state */ + xscale->handler_running = 1; + + target->state = TARGET_HALTED; + + /* process debug entry, fetching current mode regs */ + retval = xscale_debug_entry(target); + } + else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + { + USER("error while polling TX register, reset CPU"); + /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ + target->state = TARGET_HALTED; + } + + /* debug_entry could have overwritten target state (i.e. immediate resume) + * don't signal event handlers in that case + */ + if (target->state != TARGET_HALTED) + return ERROR_OK; + + /* if target was running, signal that we halted + * otherwise we reentered from debug execution */ + if (previous_state == TARGET_RUNNING) + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + else + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } + return retval; +} + +int xscale_debug_entry(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 pc; + u32 buffer[10]; + int i; + + u32 moe; + + /* clear external dbg break (will be written on next DCSR read) */ + xscale->external_debug_break = 0; + xscale_read_dcsr(target); + + /* get r0, pc, r1 to r7 and cpsr */ + xscale_receive(target, buffer, 10); + + /* move r0 from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, buffer[0]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("r0: 0x%8.8x", buffer[0]); + + /* move pc from buffer to register cache */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, buffer[1]); + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; + DEBUG("pc: 0x%8.8x", buffer[1]); + + /* move data from buffer to register cache */ + for (i = 1; i <= 7; i++) + { + buf_set_u32(armv4_5->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); + armv4_5->core_cache->reg_list[i].dirty = 1; + armv4_5->core_cache->reg_list[i].valid = 1; + DEBUG("r%i: 0x%8.8x", i, buffer[i + 1]); + } + + buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, buffer[9]); + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1; + armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1; + DEBUG("cpsr: 0x%8.8x", buffer[9]); + + armv4_5->core_mode = buffer[9] & 0x1f; + if (armv4_5_mode_to_number(armv4_5->core_mode) == -1) + { + target->state = TARGET_UNKNOWN; + ERROR("cpsr contains invalid mode value - communication failure"); + return ERROR_TARGET_FAILURE; + } + DEBUG("target entered debug state in %s mode", armv4_5_mode_strings[armv4_5_mode_to_number(armv4_5->core_mode)]); + + if (buffer[9] & 0x20) + armv4_5->core_state = ARMV4_5_STATE_THUMB; + else + armv4_5->core_state = ARMV4_5_STATE_ARM; + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5->core_mode != ARMV4_5_MODE_USR) && (armv4_5->core_mode != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).valid = 1; + } + else + { + /* r8 to r14, but no spsr */ + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (i = 8; i <= 14; i++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).value, 0, 32, buffer[i - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, i).valid = 1; + } + + /* examine debug reason */ + xscale_read_dcsr(target); + moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); + + /* stored PC (for calculating fixup) */ + pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + switch (moe) + { + case 0x0: /* Processor reset */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; + pc -= 4; + break; + case 0x1: /* Instruction breakpoint hit */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x2: /* Data breakpoint hit */ + target->debug_reason = DBG_REASON_WATCHPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x3: /* BKPT instruction executed */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x4: /* Ext. debug event */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x5: /* Vector trap occured */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x6: /* Trace buffer full break */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; + pc -= 4; + break; + case 0x7: /* Reserved */ + default: + ERROR("Method of Entry is 'Reserved'"); + exit(-1); + break; + } + + /* apply PC fixup */ + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, pc); + + /* on the first debug entry, identify cache type */ + if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) + { + u32 cache_type_reg; + + /* read cp15 cache type register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); + cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); + + armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); + } + + /* examine MMU and Cache settings */ + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; + + /* tracing enabled, read collected trace data */ + if (xscale->trace.buffer_enabled) + { + xscale_read_trace(target); + xscale->trace.buffer_fill--; + + /* resume if we're still collecting trace data */ + if ((xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) + && (xscale->trace.buffer_fill > 0)) + { + xscale_resume(target, 1, 0x0, 1, 0); + } + else + { + xscale->trace.buffer_enabled = 0; + } + } + + return ERROR_OK; +} + +int xscale_halt(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + if (target->state == TARGET_HALTED) + { + WARNING("target was already halted"); + return ERROR_TARGET_ALREADY_HALTED; + } + else if (target->state == TARGET_UNKNOWN) + { + /* this must not happen for a xscale target */ + ERROR("target was in unknown state when halt was requested"); + return ERROR_TARGET_INVALID; + } + else if (target->state == TARGET_RESET) + { + DEBUG("target->state == TARGET_RESET"); + } + else + { + /* assert external dbg break */ + xscale->external_debug_break = 1; + xscale_read_dcsr(target); + + target->debug_reason = DBG_REASON_DBGRQ; + } + + return ERROR_OK; +} + +int xscale_enable_single_step(struct target_s *target, u32 next_pc) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + if (xscale->ibcr0_used) + { + breakpoint_t *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); + + if (ibcr0_bp) + { + xscale_unset_breakpoint(target, ibcr0_bp); + } + else + { + ERROR("BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); + exit(-1); + } + } + + xscale_set_reg_u32(ibcr0, next_pc | 0x1); + + return ERROR_OK; +} + +int xscale_disable_single_step(struct target_s *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + reg_t *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; + + xscale_set_reg_u32(ibcr0, 0x0); + + return ERROR_OK; +} + +int xscale_resume(struct target_s *target, int current, u32 address, int handle_breakpoints, int debug_execution) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale= armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc; + + int retval; + int i; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) + { + target_free_all_working_areas(target); + } + + /* update vector tables */ + xscale_update_vectors(target); + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the branch */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + { + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + u32 next_pc; + + /* there's a breakpoint at the current PC, we have to step over it */ + DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); + xscale_unset_breakpoint(target, breakpoint); + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + DEBUG("set breakpoint at 0x%8.8x", breakpoint->address); + xscale_set_breakpoint(target, breakpoint); + } + } + + /* enable any pending breakpoints and watchpoints */ + xscale_enable_breakpoints(target); + xscale_enable_watchpoints(target); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target->debug_reason = DBG_REASON_NOTHALTED; + + if (!debug_execution) + { + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + } + else + { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + } + + DEBUG("target resumed"); + + xscale->handler_running = 1; + + return ERROR_OK; +} + +int xscale_step(struct target_s *target, int current, u32 address, int handle_breakpoints) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + breakpoint_t *breakpoint = target->breakpoints; + + u32 current_pc, next_pc; + int i; + int retval; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, address); + + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + /* if we're at the reset vector, we have to simulate the step */ + if (current_pc == 0x0) + { + arm_simulate_step(target, NULL); + current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + + target->debug_reason = DBG_REASON_SINGLESTEP; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) + if ((breakpoint = breakpoint_find(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)))) + { + xscale_unset_breakpoint(target, breakpoint); + } + + target->debug_reason = DBG_REASON_SINGLESTEP; + + /* calculate PC of next instruction */ + if ((retval = arm_simulate_step(target, &next_pc)) != ERROR_OK) + { + u32 current_opcode; + target_read_u32(target, current_pc, ¤t_opcode); + ERROR("BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8x", current_opcode); + } + + DEBUG("enable single-step"); + xscale_enable_single_step(target, next_pc); + + /* restore banked registers */ + xscale_restore_context(target); + + /* send resume request (command 0x30 or 0x31) + * clean the trace buffer if it is to be enabled (0x62) */ + if (xscale->trace.buffer_enabled) + { + xscale_send_u32(target, 0x62); + xscale_send_u32(target, 0x31); + } + else + xscale_send_u32(target, 0x30); + + /* send CPSR */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + DEBUG("writing cpsr with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32)); + + for (i = 7; i >= 0; i--) + { + /* send register */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + DEBUG("writing r%i with value 0x%8.8x", i, buf_get_u32(armv4_5->core_cache->reg_list[i].value, 0, 32)); + } + + /* send PC */ + xscale_send_u32(target, buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + DEBUG("writing PC with value 0x%8.8x", buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32)); + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + /* registers are now invalid */ + armv4_5_invalidate_core_regs(target); + + /* wait for and process debug entry */ + xscale_debug_entry(target); + + DEBUG("disable single-step"); + xscale_disable_single_step(target); + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + if (breakpoint) + { + xscale_set_breakpoint(target, breakpoint); + } + + DEBUG("target stepped"); + + return ERROR_OK; + +} + +int xscale_assert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("target->state: %s", target_state_strings[target->state]); + + /* select DCSR instruction (set endstate to R-T-I to ensure we don't + * end up in T-L-R, which would reset JTAG + */ + jtag_add_end_state(TAP_RTI); + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, xscale->jtag_info.dcsr); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ + xscale_jtag_set_instr(xscale->jtag_info.chain_pos, 0x7f); + jtag_execute_queue(); + + /* assert reset */ + jtag_add_reset(0, 1); + + /* sleep 1ms, to be sure we fulfill any requirements */ + jtag_add_sleep(1000); + jtag_execute_queue(); + + target->state = TARGET_RESET; + + return ERROR_OK; +} + +int xscale_deassert_reset(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + fileio_t debug_handler; + u32 address; + u32 binary_size; + + u32 buf_cnt; + int i; + int retval; + + breakpoint_t *breakpoint = target->breakpoints; + + DEBUG("-"); + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + /* mark all hardware breakpoints as unset */ + while (breakpoint) + { + if (breakpoint->type == BKPT_HARD) + { + breakpoint->set = 0; + } + breakpoint = breakpoint->next; + } + + if (!xscale->handler_installed) + { + /* release SRST */ + jtag_add_reset(0, 0); + + /* wait 300ms; 150 and 100ms were not enough */ + jtag_add_sleep(300*1000); + + jtag_add_runtest(2030, TAP_RTI); + jtag_execute_queue(); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* Load debug handler */ + if (fileio_open(&debug_handler, PKGLIBDIR "/xscale/debug_handler.bin", FILEIO_READ, FILEIO_BINARY) != ERROR_OK) + { + ERROR("file open error: %s", debug_handler.error_str); + return ERROR_OK; + } + + if ((binary_size = debug_handler.size) % 4) + { + ERROR("debug_handler.bin: size not a multiple of 4"); + exit(-1); + } + + if (binary_size > 0x800) + { + ERROR("debug_handler.bin: larger than 2kb"); + exit(-1); + } + + binary_size = CEIL(binary_size, 32) * 32; + + address = xscale->handler_address; + while (binary_size > 0) + { + u32 cache_line[8]; + u8 buffer[32]; + + if ((retval = fileio_read(&debug_handler, 32, buffer, &buf_cnt)) != ERROR_OK) + { + ERROR("reading debug handler failed: %s", debug_handler.error_str); + } + + for (i = 0; i < buf_cnt; i += 4) + { + /* convert LE buffer to host-endian u32 */ + cache_line[i / 4] = le_to_h_u32(&buffer[i]); + } + + for (; buf_cnt < 32; buf_cnt += 4) + { + cache_line[buf_cnt / 4] = 0xe1a08008; + } + + /* only load addresses other than the reset vectors */ + if ((address % 0x400) != 0x0) + { + xscale_load_ic(target, 1, address, cache_line); + } + + address += buf_cnt; + binary_size -= buf_cnt; + }; + + xscale_load_ic(target, 1, 0x0, xscale->low_vectors); + xscale_load_ic(target, 1, 0xffff0000, xscale->high_vectors); + + jtag_add_runtest(30, TAP_RTI); + + jtag_add_sleep(100000); + + /* set Hold reset, Halt mode and Trap Reset */ + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); + xscale_write_dcsr(target, 1, 0); + + /* clear Hold reset to let the target run (should enter debug handler) */ + xscale_write_dcsr(target, 0, 1); + target->state = TARGET_RUNNING; + + if ((target->reset_mode != RESET_HALT) && (target->reset_mode != RESET_INIT)) + { + jtag_add_sleep(10000); + + /* we should have entered debug now */ + xscale_debug_entry(target); + target->state = TARGET_HALTED; + + /* resume the target */ + xscale_resume(target, 1, 0x0, 1, 0); + } + + fileio_close(&debug_handler); + } + else + { + jtag_add_reset(0, 0); + } + + + return ERROR_OK; +} + +int xscale_soft_reset_halt(struct target_s *target) +{ + + return ERROR_OK; +} + +int xscale_prepare_reset_halt(struct target_s *target) +{ + /* nothing to be done for reset_halt on XScale targets + * we always halt after a reset to upload the debug handler + */ + return ERROR_OK; +} + +int xscale_read_core_reg(struct target_s *target, int num, enum armv4_5_mode mode) +{ + + return ERROR_OK; +} + +int xscale_write_core_reg(struct target_s *target, int num, enum armv4_5_mode mode, u32 value) +{ + + return ERROR_OK; +} + +int xscale_full_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + u32 *buffer; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + buffer = malloc(4 * 8); + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int valid = 1; + + /* check if there are invalid registers in the current mode + */ + for (j = 0; j <= 16; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid == 0) + valid = 0; + } + + if (!valid) + { + u32 tmp_cpsr; + + /* request banked registers */ + xscale_send_u32(target, 0x0); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_receive(target, buffer, 8); + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32, buffer[7]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; + } + else + { + xscale_receive(target, buffer, 7); + } + + /* move data from buffer to register cache */ + for (j = 8; j <= 14; j++) + { + buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).value, 0, 32, buffer[j - 8]); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).valid = 1; + } + } + } + + free(buffer); + + return ERROR_OK; +} + +int xscale_restore_context(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + + int i, j; + + DEBUG("-"); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) + * we can't enter User mode on an XScale (unpredictable), + * but User shares registers with SYS + */ + for(i = 1; i < 7; i++) + { + int dirty = 0; + + /* check if there are invalid registers in the current mode + */ + for (j = 8; j <= 14; j++) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty == 1) + dirty = 1; + } + + /* if not USR/SYS, check if the SPSR needs to be written */ + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty == 1) + dirty = 1; + } + + if (dirty) + { + u32 tmp_cpsr; + + /* send banked registers */ + xscale_send_u32(target, 0x1); + + tmp_cpsr = 0x0; + tmp_cpsr |= armv4_5_number_to_mode(i); + tmp_cpsr |= 0xc0; /* I/F bits */ + + /* send CPSR for desired mode */ + xscale_send_u32(target, tmp_cpsr); + + /* send banked registers, r8 to r14, and spsr if not in USR/SYS mode */ + for (j = 8; j <= 14; j++) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, j).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; + } + + if ((armv4_5_number_to_mode(i) != ARMV4_5_MODE_USR) && (armv4_5_number_to_mode(i) != ARMV4_5_MODE_SYS)) + { + xscale_send_u32(target, buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 16).value, 0, 32)); + ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; + } + } + } + + return ERROR_OK; +} + +int xscale_read_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 *buf32; + int i; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory read request (command 0x1n, n: access size) */ + xscale_send_u32(target, 0x10 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words */ + xscale_send_u32(target, count); + + /* receive data from target (count times 32-bit words in host endianness) */ + buf32 = malloc(4 * count); + xscale_receive(target, buf32, count); + + /* extract data from host-endian buffer into byte stream */ + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + target_buffer_set_u32(target, buffer, buf32[i]); + buffer += 4; + break; + case 2: + target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); + buffer += 2; + break; + case 1: + *buffer++ = buf32[i] & 0xff; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } + + free(buf32); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_write_memory(struct target_s *target, u32 address, u32 size, u32 count, u8 *buffer) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* sanitize arguments */ + if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) + return ERROR_INVALID_ARGUMENTS; + + if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) + return ERROR_TARGET_UNALIGNED_ACCESS; + + /* send memory write request (command 0x2n, n: access size) */ + xscale_send_u32(target, 0x20 | size); + + /* send base address for read request */ + xscale_send_u32(target, address); + + /* send number of requested data words to be written*/ + xscale_send_u32(target, count); + + /* extract data from host-endian buffer into byte stream */ +#if 0 + for (i = 0; i < count; i++) + { + switch (size) + { + case 4: + value = target_buffer_get_u32(target, buffer); + xscale_send_u32(target, value); + buffer += 4; + break; + case 2: + value = target_buffer_get_u16(target, buffer); + xscale_send_u32(target, value); + buffer += 2; + break; + case 1: + value = *buffer; + xscale_send_u32(target, value); + buffer += 1; + break; + default: + ERROR("should never get here"); + exit(-1); + } + } +#endif + xscale_send(target, buffer, count, size); + + /* examine DCSR, to see if Sticky Abort (SA) got set */ + xscale_read_dcsr(target); + if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) + { + /* clear SA bit */ + xscale_send_u32(target, 0x60); + + return ERROR_TARGET_DATA_ABORT; + } + + return ERROR_OK; +} + +int xscale_bulk_write_memory(target_t *target, u32 address, u32 count, u8 *buffer) +{ + return xscale_write_memory(target, address, 4, count, buffer); +} + +int xscale_checksum_memory(struct target_s *target, u32 address, u32 count, u32* checksum) +{ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +u32 xscale_get_ttb(target_t *target) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 ttb; + + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); + ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); + + return ttb; +} + +void xscale_disable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control &= ~0x1U; + + if (d_u_cache) + { + /* clean DCache */ + xscale_send_u32(target, 0x50); + xscale_send_u32(target, xscale->cache_clean_address); + + /* invalidate DCache */ + xscale_send_u32(target, 0x51); + + cp15_control &= ~0x4U; + } + + if (i_cache) + { + /* invalidate ICache */ + xscale_send_u32(target, 0x52); + cp15_control &= ~0x1000U; + } + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +void xscale_enable_mmu_caches(target_t *target, int mmu, int d_u_cache, int i_cache) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 cp15_control; + + /* read cp15 control register */ + xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); + cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); + + if (mmu) + cp15_control |= 0x1U; + + if (d_u_cache) + cp15_control |= 0x4U; + + if (i_cache) + cp15_control |= 0x1000U; + + /* write new cp15 control register */ + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); +} + +int xscale_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + breakpoint->type = BKPT_HARD; + + if (breakpoint->set) + { + WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + u32 value = breakpoint->address | 1; + if (!xscale->ibcr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); + xscale->ibcr0_used = 1; + breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + } + else if (!xscale->ibcr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); + xscale->ibcr1_used = 1; + breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + } + else if (breakpoint->type == BKPT_SOFT) + { + if (breakpoint->length == 4) + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->arm_bkpt); + } + else + { + /* keep the original instruction in target endianness */ + target->type->read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + /* write the original instruction in target endianness (arm7_9->arm_bkpt is host endian) */ + target_write_u32(target, breakpoint->address, xscale->thumb_bkpt); + } + breakpoint->set = 1; + } + + return ERROR_OK; + +} + +int xscale_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->force_hw_bkpts) + { + DEBUG("forcing use of hardware breakpoint at address 0x%8.8x", breakpoint->address); + breakpoint->type = BKPT_HARD; + } + + if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) + { + INFO("no breakpoint unit available for hardware breakpoint"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + else + { + xscale->ibcr_available--; + } + + if ((breakpoint->length != 2) && (breakpoint->length != 4)) + { + INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +int xscale_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!breakpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) + { + if (breakpoint->set == 1) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); + xscale->ibcr0_used = 0; + } + else if (breakpoint->set == 2) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); + xscale->ibcr1_used = 0; + } + breakpoint->set = 0; + } + else + { + /* restore original instruction (kept in target endianness) */ + if (breakpoint->length == 4) + { + target->type->write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); + } + else + { + target->type->write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); + } + breakpoint->set = 0; + } + + return ERROR_OK; +} + +int xscale_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (breakpoint->set) + { + xscale_unset_breakpoint(target, breakpoint); + } + + if (breakpoint->type == BKPT_HARD) + xscale->ibcr_available++; + + return ERROR_OK; +} + +int xscale_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u8 enable = 0; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + xscale_get_reg(dbcon); + + switch (watchpoint->rw) + { + case WPT_READ: + enable = 0x3; + break; + case WPT_ACCESS: + enable = 0x2; + break; + case WPT_WRITE: + enable = 0x1; + break; + default: + ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + if (!xscale->dbr0_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); + dbcon_value |= enable; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 1; + xscale->dbr0_used = 1; + } + else if (!xscale->dbr1_used) + { + xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); + dbcon_value |= enable << 2; + xscale_set_reg_u32(dbcon, dbcon_value); + watchpoint->set = 2; + xscale->dbr1_used = 1; + } + else + { + ERROR("BUG: no hardware comparator available"); + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xscale->dbr_available < 1) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) + { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + xscale->dbr_available--; + + return ERROR_OK; +} + +int xscale_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; + u32 dbcon_value = buf_get_u32(dbcon->value, 0, 32); + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!watchpoint->set) + { + WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (watchpoint->set == 1) + { + dbcon_value &= ~0x3; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr0_used = 0; + } + else if (watchpoint->set == 2) + { + dbcon_value &= ~0xc; + xscale_set_reg_u32(dbcon, dbcon_value); + xscale->dbr1_used = 0; + } + watchpoint->set = 0; + + return ERROR_OK; +} + +int xscale_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + { + xscale_unset_watchpoint(target, watchpoint); + } + + xscale->dbr_available++; + + return ERROR_OK; +} + +void xscale_enable_watchpoints(struct target_s *target) +{ + watchpoint_t *watchpoint = target->watchpoints; + + while (watchpoint) + { + if (watchpoint->set == 0) + xscale_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } +} + +void xscale_enable_breakpoints(struct target_s *target) +{ + breakpoint_t *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) + { + if (breakpoint->set == 0) + xscale_set_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } +} + +int xscale_get_reg(reg_t *reg) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + return xscale_read_dcsr(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* 1 = consume register content */ + return xscale_read_tx(arch_info->target, 1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + /* can't read from RX register (host -> debug handler) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) read from TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP read request (command 0x40) */ + xscale_send_u32(target, 0x40); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* read register value */ + xscale_read_tx(target, 1); + buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); + + reg->dirty = 0; + reg->valid = 1; + } + + return ERROR_OK; +} + +int xscale_set_reg(reg_t *reg, u8* buf) +{ + xscale_reg_t *arch_info = reg->arch_info; + target_t *target = arch_info->target; + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + u32 value = buf_get_u32(buf, 0, 32); + + /* DCSR, TX and RX are accessible via JTAG */ + if (strcmp(reg->name, "XSCALE_DCSR") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); + return xscale_write_dcsr(arch_info->target, -1, -1); + } + else if (strcmp(reg->name, "XSCALE_RX") == 0) + { + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); + return xscale_write_rx(arch_info->target); + } + else if (strcmp(reg->name, "XSCALE_TX") == 0) + { + /* can't write to TX register (debug-handler -> host) */ + return ERROR_OK; + } + else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) + { + /* can't (explicitly) write to TXRXCTRL register */ + return ERROR_OK; + } + else /* Other DBG registers have to be transfered by the debug handler */ + { + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(reg->value, 0, 32, value); + } + + return ERROR_OK; +} + +/* convenience wrapper to access XScale specific registers */ +int xscale_set_reg_u32(reg_t *reg, u32 value) +{ + u8 buf[4]; + + buf_set_u32(buf, 0, 32, value); + + return xscale_set_reg(reg, buf); +} + +int xscale_write_dcsr_sw(target_t *target, u32 value) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + reg_t *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; + xscale_reg_t *dcsr_arch_info = dcsr->arch_info; + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); + + /* send CP register value */ + xscale_send_u32(target, value); + buf_set_u32(dcsr->value, 0, 32, value); + + return ERROR_OK; +} + +int xscale_read_trace(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + xscale_trace_data_t **trace_data_p; + + /* 258 words from debug handler + * 256 trace buffer entries + * 2 checkpoint addresses + */ + u32 trace_buffer[258]; + int is_address[256]; + int i, j; + + if (target->state != TARGET_HALTED) + { + WARNING("target must be stopped to read trace data"); + return ERROR_TARGET_NOT_HALTED; + } + + /* send read trace buffer command (command 0x61) */ + xscale_send_u32(target, 0x61); + + /* receive trace buffer content */ + xscale_receive(target, trace_buffer, 258); + + /* parse buffer backwards to identify address entries */ + for (i = 255; i >= 0; i--) + { + is_address[i] = 0; + if (((trace_buffer[i] & 0xf0) == 0x90) || + ((trace_buffer[i] & 0xf0) == 0xd0)) + { + if (i >= 3) + is_address[--i] = 1; + if (i >= 2) + is_address[--i] = 1; + if (i >= 1) + is_address[--i] = 1; + if (i >= 0) + is_address[--i] = 1; + } + } + + + /* search first non-zero entry */ + for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) + ; + + if (j == 256) + { + DEBUG("no trace data collected"); + return ERROR_XSCALE_NO_TRACE_DATA; + } + + for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) + ; + + *trace_data_p = malloc(sizeof(xscale_trace_data_t)); + (*trace_data_p)->next = NULL; + (*trace_data_p)->chkpt0 = trace_buffer[256]; + (*trace_data_p)->chkpt1 = trace_buffer[257]; + (*trace_data_p)->last_instruction = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + (*trace_data_p)->entries = malloc(sizeof(xscale_trace_entry_t) * (256 - j)); + (*trace_data_p)->depth = 256 - j; + + for (i = j; i < 256; i++) + { + (*trace_data_p)->entries[i - j].data = trace_buffer[i]; + if (is_address[i]) + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; + else + (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; + } + + return ERROR_OK; +} + +int xscale_read_instruction(target_t *target, arm_instruction_t *instruction) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int i; + int section = -1; + u32 size_read; + u32 opcode; + int retval; + + if (!xscale->trace.image) + return ERROR_TRACE_IMAGE_UNAVAILABLE; + + /* search for the section the current instruction belongs to */ + for (i = 0; i < xscale->trace.image->num_sections; i++) + { + if ((xscale->trace.image->sections[i].base_address <= xscale->trace.current_pc) && + (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > xscale->trace.current_pc)) + { + section = i; + break; + } + } + + if (section == -1) + { + /* current instruction couldn't be found in the image */ + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + + if (xscale->trace.core_state == ARMV4_5_STATE_ARM) + { + u8 buf[4]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 4, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u32(target, buf); + arm_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else if (xscale->trace.core_state == ARMV4_5_STATE_THUMB) + { + u8 buf[2]; + if ((retval = image_read_section(xscale->trace.image, section, + xscale->trace.current_pc - xscale->trace.image->sections[section].base_address, + 2, buf, &size_read)) != ERROR_OK) + { + ERROR("error while reading instruction: %i", retval); + return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; + } + opcode = target_buffer_get_u16(target, buf); + thumb_evaluate_opcode(opcode, xscale->trace.current_pc, instruction); + } + else + { + ERROR("BUG: unknown core state encountered"); + exit(-1); + } + + return ERROR_OK; +} + +int xscale_branch_address(xscale_trace_data_t *trace_data, int i, u32 *target) +{ + /* if there are less than four entries prior to the indirect branch message + * we can't extract the address */ + if (i < 4) + { + return -1; + } + + *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | + (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); + + return 0; +} + +int xscale_analyze_trace(target_t *target, command_context_t *cmd_ctx) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + int next_pc_ok = 0; + u32 next_pc = 0x0; + xscale_trace_data_t *trace_data = xscale->trace.data; + int retval; + + while (trace_data) + { + int i, chkpt; + int rollover; + int branch; + int exception; + xscale->trace.core_state = ARMV4_5_STATE_ARM; + + chkpt = 0; + rollover = 0; + + for (i = 0; i < trace_data->depth; i++) + { + next_pc_ok = 0; + branch = 0; + exception = 0; + + if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) + continue; + + switch ((trace_data->entries[i].data & 0xf0) >> 4) + { + case 0: /* Exceptions */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + exception = (trace_data->entries[i].data & 0x70) >> 4; + next_pc_ok = 1; + next_pc = (trace_data->entries[i].data & 0xf0) >> 2; + command_print(cmd_ctx, "--- exception %i ---", (trace_data->entries[i].data & 0xf0) >> 4); + break; + case 8: /* Direct Branch */ + branch = 1; + break; + case 9: /* Indirect Branch */ + branch = 1; + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + } + break; + case 13: /* Checkpointed Indirect Branch */ + if (xscale_branch_address(trace_data, i, &next_pc) == 0) + { + next_pc_ok = 1; + if (((chkpt == 0) && (next_pc != trace_data->chkpt0)) + || ((chkpt == 1) && (next_pc != trace_data->chkpt1))) + WARNING("checkpointed indirect branch target address doesn't match checkpoint"); + } + /* explicit fall-through */ + case 12: /* Checkpointed Direct Branch */ + branch = 1; + if (chkpt == 0) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else if (chkpt == 1) + { + next_pc_ok = 1; + next_pc = trace_data->chkpt0; + chkpt++; + } + else + { + WARNING("more than two checkpointed branches encountered"); + } + break; + case 15: /* Roll-over */ + rollover++; + continue; + default: /* Reserved */ + command_print(cmd_ctx, "--- reserved trace message ---"); + ERROR("BUG: trace message %i is reserved", (trace_data->entries[i].data & 0xf0) >> 4); + return ERROR_OK; + } + + if (xscale->trace.pc_ok) + { + int executed = (trace_data->entries[i].data & 0xf) + rollover * 16; + arm_instruction_t instruction; + + if ((exception == 6) || (exception == 7)) + { + /* IRQ or FIQ exception, no instruction executed */ + executed -= 1; + } + + while (executed-- >= 0) + { + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + + /* a precise abort on a load to the PC is included in the incremental + * word count, other instructions causing data aborts are not included + */ + if ((executed == 0) && (exception == 4) + && ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDM))) + { + if ((instruction.type == ARM_LDM) + && ((instruction.info.load_store_multiple.register_list & 0x8000) == 0)) + { + executed--; + } + else if (((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) + && (instruction.info.load_store.Rd != 15)) + { + executed--; + } + } + + /* only the last instruction executed + * (the one that caused the control flow change) + * could be a taken branch + */ + if (((executed == -1) && (branch == 1)) && + (((instruction.type == ARM_B) || + (instruction.type == ARM_BL) || + (instruction.type == ARM_BLX)) && + (instruction.info.b_bl_bx_blx.target_address != -1))) + { + xscale->trace.current_pc = instruction.info.b_bl_bx_blx.target_address; + } + else + { + xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + } + command_print(cmd_ctx, "%s", instruction.text); + } + + rollover = 0; + } + + if (next_pc_ok) + { + xscale->trace.current_pc = next_pc; + xscale->trace.pc_ok = 1; + } + } + + for (; xscale->trace.current_pc < trace_data->last_instruction; xscale->trace.current_pc += (xscale->trace.core_state == ARMV4_5_STATE_ARM) ? 4 : 2) + { + arm_instruction_t instruction; + if ((retval = xscale_read_instruction(target, &instruction)) != ERROR_OK) + { + /* can't continue tracing with no image available */ + if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) + { + return retval; + } + else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) + { + /* TODO: handle incomplete images */ + } + } + command_print(cmd_ctx, "%s", instruction.text); + } + + trace_data = trace_data->next; + } + + return ERROR_OK; +} + +void xscale_build_reg_cache(target_t *target) +{ + /* get pointers to arch-specific information */ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + reg_cache_t **cache_p = register_get_last_cache_p(&target->reg_cache); + xscale_reg_t *arch_info = malloc(sizeof(xscale_reg_arch_info)); + int i; + int num_regs = sizeof(xscale_reg_arch_info) / sizeof(xscale_reg_t); + + (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); + armv4_5->core_cache = (*cache_p); + + /* register a register arch-type for XScale dbg registers only once */ + if (xscale_reg_arch_type == -1) + xscale_reg_arch_type = register_reg_arch_type(xscale_get_reg, xscale_set_reg); + + (*cache_p)->next = malloc(sizeof(reg_cache_t)); + cache_p = &(*cache_p)->next; + + /* fill in values for the xscale reg cache */ + (*cache_p)->name = "XScale registers"; + (*cache_p)->next = NULL; + (*cache_p)->reg_list = malloc(num_regs * sizeof(reg_t)); + (*cache_p)->num_regs = num_regs; + + for (i = 0; i < num_regs; i++) + { + (*cache_p)->reg_list[i].name = xscale_reg_list[i]; + (*cache_p)->reg_list[i].value = calloc(4, 1); + (*cache_p)->reg_list[i].dirty = 0; + (*cache_p)->reg_list[i].valid = 0; + (*cache_p)->reg_list[i].size = 32; + (*cache_p)->reg_list[i].bitfield_desc = NULL; + (*cache_p)->reg_list[i].num_bitfields = 0; + (*cache_p)->reg_list[i].arch_info = &arch_info[i]; + (*cache_p)->reg_list[i].arch_type = xscale_reg_arch_type; + arch_info[i] = xscale_reg_arch_info[i]; + arch_info[i].target = target; + } + + xscale->reg_cache = (*cache_p); +} + +int xscale_init_target(struct command_context_s *cmd_ctx, struct target_s *target) +{ + if (startup_mode != DAEMON_RESET) + { + ERROR("XScale target requires a reset"); + ERROR("Reset target to enable debug"); + } + + /* assert TRST once during startup */ + jtag_add_reset(1, 0); + jtag_add_sleep(5000); + jtag_add_reset(0, 0); + jtag_execute_queue(); + + return ERROR_OK; +} + +int xscale_quit() +{ + + return ERROR_OK; +} + +int xscale_init_arch_info(target_t *target, xscale_common_t *xscale, int chain_pos, char *variant) +{ + armv4_5_common_t *armv4_5; + u32 high_reset_branch, low_reset_branch; + int i; + + armv4_5 = &xscale->armv4_5_common; + + /* store architecture specfic data (none so far) */ + xscale->arch_info = NULL; + xscale->common_magic = XSCALE_COMMON_MAGIC; + + /* remember the variant (PXA25x, PXA27x, IXP42x, ...) */ + xscale->variant = strdup(variant); + + /* prepare JTAG information for the new target */ + xscale->jtag_info.chain_pos = chain_pos; + jtag_register_event_callback(xscale_jtag_callback, target); + + xscale->jtag_info.dbgrx = 0x02; + xscale->jtag_info.dbgtx = 0x10; + xscale->jtag_info.dcsr = 0x09; + xscale->jtag_info.ldic = 0x07; + + if ((strcmp(xscale->variant, "pxa250") == 0) || + (strcmp(xscale->variant, "pxa255") == 0) || + (strcmp(xscale->variant, "pxa26x") == 0)) + { + xscale->jtag_info.ir_length = 5; + } + else if ((strcmp(xscale->variant, "pxa27x") == 0) || + (strcmp(xscale->variant, "ixp42x") == 0) || + (strcmp(xscale->variant, "ixp45x") == 0) || + (strcmp(xscale->variant, "ixp46x") == 0)) + { + xscale->jtag_info.ir_length = 7; + } + + /* the debug handler isn't installed (and thus not running) at this time */ + xscale->handler_installed = 0; + xscale->handler_running = 0; + xscale->handler_address = 0xfe000800; + + /* clear the vectors we keep locally for reference */ + memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); + memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); + + /* no user-specified vectors have been configured yet */ + xscale->static_low_vectors_set = 0x0; + xscale->static_high_vectors_set = 0x0; + + /* calculate branches to debug handler */ + low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; + high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; + + xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); + xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); + + for (i = 1; i <= 7; i++) + { + xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); + xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); + } + + /* 64kB aligned region used for DCache cleaning */ + xscale->cache_clean_address = 0xfffe0000; + + xscale->hold_rst = 0; + xscale->external_debug_break = 0; + + xscale->force_hw_bkpts = 1; + + xscale->ibcr_available = 2; + xscale->ibcr0_used = 0; + xscale->ibcr1_used = 0; + + xscale->dbr_available = 2; + xscale->dbr0_used = 0; + xscale->dbr1_used = 0; + + xscale->arm_bkpt = ARMV5_BKPT(0x0); + xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; + + xscale->vector_catch = 0x1; + + xscale->trace.capture_status = TRACE_IDLE; + xscale->trace.data = NULL; + xscale->trace.image = NULL; + xscale->trace.buffer_enabled = 0; + xscale->trace.buffer_fill = 0; + + /* prepare ARMv4/5 specific information */ + armv4_5->arch_info = xscale; + armv4_5->read_core_reg = xscale_read_core_reg; + armv4_5->write_core_reg = xscale_write_core_reg; + armv4_5->full_context = xscale_full_context; + + armv4_5_init_arch_info(target, armv4_5); + + xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; + xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; + xscale->armv4_5_mmu.read_memory = xscale_read_memory; + xscale->armv4_5_mmu.write_memory = xscale_write_memory; + xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; + xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; + xscale->armv4_5_mmu.has_tiny_pages = 1; + xscale->armv4_5_mmu.mmu_enabled = 0; + + xscale->fast_memory_access = 0; + + return ERROR_OK; +} + +/* target xscale */ +int xscale_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct target_s *target) +{ + int chain_pos; + char *variant = NULL; + xscale_common_t *xscale = malloc(sizeof(xscale_common_t)); + + if (argc < 5) + { + ERROR("'target xscale' requires four arguments: "); + return ERROR_OK; + } + + chain_pos = strtoul(args[3], NULL, 0); + + variant = args[4]; + + xscale_init_arch_info(target, xscale, chain_pos, variant); + xscale_build_reg_cache(target); + + return ERROR_OK; +} + +int xscale_handle_debug_handler_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 handler_address; + + if (argc < 2) + { + ERROR("'xscale debug_handler
' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + handler_address = strtoul(args[1], NULL, 0); + + if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || + ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) + { + xscale->handler_address = handler_address; + } + else + { + ERROR("xscale debug_handler
must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); + } + + return ERROR_OK; +} + +int xscale_handle_cache_clean_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = NULL; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + u32 cache_clean_address; + + if (argc < 2) + { + ERROR("'xscale cache_clean_address
' command takes two required operands"); + return ERROR_OK; + } + + if ((target = get_target_by_num(strtoul(args[0], NULL, 0))) == NULL) + { + ERROR("no target '%s' configured", args[0]); + return ERROR_OK; + } + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + cache_clean_address = strtoul(args[1], NULL, 0); + + if (cache_clean_address & 0xffff) + { + ERROR("xscale cache_clean_address
must be 64kb aligned"); + } + else + { + xscale->cache_clean_address = cache_clean_address; + } + + return ERROR_OK; +} + +int xscale_handle_cache_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + return armv4_5_handle_cache_info_command(cmd_ctx, &xscale->armv4_5_mmu.armv4_5_cache); +} + +static int xscale_virt2phys(struct target_s *target, u32 virtual, u32 *physical) +{ + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + int retval; + int type; + u32 cb; + int domain; + u32 ap; + + if ((retval = xscale_get_arch_pointers(target, &armv4_5, &xscale)) != ERROR_OK) + { + return retval; + } + u32 ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap); + if (type == -1) + { + return ret; + } + + *physical = ret; + return ERROR_OK; +} + +static int xscale_mmu(struct target_s *target, int *enabled) +{ + armv4_5_common_t *armv4_5 = target->arch_info; + xscale_common_t *xscale = armv4_5->arch_info; + + if (target->state != TARGET_HALTED) + { + ERROR("Target not halted"); + return ERROR_TARGET_INVALID; + } + + *enabled = xscale->armv4_5_mmu.mmu_enabled; + return ERROR_OK; +} + +int xscale_handle_mmu_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 1, 0, 0); + xscale->armv4_5_mmu.mmu_enabled = 0; + } + } + + command_print(cmd_ctx, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_idcache_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + int icache = 0, dcache = 0; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (strcmp(cmd, "icache") == 0) + icache = 1; + else if (strcmp(cmd, "dcache") == 0) + dcache = 1; + + if (argc >= 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale_enable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 1; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale_disable_mmu_caches(target, 0, dcache, icache); + + if (icache) + xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + else if (dcache) + xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; + } + } + + if (icache) + command_print(cmd_ctx, "icache %s", (xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled) ? "enabled" : "disabled"); + + if (dcache) + command_print(cmd_ctx, "dcache %s", (xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_vector_catch_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale vector_catch [mask]"); + } + else + { + xscale->vector_catch = strtoul(args[0], NULL, 0); + buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); + xscale_write_dcsr(target, -1, -1); + } + + command_print(cmd_ctx, "vector catch mask: 0x%2.2x", xscale->vector_catch); + + return ERROR_OK; +} + +int xscale_handle_force_hw_bkpts_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 1; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->force_hw_bkpts = 0; + } + else + { + command_print(cmd_ctx, "usage: xscale force_hw_bkpts "); + } + + command_print(cmd_ctx, "force hardware breakpoints %s", (xscale->force_hw_bkpts) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_handle_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + u32 dcsr_value; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if ((argc >= 1) && (strcmp("enable", args[0]) == 0)) + { + xscale_trace_data_t *td, *next_td; + xscale->trace.buffer_enabled = 1; + + /* free old trace data */ + td = xscale->trace.data; + while (td) + { + next_td = td->next; + + if (td->entries) + free(td->entries); + free(td); + td = next_td; + } + xscale->trace.data = NULL; + } + else if ((argc >= 1) && (strcmp("disable", args[0]) == 0)) + { + xscale->trace.buffer_enabled = 0; + } + + if ((argc >= 2) && (strcmp("fill", args[1]) == 0)) + { + if (argc >= 3) + xscale->trace.buffer_fill = strtoul(args[2], NULL, 0); + else + xscale->trace.buffer_fill = 1; + } + else if ((argc >= 2) && (strcmp("wrap", args[1]) == 0)) + { + xscale->trace.buffer_fill = -1; + } + + if (xscale->trace.buffer_enabled) + { + /* if we enable the trace buffer in fill-once + * mode we know the address of the first instruction */ + xscale->trace.pc_ok = 1; + xscale->trace.current_pc = buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32); + } + else + { + /* otherwise the address is unknown, and we have no known good PC */ + xscale->trace.pc_ok = 0; + } + + command_print(cmd_ctx, "trace buffer %s (%s)", + (xscale->trace.buffer_enabled) ? "enabled" : "disabled", + (xscale->trace.buffer_fill > 0) ? "fill" : "wrap"); + + dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); + if (xscale->trace.buffer_fill >= 0) + xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); + else + xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); + + return ERROR_OK; +} + +int xscale_handle_trace_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target; + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale trace_image [base address] [type]"); + return ERROR_OK; + } + + target = get_current_target(cmd_ctx); + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (xscale->trace.image) + { + image_close(xscale->trace.image); + free(xscale->trace.image); + command_print(cmd_ctx, "previously loaded image found and closed"); + } + + xscale->trace.image = malloc(sizeof(image_t)); + xscale->trace.image->base_address_set = 0; + xscale->trace.image->start_address_set = 0; + + /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ + if (argc >= 2) + { + xscale->trace.image->base_address_set = 1; + xscale->trace.image->base_address = strtoul(args[1], NULL, 0); + } + else + { + xscale->trace.image->base_address_set = 0; + } + + if (image_open(xscale->trace.image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK) + { + command_print(cmd_ctx, "image opening error: %s", xscale->trace.image->error_str); + free(xscale->trace.image); + xscale->trace.image = NULL; + return ERROR_OK; + } + + return ERROR_OK; +} + +int xscale_handle_dump_trace_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + xscale_trace_data_t *trace_data; + fileio_t file; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + + if (argc < 1) + { + command_print(cmd_ctx, "usage: xscale dump_trace "); + return ERROR_OK; + } + + trace_data = xscale->trace.data; + + if (!trace_data) + { + command_print(cmd_ctx, "no trace data collected"); + return ERROR_OK; + } + + if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) + { + command_print(cmd_ctx, "file open error: %s", file.error_str); + return ERROR_OK; + } + + while (trace_data) + { + int i; + + fileio_write_u32(&file, trace_data->chkpt0); + fileio_write_u32(&file, trace_data->chkpt1); + fileio_write_u32(&file, trace_data->last_instruction); + fileio_write_u32(&file, trace_data->depth); + + for (i = 0; i < trace_data->depth; i++) + fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); + + trace_data = trace_data->next; + } + + fileio_close(&file); + + return ERROR_OK; +} + +int xscale_handle_analyze_trace_buffer_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + xscale_analyze_trace(target, cmd_ctx); + + return ERROR_OK; +} + +int xscale_handle_cp15(command_context_t *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (target->state != TARGET_HALTED) + { + command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd); + return ERROR_OK; + } + u32 reg_no = 0; + reg_t *reg = NULL; + if(argc > 0) + { + reg_no = strtoul(args[0], NULL, 0); + /*translate from xscale cp15 register no to openocd register*/ + switch(reg_no) + { + case 0: + reg_no = XSCALE_MAINID; + break; + case 1: + reg_no = XSCALE_CTRL; + break; + case 2: + reg_no = XSCALE_TTB; + break; + case 3: + reg_no = XSCALE_DAC; + break; + case 5: + reg_no = XSCALE_FSR; + break; + case 6: + reg_no = XSCALE_FAR; + break; + case 13: + reg_no = XSCALE_PID; + break; + case 15: + reg_no = XSCALE_CPACCESS; + break; + default: + command_print(cmd_ctx, "invalid register number"); + return ERROR_INVALID_ARGUMENTS; + } + reg = &xscale->reg_cache->reg_list[reg_no]; + + } + if(argc == 1) + { + u32 value; + + /* read cp15 control register */ + xscale_get_reg(reg); + value = buf_get_u32(reg->value, 0, 32); + command_print(cmd_ctx, "%s (/%i): 0x%x", reg->name, reg->size, value); + } + else if(argc == 2) + { + + u32 value = strtoul(args[1], NULL, 0); + + /* send CP write request (command 0x41) */ + xscale_send_u32(target, 0x41); + + /* send CP register number */ + xscale_send_u32(target, reg_no); + + /* send CP register value */ + xscale_send_u32(target, value); + + /* execute cpwait to ensure outstanding operations complete */ + xscale_send_u32(target, 0x53); + } + else + { + command_print(cmd_ctx, "usage: cp15 [register]<, [value]>"); + } + + return ERROR_OK; +} + +int handle_xscale_fast_memory_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) +{ + target_t *target = get_current_target(cmd_ctx); + armv4_5_common_t *armv4_5; + xscale_common_t *xscale; + + if (xscale_get_arch_pointers(target, &armv4_5, &xscale) != ERROR_OK) + { + return ERROR_OK; + } + + if (argc == 1) + { + if (strcmp("enable", args[0]) == 0) + { + xscale->fast_memory_access = 1; + } + else if (strcmp("disable", args[0]) == 0) + { + xscale->fast_memory_access = 0; + } + else + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (argc!=0) + { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(cmd_ctx, "fast memory access is %s", (xscale->fast_memory_access) ? "enabled" : "disabled"); + + return ERROR_OK; +} + +int xscale_register_commands(struct command_context_s *cmd_ctx) +{ + command_t *xscale_cmd; + + xscale_cmd = register_command(cmd_ctx, NULL, "xscale", NULL, COMMAND_ANY, "xscale specific commands"); + + register_command(cmd_ctx, xscale_cmd, "debug_handler", xscale_handle_debug_handler_command, COMMAND_ANY, "'xscale debug_handler
' command takes two required operands"); + register_command(cmd_ctx, xscale_cmd, "cache_clean_address", xscale_handle_cache_clean_address_command, COMMAND_ANY, NULL); + + register_command(cmd_ctx, xscale_cmd, "cache_info", xscale_handle_cache_info_command, COMMAND_EXEC, NULL); + register_command(cmd_ctx, xscale_cmd, "mmu", xscale_handle_mmu_command, COMMAND_EXEC, "['enable'|'disable'] the MMU"); + register_command(cmd_ctx, xscale_cmd, "icache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the ICache"); + register_command(cmd_ctx, xscale_cmd, "dcache", xscale_handle_idcache_command, COMMAND_EXEC, "['enable'|'disable'] the DCache"); + + register_command(cmd_ctx, xscale_cmd, "vector_catch", xscale_handle_idcache_command, COMMAND_EXEC, " of vectors that should be catched"); + + register_command(cmd_ctx, xscale_cmd, "trace_buffer", xscale_handle_trace_buffer_command, COMMAND_EXEC, " ['fill' [n]|'wrap']"); + + register_command(cmd_ctx, xscale_cmd, "dump_trace", xscale_handle_dump_trace_command, COMMAND_EXEC, "dump content of trace buffer to "); + register_command(cmd_ctx, xscale_cmd, "analyze_trace", xscale_handle_analyze_trace_buffer_command, COMMAND_EXEC, "analyze content of trace buffer"); + register_command(cmd_ctx, xscale_cmd, "trace_image", xscale_handle_trace_image_command, + COMMAND_EXEC, "load image from [base address]"); + + register_command(cmd_ctx, xscale_cmd, "cp15", xscale_handle_cp15, COMMAND_EXEC, "access coproc 15 [value]"); + register_command(cmd_ctx, xscale_cmd, "fast_memory_access", handle_xscale_fast_memory_access_command, + COMMAND_ANY, "use fast memory accesses instead of slower but potentially unsafe slow accesses "); + + armv4_5_register_commands(cmd_ctx); + + return ERROR_OK; +} diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index 48ca0645..298377d9 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -188,9 +188,9 @@ int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **arg field.in_handler = NULL; field.in_handler_priv = NULL; if (device == -1) - jtag_add_plain_ir_scan(1, &field, TAP_PI, NULL); + jtag_add_plain_ir_scan(1, &field, TAP_PI); else - jtag_add_ir_scan(1, &field, TAP_PI, NULL); + jtag_add_ir_scan(1, &field, TAP_PI); if (jtag_execute_queue() != ERROR_OK) { tdo_mismatch = 1; @@ -228,9 +228,9 @@ int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **arg field.in_value = NULL; jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL); if (device == -1) - jtag_add_plain_dr_scan(1, &field, TAP_PD, NULL); + jtag_add_plain_dr_scan(1, &field, TAP_PD); else - jtag_add_dr_scan(1, &field, TAP_PD, NULL); + jtag_add_dr_scan(1, &field, TAP_PD); if (jtag_execute_queue() != ERROR_OK) { tdo_mismatch = 1; @@ -302,9 +302,9 @@ int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **arg field.in_value = NULL; jtag_set_check_value(&field, dr_in_buf, dr_in_mask, NULL); if (device == -1) - jtag_add_plain_dr_scan(1, &field, TAP_PD, NULL); + jtag_add_plain_dr_scan(1, &field, TAP_PD); else - jtag_add_dr_scan(1, &field, TAP_PD, NULL); + jtag_add_dr_scan(1, &field, TAP_PD); if (jtag_execute_queue() != ERROR_OK) { tdo_mismatch = 1; @@ -428,9 +428,9 @@ int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, char **arg field.in_handler = NULL; field.in_handler_priv = NULL; if (device == -1) - jtag_add_plain_ir_scan(1, &field, xsvf_to_tap[xendir], NULL); + jtag_add_plain_ir_scan(1, &field, xsvf_to_tap[xendir]); else - jtag_add_ir_scan(1, &field, xsvf_to_tap[xendir], NULL); + jtag_add_ir_scan(1, &field, xsvf_to_tap[xendir]); } free(ir_buf); }