/*************************************************************************** * Copyright (C) 2013 Andes Technology * * Hsiangkai Wang * * * * 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., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "nds32_reg.h" #include "nds32_disassembler.h" #include "nds32.h" #include "nds32_aice.h" #include "nds32_v3_common.h" static struct nds32_v3_common_callback *v3_common_callback; static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no) { if (reg_no == PC) return IR11; return reg_no; } static int nds32_v3_get_debug_reason(struct nds32 *nds32, uint32_t *reason) { uint32_t edmsw; struct aice_port_s *aice = target_to_aice(nds32->target); aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw); *reason = (edmsw >> 12) & 0x0F; return ERROR_OK; } /** * Save processor state. This is called after a HALT instruction * succeeds, and on other occasions the processor enters debug mode * (breakpoint, watchpoint, etc). */ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) { LOG_DEBUG("nds32_v3_debug_entry"); jtag_poll_set_enabled(false); enum target_state backup_state = nds32->target->state; nds32->target->state = TARGET_HALTED; if (nds32->init_arch_info_after_halted == false) { /* init architecture info according to config registers */ CHECK_RETVAL(nds32_config(nds32)); nds32->init_arch_info_after_halted = true; } /* REVISIT entire cache should already be invalid !!! */ register_cache_invalidate(nds32->core_cache); /* deactivate all hardware breakpoints */ CHECK_RETVAL(v3_common_callback->deactivate_hardware_breakpoint(nds32->target)); if (enable_watchpoint) CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target)); if (ERROR_OK != nds32_examine_debug_reason(nds32)) { nds32->target->state = backup_state; /* re-activate all hardware breakpoints & watchpoints */ CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(nds32->target)); if (enable_watchpoint) CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target)); jtag_poll_set_enabled(true); return ERROR_FAIL; } /* Save registers. */ nds32_full_context(nds32); /* check interrupt level */ v3_common_callback->check_interrupt_stack(nds32); return ERROR_OK; } /** * Restore processor state. */ static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint) { LOG_DEBUG("nds32_v3_leave_debug_state"); struct target *target = nds32->target; /* activate all hardware breakpoints */ CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(target)); if (enable_watchpoint) { /* activate all watchpoints */ CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(target)); } /* restore interrupt stack */ v3_common_callback->restore_interrupt_stack(nds32); /* REVISIT once we start caring about MMU and cache state, * address it here ... */ /* restore PSW, PC, and R0 ... after flushing any modified * registers. */ CHECK_RETVAL(nds32_restore_context(target)); /* enable polling */ jtag_poll_set_enabled(true); return ERROR_OK; } static int nds32_v3_get_exception_address(struct nds32 *nds32, uint32_t *address, uint32_t reason) { LOG_DEBUG("nds32_v3_get_exception_address"); struct aice_port_s *aice = target_to_aice(nds32->target); struct target *target = nds32->target; uint32_t edmsw; uint32_t edm_cfg; uint32_t match_bits; uint32_t match_count; int32_t i; static int32_t number_of_hard_break; if (number_of_hard_break == 0) { aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); number_of_hard_break = (edm_cfg & 0x7) + 1; } aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw); /* clear matching bits (write-one-clear) */ aice_write_debug_reg(aice, NDS_EDM_SR_EDMSW, edmsw); match_bits = (edmsw >> 4) & 0xFF; match_count = 0; for (i = 0 ; i < number_of_hard_break ; i++) { if (match_bits & (1 << i)) { aice_read_debug_reg(aice, NDS_EDM_SR_BPA0 + i, address); match_count++; } } if (match_count > 1) { /* multiple hits */ *address = 0; return ERROR_OK; } else if (match_count == 1) { uint32_t val_pc; uint32_t opcode; struct nds32_instruction instruction; struct watchpoint *wp; bool hit; nds32_get_mapped_reg(nds32, PC, &val_pc); if ((NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE == reason) || (NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE == reason)) { if (edmsw & 0x4) /* check EDMSW.IS_16BIT */ val_pc -= 2; else val_pc -= 4; } nds32_read_opcode(nds32, val_pc, &opcode); nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction); LOG_DEBUG("PC: 0x%08x, access start: 0x%08x, end: 0x%08x", val_pc, instruction.access_start, instruction.access_end); /* check if multiple hits in the access range */ uint32_t in_range_watch_count = 0; for (wp = target->watchpoints; wp; wp = wp->next) { if ((instruction.access_start <= wp->address) && (wp->address < instruction.access_end)) in_range_watch_count++; } if (in_range_watch_count > 1) { /* Hit LSMW instruction. */ *address = 0; return ERROR_OK; } /* dispel false match */ hit = false; for (wp = target->watchpoints; wp; wp = wp->next) { if (((*address ^ wp->address) & (~wp->mask)) == 0) { uint32_t watch_start; uint32_t watch_end; watch_start = wp->address; watch_end = wp->address + wp->length; if ((watch_end <= instruction.access_start) || (instruction.access_end <= watch_start)) continue; hit = true; break; } } if (hit) return ERROR_OK; else return ERROR_FAIL; } else if (match_count == 0) { /* global stop is precise exception */ if ((NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP == reason) && nds32->global_stop) { /* parse instruction to get correct access address */ uint32_t val_pc; uint32_t opcode; struct nds32_instruction instruction; nds32_get_mapped_reg(nds32, PC, &val_pc); nds32_read_opcode(nds32, val_pc, &opcode); nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction); *address = instruction.access_start; return ERROR_OK; } } *address = 0xFFFFFFFF; return ERROR_FAIL; } void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback) { v3_common_callback = callback; } /** target_type functions: */ /* target request support */ int nds32_v3_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { /* AndesCore could use DTR register to communicate with OpenOCD * to output messages * Target data will be put in buffer * The format of DTR is as follow * DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd * target_req_cmd has three possible values: * TARGET_REQ_TRACEMSG * TARGET_REQ_DEBUGMSG * TARGET_REQ_DEBUGCHAR * if size == 0, target will call target_asciimsg(), * else call target_hexmsg() */ LOG_WARNING("Not implemented: %s", __func__); return ERROR_OK; } int nds32_v3_soft_reset_halt(struct target *target) { struct aice_port_s *aice = target_to_aice(target); return aice_assert_srst(aice, AICE_RESET_HOLD); } int nds32_v3_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { LOG_WARNING("Not implemented: %s", __func__); return ERROR_FAIL; } int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32) { nds32->register_map = nds32_v3_register_mapping; nds32->get_debug_reason = nds32_v3_get_debug_reason; nds32->enter_debug_state = nds32_v3_debug_entry; nds32->leave_debug_state = nds32_v3_leave_debug_state; nds32->get_watched_address = nds32_v3_get_exception_address; /* Init target->arch_info in nds32_init_arch_info(). * After this, user could use target_to_nds32() to get nds32 object */ nds32_init_arch_info(target, nds32); return ERROR_OK; } int nds32_v3_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { LOG_WARNING("Not implemented: %s", __func__); return ERROR_FAIL; } int nds32_v3_read_buffer(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); struct nds32_memory *memory = &(nds32->memory); if ((NDS_MEMORY_ACC_CPU == memory->access_channel) && (target->state != TARGET_HALTED)) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ /* When DEX is set to one, hardware will enforce the following behavior without * modifying the corresponding control bits in PSW. * * Disable all interrupts * Become superuser mode * Turn off IT/DT * Use MMU_CFG.DE as the data access endian * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted * Disable audio special features * Disable inline function call * * Because hardware will turn off IT/DT by default, it MUST translate virtual address * to physical address. */ if (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) address = physical_address; else return ERROR_FAIL; return nds32_read_buffer(target, address, size, buffer); } int nds32_v3_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); struct nds32_memory *memory = &(nds32->memory); if ((NDS_MEMORY_ACC_CPU == memory->access_channel) && (target->state != TARGET_HALTED)) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ /* When DEX is set to one, hardware will enforce the following behavior without * modifying the corresponding control bits in PSW. * * Disable all interrupts * Become superuser mode * Turn off IT/DT * Use MMU_CFG.DE as the data access endian * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted * Disable audio special features * Disable inline function call * * Because hardware will turn off IT/DT by default, it MUST translate virtual address * to physical address. */ if (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) address = physical_address; else return ERROR_FAIL; return nds32_write_buffer(target, address, size, buffer); } int nds32_v3_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); struct nds32_memory *memory = &(nds32->memory); if ((NDS_MEMORY_ACC_CPU == memory->access_channel) && (target->state != TARGET_HALTED)) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ /* When DEX is set to one, hardware will enforce the following behavior without * modifying the corresponding control bits in PSW. * * Disable all interrupts * Become superuser mode * Turn off IT/DT * Use MMU_CFG.DE as the data access endian * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted * Disable audio special features * Disable inline function call * * Because hardware will turn off IT/DT by default, it MUST translate virtual address * to physical address. */ if (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) address = physical_address; else return ERROR_FAIL; int result; result = nds32_read_memory(target, address, size, count, buffer); return result; } int nds32_v3_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct nds32 *nds32 = target_to_nds32(target); struct nds32_memory *memory = &(nds32->memory); if ((NDS_MEMORY_ACC_CPU == memory->access_channel) && (target->state != TARGET_HALTED)) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t physical_address; /* BUG: If access range crosses multiple pages, the translation will not correct * for second page or so. */ /* When DEX is set to one, hardware will enforce the following behavior without * modifying the corresponding control bits in PSW. * * Disable all interrupts * Become superuser mode * Turn off IT/DT * Use MMU_CFG.DE as the data access endian * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted * Disable audio special features * Disable inline function call * * Because hardware will turn off IT/DT by default, it MUST translate virtual address * to physical address. */ if (ERROR_OK == target->type->virt2phys(target, address, &physical_address)) address = physical_address; else return ERROR_FAIL; return nds32_write_memory(target, address, size, count, buffer); } int nds32_v3_init_target(struct command_context *cmd_ctx, struct target *target) { /* Initialize anything we can set up without talking to the target */ struct nds32 *nds32 = target_to_nds32(target); nds32_init(nds32); return ERROR_OK; }