diff --git a/src/target/mips32.c b/src/target/mips32.c index 16988b5a2..1067f7b63 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -472,11 +472,12 @@ int mips32_examine(struct target *target) static int mips32_configure_ibs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval, i; uint32_t bpinfo; /* get number of inst breakpoints */ - retval = target_read_u32(target, EJTAG_IBS, &bpinfo); + retval = target_read_u32(target, ejtag_info->ejtag_ibs_addr, &bpinfo); if (retval != ERROR_OK) return retval; @@ -487,21 +488,23 @@ static int mips32_configure_ibs(struct target *target) for (i = 0; i < mips32->num_inst_bpoints; i++) mips32->inst_break_list[i].reg_address = - EJTAG_IBA1 + (0x100 * i); + ejtag_info->ejtag_iba0_addr + + (ejtag_info->ejtag_iba_step_size * i); /* clear IBIS reg */ - retval = target_write_u32(target, EJTAG_IBS, 0); + retval = target_write_u32(target, ejtag_info->ejtag_ibs_addr, 0); return retval; } static int mips32_configure_dbs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval, i; uint32_t bpinfo; /* get number of data breakpoints */ - retval = target_read_u32(target, EJTAG_DBS, &bpinfo); + retval = target_read_u32(target, ejtag_info->ejtag_dbs_addr, &bpinfo); if (retval != ERROR_OK) return retval; @@ -512,10 +515,11 @@ static int mips32_configure_dbs(struct target *target) for (i = 0; i < mips32->num_data_bpoints; i++) mips32->data_break_list[i].reg_address = - EJTAG_DBA1 + (0x100 * i); + ejtag_info->ejtag_dba0_addr + + (ejtag_info->ejtag_dba_step_size * i); /* clear DBIS reg */ - retval = target_write_u32(target, EJTAG_DBS, 0); + retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); return retval; } @@ -523,6 +527,7 @@ int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval; uint32_t dcr; @@ -534,6 +539,11 @@ int mips32_configure_break_unit(struct target *target) if (retval != ERROR_OK) return retval; + /* EJTAG 2.0 does not specify EJTAG_DCR_IB and EJTAG_DCR_DB bits, + * assume IB and DB registers are always present. */ + if (ejtag_info->ejtag_version == EJTAG_VERSION_20) + dcr |= EJTAG_DCR_IB | EJTAG_DCR_DB; + if (dcr & EJTAG_DCR_IB) { retval = mips32_configure_ibs(target); if (retval != ERROR_OK) diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 85748146d..3457b78bd 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -303,6 +303,45 @@ int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) return ctx.retval; } +/* mips_ejtag_init_mmr - asign Memory-Mapped Registers depending + * on EJTAG version. + */ +static void mips_ejtag_init_mmr(struct mips_ejtag *ejtag_info) +{ + if (ejtag_info->ejtag_version == EJTAG_VERSION_20) { + ejtag_info->ejtag_ibs_addr = EJTAG_V20_IBS; + ejtag_info->ejtag_iba0_addr = EJTAG_V20_IBA0; + ejtag_info->ejtag_ibc_offs = EJTAG_V20_IBC_OFFS; + ejtag_info->ejtag_ibm_offs = EJTAG_V20_IBM_OFFS; + + ejtag_info->ejtag_dbs_addr = EJTAG_V20_DBS; + ejtag_info->ejtag_dba0_addr = EJTAG_V20_DBA0; + ejtag_info->ejtag_dbc_offs = EJTAG_V20_DBC_OFFS; + ejtag_info->ejtag_dbm_offs = EJTAG_V20_DBM_OFFS; + ejtag_info->ejtag_dbv_offs = EJTAG_V20_DBV_OFFS; + + ejtag_info->ejtag_iba_step_size = EJTAG_V20_IBAn_STEP; + ejtag_info->ejtag_dba_step_size = EJTAG_V20_DBAn_STEP; + } else { + ejtag_info->ejtag_ibs_addr = EJTAG_V25_IBS; + ejtag_info->ejtag_iba0_addr = EJTAG_V25_IBA0; + ejtag_info->ejtag_ibm_offs = EJTAG_V25_IBM_OFFS; + ejtag_info->ejtag_ibasid_offs = EJTAG_V25_IBASID_OFFS; + ejtag_info->ejtag_ibc_offs = EJTAG_V25_IBC_OFFS; + + ejtag_info->ejtag_dbs_addr = EJTAG_V25_DBS; + ejtag_info->ejtag_dba0_addr = EJTAG_V25_DBA0; + ejtag_info->ejtag_dbm_offs = EJTAG_V25_DBM_OFFS; + ejtag_info->ejtag_dbasid_offs = EJTAG_V25_DBASID_OFFS; + ejtag_info->ejtag_dbc_offs = EJTAG_V25_DBC_OFFS; + ejtag_info->ejtag_dbv_offs = EJTAG_V25_DBV_OFFS; + + ejtag_info->ejtag_iba_step_size = EJTAG_V25_IBAn_STEP; + ejtag_info->ejtag_dba_step_size = EJTAG_V25_DBAn_STEP; + } +} + + int mips_ejtag_init(struct mips_ejtag *ejtag_info) { int retval; @@ -354,6 +393,8 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info) ejtag_info->ejtag_ctrl = EJTAG_CTRL_ROCC | EJTAG_CTRL_PRACC | EJTAG_CTRL_PROBEN | EJTAG_CTRL_SETDEV; ejtag_info->fast_access_save = -1; + mips_ejtag_init_mmr(ejtag_info); + return ERROR_OK; } diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index 760a7c5a8..db20e9d0d 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -113,10 +113,34 @@ #define EJTAG_DCR_MP (1 << 2) /* breakpoint support */ -#define EJTAG_IBS 0xFF301000 -#define EJTAG_IBA1 0xFF301100 -#define EJTAG_DBS 0xFF302000 -#define EJTAG_DBA1 0xFF302100 +/* EJTAG_V20_* was tested on Broadcom BCM7401 + * and may or will differ with other hardware. For example EZ4021-FC. */ +#define EJTAG_V20_IBS 0xFF300004 +#define EJTAG_V20_IBA0 0xFF300100 +#define EJTAG_V20_IBC_OFFS 0x4 /* IBC Offset */ +#define EJTAG_V20_IBM_OFFS 0x8 +#define EJTAG_V20_IBAn_STEP 0x10 /* Offset for next channel */ +#define EJTAG_V20_DBS 0xFF30008 +#define EJTAG_V20_DBA0 0xFF300200 +#define EJTAG_V20_DBC_OFFS 0x4 +#define EJTAG_V20_DBM_OFFS 0x8 +#define EJTAG_V20_DBV_OFFS 0xc +#define EJTAG_V20_DBAn_STEP 0x10 + +#define EJTAG_V25_IBS 0xFF301000 +#define EJTAG_V25_IBA0 0xFF301100 +#define EJTAG_V25_IBM_OFFS 0x8 +#define EJTAG_V25_IBASID_OFFS 0x10 +#define EJTAG_V25_IBC_OFFS 0x18 +#define EJTAG_V25_IBAn_STEP 0x100 +#define EJTAG_V25_DBS 0xFF302000 +#define EJTAG_V25_DBA0 0xFF302100 +#define EJTAG_V25_DBM_OFFS 0x8 +#define EJTAG_V25_DBASID_OFFS 0x10 +#define EJTAG_V25_DBC_OFFS 0x18 +#define EJTAG_V25_DBV_OFFS 0x20 +#define EJTAG_V25_DBAn_STEP 0x100 + #define EJTAG_DBCn_NOSB (1 << 13) #define EJTAG_DBCn_NOLB (1 << 12) #define EJTAG_DBCn_BLM_MASK 0xff @@ -141,6 +165,25 @@ struct mips_ejtag { unsigned scan_delay; int mode; unsigned int ejtag_version; + + /* Memory-Mapped Registers. This addresses are not same on different + * EJTAG versions. */ + uint32_t ejtag_ibs_addr; /* Instruction Address Break Status */ + uint32_t ejtag_iba0_addr; /* IAB channel 0 */ + uint32_t ejtag_ibc_offs; /* IAB Control offset */ + uint32_t ejtag_ibm_offs; /* IAB Mask offset */ + uint32_t ejtag_ibasid_offs; /* IAB ASID (4Kc) */ + + uint32_t ejtag_dbs_addr; /* Data Address Break Status Register */ + uint32_t ejtag_dba0_addr; /* DAB channel 0 */ + uint32_t ejtag_dbc_offs; /* DAB Control offset */ + uint32_t ejtag_dbm_offs; /* DAB Mask offset */ + uint32_t ejtag_dbv_offs; /* DAB Value offset */ + uint32_t ejtag_dbasid_offs; /* DAB ASID (4Kc) */ + + uint32_t ejtag_iba_step_size; + uint32_t ejtag_dba_step_size; /* siez of step till next + * *DBAn register. */ }; void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index fc2a3f808..49edad184 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -51,30 +51,36 @@ static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, static int mips_m4k_examine_debug_reason(struct target *target) { + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t break_status; int retval; if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { /* get info about inst breakpoint support */ - retval = target_read_u32(target, EJTAG_IBS, &break_status); + retval = target_read_u32(target, + ejtag_info->ejtag_ibs_addr, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ - retval = target_write_u32(target, EJTAG_IBS, 0); + retval = target_write_u32(target, + ejtag_info->ejtag_ibs_addr, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_BREAKPOINT; } /* get info about data breakpoint support */ - retval = target_read_u32(target, EJTAG_DBS, &break_status); + retval = target_read_u32(target, + ejtag_info->ejtag_dbs_addr, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ - retval = target_write_u32(target, EJTAG_DBS, 0); + retval = target_write_u32(target, + ejtag_info->ejtag_dbs_addr, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_WATCHPOINT; @@ -587,6 +593,7 @@ static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; @@ -608,10 +615,19 @@ static int mips_m4k_set_breakpoint(struct target *target, breakpoint->set = bp_num + 1; comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; + + /* EJTAG 2.0 uses 30bit IBA. First 2 bits are reserved. + * Warning: there is no IB ASID registers in 2.0. + * Do not set it! :) */ + if (ejtag_info->ejtag_version == EJTAG_VERSION_20) + comparator_list[bp_num].bp_value &= 0xFFFFFFFC; + target_write_u32(target, comparator_list[bp_num].reg_address, comparator_list[bp_num].bp_value); - target_write_u32(target, comparator_list[bp_num].reg_address + 0x08, 0x00000000); - target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 1); + target_write_u32(target, comparator_list[bp_num].reg_address + + ejtag_info->ejtag_ibm_offs, 0x00000000); + target_write_u32(target, comparator_list[bp_num].reg_address + + ejtag_info->ejtag_ibc_offs, 1); LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx32 "", breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); @@ -668,6 +684,7 @@ static int mips_m4k_unset_breakpoint(struct target *target, { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; @@ -688,7 +705,8 @@ static int mips_m4k_unset_breakpoint(struct target *target, bp_num); comparator_list[bp_num].used = 0; comparator_list[bp_num].bp_value = 0; - target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 0); + target_write_u32(target, comparator_list[bp_num].reg_address + + ejtag_info->ejtag_ibc_offs, 0); } else { /* restore original instruction (kept in target endianness) */ @@ -777,6 +795,7 @@ static int mips_m4k_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; int wp_num = 0; /* @@ -826,11 +845,25 @@ static int mips_m4k_set_watchpoint(struct target *target, watchpoint->set = wp_num + 1; comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; - target_write_u32(target, comparator_list[wp_num].reg_address, comparator_list[wp_num].bp_value); - target_write_u32(target, comparator_list[wp_num].reg_address + 0x08, 0x00000000); - target_write_u32(target, comparator_list[wp_num].reg_address + 0x10, 0x00000000); - target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, enable); - target_write_u32(target, comparator_list[wp_num].reg_address + 0x20, 0); + + /* EJTAG 2.0 uses 29bit DBA. First 3 bits are reserved. + * There is as well no ASID register support. */ + if (ejtag_info->ejtag_version == EJTAG_VERSION_20) + comparator_list[wp_num].bp_value &= 0xFFFFFFF8; + else + target_write_u32(target, comparator_list[wp_num].reg_address + + ejtag_info->ejtag_dbasid_offs, 0x00000000); + + target_write_u32(target, comparator_list[wp_num].reg_address, + comparator_list[wp_num].bp_value); + target_write_u32(target, comparator_list[wp_num].reg_address + + ejtag_info->ejtag_dbm_offs, 0x00000000); + + target_write_u32(target, comparator_list[wp_num].reg_address + + ejtag_info->ejtag_dbc_offs, enable); + /* TODO: probably this value is ignored on 2.0 */ + target_write_u32(target, comparator_list[wp_num].reg_address + + ejtag_info->ejtag_dbv_offs, 0); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; @@ -841,6 +874,7 @@ static int mips_m4k_unset_watchpoint(struct target *target, { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; if (!watchpoint->set) { @@ -855,7 +889,8 @@ static int mips_m4k_unset_watchpoint(struct target *target, } comparator_list[wp_num].used = 0; comparator_list[wp_num].bp_value = 0; - target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, 0); + target_write_u32(target, comparator_list[wp_num].reg_address + + ejtag_info->ejtag_dbc_offs, 0); watchpoint->set = 0; return ERROR_OK;