2 \brief ARM7TDMI JTAG (AT91R40008, AT91SAM7xxx)
10 //! Handles ARM7TDMI JTAG commands. Forwards others to JTAG.
11 void jtagarm7_handle_fn( uint8_t const app,
15 // define the jtagarm7 app's app_t
16 app_t const jtagarm7_app = {
28 "\tThe JTAGARM7 app extends the basic JTAG app with support\n"
29 "\tfor JTAG'ing ARM7TDMI based devices.\n"
32 unsigned long last_instr = -1;
33 unsigned char last_sysstate = 0;
34 unsigned char last_ir = -1;
35 unsigned char last_scanchain = -1;
36 unsigned char tapstate = 15;
37 unsigned char current_dbgstate = -1;
38 //unsigned char last_halt_debug_state = -1;
39 //unsigned long last_halt_pc = -1;
41 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
42 GoodFET -> 7TDMI 20-pin connector (HE-10 connector)
49 9 4,6,8,10,12,14,16,18,20 (GND)
50 11 17/3 (nTRST) (different sources suggest 17 or 3 alternately)
51 ********************************/
53 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
54 GoodFET -> 7TDMI 14-pin connector
64 http://hri.sourceforge.net/tools/jtag_faq_org.html
65 ********************************/
67 /* WHAT SHOULD THIS MODULE DO?
73 * *scanchain1 (instr_primitive)
74 * *scanchain2 (hmmmm... perhaps we'll need to keep the debug calls)
81 // ! Start JTAG, setup pins, reset TAP and return IDCODE
82 void jtagarm7tdmi_start() {
89 u8 jtagarm_shift_ir(u8 ir, u8 flags){
93 jtag_shift_register();
94 retval = jtag_trans_n(ir, 4, LSB|flags);
95 tapstate = RunTest_Idle;
101 //! Connect the appropriate scan chain to TDO/TDI. SCAN_N, INTEST
102 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) { // PROVEN
104 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
105 wise, when in debug state, the core will not be correctly isolated and intrusive
106 commands occur. Therefore, it is recommended to pass directly from the “Update”
107 state” to the “Select DR” state each time the “Update” state is reached.
109 unsigned long retval = 0;
110 if (last_scanchain != chain){
111 jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
112 last_scanchain = chain;
114 jtag_shift_register();
115 retval = jtag_trans_n(chain, 4, LSB | NORETIDLE);
116 tapstate = Update_DR;
118 jtagarm_shift_ir(testmode, NORETIDLE);
123 /************************* EmbeddedICE Primitives ****************************/
124 //! shifter for writing to chain2 (EmbeddedICE).
125 unsigned long eice_write(unsigned char reg, unsigned long data){
126 unsigned long retval, temp;
127 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
129 jtag_shift_register();
130 retval = jtag_trans_n(data, 32, LSB| NOEND| NORETIDLE); // send in the data - 32-bits lsb
131 temp = jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE); // send in the register address - 5 bits lsb
132 jtag_trans_n(1, 1, LSB); // send in the WRITE bit
133 tapstate = RunTest_Idle;
137 //! shifter for reading from chain2 (EmbeddedICE).
138 unsigned long eice_read(unsigned char reg){ // PROVEN
139 unsigned long temp, retval;
140 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
142 jtag_shift_register(); // send in the register address - 5 bits LSB
143 temp = jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);
144 jtag_trans_n(0L, 1, LSB); // clear TDI to select "read only"
146 jtag_shift_register(); // Now shift out the 32 bits
147 retval = jtag_trans_n(0L, 32, LSB); // atmel arm jtag docs pp.10-11: LSB first
148 tapstate = RunTest_Idle;
153 //! push an instruction into the pipeline
154 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){ // PROVEN
155 unsigned long retval = 0;
156 jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
159 if (last_instr != instr && last_sysstate != breakpt){
161 jtag_shift_register();
162 // if the next instruction is to run using MCLK (master clock), set TDI
173 // Now shift in the 32 bits
174 retval = jtag_trans_n(instr, 32, 0); // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
175 tapstate = RunTest_Idle;
177 last_sysstate = breakpt;
183 u32 jtagarm7tdmi_nop(u8 brkpt){
184 // WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
185 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
186 return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
187 return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
190 /******************** Complex Commands **************************/
192 //! Retrieve a 32-bit Register value
193 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
194 jtagarm7tdmi_nop( 0);
195 jtagarm7tdmi_instr_primitive(instr, 0);
196 jtagarm7tdmi_nop( 0);
197 jtagarm7tdmi_nop( 0);
198 jtagarm7tdmi_nop( 0);
199 return jtagarm7tdmi_nop( 0); // recover 32-bit word
202 //! Set a 32-bit Register value
203 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){ // PROVEN - 100827 (non-PC)
204 jtagarm7tdmi_nop( 0); // push nop into pipeline - executed
205 jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch
206 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
207 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
208 jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus
209 if (reg == ARM_REG_PC){
210 //debugstr("setting pc...");
211 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
212 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
214 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
215 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
218 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){ // PROVEN - 100827
220 jtagarm7tdmi_nop( 0);
222 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
223 //debughex32((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)));
225 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
226 //debughex32((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)));
228 jtagarm7tdmi_nop( 0);
229 jtagarm7tdmi_nop( 0);
230 jtagarm7tdmi_nop( 0);
233 unsigned long jtagarm7tdmi_get_register(unsigned long reg) { // PROVEN - 100827
234 unsigned long retval=0L, instr, r0;
235 current_dbgstate = eice_read(EICE_DBGSTATUS);
236 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
238 //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
240 r0 = jtagarm7_get_reg_prim( THUMB_READ_REG); // save reg0
241 jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg); // clobber reg0 with hi reg
242 retval = jtagarm7_get_reg_prim( THUMB_READ_REG); // recover 32-bit word
243 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
246 instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
249 instr = (reg<<12L) | ARM_READ_REG; // STR Rx, [R14]
250 return jtagarm7_get_reg_prim(instr);
253 //! Set a 32-bit Register value
254 // writing to a register is a problem child in ARM, actually. if the register you are using as the indirect offset register is misaligned, your results are misaligned.
255 // this set_register implementation normalizes this process at the cost of performance. since we don't know what's in the register, we set it to 0 first
256 // we could use r14 and hope all is well, but only for arm, not thumb mode, and not always is all well then either. this is a performance trade-off we may have to revisit later
258 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) { // PROVEN - 100827
259 unsigned long instr, r0;
260 current_dbgstate = eice_read(EICE_DBGSTATUS);
261 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
264 r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
265 jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
266 instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
267 jtagarm7_set_reg_prim(instr, reg, val);
268 jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg); // place 32-bit word into a high register
269 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
271 instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
273 instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); // LDR Rx, [R14]
277 // --- first time to clear the register... this ensures the write is not 8-bit offset ---
278 jtagarm7_set_reg_prim(instr, reg, 0);
279 // --- now we actually write to the register ---
280 jtagarm7_set_reg_prim(instr, reg, val);
284 ///////////////////////////////////////////////////////////////////////////////////////////////////
285 //! Handles ARM7TDMI JTAG commands. Forwards others to JTAG.
286 void jtagarm7_handle_fn( uint8_t const app,
295 jtagarm7tdmi_start();
299 cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
304 jtag_shift_register();
305 cmddatalong[0] = jtag_trans_n(cmddatalong[1],cmddata[0],cmddata[1]);
306 tapstate = (cmddata[1]&NORETIDLE)>0?Update_DR:RunTest_Idle;
309 case JTAGARM7_CHAIN0:
310 jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
312 jtag_shift_register();
313 //debughex32(cmddatalong[0]);
314 //debughex(cmddataword[4]);
315 //debughex32(cmddatalong[1]);
316 //debughex32(cmddatalong[3]);
317 cmddatalong[0] = jtag_trans_n(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
318 cmddatalong[2] = jtag_trans_n(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
319 cmddatalong[1] = jtag_trans_n(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
320 cmddatalong[3] = jtag_trans_n(cmddatalong[3], 32, MSB);
321 tapstate = RunTest_Idle;
324 case JTAGARM7_SCANCHAIN1:
325 case JTAGARM7_DEBUG_INSTR:
326 cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
329 case JTAGARM7_EICE_READ:
330 cmddatalong[0] = eice_read(cmddata[0]);
331 txdata(app,verb,0x4);
333 case JTAGARM7_EICE_WRITE:
334 eice_write(cmddata[4], cmddatalong[0]);
337 case JTAGARM7_GET_REGISTER:
339 cmddatalong[0] = jtagarm7tdmi_get_register(val);
342 case JTAGARM7_SET_REGISTER:
343 jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
346 case JTAG_RESET_TARGET:
348 debugstr("RESET TARGET");
350 delay(cmddataword[0]);
356 //case JTAGARM7_STEP_INSTR:
357 /* case JTAGARM7_READ_CODE_MEMORY:
358 case JTAGARM7_WRITE_FLASH_PAGE:
359 case JTAGARM7_READ_FLASH_PAGE:
360 case JTAGARM7_MASS_ERASE_FLASH:
361 case JTAGARM7_PROGRAM_FLASH:
362 case JTAGARM7_LOCKCHIP:
363 case JTAGARM7_CHIP_ERASE:
366 (*(jtag_app.handle))(app,verb,len);