mips: optimize mips_ejtag_step_disable() code
[openocd.git] / src / target / mips_ejtag.c
1 /***************************************************************************
2 * Copyright (C) 2008 by Spencer Oliver *
3 * spen@spen-soft.co.uk *
4 * *
5 * Copyright (C) 2008 by David T.L. Wong *
6 * *
7 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the *
21 * Free Software Foundation, Inc., *
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "mips32.h"
30 #include "mips_ejtag.h"
31
32 void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, int new_instr)
33 {
34 struct jtag_tap *tap;
35
36 tap = ejtag_info->tap;
37 assert(tap != NULL);
38
39 if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) {
40 struct scan_field field;
41 uint8_t t[4];
42
43 field.num_bits = tap->ir_length;
44 field.out_value = t;
45 buf_set_u32(t, 0, field.num_bits, new_instr);
46 field.in_value = NULL;
47
48 jtag_add_ir_scan(tap, &field, TAP_IDLE);
49 }
50 }
51
52 int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode)
53 {
54 struct scan_field field;
55 uint8_t r[4];
56
57 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IDCODE);
58
59 field.num_bits = 32;
60 field.out_value = NULL;
61 field.in_value = r;
62
63 jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE);
64
65 int retval;
66 retval = jtag_execute_queue();
67 if (retval != ERROR_OK) {
68 LOG_ERROR("register read failed");
69 return retval;
70 }
71
72 *idcode = buf_get_u32(field.in_value, 0, 32);
73
74 return ERROR_OK;
75 }
76
77 static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info, uint32_t *impcode)
78 {
79 struct scan_field field;
80 uint8_t r[4];
81
82 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE);
83
84 field.num_bits = 32;
85 field.out_value = NULL;
86 field.in_value = r;
87
88 jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE);
89
90 int retval;
91 retval = jtag_execute_queue();
92 if (retval != ERROR_OK) {
93 LOG_ERROR("register read failed");
94 return retval;
95 }
96
97 *impcode = buf_get_u32(field.in_value, 0, 32);
98
99 return ERROR_OK;
100 }
101
102 int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data)
103 {
104 struct jtag_tap *tap;
105 tap = ejtag_info->tap;
106 assert(tap != NULL);
107
108 struct scan_field field;
109 uint8_t t[4], r[4];
110 int retval;
111
112 field.num_bits = 32;
113 field.out_value = t;
114 buf_set_u32(t, 0, field.num_bits, *data);
115 field.in_value = r;
116
117 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
118
119 retval = jtag_execute_queue();
120 if (retval != ERROR_OK) {
121 LOG_ERROR("register read failed");
122 return retval;
123 }
124
125 *data = buf_get_u32(field.in_value, 0, 32);
126
127 keep_alive();
128
129 return ERROR_OK;
130 }
131
132 void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data)
133 {
134 uint8_t t[4];
135 struct jtag_tap *tap;
136 tap = ejtag_info->tap;
137 assert(tap != NULL);
138
139 struct scan_field field;
140
141 field.num_bits = 32;
142 field.out_value = t;
143 buf_set_u32(t, 0, field.num_bits, data);
144
145 field.in_value = NULL;
146
147 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
148 }
149
150 int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data)
151 {
152 struct jtag_tap *tap;
153 tap = ejtag_info->tap;
154 assert(tap != NULL);
155
156 struct scan_field field;
157 uint8_t t[4] = {0, 0, 0, 0}, r[4];
158 int retval;
159
160 field.num_bits = 8;
161 field.out_value = t;
162 buf_set_u32(t, 0, field.num_bits, *data);
163 field.in_value = r;
164
165 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
166
167 retval = jtag_execute_queue();
168 if (retval != ERROR_OK) {
169 LOG_ERROR("register read failed");
170 return retval;
171 }
172
173 *data = buf_get_u32(field.in_value, 0, 32);
174
175 return ERROR_OK;
176 }
177
178 void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data)
179 {
180 struct jtag_tap *tap;
181 tap = ejtag_info->tap;
182 assert(tap != NULL);
183
184 struct scan_field field;
185
186 field.num_bits = 8;
187 field.out_value = &data;
188 field.in_value = NULL;
189
190 jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
191 }
192
193 /* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */
194 int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step)
195 {
196 int code_len = enable_step ? 6 : 7;
197
198 uint32_t *code = malloc(code_len * sizeof(uint32_t));
199 if (code == NULL) {
200 LOG_ERROR("Out of memory");
201 return ERROR_FAIL;
202 }
203 uint32_t *code_p = code;
204
205 *code_p++ = MIPS32_MTC0(1, 31, 0); /* move $1 to COP0 DeSave */
206 *code_p++ = MIPS32_MFC0(1, 23, 0), /* move COP0 Debug to $1 */
207 *code_p++ = MIPS32_ORI(1, 1, 0x0100); /* set SSt bit in debug reg */
208 if (!enable_step)
209 *code_p++ = MIPS32_XORI(1, 1, 0x0100); /* clear SSt bit in debug reg */
210
211 *code_p++ = MIPS32_MTC0(1, 23, 0); /* move $1 to COP0 Debug */
212 *code_p++ = MIPS32_B(NEG16((code_len - 1))); /* jump to start */
213 *code_p = MIPS32_MFC0(1, 31, 0); /* move COP0 DeSave to $1 */
214
215 int retval = mips32_pracc_exec(ejtag_info, code_len, code, 0, NULL, 0, NULL, 1);
216
217 free(code);
218 return retval;
219 }
220
221 int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info)
222 {
223 uint32_t ejtag_ctrl;
224 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
225
226 /* set debug break bit */
227 ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_JTAGBRK;
228 mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
229
230 /* break bit will be cleared by hardware */
231 ejtag_ctrl = ejtag_info->ejtag_ctrl;
232 mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
233 LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl);
234 if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) {
235 LOG_ERROR("Failed to enter Debug Mode!");
236 return ERROR_FAIL;
237 }
238
239 return ERROR_OK;
240 }
241
242 int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info)
243 {
244 uint32_t inst;
245 inst = MIPS32_DRET;
246
247 /* execute our dret instruction */
248 return mips32_pracc_exec(ejtag_info, 1, &inst, 0, NULL, 0, NULL, 0);
249 }
250
251 int mips_ejtag_read_debug(struct mips_ejtag *ejtag_info, uint32_t* debug_reg)
252 {
253 /* read ejtag ECR */
254 static const uint32_t code[] = {
255 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
256 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
257 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
258 MIPS32_SW(1, 0, 15), /* sw $1,($15) */
259 MIPS32_SW(2, 0, 15), /* sw $2,($15) */
260 MIPS32_LUI(1, UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $1 = MIPS32_PRACC_PARAM_OUT */
261 MIPS32_ORI(1, 1, LOWER16(MIPS32_PRACC_PARAM_OUT)),
262 MIPS32_MFC0(2, 23, 0), /* move COP0 Debug to $2 */
263 MIPS32_SW(2, 0, 1),
264 MIPS32_LW(2, 0, 15),
265 MIPS32_LW(1, 0, 15),
266 MIPS32_B(NEG16(12)),
267 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
268 };
269
270 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
271 0, NULL, 1, debug_reg, 1);
272 }
273
274 int mips_ejtag_init(struct mips_ejtag *ejtag_info)
275 {
276 uint32_t ejtag_version;
277 int retval;
278
279 retval = mips_ejtag_get_impcode(ejtag_info, &ejtag_info->impcode);
280 if (retval != ERROR_OK)
281 return retval;
282 LOG_DEBUG("impcode: 0x%8.8" PRIx32 "", ejtag_info->impcode);
283
284 /* get ejtag version */
285 ejtag_version = ((ejtag_info->impcode >> 29) & 0x07);
286
287 switch (ejtag_version) {
288 case 0:
289 LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected");
290 break;
291 case 1:
292 LOG_DEBUG("EJTAG: Version 2.5 Detected");
293 break;
294 case 2:
295 LOG_DEBUG("EJTAG: Version 2.6 Detected");
296 break;
297 case 3:
298 LOG_DEBUG("EJTAG: Version 3.1 Detected");
299 break;
300 default:
301 LOG_DEBUG("EJTAG: Unknown Version Detected");
302 break;
303 }
304 LOG_DEBUG("EJTAG: features:%s%s%s%s%s%s%s",
305 ejtag_info->impcode & EJTAG_IMP_R3K ? " R3k" : " R4k",
306 ejtag_info->impcode & EJTAG_IMP_DINT ? " DINT" : "",
307 ejtag_info->impcode & (1 << 22) ? " ASID_8" : "",
308 ejtag_info->impcode & (1 << 21) ? " ASID_6" : "",
309 ejtag_info->impcode & EJTAG_IMP_MIPS16 ? " MIPS16" : "",
310 ejtag_info->impcode & EJTAG_IMP_NODMA ? " noDMA" : " DMA",
311 ejtag_info->impcode & EJTAG_DCR_MIPS64 ? " MIPS64" : " MIPS32");
312
313 if ((ejtag_info->impcode & EJTAG_IMP_NODMA) == 0)
314 LOG_DEBUG("EJTAG: DMA Access Mode Support Enabled");
315
316 /* set initial state for ejtag control reg */
317 ejtag_info->ejtag_ctrl = EJTAG_CTRL_ROCC | EJTAG_CTRL_PRACC | EJTAG_CTRL_PROBEN | EJTAG_CTRL_SETDEV;
318 ejtag_info->fast_access_save = -1;
319
320 return ERROR_OK;
321 }
322
323 int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data)
324 {
325 struct jtag_tap *tap;
326
327 tap = ejtag_info->tap;
328 assert(tap != NULL);
329
330 struct scan_field fields[2];
331 uint8_t spracc = 0;
332 uint8_t t[4] = {0, 0, 0, 0};
333
334 /* fastdata 1-bit register */
335 fields[0].num_bits = 1;
336 fields[0].out_value = &spracc;
337 fields[0].in_value = NULL;
338
339 /* processor access data register 32 bit */
340 fields[1].num_bits = 32;
341 fields[1].out_value = t;
342
343 if (write_t) {
344 fields[1].in_value = NULL;
345 buf_set_u32(t, 0, 32, *data);
346 } else
347 fields[1].in_value = (void *) data;
348
349 jtag_add_dr_scan(tap, 2, fields, TAP_IDLE);
350
351 if (!write_t && data)
352 jtag_add_callback(mips_le_to_h_u32,
353 (jtag_callback_data_t) data);
354
355 keep_alive();
356
357 return ERROR_OK;
358 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)