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 current_dbgstate = -1;
37 //unsigned char last_halt_debug_state = -1;
38 //unsigned long last_halt_pc = -1;
40 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
41 GoodFET -> 7TDMI 20-pin connector (HE-10 connector)
47 9 4,6,8,10,12,14,16,18,20 (GND)
49 // no longer... (11 17/3 (nTRST) (different sources suggest 17 or 3 alternately))
50 ********************************/
52 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
53 GoodFET -> 7TDMI 14-pin connector
61 // no longer... (11 3 (nTRST))
63 http://hri.sourceforge.net/tools/jtag_faq_org.html
64 ********************************/
66 /* WHAT SHOULD THIS MODULE DO?
72 * *scanchain1 (instr_primitive)
73 * *scanchain2 (hmmmm... perhaps we'll need to keep the debug calls)
80 // ! Start JTAG, setup pins, reset TAP and return IDCODE
81 void jtagarm7tdmi_start() {
88 u8 jtagarm_shift_ir(u8 ir, u8 flags){
92 jtag_shift_register();
93 retval = jtag_trans_n(ir, 4, LSB|flags);
99 //! Connect the appropriate scan chain to TDO/TDI. SCAN_N, INTEST
100 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) { // PROVEN
102 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
103 wise, when in debug state, the core will not be correctly isolated and intrusive
104 commands occur. Therefore, it is recommended to pass directly from the “Update”
105 state” to the “Select DR” state each time the “Update” state is reached.
107 unsigned long retval = 0;
108 if (last_scanchain != chain){
109 jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
110 last_scanchain = chain;
112 jtag_shift_register();
113 retval = jtag_trans_n(chain, 4, LSB | NORETIDLE);
115 jtagarm_shift_ir(testmode, NORETIDLE);
120 /************************* EmbeddedICE Primitives ****************************/
121 //! shifter for writing to chain2 (EmbeddedICE).
122 unsigned long eice_write(unsigned char reg, unsigned long data){
123 unsigned long retval;
124 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
126 jtag_shift_register();
127 retval = jtag_trans_n(data, 32, LSB| NOEND| NORETIDLE); // send in the data - 32-bits lsb
128 jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE); // send in the register address - 5 bits lsb
129 jtag_trans_n(1, 1, LSB); // send in the WRITE bit
133 //! shifter for reading from chain2 (EmbeddedICE).
134 unsigned long eice_read(unsigned char reg){ // PROVEN
135 unsigned long retval;
136 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
138 jtag_shift_register(); // send in the register address - 5 bits LSB
139 jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);
140 jtag_trans_n(0L, 1, LSB); // clear TDI to select "read only"
142 jtag_shift_register(); // Now shift out the 32 bits
143 retval = jtag_trans_n(0L, 32, LSB); // atmel arm jtag docs pp.10-11: LSB first
148 //! push an instruction into the pipeline
149 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){ // PROVEN
150 unsigned long retval = 0;
151 //debugstr("jtagarm7tdmi_instr_primitive");
152 jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
154 //debugstr("instruction:");
156 //if (!(last_instr == instr && last_sysstate == breakpt))
159 jtag_shift_register();
160 // if the next instruction is to run using MCLK (master clock), set TDI
163 //debugstr("--breakpt flag set");
172 // Now shift in the 32 bits
173 retval = jtag_trans_n(instr, 32, 0); // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
174 //debugstr("hot off the pipeline!");
175 //debughex32(retval);
177 last_sysstate = breakpt;
179 //{ // this assumes we don't want retval! wtfo!?
185 u32 jtagarm7tdmi_nop(u8 brkpt){
186 // WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
187 //debugstr("jtagarm7tdmi_nop");
188 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
189 return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
190 return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
193 /******************** Complex Commands **************************/
195 //! Retrieve a 32-bit Register value
196 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
197 //debugstr("jtagarm7_get_reg_prim");
198 jtagarm7tdmi_nop( 0);
199 jtagarm7tdmi_instr_primitive(instr, 0);
200 jtagarm7tdmi_nop( 0);
201 jtagarm7tdmi_nop( 0);
202 jtagarm7tdmi_nop( 0);
203 return jtagarm7tdmi_nop( 0); // recover 32-bit word
206 //! Set a 32-bit Register value
207 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){ // PROVEN - 100827 (non-PC)
208 jtagarm7tdmi_nop( 0); // push nop into pipeline - executed
209 jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch
210 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
211 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
212 jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus
213 if (reg == ARM_REG_PC){
214 //debugstr("setting pc...");
215 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
216 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
218 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
219 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
222 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){ // PROVEN - 100827
224 jtagarm7tdmi_nop( 0);
226 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
228 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
230 jtagarm7tdmi_nop( 0);
231 jtagarm7tdmi_nop( 0);
232 jtagarm7tdmi_nop( 0);
235 unsigned long jtagarm7tdmi_get_register(unsigned long reg) { // PROVEN - 100827
236 unsigned long retval=0L, instr, r0;
237 current_dbgstate = eice_read(EICE_DBGSTATUS);
238 //debugstr("current_dbgstate:");
239 //debughex32(current_dbgstate);
241 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
243 //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
245 r0 = jtagarm7_get_reg_prim( THUMB_READ_REG); // save reg0
246 jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg); // clobber reg0 with hi reg
247 retval = jtagarm7_get_reg_prim( THUMB_READ_REG); // recover 32-bit word
248 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
251 //debugstr("debug: jtagarm7tdmi_get_register: thumb reg < 15");
252 instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
256 //debugstr("debug: jtagarm7tdmi_get_register: arm");
257 instr = (reg<<12L) | ARM_READ_REG; // STR Rx, [R14]
259 return jtagarm7_get_reg_prim(instr);
262 //! Set a 32-bit Register value
263 // 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.
264 // 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
265 // 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
267 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) { // PROVEN - 100827
268 unsigned long instr, r0;
269 current_dbgstate = eice_read(EICE_DBGSTATUS);
270 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
273 r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
274 jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
275 instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
276 jtagarm7_set_reg_prim(instr, reg, val);
277 jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg); // place 32-bit word into a high register
278 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
280 instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
282 instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); // LDR Rx, [R14]
286 // --- first time to clear the register... this ensures the write is not 8-bit offset ---
287 jtagarm7_set_reg_prim(instr, reg, 0);
288 // --- now we actually write to the register ---
289 jtagarm7_set_reg_prim(instr, reg, val);
293 ///////////////////////////////////////////////////////////////////////////////////////////////////
294 //! Handles ARM7TDMI JTAG commands. Forwards others to JTAG.
295 void jtagarm7_handle_fn( uint8_t const app,
304 jtagarm7tdmi_start();
308 cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
313 jtag_shift_register();
317 //debughex32(cmddatalong[0]);
318 //debughex32(cmddatalong[1]);
319 cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
320 cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
324 //debughex32(cmddatalong[0]);
325 cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
327 txdata(app,verb,val/8);
329 case JTAG_DR_SHIFT_MORE:
330 // assumes you just executed JTAG_DR_SHIFT with NOEND flag set
331 debugstr("JTAG_DR_SHIFT_MORE");
335 //debughex32(cmddatalong[0]);
336 //debughex32(cmddatalong[1]);
337 cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
338 cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
342 debughex32(cmddatalong[0]);
343 cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
345 txdata(app,verb,val/8);
347 case JTAGARM7_CHAIN0:
348 jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
350 jtag_shift_register();
351 //debughex32(cmddatalong[0]);
352 //debughex(cmddataword[4]);
353 //debughex32(cmddatalong[1]);
354 //debughex32(cmddatalong[3]);
355 cmddatalong[0] = jtag_trans_n(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
356 cmddatalong[2] = jtag_trans_n(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
357 cmddatalong[1] = jtag_trans_n(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
358 cmddatalong[3] = jtag_trans_n(cmddatalong[3], 32, MSB);
361 case JTAGARM7_SCANCHAIN1:
362 case JTAGARM7_DEBUG_INSTR:
363 cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
366 case JTAGARM7_EICE_READ:
367 cmddatalong[0] = eice_read(cmddata[0]);
368 txdata(app,verb,0x4);
370 case JTAGARM7_EICE_WRITE:
371 eice_write(cmddata[4], cmddatalong[0]);
374 case JTAGARM7_GET_REGISTER:
376 cmddatalong[0] = jtagarm7tdmi_get_register(val);
379 case JTAGARM7_SET_REGISTER:
380 jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
383 case JTAG_RESET_TARGET:
385 debugstr("RESET TARGET");
386 //debughex((P3OUT&RST));
388 //debughex((P3OUT&RST));
389 delay(cmddataword[0]);
391 //debughex((P3OUT&RST));
396 //case JTAGARM7_STEP_INSTR:
397 /* case JTAGARM7_READ_CODE_MEMORY:
398 case JTAGARM7_WRITE_FLASH_PAGE:
399 case JTAGARM7_READ_FLASH_PAGE:
400 case JTAGARM7_MASS_ERASE_FLASH:
401 case JTAGARM7_PROGRAM_FLASH:
402 case JTAGARM7_LOCKCHIP:
403 case JTAGARM7_CHIP_ERASE:
406 (*(jtag_app.handle))(app,verb,len);