int arm11_add_debug_SCAN_N(struct arm11_common *arm11, uint8_t chain, tap_state_t state) { /* Don't needlessly switch the scan chain. * NOTE: the ITRSEL instruction fakes SCREG changing; * but leaves its actual value unchanged. */ if (arm11->jtag_info.cur_scan_chain == chain) { JTAG_DEBUG("SCREG <= %d SKIPPED", chain); return jtag_add_statemove((state == ARM11_TAP_DEFAULT) ? TAP_DRPAUSE : state); } JTAG_DEBUG("SCREG <= %d", chain); arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); struct scan_field field; uint8_t tmp[1]; arm11_setup_field(arm11, 5, &chain, &tmp, &field); arm11_add_dr_scan_vc(1, &field, state == ARM11_TAP_DEFAULT ? TAP_DRPAUSE : state); jtag_execute_queue_noclear(); arm11_in_handler_SCAN_N(tmp); arm11->jtag_info.cur_scan_chain = chain; return jtag_execute_queue(); }
/** Write the Debug Status and Control Register (DSCR) * * same as CP14 c1 * * \param arm11 Target state variable. * \param dscr DSCR content * * \remarks This is a stand-alone function that executes the JTAG command queue. */ int arm11_write_DSCR(struct arm11_common * arm11, uint32_t dscr) { int retval; retval = arm11_add_debug_SCAN_N(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain1_field; arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); arm11_add_dr_scan_vc(1, &chain1_field, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DSCR <= %08x (OLD %08x)", (unsigned) dscr, (unsigned) arm11->dscr); arm11->dscr = dscr; return ERROR_OK; }
/** Execute one instruction via ITR repeatedly while * reading data from the core via DTR on each execution. * * The executed instruction \em must write data to DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to an array that receives the data words from the core * \param count Number of data words and instruction repetitions * */ void arm11_run_instr_data_from_core(arm11_common_t * arm11, u32 opcode, u32 * data, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, -1); arm11_add_debug_INST(arm11, opcode, NULL, TAP_IDLE); arm11_add_IR(arm11, ARM11_INTEST, -1); scan_field_t chain5_fields[3]; u32 Data; u8 Ready; u8 nRetry; arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); while (count--) { do { arm11_add_dr_scan_vc(asizeof(chain5_fields), chain5_fields, count ? TAP_IDLE : TAP_DRPAUSE); jtag_execute_queue(); JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", Data, Ready, nRetry); } while (!Ready); *data++ = Data; } }
/** Write JTAG instruction register * * \param arm11 Target state variable. * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default value (Pause-IR). * * \remarks This adds to the JTAG command queue but does \em not execute it. */ void arm11_add_IR(struct arm11_common * arm11, uint8_t instr, tap_state_t state) { struct jtag_tap *tap = arm11->arm.target->tap; if (buf_get_u32(tap->cur_instr, 0, 5) == instr) { JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); return; } JTAG_DEBUG("IR <= %s (0x%02x)", arm11_ir_to_string(instr), instr); struct scan_field field; arm11_setup_field(arm11, 5, &instr, NULL, &field); arm11_add_ir_scan_vc(1, &field, state == ARM11_TAP_DEFAULT ? TAP_IRPAUSE : state); }
/** Execute one instruction via ITR repeatedly while * reading data from the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * The executed instruction \em must write data to DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to an array that receives the data words from the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_from_core(struct arm11_common * arm11, uint32_t opcode, uint32_t * data, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_INST(arm11, opcode, NULL, TAP_IDLE); arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint32_t Data; uint8_t Ready; uint8_t nRetry; arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); while (count--) { int i = 0; do { arm11_add_dr_scan_vc(ARRAY_SIZE(chain5_fields), chain5_fields, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", (unsigned) Data, Ready, nRetry); long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!Ready); *data++ = Data; } return ERROR_OK; }
/** Write an instruction into the ITR register * * \param arm11 Target state variable. * \param inst An ARM11 processor instruction/opcode. * \param flag Optional parameter to retrieve the InstCompl flag * (this will be written when the JTAG chain is executed). * \param state Pass the final TAP state or -1 for the default * value (Run-Test/Idle). * * \remarks By default this ends with Run-Test/Idle state * and causes the instruction to be executed. If * a subsequent write to DTR is needed before * executing the instruction then TAP_DRPAUSE should be * passed to \p state. * * \remarks This adds to the JTAG command queue but does \em not execute it. */ void arm11_add_debug_INST(arm11_common_t * arm11, u32 inst, u8 * flag, tap_state_t state) { JTAG_DEBUG("INST <= 0x%08x", inst); scan_field_t itr[2]; arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); arm11_setup_field(arm11, 1, NULL, flag, itr + 1); arm11_add_dr_scan_vc(asizeof(itr), itr, state == -1 ? TAP_IDLE : state); }
/** * Queue a DR scan of the ITR register. Caller must have selected * scan chain 4 (ITR), possibly using ITRSEL. * * \param arm11 Target state variable. * \param inst An ARM11 processor instruction/opcode. * \param flag Optional parameter to retrieve the Ready flag; * this address will be written when the JTAG chain is scanned. * \param state The TAP state to enter after the DR scan. * * Going through the TAP_DRUPDATE state writes ITR only if Ready was * previously set. Only the Ready flag is readable by the scan. * * An instruction loaded into ITR is executed when going through the * TAP_IDLE state only if Ready was previously set and the debug state * is properly set up. Depending on the instruction, you may also need * to ensure that the rDTR is ready before that Run-Test/Idle state. */ static void arm11_add_debug_INST(struct arm11_common * arm11, uint32_t inst, uint8_t * flag, tap_state_t state) { JTAG_DEBUG("INST <= 0x%08x", (unsigned) inst); struct scan_field itr[2]; arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); arm11_setup_field(arm11, 1, NULL, flag, itr + 1); arm11_add_dr_scan_vc(ARRAY_SIZE(itr), itr, state); }
void arm11_add_debug_SCAN_N(arm11_common_t * arm11, u8 chain, tap_state_t state) { JTAG_DEBUG("SCREG <= 0x%02x", chain); arm11_add_IR(arm11, ARM11_SCAN_N, -1); scan_field_t field; arm11_setup_field(arm11, 5, &chain, NULL, &field); field.in_handler = arm11_in_handler_SCAN_N; arm11_add_dr_scan_vc(1, &field, state == -1 ? TAP_DRPAUSE : state); }
/** Verify shifted out data from Scan Chain Register (SCREG) * Used as parameter to scan_field_t::in_handler in * arm11_add_debug_SCAN_N(). * */ static int arm11_in_handler_SCAN_N(u8 *in_value, void *priv, struct scan_field_s *field) { /** \todo TODO: clarify why this isnt properly masked in jtag.c jtag_read_buffer() */ u8 v = *in_value & 0x1F; if (v != 0x10) { LOG_ERROR("'arm11 target' JTAG communication error SCREG SCAN OUT 0x%02x (expected 0x10)", v); return ERROR_FAIL; } JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); return ERROR_OK; }
/** Write JTAG instruction register * * \param arm11 Target state variable. * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. * \param state Pass the final TAP state or -1 for the default value (Pause-IR). * * \remarks This adds to the JTAG command queue but does \em not execute it. */ void arm11_add_IR(arm11_common_t * arm11, u8 instr, tap_state_t state) { jtag_tap_t *tap; tap = arm11->jtag_info.tap; if( tap == NULL ){ /* FIX!!!! error is logged, but not propagated back up the call stack... */ LOG_ERROR( "tap is null here! This is bad!"); return; } if (buf_get_u32(tap->cur_instr, 0, 5) == instr){ JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); return; } JTAG_DEBUG("IR <= 0x%02x", instr); scan_field_t field; arm11_setup_field(arm11, 5, &instr, NULL, &field); arm11_add_ir_scan_vc(1, &field, state == -1 ? TAP_IRPAUSE : state); }
int arm11_add_debug_SCAN_N(struct arm11_common *arm11, uint8_t chain, tap_state_t state) { /* Don't needlessly switch the scan chain. * NOTE: the ITRSEL instruction fakes SCREG changing; * but leaves its actual value unchanged. */ #if 0 // FIX!!! the optimization below is broken because we do not // invalidate the cur_scan_chain upon a TRST/TMS. See arm_jtag.c // for example on how to invalidate cur_scan_chain. Tested patches gladly // accepted! if (arm11->jtag_info.cur_scan_chain == chain) { JTAG_DEBUG("SCREG <= %d SKIPPED", chain); return jtag_add_statemove((state == ARM11_TAP_DEFAULT) ? TAP_DRPAUSE : state); } #endif JTAG_DEBUG("SCREG <= %d", chain); arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); struct scan_field field; uint8_t tmp[1]; arm11_setup_field(arm11, 5, &chain, &tmp, &field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &field, state == ARM11_TAP_DEFAULT ? TAP_DRPAUSE : state); jtag_execute_queue_noclear(); arm11_in_handler_SCAN_N(tmp); arm11->jtag_info.cur_scan_chain = chain; return jtag_execute_queue(); }
/** Write the Debug Status and Control Register (DSCR) * * same as CP14 c1 * * \param arm11 Target state variable. * \param dscr DSCR content * * \remarks This is a stand-alone function that executes the JTAG command queue. */ void arm11_write_DSCR(arm11_common_t * arm11, u32 dscr) { arm11_add_debug_SCAN_N(arm11, 0x01, -1); arm11_add_IR(arm11, ARM11_EXTEST, -1); scan_field_t chain1_field; arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); arm11_add_dr_scan_vc(1, &chain1_field, TAP_DRPAUSE); jtag_execute_queue(); JTAG_DEBUG("DSCR <= %08x (OLD %08x)", dscr, arm11->last_dscr); arm11->last_dscr = dscr; }
/** Read the Debug Status and Control Register (DSCR) * * same as CP14 c1 * * \param arm11 Target state variable. * \return DSCR content * * \remarks This is a stand-alone function that executes the JTAG command queue. */ u32 arm11_read_DSCR(arm11_common_t * arm11) { arm11_add_debug_SCAN_N(arm11, 0x01, -1); arm11_add_IR(arm11, ARM11_INTEST, -1); u32 dscr; scan_field_t chain1_field; arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); arm11_add_dr_scan_vc(1, &chain1_field, TAP_DRPAUSE); jtag_execute_queue(); if (arm11->last_dscr != dscr) JTAG_DEBUG("DSCR = %08x (OLD %08x)", dscr, arm11->last_dscr); arm11->last_dscr = dscr; return dscr; }
/** Apply reads and writes to scan chain 7 * * \see struct arm11_sc7_action * * \param arm11 Target state variable. * \param actions A list of read and/or write instructions * \param count Number of instructions in the list. * */ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions, size_t count) { int retval; retval = arm11_add_debug_SCAN_N(arm11, 0x07, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain7_fields[3]; uint8_t nRW; uint32_t DataOut; uint8_t AddressOut; uint8_t Ready; uint32_t DataIn; uint8_t AddressIn; arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); for (size_t i = 0; i < count + 1; i++) { if (i < count) { nRW = actions[i].write ? 1 : 0; DataOut = actions[i].value; AddressOut = actions[i].address; } else { nRW = 1; DataOut = 0; AddressOut = 0; } /* Timeout here so we don't get stuck. */ int i = 0; while (1) { JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", (unsigned) AddressOut, (unsigned) DataOut, nRW ? "write" : "read"); arm11_add_dr_scan_vc(ARRAY_SIZE(chain7_fields), chain7_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); /* 'nRW' is 'Ready' on read out */ if (Ready) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } if (!nRW) JTAG_DEBUG("SC7 => Data %08x", (unsigned) DataIn); if (i > 0) { if (actions[i - 1].address != AddressIn) { LOG_WARNING("Scan chain 7 shifted out unexpected address"); } if (!actions[i - 1].write) { actions[i - 1].value = DataIn; } else { if (actions[i - 1].value != DataIn) { LOG_WARNING("Scan chain 7 shifted out unexpected data"); } } } } return ERROR_OK; }
/** Apply reads and writes to scan chain 7 * * \see arm11_sc7_action_t * * \param arm11 Target state variable. * \param actions A list of read and/or write instructions * \param count Number of instructions in the list. * */ void arm11_sc7_run(arm11_common_t * arm11, arm11_sc7_action_t * actions, size_t count) { arm11_add_debug_SCAN_N(arm11, 0x07, -1); arm11_add_IR(arm11, ARM11_EXTEST, -1); scan_field_t chain7_fields[3]; u8 nRW; u32 DataOut; u8 AddressOut; u8 Ready; u32 DataIn; u8 AddressIn; arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); {size_t i; for (i = 0; i < count + 1; i++) { if (i < count) { nRW = actions[i].write ? 1 : 0; DataOut = actions[i].value; AddressOut = actions[i].address; } else { nRW = 0; DataOut = 0; AddressOut = 0; } do { JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", AddressOut, DataOut, nRW); arm11_add_dr_scan_vc(asizeof(chain7_fields), chain7_fields, TAP_DRPAUSE); jtag_execute_queue(); JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", AddressIn, DataIn, Ready); } while (!Ready); /* 'nRW' is 'Ready' on read out */ if (i > 0) { if (actions[i - 1].address != AddressIn) { LOG_WARNING("Scan chain 7 shifted out unexpected address"); } if (!actions[i - 1].write) { actions[i - 1].value = DataIn; } else { if (actions[i - 1].value != DataIn) { LOG_WARNING("Scan chain 7 shifted out unexpected data"); } } } }} {size_t i; for (i = 0; i < count; i++) { JTAG_DEBUG("SC7 %02d: %02x %s %08x", i, actions[i].address, actions[i].write ? "<=" : "=>", actions[i].value); }} }