nds32: drop it, together with aice adapter driver
The target nds32 and its companion adapter aice have not received
any real improvement since 2013.
It has been hard to keep them aligned during the evolution of
OpenOCD code, with no way for maintainers to really check if they
are still working.
No real documentation is present for them in OpenOCD.
The nds32 code triggers ~50 errors/warnings with scan-build.
The arch nds32 has been dropped from Linux kernel v5.18-rc1.
For all the reasons above, this code has been deprecated with
commit 2e5df83de7 ("nds32: deprecate it, together with aice
adapter driver") and tagged to be dropped before v0.13.0.
Let it r.i.p. in OpenOCD git history.
While there, drop from checkpatch list the camelcase symbols that
where only used in this code.
Change-Id: Ide52a217f2228e9da2f1cc5036c48f3536f26952
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7382
Tested-by: jenkins
This commit is contained in:
@@ -19,7 +19,6 @@ noinst_LTLIBRARIES += %D%/libtarget.la
|
||||
$(ARM_MISC_SRC) \
|
||||
$(AVR32_SRC) \
|
||||
$(MIPS32_SRC) \
|
||||
$(NDS32_SRC) \
|
||||
$(STM8_SRC) \
|
||||
$(INTEL_IA32_SRC) \
|
||||
$(ESIRISC_SRC) \
|
||||
@@ -134,18 +133,6 @@ MIPS64_SRC = \
|
||||
%D%/trace.c \
|
||||
%D%/mips_ejtag.c
|
||||
|
||||
NDS32_SRC = \
|
||||
%D%/nds32.c \
|
||||
%D%/nds32_reg.c \
|
||||
%D%/nds32_cmd.c \
|
||||
%D%/nds32_disassembler.c \
|
||||
%D%/nds32_tlb.c \
|
||||
%D%/nds32_v2.c \
|
||||
%D%/nds32_v3_common.c \
|
||||
%D%/nds32_v3.c \
|
||||
%D%/nds32_v3m.c \
|
||||
%D%/nds32_aice.c
|
||||
|
||||
STM8_SRC = \
|
||||
%D%/stm8.c
|
||||
|
||||
@@ -235,18 +222,6 @@ ARC_SRC = \
|
||||
%D%/avr32_jtag.h \
|
||||
%D%/avr32_mem.h \
|
||||
%D%/avr32_regs.h \
|
||||
%D%/nds32.h \
|
||||
%D%/nds32_cmd.h \
|
||||
%D%/nds32_disassembler.h \
|
||||
%D%/nds32_edm.h \
|
||||
%D%/nds32_insn.h \
|
||||
%D%/nds32_reg.h \
|
||||
%D%/nds32_tlb.h \
|
||||
%D%/nds32_v2.h \
|
||||
%D%/nds32_v3_common.h \
|
||||
%D%/nds32_v3.h \
|
||||
%D%/nds32_v3m.h \
|
||||
%D%/nds32_aice.h \
|
||||
%D%/semihosting_common.h \
|
||||
%D%/stm8.h \
|
||||
%D%/lakemont.h \
|
||||
@@ -265,4 +240,4 @@ ARC_SRC = \
|
||||
include %D%/openrisc/Makefile.am
|
||||
include %D%/riscv/Makefile.am
|
||||
include %D%/xtensa/Makefile.am
|
||||
include %D%/espressif/Makefile.am
|
||||
include %D%/espressif/Makefile.am
|
||||
|
||||
2613
src/target/nds32.c
2613
src/target/nds32.c
File diff suppressed because it is too large
Load Diff
@@ -1,447 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_H
|
||||
#define OPENOCD_TARGET_NDS32_H
|
||||
|
||||
#include <jtag/jtag.h>
|
||||
#include "target.h"
|
||||
#include "target_type.h"
|
||||
#include "register.h"
|
||||
#include "breakpoints.h"
|
||||
#include "nds32_reg.h"
|
||||
#include "nds32_insn.h"
|
||||
#include "nds32_edm.h"
|
||||
|
||||
#define NDS32_EDM_OPERATION_MAX_NUM 64
|
||||
|
||||
#define CHECK_RETVAL(action) \
|
||||
do { \
|
||||
int __retval = (action); \
|
||||
if (__retval != ERROR_OK) { \
|
||||
LOG_DEBUG("error while calling \"%s\"", \
|
||||
# action); \
|
||||
return __retval; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Holds the interface to Andes cores.
|
||||
*/
|
||||
|
||||
extern const char *nds32_debug_type_name[11];
|
||||
|
||||
enum nds32_debug_reason {
|
||||
NDS32_DEBUG_BREAK = 0,
|
||||
NDS32_DEBUG_BREAK_16,
|
||||
NDS32_DEBUG_INST_BREAK,
|
||||
NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE,
|
||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE,
|
||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE,
|
||||
NDS32_DEBUG_DEBUG_INTERRUPT,
|
||||
NDS32_DEBUG_HARDWARE_SINGLE_STEP,
|
||||
NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE,
|
||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE,
|
||||
NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP,
|
||||
};
|
||||
|
||||
#define NDS32_STRUCT_STAT_SIZE 60
|
||||
#define NDS32_STRUCT_TIMEVAL_SIZE 8
|
||||
|
||||
enum nds32_syscall_id {
|
||||
NDS32_SYSCALL_UNDEFINED = 0,
|
||||
NDS32_SYSCALL_EXIT = 1,
|
||||
NDS32_SYSCALL_OPEN = 2,
|
||||
NDS32_SYSCALL_CLOSE = 3,
|
||||
NDS32_SYSCALL_READ = 4,
|
||||
NDS32_SYSCALL_WRITE = 5,
|
||||
NDS32_SYSCALL_LSEEK = 6,
|
||||
NDS32_SYSCALL_UNLINK = 7,
|
||||
NDS32_SYSCALL_RENAME = 3001,
|
||||
NDS32_SYSCALL_FSTAT = 10,
|
||||
NDS32_SYSCALL_STAT = 15,
|
||||
NDS32_SYSCALL_GETTIMEOFDAY = 19,
|
||||
NDS32_SYSCALL_ISATTY = 3002,
|
||||
NDS32_SYSCALL_SYSTEM = 3003,
|
||||
NDS32_SYSCALL_ERRNO = 6001,
|
||||
};
|
||||
|
||||
#define NDS32_COMMON_MAGIC 0xADE5ADE5U
|
||||
|
||||
struct nds32_edm {
|
||||
|
||||
/** EDM_CFG.VER, indicate the EDM version */
|
||||
int version;
|
||||
|
||||
/** The number of hardware breakpoints */
|
||||
int breakpoint_num;
|
||||
|
||||
/** EDM_CFG.DALM, indicate if direct local memory access
|
||||
* feature is supported or not */
|
||||
bool direct_access_local_memory;
|
||||
|
||||
/** Support ACC_CTL register */
|
||||
bool access_control;
|
||||
|
||||
/** */
|
||||
bool support_max_stop;
|
||||
};
|
||||
|
||||
struct nds32_cache {
|
||||
|
||||
/** enable cache or not */
|
||||
bool enable;
|
||||
|
||||
/** cache sets per way */
|
||||
int set;
|
||||
|
||||
/** cache ways */
|
||||
int way;
|
||||
|
||||
/** cache line size */
|
||||
int line_size;
|
||||
|
||||
/** cache locking support */
|
||||
bool lock_support;
|
||||
};
|
||||
|
||||
struct nds32_memory {
|
||||
|
||||
/** ICache */
|
||||
struct nds32_cache icache;
|
||||
|
||||
/** DCache */
|
||||
struct nds32_cache dcache;
|
||||
|
||||
/** On-chip instruction local memory base */
|
||||
int ilm_base;
|
||||
|
||||
/** On-chip instruction local memory size */
|
||||
int ilm_size;
|
||||
|
||||
/** ILM base register alignment version */
|
||||
int ilm_align_ver;
|
||||
|
||||
/** DLM is enabled or not */
|
||||
bool ilm_enable;
|
||||
|
||||
/** DLM start address */
|
||||
int ilm_start;
|
||||
|
||||
/** DLM end address */
|
||||
int ilm_end;
|
||||
|
||||
/** On-chip data local memory base */
|
||||
int dlm_base;
|
||||
|
||||
/** On-chip data local memory size */
|
||||
int dlm_size;
|
||||
|
||||
/** DLM base register alignment version */
|
||||
int dlm_align_ver;
|
||||
|
||||
/** DLM is enabled or not */
|
||||
bool dlm_enable;
|
||||
|
||||
/** DLM start address */
|
||||
int dlm_start;
|
||||
|
||||
/** DLM end address */
|
||||
int dlm_end;
|
||||
|
||||
/** Memory access method */
|
||||
enum nds_memory_access access_channel;
|
||||
|
||||
/** Memory access mode */
|
||||
enum nds_memory_select mode;
|
||||
|
||||
/** Address translation */
|
||||
bool address_translation;
|
||||
};
|
||||
|
||||
struct nds32_cpu_version {
|
||||
bool performance_extension;
|
||||
bool _16bit_extension;
|
||||
bool performance_extension_2;
|
||||
bool cop_fpu_extension;
|
||||
bool string_extension;
|
||||
|
||||
int revision;
|
||||
int cpu_id_family;
|
||||
int cpu_id_version;
|
||||
};
|
||||
|
||||
struct nds32_mmu_config {
|
||||
int memory_protection;
|
||||
int memory_protection_version;
|
||||
bool fully_associative_tlb;
|
||||
int tlb_size;
|
||||
int tlb_ways;
|
||||
int tlb_sets;
|
||||
bool _8k_page_support;
|
||||
int extra_page_size_support;
|
||||
bool tlb_lock;
|
||||
bool hardware_page_table_walker;
|
||||
bool default_endian;
|
||||
int partition_num;
|
||||
bool invisible_tlb;
|
||||
bool vlpt;
|
||||
bool ntme;
|
||||
bool drde;
|
||||
int default_min_page_size;
|
||||
bool multiple_page_size_in_use;
|
||||
};
|
||||
|
||||
struct nds32_misc_config {
|
||||
bool edm;
|
||||
bool local_memory_dma;
|
||||
bool performance_monitor;
|
||||
bool high_speed_memory_port;
|
||||
bool debug_tracer;
|
||||
bool div_instruction;
|
||||
bool mac_instruction;
|
||||
int audio_isa;
|
||||
bool l2_cache;
|
||||
bool reduce_register;
|
||||
bool addr_24;
|
||||
bool interruption_level;
|
||||
int baseline_instruction;
|
||||
bool no_dx_register;
|
||||
bool implement_dependant_register;
|
||||
bool implement_dependant_sr_encoding;
|
||||
bool ifc;
|
||||
bool mcu;
|
||||
bool ex9;
|
||||
int shadow;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a generic Andes core.
|
||||
*/
|
||||
struct nds32 {
|
||||
unsigned int common_magic;
|
||||
|
||||
struct reg_cache *core_cache;
|
||||
|
||||
/** Handle for the debug module. */
|
||||
struct nds32_edm edm;
|
||||
|
||||
/** Memory information */
|
||||
struct nds32_memory memory;
|
||||
|
||||
/** cpu version */
|
||||
struct nds32_cpu_version cpu_version;
|
||||
|
||||
/** MMU configuration */
|
||||
struct nds32_mmu_config mmu_config;
|
||||
|
||||
/** Misc configuration */
|
||||
struct nds32_misc_config misc_config;
|
||||
|
||||
/** Retrieve all core registers, for display. */
|
||||
int (*full_context)(struct nds32 *nds32);
|
||||
|
||||
/** Register mappings */
|
||||
int (*register_map)(struct nds32 *nds32, int reg_no);
|
||||
|
||||
/** Get debug exception virtual address */
|
||||
int (*get_debug_reason)(struct nds32 *nds32, uint32_t *reason);
|
||||
|
||||
/** Restore target registers may be modified in debug state */
|
||||
int (*leave_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
|
||||
|
||||
/** Backup target registers may be modified in debug state */
|
||||
int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
|
||||
|
||||
/** Get address hit watchpoint */
|
||||
int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason);
|
||||
|
||||
/** maximum interrupt level */
|
||||
uint32_t max_interrupt_level;
|
||||
|
||||
/** current interrupt level */
|
||||
uint32_t current_interrupt_level;
|
||||
|
||||
uint32_t watched_address;
|
||||
|
||||
/** Flag reporting whether virtual hosting is active. */
|
||||
bool virtual_hosting;
|
||||
|
||||
/** Flag reporting whether continue/step hits syscall or not */
|
||||
bool hit_syscall;
|
||||
|
||||
/** Value to be returned by virtual hosting SYS_ERRNO request. */
|
||||
int virtual_hosting_errno;
|
||||
|
||||
/** Flag reporting whether syscall is aborted */
|
||||
bool virtual_hosting_ctrl_c;
|
||||
|
||||
/** Record syscall ID for other operations to do special processing for target */
|
||||
int active_syscall_id;
|
||||
|
||||
struct breakpoint syscall_break;
|
||||
|
||||
/** Flag reporting whether global stop is active. */
|
||||
bool global_stop;
|
||||
|
||||
/** Flag reporting whether to use soft-reset-halt or not as issuing reset-halt. */
|
||||
bool soft_reset_halt;
|
||||
|
||||
/** reset-halt as target examine */
|
||||
bool reset_halt_as_examine;
|
||||
|
||||
/** backup/restore target EDM_CTL value. As debugging target debug
|
||||
* handler, it should be true. */
|
||||
bool keep_target_edm_ctl;
|
||||
|
||||
/* Value of $EDM_CTL before target enters debug mode */
|
||||
uint32_t backup_edm_ctl;
|
||||
|
||||
/** always use word-aligned address to access memory */
|
||||
bool word_access_mem;
|
||||
|
||||
/** EDM passcode for debugging secure MCU */
|
||||
char *edm_passcode;
|
||||
|
||||
/** current privilege_level if using secure MCU. value 0 is the highest level. */
|
||||
int privilege_level;
|
||||
|
||||
/** Period to wait after SRST. */
|
||||
uint32_t boot_time;
|
||||
|
||||
/** Flag to indicate HSS steps into ISR or not */
|
||||
bool step_isr_enable;
|
||||
|
||||
/** Flag to indicate register table is ready or not */
|
||||
bool init_arch_info_after_halted;
|
||||
|
||||
/** Flag to indicate audio-extension is enabled or not */
|
||||
bool audio_enable;
|
||||
|
||||
/** Flag to indicate fpu-extension is enabled or not */
|
||||
bool fpu_enable;
|
||||
|
||||
/* Andes Core has mixed endian model. Instruction is always big-endian.
|
||||
* Data may be big or little endian. Device registers may have different
|
||||
* endian from data and instruction. */
|
||||
/** Endian of data memory */
|
||||
enum target_endianness data_endian;
|
||||
|
||||
/** Endian of device registers */
|
||||
enum target_endianness device_reg_endian;
|
||||
|
||||
/** Flag to indicate if auto convert software breakpoints to
|
||||
* hardware breakpoints or not in ROM */
|
||||
bool auto_convert_hw_bp;
|
||||
|
||||
/* Flag to indicate the target is attached by debugger or not */
|
||||
bool attached;
|
||||
|
||||
/** Backpointer to the target. */
|
||||
struct target *target;
|
||||
|
||||
void *arch_info;
|
||||
};
|
||||
|
||||
struct nds32_reg {
|
||||
int32_t num;
|
||||
uint8_t value[8];
|
||||
struct target *target;
|
||||
struct nds32 *nds32;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct nds32_edm_operation {
|
||||
uint32_t reg_no;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
extern int nds32_config(struct nds32 *nds32);
|
||||
extern int nds32_init_arch_info(struct target *target, struct nds32 *nds32);
|
||||
extern int nds32_full_context(struct nds32 *nds32);
|
||||
extern int nds32_arch_state(struct target *target);
|
||||
extern int nds32_add_software_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint);
|
||||
extern int nds32_remove_software_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint);
|
||||
|
||||
extern int nds32_get_gdb_reg_list(struct target *target,
|
||||
struct reg **reg_list[], int *reg_list_size,
|
||||
enum target_register_class reg_class);
|
||||
|
||||
extern int nds32_write_buffer(struct target *target, uint32_t address,
|
||||
uint32_t size, const uint8_t *buffer);
|
||||
extern int nds32_read_buffer(struct target *target, uint32_t address,
|
||||
uint32_t size, uint8_t *buffer);
|
||||
extern int nds32_read_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
||||
extern int nds32_write_memory(struct target *target, uint32_t address,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
||||
|
||||
extern int nds32_init_register_table(struct nds32 *nds32);
|
||||
extern int nds32_init_memory_info(struct nds32 *nds32);
|
||||
extern int nds32_restore_context(struct target *target);
|
||||
extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value);
|
||||
extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value);
|
||||
|
||||
extern int nds32_edm_config(struct nds32 *nds32);
|
||||
extern int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length);
|
||||
extern int nds32_mmu(struct target *target, int *enabled);
|
||||
extern int nds32_virtual_to_physical(struct target *target, target_addr_t address,
|
||||
target_addr_t *physical);
|
||||
extern int nds32_read_phys_memory(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
||||
extern int nds32_write_phys_memory(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
||||
extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address);
|
||||
extern int nds32_examine_debug_reason(struct nds32 *nds32);
|
||||
extern int nds32_step(struct target *target, int current,
|
||||
target_addr_t address, int handle_breakpoints);
|
||||
extern int nds32_target_state(struct nds32 *nds32, enum target_state *state);
|
||||
extern int nds32_halt(struct target *target);
|
||||
extern int nds32_poll(struct target *target);
|
||||
extern int nds32_resume(struct target *target, int current,
|
||||
target_addr_t address, int handle_breakpoints, int debug_execution);
|
||||
extern int nds32_assert_reset(struct target *target);
|
||||
extern int nds32_init(struct nds32 *nds32);
|
||||
extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
|
||||
extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
|
||||
uint32_t size, const uint8_t *buffer);
|
||||
extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
|
||||
extern int nds32_reset_halt(struct nds32 *nds32);
|
||||
extern int nds32_login(struct nds32 *nds32);
|
||||
extern int nds32_profiling(struct target *target, uint32_t *samples,
|
||||
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
|
||||
|
||||
/** Convert target handle to generic Andes target state handle. */
|
||||
static inline struct nds32 *target_to_nds32(struct target *target)
|
||||
{
|
||||
assert(target);
|
||||
return target->arch_info;
|
||||
}
|
||||
|
||||
/** */
|
||||
static inline struct aice_port_s *target_to_aice(struct target *target)
|
||||
{
|
||||
assert(target);
|
||||
return target->tap->priv;
|
||||
}
|
||||
|
||||
static inline bool is_nds32(struct nds32 *nds32)
|
||||
{
|
||||
assert(nds32);
|
||||
return nds32->common_magic == NDS32_COMMON_MAGIC;
|
||||
}
|
||||
|
||||
static inline bool nds32_reach_max_interrupt_level(struct nds32 *nds32)
|
||||
{
|
||||
assert(nds32);
|
||||
return nds32->max_interrupt_level == nds32->current_interrupt_level;
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_H */
|
||||
@@ -1,147 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes technology. *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/log.h>
|
||||
#include "nds32_aice.h"
|
||||
|
||||
int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val)
|
||||
{
|
||||
if (!aice->port->api->read_reg_64) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->read_reg_64(aice->coreid, num, val);
|
||||
}
|
||||
|
||||
int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val)
|
||||
{
|
||||
if (!aice->port->api->write_reg_64) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->write_reg_64(aice->coreid, num, val);
|
||||
}
|
||||
|
||||
int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address,
|
||||
target_addr_t *physical_address)
|
||||
{
|
||||
if (!aice->port->api->read_tlb) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->read_tlb(aice->coreid, virtual_address, physical_address);
|
||||
}
|
||||
|
||||
int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address)
|
||||
{
|
||||
if (!aice->port->api->cache_ctl) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->cache_ctl(aice->coreid, subtype, address);
|
||||
}
|
||||
|
||||
int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times)
|
||||
{
|
||||
if (!aice->port->api->set_retry_times) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_retry_times(a_retry_times);
|
||||
}
|
||||
|
||||
int aice_program_edm(struct aice_port_s *aice, char *command_sequence)
|
||||
{
|
||||
if (!aice->port->api->program_edm) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->program_edm(aice->coreid, command_sequence);
|
||||
}
|
||||
|
||||
int aice_set_command_mode(struct aice_port_s *aice,
|
||||
enum aice_command_mode command_mode)
|
||||
{
|
||||
if (!aice->port->api->set_command_mode) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_command_mode(command_mode);
|
||||
}
|
||||
|
||||
int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
|
||||
uint32_t instruction_num)
|
||||
{
|
||||
if (!aice->port->api->execute) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->execute(aice->coreid, instructions, instruction_num);
|
||||
}
|
||||
|
||||
int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script)
|
||||
{
|
||||
if (!aice->port->api->set_custom_srst_script) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_custom_srst_script(script);
|
||||
}
|
||||
|
||||
int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script)
|
||||
{
|
||||
if (!aice->port->api->set_custom_trst_script) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_custom_trst_script(script);
|
||||
}
|
||||
|
||||
int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script)
|
||||
{
|
||||
if (!aice->port->api->set_custom_restart_script) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_custom_restart_script(script);
|
||||
}
|
||||
|
||||
int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check)
|
||||
{
|
||||
if (!aice->port->api->set_count_to_check_dbger) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->set_count_to_check_dbger(count_to_check);
|
||||
}
|
||||
|
||||
int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration,
|
||||
uint32_t reg_no, uint32_t *samples, uint32_t *num_samples)
|
||||
{
|
||||
if (!aice->port->api->profiling) {
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return aice->port->api->profiling(aice->coreid, interval, iteration,
|
||||
reg_no, samples, num_samples);
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes technology. *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_AICE_H
|
||||
#define OPENOCD_TARGET_NDS32_AICE_H
|
||||
|
||||
#include <jtag/aice/aice_port.h>
|
||||
|
||||
int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val);
|
||||
int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val);
|
||||
int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address,
|
||||
target_addr_t *physical_address);
|
||||
int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address);
|
||||
int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times);
|
||||
int aice_program_edm(struct aice_port_s *aice, char *command_sequence);
|
||||
int aice_set_command_mode(struct aice_port_s *aice,
|
||||
enum aice_command_mode command_mode);
|
||||
int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
|
||||
uint32_t instruction_num);
|
||||
int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script);
|
||||
int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script);
|
||||
int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script);
|
||||
int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check);
|
||||
int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration,
|
||||
uint32_t reg_no, uint32_t *samples, uint32_t *num_samples);
|
||||
|
||||
static inline int aice_open(struct aice_port_s *aice, struct aice_port_param_s *param)
|
||||
{
|
||||
return aice->port->api->open(param);
|
||||
}
|
||||
|
||||
static inline int aice_close(struct aice_port_s *aice)
|
||||
{
|
||||
return aice->port->api->close();
|
||||
}
|
||||
|
||||
static inline int aice_reset(struct aice_port_s *aice)
|
||||
{
|
||||
return aice->port->api->reset();
|
||||
}
|
||||
|
||||
static inline int aice_assert_srst(struct aice_port_s *aice,
|
||||
enum aice_srst_type_s srst)
|
||||
{
|
||||
return aice->port->api->assert_srst(aice->coreid, srst);
|
||||
}
|
||||
|
||||
static inline int aice_run(struct aice_port_s *aice)
|
||||
{
|
||||
return aice->port->api->run(aice->coreid);
|
||||
}
|
||||
|
||||
static inline int aice_halt(struct aice_port_s *aice)
|
||||
{
|
||||
return aice->port->api->halt(aice->coreid);
|
||||
}
|
||||
|
||||
static inline int aice_step(struct aice_port_s *aice)
|
||||
{
|
||||
return aice->port->api->step(aice->coreid);
|
||||
}
|
||||
|
||||
static inline int aice_read_register(struct aice_port_s *aice, uint32_t num,
|
||||
uint32_t *val)
|
||||
{
|
||||
return aice->port->api->read_reg(aice->coreid, num, val);
|
||||
}
|
||||
|
||||
static inline int aice_write_register(struct aice_port_s *aice, uint32_t num,
|
||||
uint32_t val)
|
||||
{
|
||||
return aice->port->api->write_reg(aice->coreid, num, val);
|
||||
}
|
||||
|
||||
static inline int aice_read_debug_reg(struct aice_port_s *aice, uint32_t addr,
|
||||
uint32_t *val)
|
||||
{
|
||||
return aice->port->api->read_debug_reg(aice->coreid, addr, val);
|
||||
}
|
||||
|
||||
static inline int aice_write_debug_reg(struct aice_port_s *aice, uint32_t addr,
|
||||
const uint32_t val)
|
||||
{
|
||||
return aice->port->api->write_debug_reg(aice->coreid, addr, val);
|
||||
}
|
||||
|
||||
static inline int aice_read_mem_unit(struct aice_port_s *aice, uint32_t addr,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
return aice->port->api->read_mem_unit(aice->coreid, addr, size, count, buffer);
|
||||
}
|
||||
|
||||
static inline int aice_write_mem_unit(struct aice_port_s *aice, uint32_t addr,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
||||
{
|
||||
return aice->port->api->write_mem_unit(aice->coreid, addr, size, count, buffer);
|
||||
}
|
||||
|
||||
static inline int aice_read_mem_bulk(struct aice_port_s *aice, uint32_t addr,
|
||||
uint32_t length, uint8_t *buffer)
|
||||
{
|
||||
return aice->port->api->read_mem_bulk(aice->coreid, addr, length, buffer);
|
||||
}
|
||||
|
||||
static inline int aice_write_mem_bulk(struct aice_port_s *aice, uint32_t addr,
|
||||
uint32_t length, const uint8_t *buffer)
|
||||
{
|
||||
return aice->port->api->write_mem_bulk(aice->coreid, addr, length, buffer);
|
||||
}
|
||||
|
||||
static inline int aice_idcode(struct aice_port_s *aice, uint32_t *idcode,
|
||||
uint8_t *num_of_idcode)
|
||||
{
|
||||
return aice->port->api->idcode(idcode, num_of_idcode);
|
||||
}
|
||||
|
||||
static inline int aice_state(struct aice_port_s *aice,
|
||||
enum aice_target_state_s *state)
|
||||
{
|
||||
return aice->port->api->state(aice->coreid, state);
|
||||
}
|
||||
|
||||
static inline int aice_set_jtag_clock(struct aice_port_s *aice, uint32_t a_clock)
|
||||
{
|
||||
return aice->port->api->set_jtag_clock(a_clock);
|
||||
}
|
||||
|
||||
static inline int aice_memory_access(struct aice_port_s *aice,
|
||||
enum nds_memory_access a_access)
|
||||
{
|
||||
return aice->port->api->memory_access(aice->coreid, a_access);
|
||||
}
|
||||
|
||||
static inline int aice_memory_mode(struct aice_port_s *aice,
|
||||
enum nds_memory_select mem_select)
|
||||
{
|
||||
return aice->port->api->memory_mode(aice->coreid, mem_select);
|
||||
}
|
||||
|
||||
static inline int aice_set_data_endian(struct aice_port_s *aice,
|
||||
enum aice_target_endian target_data_endian)
|
||||
{
|
||||
return aice->port->api->set_data_endian(aice->coreid, target_data_endian);
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_AICE_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_CMD_H
|
||||
#define OPENOCD_TARGET_NDS32_CMD_H
|
||||
|
||||
#include <helper/command.h>
|
||||
|
||||
extern const struct command_registration nds32_command_handlers[];
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_CMD_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,45 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_DISASSEMBLER_H
|
||||
#define OPENOCD_TARGET_NDS32_DISASSEMBLER_H
|
||||
|
||||
#include <target/nds32.h>
|
||||
|
||||
enum nds32_instruction_type {
|
||||
NDS32_INSN_DATA_PROC = 0,
|
||||
NDS32_INSN_LOAD_STORE,
|
||||
NDS32_INSN_JUMP_BRANCH,
|
||||
NDS32_INSN_RESOURCE_ACCESS,
|
||||
NDS32_INSN_MISC,
|
||||
};
|
||||
|
||||
struct nds32_instruction {
|
||||
enum nds32_instruction_type type;
|
||||
char text[128];
|
||||
uint32_t opcode;
|
||||
uint8_t instruction_size;
|
||||
uint32_t access_start;
|
||||
uint32_t access_end;
|
||||
|
||||
struct {
|
||||
uint8_t opc_6;
|
||||
uint8_t rt;
|
||||
uint8_t ra;
|
||||
uint8_t rb;
|
||||
uint8_t rd;
|
||||
uint8_t sub_opc;
|
||||
int32_t imm;
|
||||
} info;
|
||||
|
||||
};
|
||||
|
||||
int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value);
|
||||
int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address,
|
||||
struct nds32_instruction *instruction);
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_DISASSEMBLER_H */
|
||||
@@ -1,106 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_EDM_H
|
||||
#define OPENOCD_TARGET_NDS32_EDM_H
|
||||
|
||||
#include "helper/types.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This is the interface to the Embedded Debug Module for Andes cores.
|
||||
*/
|
||||
|
||||
/* EDM misc registers */
|
||||
enum nds_edm_misc_reg {
|
||||
NDS_EDM_MISC_DIMIR = 0x0,
|
||||
NDS_EDM_MISC_SBAR,
|
||||
NDS_EDM_MISC_EDM_CMDR,
|
||||
NDS_EDM_MISC_DBGER,
|
||||
NDS_EDM_MISC_ACC_CTL,
|
||||
NDS_EDM_MISC_EDM_PROBE,
|
||||
NDS_EDM_MISC_GEN_PORT0,
|
||||
NDS_EDM_MISC_GEN_PORT1,
|
||||
};
|
||||
|
||||
/* EDM system registers */
|
||||
enum nds_edm_system_reg {
|
||||
NDS_EDM_SR_BPC0 = 0x00,
|
||||
NDS_EDM_SR_BPC1,
|
||||
NDS_EDM_SR_BPC2,
|
||||
NDS_EDM_SR_BPC3,
|
||||
NDS_EDM_SR_BPC4,
|
||||
NDS_EDM_SR_BPC5,
|
||||
NDS_EDM_SR_BPC6,
|
||||
NDS_EDM_SR_BPC7,
|
||||
NDS_EDM_SR_BPA0 = 0x08,
|
||||
NDS_EDM_SR_BPA1,
|
||||
NDS_EDM_SR_BPA2,
|
||||
NDS_EDM_SR_BPA3,
|
||||
NDS_EDM_SR_BPA4,
|
||||
NDS_EDM_SR_BPA5,
|
||||
NDS_EDM_SR_BPA6,
|
||||
NDS_EDM_SR_BPA7,
|
||||
NDS_EDM_SR_BPAM0 = 0x10,
|
||||
NDS_EDM_SR_BPAM1,
|
||||
NDS_EDM_SR_BPAM2,
|
||||
NDS_EDM_SR_BPAM3,
|
||||
NDS_EDM_SR_BPAM4,
|
||||
NDS_EDM_SR_BPAM5,
|
||||
NDS_EDM_SR_BPAM6,
|
||||
NDS_EDM_SR_BPAM7,
|
||||
NDS_EDM_SR_BPV0 = 0x18,
|
||||
NDS_EDM_SR_BPV1,
|
||||
NDS_EDM_SR_BPV2,
|
||||
NDS_EDM_SR_BPV3,
|
||||
NDS_EDM_SR_BPV4,
|
||||
NDS_EDM_SR_BPV5,
|
||||
NDS_EDM_SR_BPV6,
|
||||
NDS_EDM_SR_BPV7,
|
||||
NDS_EDM_SR_BPCID0 = 0x20,
|
||||
NDS_EDM_SR_BPCID1,
|
||||
NDS_EDM_SR_BPCID2,
|
||||
NDS_EDM_SR_BPCID3,
|
||||
NDS_EDM_SR_BPCID4,
|
||||
NDS_EDM_SR_BPCID5,
|
||||
NDS_EDM_SR_BPCID6,
|
||||
NDS_EDM_SR_BPCID7,
|
||||
NDS_EDM_SR_EDM_CFG = 0x28,
|
||||
NDS_EDM_SR_EDMSW = 0x30,
|
||||
NDS_EDM_SR_EDM_CTL = 0x38,
|
||||
NDS_EDM_SR_EDM_DTR = 0x40,
|
||||
NDS_EDM_SR_BPMTV = 0x48,
|
||||
NDS_EDM_SR_DIMBR = 0x50,
|
||||
NDS_EDM_SR_TECR0 = 0x70,
|
||||
NDS_EDM_SR_TECR1 = 0x71,
|
||||
};
|
||||
|
||||
enum nds_memory_access {
|
||||
NDS_MEMORY_ACC_BUS = 0,
|
||||
NDS_MEMORY_ACC_CPU,
|
||||
};
|
||||
|
||||
enum nds_memory_select {
|
||||
NDS_MEMORY_SELECT_AUTO = 0,
|
||||
NDS_MEMORY_SELECT_MEM = 1,
|
||||
NDS_MEMORY_SELECT_ILM = 2,
|
||||
NDS_MEMORY_SELECT_DLM = 3,
|
||||
};
|
||||
|
||||
#define NDS_DBGER_DEX (0x1)
|
||||
#define NDS_DBGER_DPED (0x2)
|
||||
#define NDS_DBGER_CRST (0x4)
|
||||
#define NDS_DBGER_AT_MAX (0x8)
|
||||
#define NDS_DBGER_ILL_SEC_ACC (0x10)
|
||||
#define NDS_DBGER_ALL_SUPRS_EX (0x40000000)
|
||||
#define NDS_DBGER_RESACC (0x80000000)
|
||||
#define NDS_DBGER_CLEAR_ALL (0x1F)
|
||||
|
||||
#define NDS_EDMSW_WDV (1 << 0)
|
||||
#define NDS_EDMSW_RDV (1 << 1)
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_EDM_H */
|
||||
@@ -1,67 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_INSN_H
|
||||
#define OPENOCD_TARGET_NDS32_INSN_H
|
||||
|
||||
#define NOP (0x40000009)
|
||||
#define DSB (0x64000008)
|
||||
#define ISB (0x64000009)
|
||||
#define BEQ_MINUS_12 (0x4C000000 | 0x3FFA)
|
||||
#define MTSR_DTR(a) (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
|
||||
#define MFSR_DTR(a) (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
|
||||
#define SETHI(a, b) (0x46000000 | ((a) << 20) | (b))
|
||||
#define ORI(a, b, c) (0x58000000 | ((a) << 20) | ((b) << 15) | (c))
|
||||
#define LWI_BI(a, b) (0x0C000001 | (a << 20) | (b << 15))
|
||||
#define LHI_BI(a, b) (0x0A000001 | (a << 20) | (b << 15))
|
||||
#define LBI_BI(a, b) (0x08000001 | (a << 20) | (b << 15))
|
||||
#define SWI_BI(a, b) (0x1C000001 | (a << 20) | (b << 15))
|
||||
#define SHI_BI(a, b) (0x1A000001 | (a << 20) | (b << 15))
|
||||
#define SBI_BI(a, b) (0x18000001 | (a << 20) | (b << 15))
|
||||
#define IRET (0x64000004)
|
||||
#define L1D_IX_WB(a) (0x64000021 | ((a) << 15))
|
||||
#define L1D_IX_INVAL(a) (0x64000001 | ((a) << 15))
|
||||
#define L1D_VA_INVAL(a) (0x64000101 | ((a) << 15))
|
||||
#define L1D_VA_WB(a) (0x64000121 | ((a) << 15))
|
||||
#define L1D_IX_RTAG(a) (0x64000061 | ((a) << 15))
|
||||
#define L1D_IX_RWD(a) (0x64000081 | ((a) << 15))
|
||||
#define L1I_IX_INVAL(a) (0x64000201 | ((a) << 15))
|
||||
#define L1I_VA_INVAL(a) (0x64000301 | ((a) << 15))
|
||||
#define L1I_IX_RTAG(a) (0x64000261 | ((a) << 15))
|
||||
#define L1I_IX_RWD(a) (0x64000281 | ((a) << 15))
|
||||
#define L1I_VA_FILLCK(a) (0x64000361 | ((a) << 15))
|
||||
#define ISYNC(a) (0x6400000d | ((a) << 20))
|
||||
#define MSYNC_STORE (0x6400002c)
|
||||
#define MSYNC_ALL (0x6400000c)
|
||||
#define TLBOP_TARGET_READ(a) (0x6400000e | ((a) << 15))
|
||||
#define TLBOP_TARGET_PROBE(a, b) (0x640000AE | ((a) << 20) | ((b) << 15))
|
||||
#define MFCPD(a, b, c) (0x6A000041 | (a << 20) | (b << 8) | (c << 4))
|
||||
#define MFCPW(a, b, c) (0x6A000001 | (a << 20) | (b << 8) | (c << 4))
|
||||
#define MTCPD(a, b, c) (0x6A000049 | (a << 20) | (b << 8) | (c << 4))
|
||||
#define MTCPW(a, b, c) (0x6A000009 | (a << 20) | (b << 8) | (c << 4))
|
||||
#define MOVI_(a, b) (0x44000000 | (a << 20) | (b & 0xFFFFF))
|
||||
#define MFUSR_G0(a, b) (0x42000020 | (a << 20) | (b << 15))
|
||||
#define MTUSR_G0(a, b) (0x42000021 | (a << 20) | (b << 15))
|
||||
#define MFSR(a, b) (0x64000002 | (b << 10) | (a << 20))
|
||||
#define MTSR(a, b) (0x64000003 | (b << 10) | (a << 20))
|
||||
#define AMFAR(a, b) (0x60300060 | (a << 15) | b)
|
||||
#define AMTAR(a, b) (0x60300040 | (a << 15) | b)
|
||||
#define AMFAR2(a, b) (0x60300260 | (a << 15) | b)
|
||||
#define AMTAR2(a, b) (0x60300240 | (a << 15) | b)
|
||||
#define FMFCSR (0x6A000701)
|
||||
#define FMTCSR (0x6A000709)
|
||||
#define FMFCFG (0x6A000301)
|
||||
#define FMFSR(a, b) (0x6A000001 | ((a) << 20) | ((b) << 15))
|
||||
#define FMTSR(a, b) (0x6A000009 | ((a) << 20) | ((b) << 15))
|
||||
#define FMFDR(a, b) (0x6A000041 | ((a) << 20) | ((b) << 15))
|
||||
#define FMTDR(a, b) (0x6A000049 | ((a) << 20) | ((b) << 15))
|
||||
|
||||
/* break instructions */
|
||||
#define NDS32_BREAK_16 (0x00EA)
|
||||
#define NDS32_BREAK_32 (0x0A000064)
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_INSN_H */
|
||||
@@ -1,369 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/log.h>
|
||||
#include "nds32_reg.h"
|
||||
|
||||
static bool nds32_reg_init_done;
|
||||
static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM];
|
||||
static const struct nds32_reg_exception_s nds32_ex_reg_values[] = {
|
||||
{IR0, 3, 0x3, 2},
|
||||
{IR0, 3, 0x3, 3},
|
||||
{IR1, 3, 0x3, 2},
|
||||
{IR1, 3, 0x3, 3},
|
||||
{IR2, 3, 0x3, 2},
|
||||
{IR2, 3, 0x3, 3},
|
||||
{MR3, 1, 0x7, 0},
|
||||
{MR3, 1, 0x7, 4},
|
||||
{MR3, 1, 0x7, 6},
|
||||
{MR3, 8, 0x7, 3},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static inline void nds32_reg_set(uint32_t number, const char *simple_mnemonic,
|
||||
const char *symbolic_mnemonic, uint32_t sr_index,
|
||||
enum nds32_reg_type_s type, uint8_t size)
|
||||
{
|
||||
nds32_regs[number].simple_mnemonic = simple_mnemonic;
|
||||
nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic;
|
||||
nds32_regs[number].sr_index = sr_index;
|
||||
nds32_regs[number].type = type;
|
||||
nds32_regs[number].size = size;
|
||||
}
|
||||
|
||||
void nds32_reg_init(void)
|
||||
{
|
||||
if (nds32_reg_init_done == true)
|
||||
return;
|
||||
|
||||
nds32_reg_set(R0, "r0", "r0", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R1, "r1", "r1", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R2, "r2", "r2", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R3, "r3", "r3", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R4, "r4", "r4", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R5, "r5", "r5", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R6, "r6", "r6", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R7, "r7", "r7", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R8, "r8", "r8", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R9, "r9", "r9", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R10, "r10", "r10", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R11, "r11", "r11", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R12, "r12", "r12", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R13, "r13", "r13", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R14, "r14", "r14", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R15, "r15", "r15", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R16, "r16", "r16", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R17, "r17", "r17", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R18, "r18", "r18", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R19, "r19", "r19", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R20, "r20", "r20", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R21, "r21", "r21", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R22, "r22", "r22", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R23, "r23", "r23", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R24, "r24", "r24", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R25, "r25", "r25", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R26, "r26", "p0", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R27, "r27", "p1", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R28, "fp", "fp", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R29, "gp", "gp", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R30, "lp", "lp", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(R31, "sp", "sp", 0, NDS32_REG_TYPE_GPR, 32);
|
||||
nds32_reg_set(PC, "pc", "pc", 31, NDS32_REG_TYPE_SPR, 32);
|
||||
|
||||
nds32_reg_set(D0LO, "d0lo", "d0lo", 0, NDS32_REG_TYPE_SPR, 32);
|
||||
nds32_reg_set(D0HI, "d0hi", "d0hi", 1, NDS32_REG_TYPE_SPR, 32);
|
||||
nds32_reg_set(D1LO, "d1lo", "d1lo", 2, NDS32_REG_TYPE_SPR, 32);
|
||||
nds32_reg_set(D1HI, "d1hi", "d1hi", 3, NDS32_REG_TYPE_SPR, 32);
|
||||
nds32_reg_set(ITB, "itb", "itb", 28, NDS32_REG_TYPE_SPR, 32);
|
||||
nds32_reg_set(IFC_LP, "ifc_lp", "ifc_lp", 29, NDS32_REG_TYPE_SPR, 32);
|
||||
|
||||
nds32_reg_set(CR0, "cr0", "CPU_VER", SRIDX(0, 0, 0), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR1, "cr1", "ICM_CFG", SRIDX(0, 1, 0), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR2, "cr2", "DCM_CFG", SRIDX(0, 2, 0), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR3, "cr3", "MMU_CFG", SRIDX(0, 3, 0), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR4, "cr4", "MSC_CFG", SRIDX(0, 4, 0), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR5, "cr5", "CORE_ID", SRIDX(0, 0, 1), NDS32_REG_TYPE_CR, 32);
|
||||
nds32_reg_set(CR6, "cr6", "FUCOP_EXIST", SRIDX(0, 5, 0), NDS32_REG_TYPE_CR, 32);
|
||||
|
||||
nds32_reg_set(IR0, "ir0", "PSW", SRIDX(1, 0, 0), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR1, "ir1", "IPSW", SRIDX(1, 0, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR2, "ir2", "P_IPSW", SRIDX(1, 0, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR3, "ir3", "IVB", SRIDX(1, 1, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR4, "ir4", "EVA", SRIDX(1, 2, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR5, "ir5", "P_EVA", SRIDX(1, 2, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR6, "ir6", "ITYPE", SRIDX(1, 3, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR7, "ir7", "P_ITYPE", SRIDX(1, 3, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR8, "ir8", "MERR", SRIDX(1, 4, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR9, "ir9", "IPC", SRIDX(1, 5, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR10, "ir10", "P_IPC", SRIDX(1, 5, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR11, "ir11", "OIPC", SRIDX(1, 5, 3), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR12, "ir12", "P_P0", SRIDX(1, 6, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR13, "ir13", "P_P1", SRIDX(1, 7, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR14, "ir14", "INT_MASK", SRIDX(1, 8, 0), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR15, "ir15", "INT_PEND", SRIDX(1, 9, 0), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR16, "ir16", "", SRIDX(1, 10, 0), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR17, "ir17", "", SRIDX(1, 10, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR18, "ir18", "", SRIDX(1, 11, 0), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR19, "ir19", "", SRIDX(1, 1, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR20, "ir20", "", SRIDX(1, 10, 2), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR21, "ir21", "", SRIDX(1, 10, 3), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR22, "ir22", "", SRIDX(1, 10, 4), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR26, "ir26", "", SRIDX(1, 8, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR27, "ir27", "", SRIDX(1, 9, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR28, "ir28", "", SRIDX(1, 11, 1), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR29, "ir29", "", SRIDX(1, 9, 4), NDS32_REG_TYPE_IR, 32);
|
||||
nds32_reg_set(IR30, "ir30", "", SRIDX(1, 1, 3), NDS32_REG_TYPE_IR, 32);
|
||||
|
||||
nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR2, "mr2", "TLB_VPN", SRIDX(2, 2, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR3, "mr3", "TLB_DATA", SRIDX(2, 3, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR4, "mr4", "TLB_MISC", SRIDX(2, 4, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR5, "mr5", "VLPT_IDX", SRIDX(2, 5, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR6, "mr6", "ILMB", SRIDX(2, 6, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR7, "mr7", "DLMB", SRIDX(2, 7, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR8, "mr8", "CACHE_CTL", SRIDX(2, 8, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR9, "mr9", "HSMP_SADDR", SRIDX(2, 9, 0), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR10, "mr10", "HSMP_EADDR", SRIDX(2, 9, 1), NDS32_REG_TYPE_MR, 32);
|
||||
nds32_reg_set(MR11, "mr11", "", SRIDX(2, 0, 1), NDS32_REG_TYPE_MR, 32);
|
||||
|
||||
nds32_reg_set(DR0, "dr0", "BPC0", SRIDX(3, 0, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR1, "dr1", "BPA0", SRIDX(3, 1, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR2, "dr2", "BPAM0", SRIDX(3, 2, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR3, "dr3", "BPV0", SRIDX(3, 3, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR4, "dr4", "BPCID0", SRIDX(3, 4, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR5, "dr5", "BPC1", SRIDX(3, 0, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR6, "dr6", "BPA1", SRIDX(3, 1, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR7, "dr7", "BPAM1", SRIDX(3, 2, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR8, "dr8", "BPV1", SRIDX(3, 3, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR9, "dr9", "BPCID1", SRIDX(3, 4, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR10, "dr10", "BPC2", SRIDX(3, 0, 2), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR11, "dr11", "BPA2", SRIDX(3, 1, 2), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR12, "dr12", "BPAM2", SRIDX(3, 2, 2), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR13, "dr13", "BPV2", SRIDX(3, 3, 2), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR14, "dr14", "BPCID2", SRIDX(3, 4, 2), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR15, "dr15", "BPC3", SRIDX(3, 0, 3), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR16, "dr16", "BPA3", SRIDX(3, 1, 3), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR17, "dr17", "BPAM3", SRIDX(3, 2, 3), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR18, "dr18", "BPV3", SRIDX(3, 3, 3), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR19, "dr19", "BPCID3", SRIDX(3, 4, 3), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR20, "dr20", "BPC4", SRIDX(3, 0, 4), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR21, "dr21", "BPA4", SRIDX(3, 1, 4), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR22, "dr22", "BPAM4", SRIDX(3, 2, 4), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR23, "dr23", "BPV4", SRIDX(3, 3, 4), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR24, "dr24", "BPCID4", SRIDX(3, 4, 4), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR25, "dr25", "BPC5", SRIDX(3, 0, 5), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR26, "dr26", "BPA5", SRIDX(3, 1, 5), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR27, "dr27", "BPAM5", SRIDX(3, 2, 5), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR28, "dr28", "BPV5", SRIDX(3, 3, 5), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR29, "dr29", "BPCID5", SRIDX(3, 4, 5), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR30, "dr30", "BPC6", SRIDX(3, 0, 6), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR31, "dr31", "BPA6", SRIDX(3, 1, 6), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR32, "dr32", "BPAM6", SRIDX(3, 2, 6), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR33, "dr33", "BPV6", SRIDX(3, 3, 6), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR34, "dr34", "BPCID6", SRIDX(3, 4, 6), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR35, "dr35", "BPC7", SRIDX(3, 0, 7), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR36, "dr36", "BPA7", SRIDX(3, 1, 7), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR37, "dr37", "BPAM7", SRIDX(3, 2, 7), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR38, "dr38", "BPV7", SRIDX(3, 3, 7), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR39, "dr39", "BPCID7", SRIDX(3, 4, 7), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR40, "dr40", "EDM_CFG", SRIDX(3, 5, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR41, "dr41", "EDMSW", SRIDX(3, 6, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR42, "dr42", "EDM_CTL", SRIDX(3, 7, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR43, "dr43", "EDM_DTR", SRIDX(3, 8, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR44, "dr44", "BPMTC", SRIDX(3, 9, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR45, "dr45", "DIMBR", SRIDX(3, 10, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR46, "dr46", "TECR0", SRIDX(3, 14, 0), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR47, "dr47", "TECR1", SRIDX(3, 14, 1), NDS32_REG_TYPE_DR, 32);
|
||||
nds32_reg_set(DR48, "dr48", "", SRIDX(3, 11, 0), NDS32_REG_TYPE_DR, 32);
|
||||
|
||||
nds32_reg_set(PFR0, "pfr0", "PFMC0", SRIDX(4, 0, 0), NDS32_REG_TYPE_PFR, 32);
|
||||
nds32_reg_set(PFR1, "pfr1", "PFMC1", SRIDX(4, 0, 1), NDS32_REG_TYPE_PFR, 32);
|
||||
nds32_reg_set(PFR2, "pfr2", "PFMC2", SRIDX(4, 0, 2), NDS32_REG_TYPE_PFR, 32);
|
||||
nds32_reg_set(PFR3, "pfr3", "PFM_CTL", SRIDX(4, 1, 0), NDS32_REG_TYPE_PFR, 32);
|
||||
|
||||
nds32_reg_set(DMAR0, "dmar0", "DMA_CFG", SRIDX(5, 0, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR1, "dmar1", "DMA_GCSW", SRIDX(5, 1, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR2, "dmar2", "DMA_CHNSEL", SRIDX(5, 2, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR3, "dmar3", "DMA_ACT", SRIDX(5, 3, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR4, "dmar4", "DMA_SETUP", SRIDX(5, 4, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR5, "dmar5", "DMA_ISADDR", SRIDX(5, 5, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR6, "dmar6", "DMA_ESADDR", SRIDX(5, 6, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR7, "dmar7", "DMA_TCNT", SRIDX(5, 7, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR8, "dmar8", "DMA_STATUS", SRIDX(5, 8, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR9, "dmar9", "DMA_2DSET", SRIDX(5, 9, 0), NDS32_REG_TYPE_DMAR, 32);
|
||||
nds32_reg_set(DMAR10, "dmar10", "DMA_2DSCTL", SRIDX(5, 9, 1), NDS32_REG_TYPE_DMAR, 32);
|
||||
|
||||
nds32_reg_set(RACR, "racr", "PRUSR_ACC_CTL", SRIDX(4, 4, 0), NDS32_REG_TYPE_RACR, 32);
|
||||
nds32_reg_set(FUCPR, "fucpr", "FUCOP_CTL", SRIDX(4, 5, 0), NDS32_REG_TYPE_RACR, 32);
|
||||
|
||||
nds32_reg_set(IDR0, "idr0", "SDZ_CTL", SRIDX(2, 15, 0), NDS32_REG_TYPE_IDR, 32);
|
||||
nds32_reg_set(IDR1, "idr1", "MISC_CTL", SRIDX(2, 15, 1), NDS32_REG_TYPE_IDR, 32);
|
||||
|
||||
nds32_reg_set(SECUR0, "secur0", "", SRIDX(6, 0, 0), NDS32_REG_TYPE_SECURE, 32);
|
||||
|
||||
nds32_reg_set(D0L24, "D0L24", "D0L24", 0x10, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(D1L24, "D1L24", "D1L24", 0x11, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I0, "I0", "I0", 0x0, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I1, "I1", "I1", 0x1, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I2, "I2", "I2", 0x2, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I3, "I3", "I3", 0x3, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I4, "I4", "I4", 0x4, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I5, "I5", "I5", 0x5, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I6, "I6", "I6", 0x6, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(I7, "I7", "I7", 0x7, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M1, "M1", "M1", 0x9, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M2, "M2", "M2", 0xA, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M3, "M3", "M3", 0xB, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M5, "M5", "M5", 0xD, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M6, "M6", "M6", 0xE, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(M7, "M7", "M7", 0xF, NDS32_REG_TYPE_AUMR, 32);
|
||||
|
||||
nds32_reg_set(MOD, "MOD", "MOD", 0x8, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(LBE, "LBE", "LBE", 0x18, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(LE, "LE", "LE", 0x19, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(LC, "LC", "LC", 0x1A, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(ADM_VBASE, "ADM_VBASE", "ADM_VBASE", 0x1B, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(SHFT_CTL0, "SHFT_CTL0", "SHFT_CTL0", 0x12, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(SHFT_CTL1, "SHFT_CTL1", "SHFT_CTL1", 0x13, NDS32_REG_TYPE_AUMR, 32);
|
||||
|
||||
nds32_reg_set(CB_CTL, "CB_CTL", "CB_CTL", 0x1F, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBB0, "CBB0", "CBB0", 0x0, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBB1, "CBB1", "CBB1", 0x1, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBB2, "CBB2", "CBB2", 0x2, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBB3, "CBB3", "CBB3", 0x3, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBE0, "CBE0", "CBE0", 0x4, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBE1, "CBE1", "CBE1", 0x5, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBE2, "CBE2", "CBE2", 0x6, NDS32_REG_TYPE_AUMR, 32);
|
||||
nds32_reg_set(CBE3, "CBE3", "CBE3", 0x7, NDS32_REG_TYPE_AUMR, 32);
|
||||
|
||||
nds32_reg_set(FPCSR, "fpcsr", "FPCSR", 0x7, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FPCFG, "fpcfg", "FPCFG", 0x7, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS0, "fs0", "FS0", 0, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS1, "fs1", "FS1", 1, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS2, "fs2", "FS2", 2, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS3, "fs3", "FS3", 3, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS4, "fs4", "FS4", 4, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS5, "fs5", "FS5", 5, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS6, "fs6", "FS6", 6, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS7, "fs7", "FS7", 7, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS8, "fs8", "FS8", 8, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS9, "fs9", "FS9", 9, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS10, "fs10", "FS10", 10, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS11, "fs11", "FS11", 11, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS12, "fs12", "FS12", 12, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS13, "fs13", "FS13", 13, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS14, "fs14", "FS14", 14, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS15, "fs15", "FS15", 15, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS16, "fs16", "FS16", 16, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS17, "fs17", "FS17", 17, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS18, "fs18", "FS18", 18, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS19, "fs19", "FS19", 19, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS20, "fs20", "FS20", 20, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS21, "fs21", "FS21", 21, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS22, "fs22", "FS22", 22, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS23, "fs23", "FS23", 23, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS24, "fs24", "FS24", 24, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS25, "fs25", "FS25", 25, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS26, "fs26", "FS26", 26, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS27, "fs27", "FS27", 27, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS28, "fs28", "FS28", 28, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS29, "fs29", "FS29", 29, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS30, "fs30", "FS30", 30, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FS31, "fs31", "FS31", 31, NDS32_REG_TYPE_FPU, 32);
|
||||
nds32_reg_set(FD0, "fd0", "FD0", 0, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD1, "fd1", "FD1", 1, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD2, "fd2", "FD2", 2, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD3, "fd3", "FD3", 3, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD4, "fd4", "FD4", 4, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD5, "fd5", "FD5", 5, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD6, "fd6", "FD6", 6, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD7, "fd7", "FD7", 7, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD8, "fd8", "FD8", 8, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD9, "fd9", "FD9", 9, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD10, "fd10", "FD10", 10, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD11, "fd11", "FD11", 11, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD12, "fd12", "FD12", 12, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD13, "fd13", "FD13", 13, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD14, "fd14", "FD14", 14, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD15, "fd15", "FD15", 15, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD16, "fd16", "FD16", 16, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD17, "fd17", "FD17", 17, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD18, "fd18", "FD18", 18, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD19, "fd19", "FD19", 19, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD20, "fd20", "FD20", 20, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD21, "fd21", "FD21", 21, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD22, "fd22", "FD22", 22, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD23, "fd23", "FD23", 23, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD24, "fd24", "FD24", 24, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD25, "fd25", "FD25", 25, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD26, "fd26", "FD26", 26, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD27, "fd27", "FD27", 27, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD28, "fd28", "FD28", 28, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD29, "fd29", "FD29", 29, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD30, "fd30", "FD30", 30, NDS32_REG_TYPE_FPU, 64);
|
||||
nds32_reg_set(FD31, "fd31", "FD31", 31, NDS32_REG_TYPE_FPU, 64);
|
||||
|
||||
nds32_reg_init_done = true;
|
||||
}
|
||||
|
||||
uint32_t nds32_reg_sr_index(uint32_t number)
|
||||
{
|
||||
return nds32_regs[number].sr_index;
|
||||
}
|
||||
|
||||
enum nds32_reg_type_s nds32_reg_type(uint32_t number)
|
||||
{
|
||||
return nds32_regs[number].type;
|
||||
}
|
||||
|
||||
uint8_t nds32_reg_size(uint32_t number)
|
||||
{
|
||||
return nds32_regs[number].size;
|
||||
}
|
||||
|
||||
const char *nds32_reg_simple_name(uint32_t number)
|
||||
{
|
||||
return nds32_regs[number].simple_mnemonic;
|
||||
}
|
||||
|
||||
const char *nds32_reg_symbolic_name(uint32_t number)
|
||||
{
|
||||
return nds32_regs[number].symbolic_mnemonic;
|
||||
}
|
||||
|
||||
bool nds32_reg_exception(uint32_t number, uint32_t value)
|
||||
{
|
||||
int i;
|
||||
const struct nds32_reg_exception_s *ex_reg_value;
|
||||
uint32_t field_value;
|
||||
|
||||
i = 0;
|
||||
while (nds32_ex_reg_values[i].reg_num != 0) {
|
||||
ex_reg_value = nds32_ex_reg_values + i;
|
||||
|
||||
if (ex_reg_value->reg_num == number) {
|
||||
field_value = (value >> ex_reg_value->ex_value_bit_pos) &
|
||||
ex_reg_value->ex_value_mask;
|
||||
if (field_value == ex_reg_value->ex_value) {
|
||||
LOG_WARNING("It will generate exceptions as setting %" PRIu32 " to %s",
|
||||
value, nds32_regs[number].simple_mnemonic);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_REG_H
|
||||
#define OPENOCD_TARGET_NDS32_REG_H
|
||||
|
||||
#define SRIDX(a, b, c) ((a << 7) | (b << 3) | c)
|
||||
#define NDS32_REGISTER_DISABLE (0x0)
|
||||
|
||||
enum nds32_reg_number_s {
|
||||
R0 = 0, /* general registers */
|
||||
R1,
|
||||
R2,
|
||||
R3,
|
||||
R4,
|
||||
R5,
|
||||
R6,
|
||||
R7,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15,
|
||||
R16,
|
||||
R17,
|
||||
R18,
|
||||
R19,
|
||||
R20,
|
||||
R21,
|
||||
R22,
|
||||
R23,
|
||||
R24,
|
||||
R25,
|
||||
R26,
|
||||
R27,
|
||||
R28,
|
||||
R29,
|
||||
R30,
|
||||
R31,
|
||||
PC,
|
||||
D0LO,
|
||||
D0HI,
|
||||
D1LO,
|
||||
D1HI,
|
||||
ITB,
|
||||
IFC_LP,
|
||||
CR0, /* system registers */
|
||||
CR1,
|
||||
CR2,
|
||||
CR3,
|
||||
CR4,
|
||||
CR5,
|
||||
CR6,
|
||||
IR0,
|
||||
IR1,
|
||||
IR2,
|
||||
IR3,
|
||||
IR4,
|
||||
IR5,
|
||||
IR6,
|
||||
IR7,
|
||||
IR8,
|
||||
IR9,
|
||||
IR10,
|
||||
IR11,
|
||||
IR12,
|
||||
IR13,
|
||||
IR14,
|
||||
IR15,
|
||||
IR16,
|
||||
IR17,
|
||||
IR18,
|
||||
IR19,
|
||||
IR20,
|
||||
IR21,
|
||||
IR22,
|
||||
IR23,
|
||||
IR24,
|
||||
IR25,
|
||||
IR26,
|
||||
IR27,
|
||||
IR28,
|
||||
IR29,
|
||||
IR30,
|
||||
MR0,
|
||||
MR1,
|
||||
MR2,
|
||||
MR3,
|
||||
MR4,
|
||||
MR5,
|
||||
MR6,
|
||||
MR7,
|
||||
MR8,
|
||||
MR9,
|
||||
MR10,
|
||||
MR11,
|
||||
DR0,
|
||||
DR1,
|
||||
DR2,
|
||||
DR3,
|
||||
DR4,
|
||||
DR5,
|
||||
DR6,
|
||||
DR7,
|
||||
DR8,
|
||||
DR9,
|
||||
DR10,
|
||||
DR11,
|
||||
DR12,
|
||||
DR13,
|
||||
DR14,
|
||||
DR15,
|
||||
DR16,
|
||||
DR17,
|
||||
DR18,
|
||||
DR19,
|
||||
DR20,
|
||||
DR21,
|
||||
DR22,
|
||||
DR23,
|
||||
DR24,
|
||||
DR25,
|
||||
DR26,
|
||||
DR27,
|
||||
DR28,
|
||||
DR29,
|
||||
DR30,
|
||||
DR31,
|
||||
DR32,
|
||||
DR33,
|
||||
DR34,
|
||||
DR35,
|
||||
DR36,
|
||||
DR37,
|
||||
DR38,
|
||||
DR39,
|
||||
DR40,
|
||||
DR41,
|
||||
DR42,
|
||||
DR43,
|
||||
DR44,
|
||||
DR45,
|
||||
DR46,
|
||||
DR47,
|
||||
DR48,
|
||||
PFR0,
|
||||
PFR1,
|
||||
PFR2,
|
||||
PFR3,
|
||||
DMAR0,
|
||||
DMAR1,
|
||||
DMAR2,
|
||||
DMAR3,
|
||||
DMAR4,
|
||||
DMAR5,
|
||||
DMAR6,
|
||||
DMAR7,
|
||||
DMAR8,
|
||||
DMAR9,
|
||||
DMAR10,
|
||||
RACR,
|
||||
FUCPR,
|
||||
IDR0,
|
||||
IDR1,
|
||||
SECUR0,
|
||||
D0L24, /* audio registers */
|
||||
D1L24,
|
||||
I0,
|
||||
I1,
|
||||
I2,
|
||||
I3,
|
||||
I4,
|
||||
I5,
|
||||
I6,
|
||||
I7,
|
||||
M1,
|
||||
M2,
|
||||
M3,
|
||||
M5,
|
||||
M6,
|
||||
M7,
|
||||
MOD,
|
||||
LBE,
|
||||
LE,
|
||||
LC,
|
||||
ADM_VBASE,
|
||||
SHFT_CTL0,
|
||||
SHFT_CTL1,
|
||||
CB_CTL,
|
||||
CBB0,
|
||||
CBB1,
|
||||
CBB2,
|
||||
CBB3,
|
||||
CBE0,
|
||||
CBE1,
|
||||
CBE2,
|
||||
CBE3,
|
||||
FPCSR, /* fpu */
|
||||
FPCFG,
|
||||
FS0,
|
||||
FS1,
|
||||
FS2,
|
||||
FS3,
|
||||
FS4,
|
||||
FS5,
|
||||
FS6,
|
||||
FS7,
|
||||
FS8,
|
||||
FS9,
|
||||
FS10,
|
||||
FS11,
|
||||
FS12,
|
||||
FS13,
|
||||
FS14,
|
||||
FS15,
|
||||
FS16,
|
||||
FS17,
|
||||
FS18,
|
||||
FS19,
|
||||
FS20,
|
||||
FS21,
|
||||
FS22,
|
||||
FS23,
|
||||
FS24,
|
||||
FS25,
|
||||
FS26,
|
||||
FS27,
|
||||
FS28,
|
||||
FS29,
|
||||
FS30,
|
||||
FS31,
|
||||
FD0,
|
||||
FD1,
|
||||
FD2,
|
||||
FD3,
|
||||
FD4,
|
||||
FD5,
|
||||
FD6,
|
||||
FD7,
|
||||
FD8,
|
||||
FD9,
|
||||
FD10,
|
||||
FD11,
|
||||
FD12,
|
||||
FD13,
|
||||
FD14,
|
||||
FD15,
|
||||
FD16,
|
||||
FD17,
|
||||
FD18,
|
||||
FD19,
|
||||
FD20,
|
||||
FD21,
|
||||
FD22,
|
||||
FD23,
|
||||
FD24,
|
||||
FD25,
|
||||
FD26,
|
||||
FD27,
|
||||
FD28,
|
||||
FD29,
|
||||
FD30,
|
||||
FD31,
|
||||
|
||||
TOTAL_REG_NUM,
|
||||
};
|
||||
|
||||
enum nds32_reg_type_s {
|
||||
NDS32_REG_TYPE_GPR = 0,
|
||||
NDS32_REG_TYPE_SPR,
|
||||
NDS32_REG_TYPE_CR,
|
||||
NDS32_REG_TYPE_IR,
|
||||
NDS32_REG_TYPE_MR,
|
||||
NDS32_REG_TYPE_DR,
|
||||
NDS32_REG_TYPE_PFR,
|
||||
NDS32_REG_TYPE_DMAR,
|
||||
NDS32_REG_TYPE_RACR,
|
||||
NDS32_REG_TYPE_IDR,
|
||||
NDS32_REG_TYPE_AUMR,
|
||||
NDS32_REG_TYPE_SECURE,
|
||||
NDS32_REG_TYPE_FPU,
|
||||
};
|
||||
|
||||
struct nds32_reg_s {
|
||||
const char *simple_mnemonic;
|
||||
const char *symbolic_mnemonic;
|
||||
uint32_t sr_index;
|
||||
enum nds32_reg_type_s type;
|
||||
uint8_t size;
|
||||
};
|
||||
|
||||
struct nds32_reg_exception_s {
|
||||
uint32_t reg_num;
|
||||
uint32_t ex_value_bit_pos;
|
||||
uint32_t ex_value_mask;
|
||||
uint32_t ex_value;
|
||||
};
|
||||
|
||||
void nds32_reg_init(void);
|
||||
uint32_t nds32_reg_sr_index(uint32_t number);
|
||||
enum nds32_reg_type_s nds32_reg_type(uint32_t number);
|
||||
uint8_t nds32_reg_size(uint32_t number);
|
||||
const char *nds32_reg_simple_name(uint32_t number);
|
||||
const char *nds32_reg_symbolic_name(uint32_t number);
|
||||
bool nds32_reg_exception(uint32_t number, uint32_t value);
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_REG_H */
|
||||
@@ -1,67 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "nds32_aice.h"
|
||||
#include "nds32_tlb.h"
|
||||
|
||||
int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address,
|
||||
target_addr_t *physical_address)
|
||||
{
|
||||
struct target *target = nds32->target;
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
|
||||
return aice_read_tlb(aice, virtual_address, physical_address);
|
||||
}
|
||||
|
||||
static struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = {
|
||||
/* 4K page */
|
||||
{0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000},
|
||||
/* 8K page */
|
||||
{0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000},
|
||||
};
|
||||
|
||||
int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address,
|
||||
target_addr_t *physical_address)
|
||||
{
|
||||
struct target *target = nds32->target;
|
||||
uint32_t value_mr1;
|
||||
uint32_t load_address;
|
||||
uint32_t l1_page_table_entry;
|
||||
uint32_t l2_page_table_entry;
|
||||
uint32_t page_size_index = nds32->mmu_config.default_min_page_size;
|
||||
struct page_table_walker_info_s *page_table_info_p =
|
||||
&(page_table_info[page_size_index]);
|
||||
|
||||
/* Read L1 Physical Page Table */
|
||||
nds32_get_mapped_reg(nds32, MR1, &value_mr1);
|
||||
load_address = (value_mr1 & page_table_info_p->l1_base_mask) |
|
||||
((virtual_address & page_table_info_p->l1_offset_mask) >>
|
||||
page_table_info_p->l1_offset_shift);
|
||||
/* load_address is physical address */
|
||||
nds32_read_buffer(target, load_address, 4, (uint8_t *)&l1_page_table_entry);
|
||||
|
||||
/* Read L2 Physical Page Table */
|
||||
if (l1_page_table_entry & 0x1) /* L1_PTE not present */
|
||||
return ERROR_FAIL;
|
||||
|
||||
load_address = (l1_page_table_entry & page_table_info_p->l2_base_mask) |
|
||||
((virtual_address & page_table_info_p->l2_offset_mask) >>
|
||||
page_table_info_p->l2_offset_shift);
|
||||
/* load_address is physical address */
|
||||
nds32_read_buffer(target, load_address, 4, (uint8_t *)&l2_page_table_entry);
|
||||
|
||||
if ((l2_page_table_entry & 0x1) != 0x1) /* L2_PTE not valid */
|
||||
return ERROR_FAIL;
|
||||
|
||||
*physical_address = (l2_page_table_entry & page_table_info_p->ppn_mask) |
|
||||
(virtual_address & page_table_info_p->va_offset_mask);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_TLB_H
|
||||
#define OPENOCD_TARGET_NDS32_TLB_H
|
||||
|
||||
#include "nds32.h"
|
||||
|
||||
enum {
|
||||
PAGE_SIZE_4K = 0,
|
||||
PAGE_SIZE_8K,
|
||||
PAGE_SIZE_NUM,
|
||||
};
|
||||
|
||||
struct page_table_walker_info_s {
|
||||
|
||||
uint32_t l1_offset_mask;
|
||||
uint32_t l1_offset_shift;
|
||||
uint32_t l2_offset_mask;
|
||||
uint32_t l2_offset_shift;
|
||||
uint32_t va_offset_mask;
|
||||
uint32_t l1_base_mask;
|
||||
uint32_t l2_base_mask;
|
||||
uint32_t ppn_mask;
|
||||
};
|
||||
|
||||
extern int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address,
|
||||
target_addr_t *physical_address);
|
||||
extern int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address,
|
||||
target_addr_t *physical_address);
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_TLB_H */
|
||||
@@ -1,774 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/binarybuffer.h>
|
||||
#include "breakpoints.h"
|
||||
#include "nds32_insn.h"
|
||||
#include "nds32_reg.h"
|
||||
#include "nds32_edm.h"
|
||||
#include "nds32_cmd.h"
|
||||
#include "nds32_v2.h"
|
||||
#include "nds32_aice.h"
|
||||
#include "target_type.h"
|
||||
|
||||
static int nds32_v2_register_mapping(struct nds32 *nds32, int reg_no)
|
||||
{
|
||||
uint32_t max_level = nds32->max_interrupt_level;
|
||||
uint32_t cur_level = nds32->current_interrupt_level;
|
||||
|
||||
if ((cur_level >= 1) && (cur_level < max_level)) {
|
||||
if (reg_no == IR0) {
|
||||
LOG_DEBUG("Map PSW to IPSW");
|
||||
return IR1;
|
||||
} else if (reg_no == PC) {
|
||||
LOG_DEBUG("Map PC to IPC");
|
||||
return IR9;
|
||||
}
|
||||
} else if ((cur_level >= 2) && (cur_level < max_level)) {
|
||||
if (reg_no == R26) {
|
||||
LOG_DEBUG("Mapping P0 to P_P0");
|
||||
return IR12;
|
||||
} else if (reg_no == R27) {
|
||||
LOG_DEBUG("Mapping P1 to P_P1");
|
||||
return IR13;
|
||||
} else if (reg_no == IR1) {
|
||||
LOG_DEBUG("Mapping IPSW to P_IPSW");
|
||||
return IR2;
|
||||
} else if (reg_no == IR4) {
|
||||
LOG_DEBUG("Mapping EVA to P_EVA");
|
||||
return IR5;
|
||||
} else if (reg_no == IR6) {
|
||||
LOG_DEBUG("Mapping ITYPE to P_ITYPE");
|
||||
return IR7;
|
||||
} else if (reg_no == IR9) {
|
||||
LOG_DEBUG("Mapping IPC to P_IPC");
|
||||
return IR10;
|
||||
}
|
||||
} else if (cur_level == max_level) {
|
||||
if (reg_no == PC) {
|
||||
LOG_DEBUG("Mapping PC to O_IPC");
|
||||
return IR11;
|
||||
}
|
||||
}
|
||||
|
||||
return reg_no;
|
||||
}
|
||||
|
||||
static int nds32_v2_get_debug_reason(struct nds32 *nds32, uint32_t *reason)
|
||||
{
|
||||
uint32_t val_itype;
|
||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
||||
|
||||
aice_read_register(aice, IR6, &val_itype);
|
||||
|
||||
*reason = val_itype & 0x0F;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_activate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
int32_t hbr_index = 0;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT) {
|
||||
/* already set at nds32_v2_add_breakpoint() */
|
||||
continue;
|
||||
} else if (bp->type == BKPT_HARD) {
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
|
||||
/* set value */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
|
||||
|
||||
if (nds32_v2->nds32.memory.address_translation)
|
||||
/* enable breakpoint (virtual address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
|
||||
else
|
||||
/* enable breakpoint (physical address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
|
||||
|
||||
LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
||||
bp->address);
|
||||
|
||||
hbr_index++;
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_deactivate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
int32_t hbr_index = 0;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT)
|
||||
continue;
|
||||
else if (bp->type == BKPT_HARD)
|
||||
/* disable breakpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
|
||||
LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
||||
bp->address);
|
||||
|
||||
hbr_index++;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_activate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
struct watchpoint *wp;
|
||||
int32_t wp_num = nds32_v2->next_hbr_index;
|
||||
uint32_t wp_config = 0;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
|
||||
wp_num--;
|
||||
wp->mask = wp->length - 1;
|
||||
if ((wp->address % wp->length) != 0)
|
||||
wp->mask = (wp->mask << 1) + 1;
|
||||
|
||||
if (wp->rw == WPT_READ)
|
||||
wp_config = 0x3;
|
||||
else if (wp->rw == WPT_WRITE)
|
||||
wp_config = 0x5;
|
||||
else if (wp->rw == WPT_ACCESS)
|
||||
wp_config = 0x7;
|
||||
|
||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
||||
if (nds32_v2->nds32.memory.address_translation == false)
|
||||
wp_config |= 0x8;
|
||||
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
||||
wp->address - (wp->address % wp->length));
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
||||
/* enable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
||||
/* set value */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
|
||||
|
||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num,
|
||||
wp->address, wp->mask);
|
||||
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_deactivate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
int32_t wp_num = nds32_v2->next_hbr_index;
|
||||
struct watchpoint *wp;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
wp_num--;
|
||||
/* disable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
||||
|
||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32,
|
||||
wp_num, wp->address, wp->mask);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_check_interrupt_stack(struct nds32_v2_common *nds32_v2)
|
||||
{
|
||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
||||
uint32_t val_ir0;
|
||||
uint32_t val_ir1;
|
||||
uint32_t val_ir2;
|
||||
uint32_t modified_psw;
|
||||
|
||||
/* Save interrupt level */
|
||||
aice_read_register(aice, IR0, &val_ir0); /* get $IR0 directly */
|
||||
|
||||
/* backup $IR0 */
|
||||
nds32_v2->backup_ir0 = val_ir0;
|
||||
|
||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
||||
|
||||
if (nds32_reach_max_interrupt_level(nds32)) {
|
||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
||||
nds32->current_interrupt_level);
|
||||
|
||||
/* decrease interrupt level */
|
||||
modified_psw = val_ir0 - 0x2;
|
||||
|
||||
/* disable GIE, IT, DT, HSS */
|
||||
modified_psw &= (~0x8C1);
|
||||
|
||||
aice_write_register(aice, IR0, modified_psw);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* There is a case that single step also trigger another interrupt,
|
||||
then HSS bit in psw(ir0) will push to ipsw(ir1).
|
||||
Then hit debug interrupt HSS bit in ipsw(ir1) will push to (p_ipsw)ir2
|
||||
Therefore, HSS bit in p_ipsw(ir2) also need clear.
|
||||
|
||||
Only update $ir2 as current interrupt level is 2, because $ir2 will be random
|
||||
value if the target never reaches interrupt level 2. */
|
||||
if ((nds32->max_interrupt_level == 3) && (nds32->current_interrupt_level == 2)) {
|
||||
aice_read_register(aice, IR2, &val_ir2); /* get $IR2 directly */
|
||||
val_ir2 &= ~(0x01 << 11);
|
||||
aice_write_register(aice, IR2, val_ir2);
|
||||
}
|
||||
|
||||
/* get original DT bit and set to current state let debugger has same memory view
|
||||
PSW.IT MUST be turned off. Otherwise, DIM could not operate normally. */
|
||||
aice_read_register(aice, IR1, &val_ir1);
|
||||
modified_psw = val_ir0 | (val_ir1 & 0x80);
|
||||
aice_write_register(aice, IR0, modified_psw);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_restore_interrupt_stack(struct nds32_v2_common *nds32_v2)
|
||||
{
|
||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
||||
|
||||
/* restore origin $IR0 */
|
||||
aice_write_register(aice, IR0, nds32_v2->backup_ir0);
|
||||
|
||||
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_v2_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
|
||||
{
|
||||
LOG_DEBUG("nds32_v2_debug_entry");
|
||||
|
||||
if (nds32->virtual_hosting)
|
||||
LOG_WARNING("<-- TARGET WARNING! Virtual hosting is not supported "
|
||||
"under V1/V2 architecture. -->");
|
||||
|
||||
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(nds32_v2_deactivate_hardware_breakpoint(nds32->target));
|
||||
|
||||
if (enable_watchpoint)
|
||||
CHECK_RETVAL(nds32_v2_deactivate_hardware_watchpoint(nds32->target));
|
||||
|
||||
if (nds32_examine_debug_reason(nds32) != ERROR_OK) {
|
||||
nds32->target->state = backup_state;
|
||||
|
||||
/* re-activate all hardware breakpoints & watchpoints */
|
||||
CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target));
|
||||
|
||||
if (enable_watchpoint) {
|
||||
/* activate all watchpoints */
|
||||
CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target));
|
||||
}
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* check interrupt level before .full_context(), because
|
||||
* get_mapped_reg() in nds32_full_context() needs current_interrupt_level
|
||||
* information */
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
|
||||
nds32_v2_check_interrupt_stack(nds32_v2);
|
||||
|
||||
/* Save registers. */
|
||||
nds32_full_context(nds32);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* target request support */
|
||||
static int nds32_v2_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore processor state.
|
||||
*/
|
||||
static int nds32_v2_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint)
|
||||
{
|
||||
LOG_DEBUG("nds32_v2_leave_debug_state");
|
||||
|
||||
struct target *target = nds32->target;
|
||||
|
||||
/* activate all hardware breakpoints */
|
||||
CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target));
|
||||
|
||||
if (enable_watchpoint) {
|
||||
/* activate all watchpoints */
|
||||
CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target));
|
||||
}
|
||||
|
||||
/* restore interrupt stack */
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
|
||||
nds32_v2_restore_interrupt_stack(nds32_v2);
|
||||
|
||||
/* restore PSW, PC, and R0 ... after flushing any modified
|
||||
* registers.
|
||||
*/
|
||||
CHECK_RETVAL(nds32_restore_context(target));
|
||||
|
||||
register_cache_invalidate(nds32->core_cache);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_deassert_reset(struct target *target)
|
||||
{
|
||||
int retval;
|
||||
|
||||
CHECK_RETVAL(nds32_poll(target));
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
/* reset only */
|
||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||
target_name(target));
|
||||
retval = target_halt(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum)
|
||||
{
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int nds32_v2_add_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
||||
int result;
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
/* check hardware resource */
|
||||
if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
||||
"breakpoints/watchpoints! The limit of "
|
||||
"combined hardware breakpoints/watchpoints "
|
||||
"is %" PRId32 ". -->", nds32_v2->n_hbr);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v2->next_hbr_index++;
|
||||
|
||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
||||
if (result != ERROR_OK) {
|
||||
/* auto convert to hardware breakpoint if failed */
|
||||
if (nds32->auto_convert_hw_bp) {
|
||||
/* convert to hardware breakpoint */
|
||||
breakpoint->type = BKPT_HARD;
|
||||
|
||||
return nds32_v2_add_breakpoint(target, breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_remove_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
if (nds32_v2->next_hbr_index <= 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v2->next_hbr_index--;
|
||||
|
||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_add_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
|
||||
/* check hardware resource */
|
||||
if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
||||
"breakpoints/watchpoints! The limit of "
|
||||
"combined hardware breakpoints/watchpoints is %" PRId32 ". -->", nds32_v2->n_hbr);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware watchpoint */
|
||||
nds32_v2->next_hbr_index++;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_remove_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
|
||||
if (nds32_v2->next_hbr_index <= 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v2->next_hbr_index--;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_get_exception_address(struct nds32 *nds32,
|
||||
uint32_t *address, uint32_t reason)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
||||
|
||||
aice_read_register(aice, IR4, address); /* read $EVA directly */
|
||||
|
||||
/* TODO: hit multiple watchpoints */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* find out which watchpoint hits
|
||||
* get exception address and compare the address to watchpoints
|
||||
*/
|
||||
static int nds32_v2_hit_watchpoint(struct target *target,
|
||||
struct watchpoint **hit_watchpoint)
|
||||
{
|
||||
uint32_t exception_address;
|
||||
struct watchpoint *wp;
|
||||
static struct watchpoint scan_all_watchpoint;
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
|
||||
scan_all_watchpoint.address = 0;
|
||||
scan_all_watchpoint.rw = WPT_WRITE;
|
||||
scan_all_watchpoint.next = 0;
|
||||
scan_all_watchpoint.unique_id = 0x5CA8;
|
||||
|
||||
exception_address = nds32->watched_address;
|
||||
|
||||
if (exception_address == 0) {
|
||||
/* send watch:0 to tell GDB to do software scan for hitting multiple watchpoints */
|
||||
*hit_watchpoint = &scan_all_watchpoint;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
if (((exception_address ^ wp->address) & (~wp->mask)) == 0) {
|
||||
/* TODO: dispel false match */
|
||||
*hit_watchpoint = wp;
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int nds32_v2_run_algorithm(struct target *target,
|
||||
int num_mem_params,
|
||||
struct mem_param *mem_params,
|
||||
int num_reg_params,
|
||||
struct reg_param *reg_params,
|
||||
target_addr_t entry_point,
|
||||
target_addr_t exit_point,
|
||||
int timeout_ms,
|
||||
void *arch_info)
|
||||
{
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
static int nds32_v2_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2;
|
||||
|
||||
nds32_v2 = calloc(1, sizeof(*nds32_v2));
|
||||
if (!nds32_v2)
|
||||
return ERROR_FAIL;
|
||||
|
||||
nds32_v2->nds32.register_map = nds32_v2_register_mapping;
|
||||
nds32_v2->nds32.get_debug_reason = nds32_v2_get_debug_reason;
|
||||
nds32_v2->nds32.enter_debug_state = nds32_v2_debug_entry;
|
||||
nds32_v2->nds32.leave_debug_state = nds32_v2_leave_debug_state;
|
||||
nds32_v2->nds32.get_watched_address = nds32_v2_get_exception_address;
|
||||
|
||||
nds32_init_arch_info(target, &(nds32_v2->nds32));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_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;
|
||||
}
|
||||
|
||||
/* talk to the target and set things up */
|
||||
static int nds32_v2_examine(struct target *target)
|
||||
{
|
||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
||||
|
||||
if (nds32->reset_halt_as_examine)
|
||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
||||
}
|
||||
|
||||
uint32_t edm_cfg;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
||||
|
||||
/* get the number of hardware breakpoints */
|
||||
nds32_v2->n_hbr = (edm_cfg & 0x7) + 1;
|
||||
|
||||
nds32_v2->next_hbr_index = 0;
|
||||
|
||||
LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target),
|
||||
nds32_v2->n_hbr);
|
||||
|
||||
nds32->target->state = TARGET_RUNNING;
|
||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
||||
|
||||
target_set_examined(target);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_translate_address(struct target *target, target_addr_t *address)
|
||||
{
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
struct nds32_memory *memory = &(nds32->memory);
|
||||
target_addr_t physical_address;
|
||||
|
||||
/* Following conditions need to do address translation
|
||||
* 1. BUS mode
|
||||
* 2. CPU mode under maximum interrupt level */
|
||||
if ((memory->access_channel == NDS_MEMORY_ACC_BUS) ||
|
||||
((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
nds32_reach_max_interrupt_level(nds32))) {
|
||||
if (target->type->virt2phys(target, *address, &physical_address) == ERROR_OK)
|
||||
*address = physical_address;
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v2_read_buffer(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint8_t *buffer)
|
||||
{
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
struct nds32_memory *memory = &(nds32->memory);
|
||||
|
||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
||||
* for second page or so. */
|
||||
|
||||
nds32_v2_translate_address(target, &address);
|
||||
|
||||
return nds32_read_buffer(target, address, size, buffer);
|
||||
}
|
||||
|
||||
static int nds32_v2_write_buffer(struct target *target, target_addr_t address,
|
||||
uint32_t size, const uint8_t *buffer)
|
||||
{
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
struct nds32_memory *memory = &(nds32->memory);
|
||||
|
||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
||||
* for second page or so. */
|
||||
|
||||
nds32_v2_translate_address(target, &address);
|
||||
|
||||
return nds32_write_buffer(target, address, size, buffer);
|
||||
}
|
||||
|
||||
static int nds32_v2_read_memory(struct target *target, target_addr_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 ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
||||
* for second page or so. */
|
||||
|
||||
nds32_v2_translate_address(target, &address);
|
||||
|
||||
return nds32_read_memory(target, address, size, count, buffer);
|
||||
}
|
||||
|
||||
static int nds32_v2_write_memory(struct target *target, target_addr_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 ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
||||
* for second page or so. */
|
||||
|
||||
nds32_v2_translate_address(target, &address);
|
||||
|
||||
return nds32_write_memory(target, address, size, count, buffer);
|
||||
}
|
||||
|
||||
/** Holds methods for V2 targets. */
|
||||
struct target_type nds32_v2_target = {
|
||||
.name = "nds32_v2",
|
||||
|
||||
.poll = nds32_poll,
|
||||
.arch_state = nds32_arch_state,
|
||||
|
||||
.target_request_data = nds32_v2_target_request_data,
|
||||
|
||||
.halt = nds32_halt,
|
||||
.resume = nds32_resume,
|
||||
.step = nds32_step,
|
||||
|
||||
.assert_reset = nds32_assert_reset,
|
||||
.deassert_reset = nds32_v2_deassert_reset,
|
||||
|
||||
/* register access */
|
||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
||||
|
||||
/* memory access */
|
||||
.read_buffer = nds32_v2_read_buffer,
|
||||
.write_buffer = nds32_v2_write_buffer,
|
||||
.read_memory = nds32_v2_read_memory,
|
||||
.write_memory = nds32_v2_write_memory,
|
||||
|
||||
.checksum_memory = nds32_v2_checksum_memory,
|
||||
|
||||
/* breakpoint/watchpoint */
|
||||
.add_breakpoint = nds32_v2_add_breakpoint,
|
||||
.remove_breakpoint = nds32_v2_remove_breakpoint,
|
||||
.add_watchpoint = nds32_v2_add_watchpoint,
|
||||
.remove_watchpoint = nds32_v2_remove_watchpoint,
|
||||
.hit_watchpoint = nds32_v2_hit_watchpoint,
|
||||
|
||||
/* MMU */
|
||||
.mmu = nds32_mmu,
|
||||
.virt2phys = nds32_virtual_to_physical,
|
||||
.read_phys_memory = nds32_read_phys_memory,
|
||||
.write_phys_memory = nds32_write_phys_memory,
|
||||
|
||||
.run_algorithm = nds32_v2_run_algorithm,
|
||||
|
||||
.commands = nds32_command_handlers,
|
||||
.target_create = nds32_v2_target_create,
|
||||
.init_target = nds32_v2_init_target,
|
||||
.examine = nds32_v2_examine,
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_V2_H
|
||||
#define OPENOCD_TARGET_NDS32_V2_H
|
||||
|
||||
#include "nds32.h"
|
||||
|
||||
struct nds32_v2_common {
|
||||
struct nds32 nds32;
|
||||
|
||||
uint32_t backup_ir0;
|
||||
|
||||
/** number of hardware breakpoints */
|
||||
int32_t n_hbr;
|
||||
|
||||
/** next hardware breakpoint index */
|
||||
/** increase from low index to high index */
|
||||
int32_t next_hbr_index;
|
||||
};
|
||||
|
||||
static inline struct nds32_v2_common *target_to_nds32_v2(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info, struct nds32_v2_common, nds32);
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_V2_H */
|
||||
@@ -1,510 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "breakpoints.h"
|
||||
#include "nds32_cmd.h"
|
||||
#include "nds32_aice.h"
|
||||
#include "nds32_v3.h"
|
||||
#include "nds32_v3_common.h"
|
||||
|
||||
static int nds32_v3_activate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
int32_t hbr_index = nds32_v3->next_hbr_index;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT) {
|
||||
/* already set at nds32_v3_add_breakpoint() */
|
||||
continue;
|
||||
} else if (bp->type == BKPT_HARD) {
|
||||
hbr_index--;
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
|
||||
/* set value */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
|
||||
|
||||
if (nds32_v3->nds32.memory.address_translation)
|
||||
/* enable breakpoint (virtual address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
|
||||
else
|
||||
/* enable breakpoint (physical address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
|
||||
|
||||
LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
||||
bp->address);
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_deactivate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
int32_t hbr_index = nds32_v3->next_hbr_index;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT) {
|
||||
continue;
|
||||
} else if (bp->type == BKPT_HARD) {
|
||||
hbr_index--;
|
||||
/* disable breakpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
||||
bp->address);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_activate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct watchpoint *wp;
|
||||
int32_t wp_num = 0;
|
||||
uint32_t wp_config = 0;
|
||||
bool ld_stop, st_stop;
|
||||
|
||||
if (nds32_v3->nds32.global_stop)
|
||||
ld_stop = st_stop = false;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
|
||||
if (wp_num < nds32_v3->used_n_wp) {
|
||||
wp->mask = wp->length - 1;
|
||||
if ((wp->address % wp->length) != 0)
|
||||
wp->mask = (wp->mask << 1) + 1;
|
||||
|
||||
if (wp->rw == WPT_READ)
|
||||
wp_config = 0x3;
|
||||
else if (wp->rw == WPT_WRITE)
|
||||
wp_config = 0x5;
|
||||
else if (wp->rw == WPT_ACCESS)
|
||||
wp_config = 0x7;
|
||||
|
||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
||||
if (nds32_v3->nds32.memory.address_translation == false)
|
||||
wp_config |= 0x8;
|
||||
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
||||
wp->address - (wp->address % wp->length));
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
||||
/* enable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
||||
/* set value */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
|
||||
|
||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32,
|
||||
wp_num, wp->address, wp->mask);
|
||||
|
||||
wp_num++;
|
||||
} else if (nds32_v3->nds32.global_stop) {
|
||||
if (wp->rw == WPT_READ)
|
||||
ld_stop = true;
|
||||
else if (wp->rw == WPT_WRITE)
|
||||
st_stop = true;
|
||||
else if (wp->rw == WPT_ACCESS)
|
||||
ld_stop = st_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nds32_v3->nds32.global_stop) {
|
||||
uint32_t edm_ctl;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
||||
if (ld_stop)
|
||||
edm_ctl |= 0x10;
|
||||
if (st_stop)
|
||||
edm_ctl |= 0x20;
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_deactivate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
int32_t wp_num = 0;
|
||||
struct watchpoint *wp;
|
||||
bool clean_global_stop = false;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
|
||||
if (wp_num < nds32_v3->used_n_wp) {
|
||||
/* disable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
||||
|
||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
||||
" mask %08" PRIx32, wp_num,
|
||||
wp->address, wp->mask);
|
||||
wp_num++;
|
||||
} else if (nds32_v3->nds32.global_stop) {
|
||||
clean_global_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (clean_global_stop) {
|
||||
uint32_t edm_ctl;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
||||
edm_ctl = edm_ctl & (~0x30);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_check_interrupt_stack(struct nds32 *nds32)
|
||||
{
|
||||
uint32_t val_ir0;
|
||||
uint32_t value;
|
||||
|
||||
/* Save interrupt level */
|
||||
nds32_get_mapped_reg(nds32, IR0, &val_ir0);
|
||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
||||
|
||||
if (nds32_reach_max_interrupt_level(nds32))
|
||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
||||
nds32->current_interrupt_level);
|
||||
|
||||
/* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
|
||||
nds32_get_mapped_reg(nds32, IR4, &value);
|
||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
/* get backup value from cache */
|
||||
/* then set back to make the register dirty */
|
||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
||||
nds32_set_mapped_reg(nds32, IR0, value);
|
||||
|
||||
nds32_get_mapped_reg(nds32, IR4, &value);
|
||||
nds32_set_mapped_reg(nds32, IR4, value);
|
||||
|
||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
||||
nds32_set_mapped_reg(nds32, IR6, value);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_deassert_reset(struct target *target)
|
||||
{
|
||||
int retval;
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
bool switch_to_v3_stack = false;
|
||||
uint32_t value_edm_ctl;
|
||||
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
|
||||
if (((value_edm_ctl >> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, value_edm_ctl | (0x1 << 6));
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
|
||||
if (((value_edm_ctl >> 6) & 0x1) == 1)
|
||||
switch_to_v3_stack = true;
|
||||
} else
|
||||
switch_to_v3_stack = false;
|
||||
|
||||
CHECK_RETVAL(nds32_poll(target));
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
/* reset only */
|
||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||
target_name(target));
|
||||
retval = target_halt(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
} else {
|
||||
/* reset-halt */
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
||||
uint32_t value;
|
||||
uint32_t interrupt_level;
|
||||
|
||||
if (switch_to_v3_stack == true) {
|
||||
/* PSW.INTL-- */
|
||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
||||
interrupt_level = (value >> 1) & 0x3;
|
||||
interrupt_level--;
|
||||
value &= ~(0x6);
|
||||
value |= (interrupt_level << 1);
|
||||
value |= 0x400; /* set PSW.DEX */
|
||||
nds32_set_mapped_reg(nds32, IR0, value);
|
||||
|
||||
/* copy IPC to OIPC */
|
||||
if ((interrupt_level + 1) < nds32->max_interrupt_level) {
|
||||
nds32_get_mapped_reg(nds32, IR9, &value);
|
||||
nds32_set_mapped_reg(nds32, IR11, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_add_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
||||
int result;
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
/* check hardware resource */
|
||||
if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many "
|
||||
"hardware breakpoints/watchpoints! "
|
||||
"The limit of combined hardware "
|
||||
"breakpoints/watchpoints is %" PRId32 ". -->",
|
||||
nds32_v3->n_hbr);
|
||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
||||
"hardware breakpoint: %" PRId32 ", hardware "
|
||||
"watchpoints: %" PRId32 ". -->",
|
||||
nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
|
||||
nds32_v3->used_n_wp);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v3->next_hbr_index++;
|
||||
|
||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
||||
if (result != ERROR_OK) {
|
||||
/* auto convert to hardware breakpoint if failed */
|
||||
if (nds32->auto_convert_hw_bp) {
|
||||
/* convert to hardware breakpoint */
|
||||
breakpoint->type = BKPT_HARD;
|
||||
|
||||
return nds32_v3_add_breakpoint(target, breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_remove_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
if (nds32_v3->next_hbr_index <= 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v3->next_hbr_index--;
|
||||
|
||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_add_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
|
||||
/* check hardware resource */
|
||||
if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
|
||||
/* No hardware resource */
|
||||
if (nds32_v3->nds32.global_stop) {
|
||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
||||
"watchpoints exceeds the hardware "
|
||||
"resources. Stop at every load/store "
|
||||
"instruction to check for watchpoint matches. -->");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
||||
"breakpoints/watchpoints! The limit of combined "
|
||||
"hardware breakpoints/watchpoints is %" PRId32 ". -->",
|
||||
nds32_v3->n_hbr);
|
||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
||||
"hardware breakpoint: %" PRId32 ", hardware "
|
||||
"watchpoints: %" PRId32 ". -->",
|
||||
nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
|
||||
nds32_v3->used_n_wp);
|
||||
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware watchpoint */
|
||||
nds32_v3->next_hbr_index++;
|
||||
nds32_v3->used_n_wp++;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3_remove_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
|
||||
if (nds32_v3->next_hbr_index <= 0) {
|
||||
if (nds32_v3->nds32.global_stop)
|
||||
return ERROR_OK;
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v3->next_hbr_index--;
|
||||
nds32_v3->used_n_wp--;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static struct nds32_v3_common_callback nds32_v3_common_callback = {
|
||||
.check_interrupt_stack = nds32_v3_check_interrupt_stack,
|
||||
.restore_interrupt_stack = nds32_v3_restore_interrupt_stack,
|
||||
.activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint,
|
||||
.activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint,
|
||||
.deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint,
|
||||
.deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint,
|
||||
};
|
||||
|
||||
static int nds32_v3_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3;
|
||||
|
||||
nds32_v3 = calloc(1, sizeof(*nds32_v3));
|
||||
if (!nds32_v3)
|
||||
return ERROR_FAIL;
|
||||
|
||||
nds32_v3_common_register_callback(&nds32_v3_common_callback);
|
||||
nds32_v3_target_create_common(target, &(nds32_v3->nds32));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* talk to the target and set things up */
|
||||
static int nds32_v3_examine(struct target *target)
|
||||
{
|
||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
||||
|
||||
if (nds32->reset_halt_as_examine)
|
||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
||||
}
|
||||
|
||||
uint32_t edm_cfg;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
||||
|
||||
/* get the number of hardware breakpoints */
|
||||
nds32_v3->n_hbr = (edm_cfg & 0x7) + 1;
|
||||
|
||||
/* low interference profiling */
|
||||
if (edm_cfg & 0x100)
|
||||
nds32_v3->low_interference_profile = true;
|
||||
else
|
||||
nds32_v3->low_interference_profile = false;
|
||||
|
||||
nds32_v3->next_hbr_index = 0;
|
||||
nds32_v3->used_n_wp = 0;
|
||||
|
||||
LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target),
|
||||
nds32_v3->n_hbr);
|
||||
|
||||
nds32->target->state = TARGET_RUNNING;
|
||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
||||
|
||||
target_set_examined(target);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Holds methods for Andes1337 targets. */
|
||||
struct target_type nds32_v3_target = {
|
||||
.name = "nds32_v3",
|
||||
|
||||
.poll = nds32_poll,
|
||||
.arch_state = nds32_arch_state,
|
||||
|
||||
.target_request_data = nds32_v3_target_request_data,
|
||||
|
||||
.halt = nds32_halt,
|
||||
.resume = nds32_resume,
|
||||
.step = nds32_step,
|
||||
|
||||
.assert_reset = nds32_assert_reset,
|
||||
.deassert_reset = nds32_v3_deassert_reset,
|
||||
|
||||
/* register access */
|
||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
||||
|
||||
/* memory access */
|
||||
.read_buffer = nds32_v3_read_buffer,
|
||||
.write_buffer = nds32_v3_write_buffer,
|
||||
.read_memory = nds32_v3_read_memory,
|
||||
.write_memory = nds32_v3_write_memory,
|
||||
|
||||
.checksum_memory = nds32_v3_checksum_memory,
|
||||
|
||||
/* breakpoint/watchpoint */
|
||||
.add_breakpoint = nds32_v3_add_breakpoint,
|
||||
.remove_breakpoint = nds32_v3_remove_breakpoint,
|
||||
.add_watchpoint = nds32_v3_add_watchpoint,
|
||||
.remove_watchpoint = nds32_v3_remove_watchpoint,
|
||||
.hit_watchpoint = nds32_v3_hit_watchpoint,
|
||||
|
||||
/* MMU */
|
||||
.mmu = nds32_mmu,
|
||||
.virt2phys = nds32_virtual_to_physical,
|
||||
.read_phys_memory = nds32_read_phys_memory,
|
||||
.write_phys_memory = nds32_write_phys_memory,
|
||||
|
||||
.run_algorithm = nds32_v3_run_algorithm,
|
||||
|
||||
.commands = nds32_command_handlers,
|
||||
.target_create = nds32_v3_target_create,
|
||||
.init_target = nds32_v3_init_target,
|
||||
.examine = nds32_v3_examine,
|
||||
|
||||
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
||||
.gdb_fileio_end = nds32_gdb_fileio_end,
|
||||
|
||||
.profiling = nds32_profiling,
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_V3_H
|
||||
#define OPENOCD_TARGET_NDS32_V3_H
|
||||
|
||||
#include "nds32.h"
|
||||
|
||||
struct nds32_v3_common {
|
||||
struct nds32 nds32;
|
||||
|
||||
/** number of hardware breakpoints */
|
||||
int32_t n_hbr;
|
||||
|
||||
/** number of used hardware watchpoints */
|
||||
int32_t used_n_wp;
|
||||
|
||||
/** next hardware breakpoint index */
|
||||
int32_t next_hbr_index;
|
||||
|
||||
/** low interference profiling */
|
||||
bool low_interference_profile;
|
||||
};
|
||||
|
||||
static inline struct nds32_v3_common *target_to_nds32_v3(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info, struct nds32_v3_common, nds32);
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_V3_H */
|
||||
@@ -1,664 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#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");
|
||||
|
||||
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));
|
||||
|
||||
struct breakpoint *syscall_break = &(nds32->syscall_break);
|
||||
if (nds32->virtual_hosting) {
|
||||
if (syscall_break->is_set) {
|
||||
/** disable virtual hosting */
|
||||
|
||||
/* remove breakpoint at syscall entry */
|
||||
target_remove_breakpoint(nds32->target, syscall_break);
|
||||
syscall_break->is_set = false;
|
||||
|
||||
uint32_t value_pc;
|
||||
nds32_get_mapped_reg(nds32, PC, &value_pc);
|
||||
if (value_pc == syscall_break->address)
|
||||
/** process syscall for virtual hosting */
|
||||
nds32->hit_syscall = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nds32_examine_debug_reason(nds32) != ERROR_OK) {
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
if (nds32->virtual_hosting) {
|
||||
/** enable virtual hosting */
|
||||
uint32_t value_ir3;
|
||||
uint32_t entry_size;
|
||||
uint32_t syscall_address;
|
||||
|
||||
/* get syscall entry address */
|
||||
nds32_get_mapped_reg(nds32, IR3, &value_ir3);
|
||||
entry_size = 0x4 << (((value_ir3 >> 14) & 0x3) << 1);
|
||||
syscall_address = (value_ir3 & 0xFFFF0000) + entry_size * 8; /* The index of SYSCALL is 8 */
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
/* single step to skip syscall entry */
|
||||
/* use IRET to skip syscall */
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
uint32_t value_ir9;
|
||||
uint32_t value_ir6;
|
||||
uint32_t syscall_id;
|
||||
|
||||
nds32_get_mapped_reg(nds32, IR6, &value_ir6);
|
||||
syscall_id = (value_ir6 >> 16) & 0x7FFF;
|
||||
|
||||
if (syscall_id == NDS32_SYSCALL_EXIT) {
|
||||
/* If target hits exit syscall, do not use IRET to skip handler. */
|
||||
aice_step(aice);
|
||||
} else {
|
||||
/* use api->read/write_reg to skip nds32 register cache */
|
||||
uint32_t value_dimbr;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_DIMBR, &value_dimbr);
|
||||
aice_write_register(aice, IR11, value_dimbr + 0xC);
|
||||
|
||||
aice_read_register(aice, IR9, &value_ir9);
|
||||
value_ir9 += 4; /* syscall is always 4 bytes */
|
||||
aice_write_register(aice, IR9, value_ir9);
|
||||
|
||||
/* backup hardware breakpoint 0 */
|
||||
uint32_t backup_bpa, backup_bpam, backup_bpc;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPA0, &backup_bpa);
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPAM0, &backup_bpam);
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0, &backup_bpc);
|
||||
|
||||
/* use hardware breakpoint 0 to stop cpu after skipping syscall */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, value_ir9);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, 0);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, 0xA);
|
||||
|
||||
/* Execute two IRET.
|
||||
* First IRET is used to quit debug mode.
|
||||
* Second IRET is used to quit current syscall. */
|
||||
uint32_t dim_inst[4] = {NOP, NOP, IRET, IRET};
|
||||
aice_execute(aice, dim_inst, 4);
|
||||
|
||||
/* restore origin hardware breakpoint 0 */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, backup_bpa);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, backup_bpam);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, backup_bpc);
|
||||
}
|
||||
|
||||
nds32->hit_syscall = false;
|
||||
}
|
||||
|
||||
/* insert breakpoint at syscall entry */
|
||||
struct breakpoint *syscall_break = &(nds32->syscall_break);
|
||||
|
||||
syscall_break->address = syscall_address;
|
||||
syscall_break->type = BKPT_SOFT;
|
||||
syscall_break->is_set = true;
|
||||
target_add_breakpoint(target, syscall_break);
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t bp_control;
|
||||
|
||||
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 target hits multiple read/access watchpoint,
|
||||
* select the first one. */
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &bp_control);
|
||||
if (0x3 == (bp_control & 0x3)) {
|
||||
match_count = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ((reason == NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE) ||
|
||||
(reason == NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE)) {
|
||||
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%08" PRIx32 ", access start: 0x%08" PRIx32 ", end: 0x%08" PRIx32,
|
||||
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 ((reason == NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP) && 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_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum)
|
||||
{
|
||||
LOG_WARNING("Not implemented: %s", __func__);
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* find out which watchpoint hits
|
||||
* get exception address and compare the address to watchpoints
|
||||
*/
|
||||
int nds32_v3_hit_watchpoint(struct target *target,
|
||||
struct watchpoint **hit_watchpoint)
|
||||
{
|
||||
static struct watchpoint scan_all_watchpoint;
|
||||
|
||||
uint32_t exception_address;
|
||||
struct watchpoint *wp;
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
|
||||
exception_address = nds32->watched_address;
|
||||
|
||||
if (exception_address == 0xFFFFFFFF)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (exception_address == 0) {
|
||||
scan_all_watchpoint.address = 0;
|
||||
scan_all_watchpoint.rw = WPT_WRITE;
|
||||
scan_all_watchpoint.next = 0;
|
||||
scan_all_watchpoint.unique_id = 0x5CA8;
|
||||
|
||||
*hit_watchpoint = &scan_all_watchpoint;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
if (((exception_address ^ wp->address) & (~wp->mask)) == 0) {
|
||||
*hit_watchpoint = wp;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
target_addr_t entry_point,
|
||||
target_addr_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, target_addr_t address,
|
||||
uint32_t size, uint8_t *buffer)
|
||||
{
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
struct nds32_memory *memory = &(nds32->memory);
|
||||
|
||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
target_addr_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 (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
||||
address = physical_address;
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
|
||||
int result;
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
/* give arbitrary initial value to avoid warning messages */
|
||||
enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
/* Use bus mode to access memory during virtual hosting */
|
||||
origin_access_channel = memory->access_channel;
|
||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
||||
}
|
||||
|
||||
result = nds32_read_buffer(target, address, size, buffer);
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
/* Restore access_channel after virtual hosting */
|
||||
memory->access_channel = origin_access_channel;
|
||||
aice_memory_access(aice, origin_access_channel);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int nds32_v3_write_buffer(struct target *target, target_addr_t address,
|
||||
uint32_t size, const uint8_t *buffer)
|
||||
{
|
||||
struct nds32 *nds32 = target_to_nds32(target);
|
||||
struct nds32_memory *memory = &(nds32->memory);
|
||||
|
||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
target_addr_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 (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
||||
address = physical_address;
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
enum nds_memory_access origin_access_channel;
|
||||
origin_access_channel = memory->access_channel;
|
||||
|
||||
/* If target has no cache, use BUS mode to access memory. */
|
||||
if ((memory->dcache.line_size == 0)
|
||||
|| (memory->dcache.enable == false)) {
|
||||
/* There is no Dcache or Dcache is disabled. */
|
||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
||||
}
|
||||
|
||||
int result;
|
||||
result = nds32_gdb_fileio_write_memory(nds32, address, size, buffer);
|
||||
|
||||
if (origin_access_channel == NDS_MEMORY_ACC_CPU) {
|
||||
memory->access_channel = NDS_MEMORY_ACC_CPU;
|
||||
aice_memory_access(aice, NDS_MEMORY_ACC_CPU);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return nds32_write_buffer(target, address, size, buffer);
|
||||
}
|
||||
|
||||
int nds32_v3_read_memory(struct target *target, target_addr_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 ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
target_addr_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 (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
||||
address = physical_address;
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
/* give arbitrary initial value to avoid warning messages */
|
||||
enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
|
||||
int result;
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
/* Use bus mode to access memory during virtual hosting */
|
||||
origin_access_channel = memory->access_channel;
|
||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
||||
}
|
||||
|
||||
result = nds32_read_memory(target, address, size, count, buffer);
|
||||
|
||||
if (nds32->hit_syscall) {
|
||||
/* Restore access_channel after virtual hosting */
|
||||
memory->access_channel = origin_access_channel;
|
||||
aice_memory_access(aice, origin_access_channel);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int nds32_v3_write_memory(struct target *target, target_addr_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 ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
||||
(target->state != TARGET_HALTED)) {
|
||||
LOG_WARNING("target was not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
target_addr_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 (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
||||
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);
|
||||
|
||||
target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
|
||||
target->fileio_info->identifier = NULL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_V3_COMMON_H
|
||||
#define OPENOCD_TARGET_NDS32_V3_COMMON_H
|
||||
|
||||
#include "target.h"
|
||||
|
||||
struct nds32_v3_common_callback {
|
||||
int (*check_interrupt_stack)(struct nds32 *nds32);
|
||||
int (*restore_interrupt_stack)(struct nds32 *nds32);
|
||||
int (*activate_hardware_breakpoint)(struct target *target);
|
||||
int (*activate_hardware_watchpoint)(struct target *target);
|
||||
int (*deactivate_hardware_breakpoint)(struct target *target);
|
||||
int (*deactivate_hardware_watchpoint)(struct target *target);
|
||||
};
|
||||
|
||||
void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback);
|
||||
int nds32_v3_target_request_data(struct target *target,
|
||||
uint32_t size, uint8_t *buffer);
|
||||
int nds32_v3_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
||||
int nds32_v3_hit_watchpoint(struct target *target,
|
||||
struct watchpoint **hit_watchpoint);
|
||||
int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32);
|
||||
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,
|
||||
target_addr_t entry_point,
|
||||
target_addr_t exit_point,
|
||||
int timeout_ms,
|
||||
void *arch_info);
|
||||
int nds32_v3_read_buffer(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint8_t *buffer);
|
||||
int nds32_v3_write_buffer(struct target *target, target_addr_t address,
|
||||
uint32_t size, const uint8_t *buffer);
|
||||
int nds32_v3_read_memory(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
||||
int nds32_v3_write_memory(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
||||
int nds32_v3_init_target(struct command_context *cmd_ctx,
|
||||
struct target *target);
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_V3_COMMON_H */
|
||||
@@ -1,495 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "breakpoints.h"
|
||||
#include "nds32_cmd.h"
|
||||
#include "nds32_aice.h"
|
||||
#include "nds32_v3m.h"
|
||||
#include "nds32_v3_common.h"
|
||||
|
||||
static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
unsigned brp_num = nds32_v3m->n_hbr - 1;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT) {
|
||||
/* already set at nds32_v3m_add_breakpoint() */
|
||||
continue;
|
||||
} else if (bp->type == BKPT_HARD) {
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
|
||||
|
||||
if (nds32_v3m->nds32.memory.address_translation)
|
||||
/* enable breakpoint (virtual address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
|
||||
else
|
||||
/* enable breakpoint (physical address) */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
|
||||
|
||||
LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
|
||||
bp->address);
|
||||
|
||||
brp_num--;
|
||||
} else {
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct breakpoint *bp;
|
||||
unsigned brp_num = nds32_v3m->n_hbr - 1;
|
||||
|
||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
||||
if (bp->type == BKPT_SOFT)
|
||||
continue;
|
||||
else if (bp->type == BKPT_HARD)
|
||||
/* disable breakpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
|
||||
else
|
||||
return ERROR_FAIL;
|
||||
|
||||
LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
|
||||
bp->address);
|
||||
|
||||
brp_num--;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct watchpoint *wp;
|
||||
int32_t wp_num = 0;
|
||||
uint32_t wp_config = 0;
|
||||
bool ld_stop, st_stop;
|
||||
|
||||
if (nds32_v3m->nds32.global_stop)
|
||||
ld_stop = st_stop = false;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
|
||||
if (wp_num < nds32_v3m->used_n_wp) {
|
||||
wp->mask = wp->length - 1;
|
||||
if ((wp->address % wp->length) != 0)
|
||||
wp->mask = (wp->mask << 1) + 1;
|
||||
|
||||
if (wp->rw == WPT_READ)
|
||||
wp_config = 0x3;
|
||||
else if (wp->rw == WPT_WRITE)
|
||||
wp_config = 0x5;
|
||||
else if (wp->rw == WPT_ACCESS)
|
||||
wp_config = 0x7;
|
||||
|
||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
||||
if (nds32_v3m->nds32.memory.address_translation == false)
|
||||
wp_config |= 0x8;
|
||||
|
||||
/* set address */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
||||
wp->address - (wp->address % wp->length));
|
||||
/* set mask */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
||||
/* enable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
||||
|
||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
||||
" mask %08" PRIx32, wp_num, wp->address, wp->mask);
|
||||
|
||||
wp_num++;
|
||||
} else if (nds32_v3m->nds32.global_stop) {
|
||||
if (wp->rw == WPT_READ)
|
||||
ld_stop = true;
|
||||
else if (wp->rw == WPT_WRITE)
|
||||
st_stop = true;
|
||||
else if (wp->rw == WPT_ACCESS)
|
||||
ld_stop = st_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nds32_v3m->nds32.global_stop) {
|
||||
uint32_t edm_ctl;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
||||
if (ld_stop)
|
||||
edm_ctl |= 0x10;
|
||||
if (st_stop)
|
||||
edm_ctl |= 0x20;
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
struct watchpoint *wp;
|
||||
int32_t wp_num = 0;
|
||||
bool clean_global_stop = false;
|
||||
|
||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
||||
|
||||
if (wp_num < nds32_v3m->used_n_wp) {
|
||||
/* disable watchpoint */
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
||||
|
||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
||||
" mask %08" PRIx32, wp_num, wp->address, wp->mask);
|
||||
wp_num++;
|
||||
} else if (nds32_v3m->nds32.global_stop) {
|
||||
clean_global_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (clean_global_stop) {
|
||||
uint32_t edm_ctl;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
||||
edm_ctl = edm_ctl & (~0x30);
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
|
||||
{
|
||||
uint32_t val_ir0;
|
||||
uint32_t value;
|
||||
|
||||
/* Save interrupt level */
|
||||
nds32_get_mapped_reg(nds32, IR0, &val_ir0);
|
||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
||||
|
||||
if (nds32_reach_max_interrupt_level(nds32))
|
||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
||||
nds32->current_interrupt_level);
|
||||
|
||||
/* backup $ir6 to avoid suppressed exception overwrite */
|
||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
/* get backup value from cache */
|
||||
/* then set back to make the register dirty */
|
||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
||||
nds32_set_mapped_reg(nds32, IR0, value);
|
||||
|
||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
||||
nds32_set_mapped_reg(nds32, IR6, value);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_deassert_reset(struct target *target)
|
||||
{
|
||||
int retval;
|
||||
|
||||
CHECK_RETVAL(nds32_poll(target));
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
/* reset only */
|
||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
||||
target_name(target));
|
||||
retval = target_halt(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_add_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct nds32 *nds32 = &(nds32_v3m->nds32);
|
||||
int result;
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
/* check hardware resource */
|
||||
if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many "
|
||||
"hardware breakpoints/watchpoints! "
|
||||
"The limit of combined hardware "
|
||||
"breakpoints/watchpoints is %" PRId32 ". -->",
|
||||
nds32_v3m->n_hbr);
|
||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
||||
"hardware breakpoint: %" PRId32 ", hardware "
|
||||
"watchpoints: %" PRId32 ". -->",
|
||||
nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
|
||||
nds32_v3m->used_n_wp);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v3m->next_hbr_index--;
|
||||
|
||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
||||
if (result != ERROR_OK) {
|
||||
/* auto convert to hardware breakpoint if failed */
|
||||
if (nds32->auto_convert_hw_bp) {
|
||||
/* convert to hardware breakpoint */
|
||||
breakpoint->type = BKPT_HARD;
|
||||
|
||||
return nds32_v3m_add_breakpoint(target, breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_remove_breakpoint(struct target *target,
|
||||
struct breakpoint *breakpoint)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
|
||||
if (breakpoint->type == BKPT_HARD) {
|
||||
if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* update next place to put hardware breakpoint */
|
||||
nds32_v3m->next_hbr_index++;
|
||||
|
||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
||||
return ERROR_OK;
|
||||
} else if (breakpoint->type == BKPT_SOFT) {
|
||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
||||
} else /* unrecognized breakpoint type */
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_add_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
|
||||
/* check hardware resource */
|
||||
if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
|
||||
/* No hardware resource */
|
||||
if (nds32_v3m->nds32.global_stop) {
|
||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
||||
"watchpoints exceeds the hardware "
|
||||
"resources. Stop at every load/store "
|
||||
"instruction to check for watchpoint matches. -->");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
||||
"watchpoints! The limit of hardware watchpoints "
|
||||
"is %" PRId32 ". -->", nds32_v3m->n_hwp);
|
||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
||||
"hardware watchpoint: %" PRId32 ". -->",
|
||||
nds32_v3m->used_n_wp);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
|
||||
/* No hardware resource */
|
||||
if (nds32_v3m->nds32.global_stop) {
|
||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
||||
"watchpoints exceeds the hardware "
|
||||
"resources. Stop at every load/store "
|
||||
"instruction to check for watchpoint matches. -->");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
||||
"breakpoints/watchpoints! The limit of combined "
|
||||
"hardware breakpoints/watchpoints is %" PRId32 ". -->",
|
||||
nds32_v3m->n_hbr);
|
||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
||||
"hardware breakpoint: %" PRId32 ", hardware "
|
||||
"watchpoints: %" PRId32 ". -->",
|
||||
nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
|
||||
nds32_v3m->used_n_wp);
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* update next place to put hardware watchpoint */
|
||||
nds32_v3m->next_hwp_index++;
|
||||
nds32_v3m->used_n_wp++;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nds32_v3m_remove_watchpoint(struct target *target,
|
||||
struct watchpoint *watchpoint)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
|
||||
if (nds32_v3m->next_hwp_index <= 0) {
|
||||
if (nds32_v3m->nds32.global_stop)
|
||||
return ERROR_OK;
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* update next place to put hardware watchpoint */
|
||||
nds32_v3m->next_hwp_index--;
|
||||
nds32_v3m->used_n_wp--;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static struct nds32_v3_common_callback nds32_v3m_common_callback = {
|
||||
.check_interrupt_stack = nds32_v3m_check_interrupt_stack,
|
||||
.restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
|
||||
.activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
|
||||
.activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
|
||||
.deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
|
||||
.deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
|
||||
};
|
||||
|
||||
static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m;
|
||||
|
||||
nds32_v3m = calloc(1, sizeof(*nds32_v3m));
|
||||
if (!nds32_v3m)
|
||||
return ERROR_FAIL;
|
||||
|
||||
nds32_v3_common_register_callback(&nds32_v3m_common_callback);
|
||||
nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* talk to the target and set things up */
|
||||
static int nds32_v3m_examine(struct target *target)
|
||||
{
|
||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
||||
struct nds32 *nds32 = &(nds32_v3m->nds32);
|
||||
struct aice_port_s *aice = target_to_aice(target);
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
||||
|
||||
if (nds32->reset_halt_as_examine)
|
||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
||||
}
|
||||
|
||||
uint32_t edm_cfg;
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
||||
|
||||
/* get the number of hardware breakpoints */
|
||||
nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
|
||||
nds32_v3m->used_n_wp = 0;
|
||||
|
||||
/* get the number of hardware watchpoints */
|
||||
/* If the WP field is hardwired to zero, it means this is a
|
||||
* simple breakpoint. Otherwise, if the WP field is writable
|
||||
* then it means this is a regular watchpoints. */
|
||||
nds32_v3m->n_hwp = 0;
|
||||
for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
|
||||
/** check the hardware breakpoint is simple or not */
|
||||
uint32_t tmp_value;
|
||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
|
||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
|
||||
|
||||
if (tmp_value)
|
||||
nds32_v3m->n_hwp++;
|
||||
}
|
||||
/* hardware breakpoint is inserted from high index to low index */
|
||||
nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
|
||||
/* hardware watchpoint is inserted from low index to high index */
|
||||
nds32_v3m->next_hwp_index = 0;
|
||||
|
||||
LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
|
||||
target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
|
||||
LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
|
||||
|
||||
nds32->target->state = TARGET_RUNNING;
|
||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
||||
|
||||
target_set_examined(target);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/** Holds methods for NDS32 V3m targets. */
|
||||
struct target_type nds32_v3m_target = {
|
||||
.name = "nds32_v3m",
|
||||
|
||||
.poll = nds32_poll,
|
||||
.arch_state = nds32_arch_state,
|
||||
|
||||
.target_request_data = nds32_v3_target_request_data,
|
||||
|
||||
.halt = nds32_halt,
|
||||
.resume = nds32_resume,
|
||||
.step = nds32_step,
|
||||
|
||||
.assert_reset = nds32_assert_reset,
|
||||
.deassert_reset = nds32_v3m_deassert_reset,
|
||||
|
||||
/* register access */
|
||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
||||
|
||||
/* memory access */
|
||||
.read_buffer = nds32_v3_read_buffer,
|
||||
.write_buffer = nds32_v3_write_buffer,
|
||||
.read_memory = nds32_v3_read_memory,
|
||||
.write_memory = nds32_v3_write_memory,
|
||||
|
||||
.checksum_memory = nds32_v3_checksum_memory,
|
||||
|
||||
/* breakpoint/watchpoint */
|
||||
.add_breakpoint = nds32_v3m_add_breakpoint,
|
||||
.remove_breakpoint = nds32_v3m_remove_breakpoint,
|
||||
.add_watchpoint = nds32_v3m_add_watchpoint,
|
||||
.remove_watchpoint = nds32_v3m_remove_watchpoint,
|
||||
.hit_watchpoint = nds32_v3_hit_watchpoint,
|
||||
|
||||
/* MMU */
|
||||
.mmu = nds32_mmu,
|
||||
.virt2phys = nds32_virtual_to_physical,
|
||||
.read_phys_memory = nds32_read_phys_memory,
|
||||
.write_phys_memory = nds32_write_phys_memory,
|
||||
|
||||
.run_algorithm = nds32_v3_run_algorithm,
|
||||
|
||||
.commands = nds32_command_handlers,
|
||||
.target_create = nds32_v3m_target_create,
|
||||
.init_target = nds32_v3_init_target,
|
||||
.examine = nds32_v3m_examine,
|
||||
|
||||
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
||||
.gdb_fileio_end = nds32_gdb_fileio_end,
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2013 Andes Technology *
|
||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_NDS32_V3M_H
|
||||
#define OPENOCD_TARGET_NDS32_V3M_H
|
||||
|
||||
#include "nds32.h"
|
||||
|
||||
struct nds32_v3m_common {
|
||||
struct nds32 nds32;
|
||||
|
||||
/** number of hardware breakpoints */
|
||||
int32_t n_hbr;
|
||||
|
||||
/** number of hardware watchpoints */
|
||||
int32_t n_hwp;
|
||||
|
||||
/** number of used hardware watchpoints */
|
||||
int32_t used_n_wp;
|
||||
|
||||
/** next hardware breakpoint index */
|
||||
/** for simple breakpoints, hardware breakpoints are inserted
|
||||
* from high index to low index */
|
||||
int32_t next_hbr_index;
|
||||
|
||||
/** next hardware watchpoint index */
|
||||
/** increase from low index to high index */
|
||||
int32_t next_hwp_index;
|
||||
};
|
||||
|
||||
static inline struct nds32_v3m_common *target_to_nds32_v3m(struct target *target)
|
||||
{
|
||||
return container_of(target->arch_info, struct nds32_v3m_common, nds32);
|
||||
}
|
||||
|
||||
#endif /* OPENOCD_TARGET_NDS32_V3M_H */
|
||||
@@ -92,9 +92,6 @@ extern struct target_type dsp5680xx_target;
|
||||
extern struct target_type testee_target;
|
||||
extern struct target_type avr32_ap7k_target;
|
||||
extern struct target_type hla_target;
|
||||
extern struct target_type nds32_v2_target;
|
||||
extern struct target_type nds32_v3_target;
|
||||
extern struct target_type nds32_v3m_target;
|
||||
extern struct target_type esp32_target;
|
||||
extern struct target_type esp32s2_target;
|
||||
extern struct target_type esp32s3_target;
|
||||
@@ -132,9 +129,6 @@ static struct target_type *target_types[] = {
|
||||
&testee_target,
|
||||
&avr32_ap7k_target,
|
||||
&hla_target,
|
||||
&nds32_v2_target,
|
||||
&nds32_v3_target,
|
||||
&nds32_v3m_target,
|
||||
&esp32_target,
|
||||
&esp32s2_target,
|
||||
&esp32s3_target,
|
||||
|
||||
Reference in New Issue
Block a user