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 retval = jtagtransn(ir, 4, LSB|flags);
94 tapstate = RunTest_Idle;
100 //! Connect the appropriate scan chain to TDO/TDI. SCAN_N, INTEST
101 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) { // PROVEN
103 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
104 wise, when in debug state, the core will not be correctly isolated and intrusive
105 commands occur. Therefore, it is recommended to pass directly from the “Update”
106 state” to the “Select DR” state each time the “Update” state is reached.
108 unsigned long retval = 0;
109 if (last_scanchain != chain){
110 jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
111 last_scanchain = chain;
112 jtag_goto_shift_dr();
113 retval = jtagtransn(chain, 4, LSB | NORETIDLE);
114 tapstate = Update_DR;
116 jtagarm_shift_ir(testmode, NORETIDLE);
121 /************************* EmbeddedICE Primitives ****************************/
122 //! shifter for writing to chain2 (EmbeddedICE).
123 unsigned long eice_write(unsigned char reg, unsigned long data){
124 unsigned long retval, temp;
125 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
126 jtag_goto_shift_dr();
127 retval = jtagtransn(data, 32, LSB| NOEND| NORETIDLE); // send in the data - 32-bits lsb
128 temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE); // send in the register address - 5 bits lsb
129 jtagtransn(1, 1, LSB); // send in the WRITE bit
130 tapstate = RunTest_Idle;
134 //! shifter for reading from chain2 (EmbeddedICE).
135 unsigned long eice_read(unsigned char reg){ // PROVEN
136 unsigned long temp, retval;
137 jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
138 jtag_goto_shift_dr(); // send in the register address - 5 bits LSB
139 temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);
140 jtagtransn(0L, 1, LSB); // clear TDI to select "read only"
141 jtag_goto_shift_dr(); // Now shift out the 32 bits
142 retval = jtagtransn(0L, 32, LSB); // atmel arm jtag docs pp.10-11: LSB first
143 tapstate = RunTest_Idle;
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 jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
154 if (last_instr != instr && last_sysstate != breakpt){
155 jtag_goto_shift_dr();
156 // if the next instruction is to run using MCLK (master clock), set TDI
167 // Now shift in the 32 bits
168 retval = jtagtransn(instr, 32, 0); // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
169 tapstate = RunTest_Idle;
171 last_sysstate = breakpt;
177 u32 jtagarm7tdmi_nop(u8 brkpt){
178 // WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
179 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
180 return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
181 return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
184 /******************** Complex Commands **************************/
186 //! Retrieve a 32-bit Register value
187 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
188 jtagarm7tdmi_nop( 0);
189 jtagarm7tdmi_instr_primitive(instr, 0);
190 jtagarm7tdmi_nop( 0);
191 jtagarm7tdmi_nop( 0);
192 jtagarm7tdmi_nop( 0);
193 return jtagarm7tdmi_nop( 0); // recover 32-bit word
196 //! Set a 32-bit Register value
197 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){ // PROVEN - 100827 (non-PC)
198 jtagarm7tdmi_nop( 0); // push nop into pipeline - executed
199 jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch
200 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
201 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
202 jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus
203 if (reg == ARM_REG_PC){
204 //debugstr("setting pc...");
205 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
206 jtagarm7tdmi_nop( 0); // push nop into pipeline - refill
208 jtagarm7tdmi_nop( 0); // push nop into pipeline - decode
209 jtagarm7tdmi_nop( 0); // push nop into pipeline - execute
212 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){ // PROVEN - 100827
214 jtagarm7tdmi_nop( 0);
216 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
217 //debughex32((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)));
219 jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
220 //debughex32((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)));
222 jtagarm7tdmi_nop( 0);
223 jtagarm7tdmi_nop( 0);
224 jtagarm7tdmi_nop( 0);
227 unsigned long jtagarm7tdmi_get_register(unsigned long reg) { // PROVEN - 100827
228 unsigned long retval=0L, instr, r0;
229 current_dbgstate = eice_read(EICE_DBGSTATUS);
230 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
232 //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
234 r0 = jtagarm7_get_reg_prim( THUMB_READ_REG); // save reg0
235 jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg); // clobber reg0 with hi reg
236 retval = jtagarm7_get_reg_prim( THUMB_READ_REG); // recover 32-bit word
237 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
240 instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
243 instr = (reg<<12L) | ARM_READ_REG; // STR Rx, [R14]
244 return jtagarm7_get_reg_prim(instr);
247 //! Set a 32-bit Register value
248 // 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.
249 // 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
250 // 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
252 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) { // PROVEN - 100827
253 unsigned long instr, r0;
254 current_dbgstate = eice_read(EICE_DBGSTATUS);
255 if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
258 r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
259 jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
260 instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
261 jtagarm7_set_reg_prim(instr, reg, val);
262 jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg); // place 32-bit word into a high register
263 jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0
265 instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
267 instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); // LDR Rx, [R14]
271 // --- first time to clear the register... this ensures the write is not 8-bit offset ---
272 jtagarm7_set_reg_prim(instr, reg, 0);
273 // --- now we actually write to the register ---
274 jtagarm7_set_reg_prim(instr, reg, val);
278 ///////////////////////////////////////////////////////////////////////////////////////////////////
279 //! Handles ARM7TDMI JTAG commands. Forwards others to JTAG.
280 void jtagarm7_handle_fn( uint8_t const app,
289 jtagarm7tdmi_start();
293 cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
297 jtag_goto_shift_dr();
298 cmddatalong[0] = jtagtransn(cmddatalong[1],cmddata[0],cmddata[1]);
299 tapstate = (cmddata[1]&NORETIDLE)>0?Update_DR:RunTest_Idle;
302 case JTAGARM7_CHAIN0:
303 jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
304 jtag_goto_shift_dr();
305 //debughex32(cmddatalong[0]);
306 //debughex(cmddataword[4]);
307 //debughex32(cmddatalong[1]);
308 //debughex32(cmddatalong[3]);
309 cmddatalong[0] = jtagtransn(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
310 cmddatalong[2] = jtagtransn(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
311 cmddatalong[1] = jtagtransn(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
312 cmddatalong[3] = jtagtransn(cmddatalong[3], 32, MSB);
313 tapstate = RunTest_Idle;
316 case JTAGARM7_SCANCHAIN1:
317 case JTAGARM7_DEBUG_INSTR:
318 cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
321 case JTAGARM7_EICE_READ:
322 cmddatalong[0] = eice_read(cmddata[0]);
323 txdata(app,verb,0x4);
325 case JTAGARM7_EICE_WRITE:
326 eice_write(cmddata[4], cmddatalong[0]);
329 case JTAGARM7_GET_REGISTER:
331 cmddatalong[0] = jtagarm7tdmi_get_register(val);
334 case JTAGARM7_SET_REGISTER:
335 jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
338 case JTAG_RESETTARGET:
340 debugstr("RESET TARGET");
342 delay(cmddataword[0]);
348 //case JTAGARM7_STEP_INSTR:
349 /* case JTAGARM7_READ_CODE_MEMORY:
350 case JTAGARM7_WRITE_FLASH_PAGE:
351 case JTAGARM7_READ_FLASH_PAGE:
352 case JTAGARM7_MASS_ERASE_FLASH:
353 case JTAGARM7_PROGRAM_FLASH:
354 case JTAGARM7_LOCKCHIP:
355 case JTAGARM7_CHIP_ERASE:
358 (*(jtag_app.handle))(app,verb,len);