1 /***************************************************************************
2 * Generic Xtensa debug module API for OpenOCD *
3 * Copyright (C) 2019 Espressif Systems Ltd. *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include "xtensa_debug_module.h"
25 #define TAPINS_PWRCTL 0x08
26 #define TAPINS_PWRSTAT 0x09
27 #define TAPINS_NARSEL 0x1C
28 #define TAPINS_IDCODE 0x1E
29 #define TAPINS_BYPASS 0x1F
31 #define TAPINS_PWRCTL_LEN 8
32 #define TAPINS_PWRSTAT_LEN 8
33 #define TAPINS_NARSEL_ADRLEN 8
34 #define TAPINS_NARSEL_DATALEN 32
35 #define TAPINS_IDCODE_LEN 32
36 #define TAPINS_BYPASS_LEN 1
39 static void xtensa_dm_add_set_ir(struct xtensa_debug_module
*dm
, uint8_t value
)
41 struct scan_field field
;
44 memset(&field
, 0, sizeof(field
));
45 field
.num_bits
= dm
->tap
->ir_length
;
47 buf_set_u32(t
, 0, field
.num_bits
, value
);
48 jtag_add_ir_scan(dm
->tap
, &field
, TAP_IDLE
);
51 static void xtensa_dm_add_dr_scan(struct xtensa_debug_module
*dm
,
57 struct scan_field field
;
59 memset(&field
, 0, sizeof(field
));
61 field
.out_value
= src
;
62 field
.in_value
= dest
;
63 jtag_add_dr_scan(dm
->tap
, 1, &field
, endstate
);
66 int xtensa_dm_init(struct xtensa_debug_module
*dm
, const struct xtensa_debug_module_config
*cfg
)
71 dm
->pwr_ops
= cfg
->pwr_ops
;
72 dm
->dbg_ops
= cfg
->dbg_ops
;
74 dm
->queue_tdi_idle
= cfg
->queue_tdi_idle
;
75 dm
->queue_tdi_idle_arg
= cfg
->queue_tdi_idle_arg
;
79 int xtensa_dm_queue_enable(struct xtensa_debug_module
*dm
)
81 return dm
->dbg_ops
->queue_reg_write(dm
, NARADR_DCRSET
, OCDDCR_ENABLEOCD
);
84 int xtensa_dm_queue_reg_read(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t *value
)
86 uint8_t regdata
= (reg
<< 1) | 0;
87 uint8_t dummy
[4] = { 0, 0, 0, 0 };
89 if (reg
> NARADR_MAX
) {
90 LOG_ERROR("Invalid DBG reg ID %d!", reg
);
93 xtensa_dm_add_set_ir(dm
, TAPINS_NARSEL
);
94 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_ADRLEN
, ®data
, NULL
, TAP_IDLE
);
95 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_DATALEN
, dummy
, value
, TAP_IDLE
);
99 int xtensa_dm_queue_reg_write(struct xtensa_debug_module
*dm
, unsigned int reg
, uint32_t value
)
101 uint8_t regdata
= (reg
<< 1) | 1;
102 uint8_t valdata
[] = { value
, value
>> 8, value
>> 16, value
>> 24 };
104 if (reg
> NARADR_MAX
) {
105 LOG_ERROR("Invalid DBG reg ID %d!", reg
);
108 xtensa_dm_add_set_ir(dm
, TAPINS_NARSEL
);
109 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_ADRLEN
, ®data
, NULL
, TAP_IDLE
);
110 xtensa_dm_add_dr_scan(dm
, TAPINS_NARSEL_DATALEN
, valdata
, NULL
, TAP_IDLE
);
114 int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t *data
, uint8_t clear
)
116 uint8_t value_clr
= clear
;
120 if (reg
== DMREG_PWRCTL
) {
121 tap_insn
= TAPINS_PWRCTL
;
122 tap_insn_sz
= TAPINS_PWRCTL_LEN
;
123 } else if (reg
== DMREG_PWRSTAT
) {
124 tap_insn
= TAPINS_PWRSTAT
;
125 tap_insn_sz
= TAPINS_PWRSTAT_LEN
;
127 LOG_ERROR("Invalid PWR reg ID %d!", reg
);
130 xtensa_dm_add_set_ir(dm
, tap_insn
);
131 xtensa_dm_add_dr_scan(dm
, tap_insn_sz
, &value_clr
, data
, TAP_IDLE
);
135 int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module
*dm
, unsigned int reg
, uint8_t data
)
137 uint8_t value
= data
;
141 if (reg
== DMREG_PWRCTL
) {
142 tap_insn
= TAPINS_PWRCTL
;
143 tap_insn_sz
= TAPINS_PWRCTL_LEN
;
144 } else if (reg
== DMREG_PWRSTAT
) {
145 tap_insn
= TAPINS_PWRSTAT
;
146 tap_insn_sz
= TAPINS_PWRSTAT_LEN
;
148 LOG_ERROR("Invalid PWR reg ID %d!", reg
);
151 xtensa_dm_add_set_ir(dm
, tap_insn
);
152 xtensa_dm_add_dr_scan(dm
, tap_insn_sz
, &value
, NULL
, TAP_IDLE
);
156 int xtensa_dm_device_id_read(struct xtensa_debug_module
*dm
)
158 uint8_t id_buf
[sizeof(uint32_t)];
160 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_OCDID
, id_buf
);
161 xtensa_dm_queue_tdi_idle(dm
);
162 int res
= jtag_execute_queue();
165 dm
->device_id
= buf_get_u32(id_buf
, 0, 32);
169 int xtensa_dm_power_status_read(struct xtensa_debug_module
*dm
, uint32_t clear
)
171 /* uint8_t id_buf[sizeof(uint32_t)]; */
173 /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
174 * It is set in xtensa_examine(), need to move reading of NARADR_OCDID out of this function */
175 /* dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
177 dm
->pwr_ops
->queue_reg_read(dm
, DMREG_PWRSTAT
, &dm
->power_status
.stat
, clear
);
178 dm
->pwr_ops
->queue_reg_read(dm
, DMREG_PWRSTAT
, &dm
->power_status
.stath
, clear
);
179 xtensa_dm_queue_tdi_idle(dm
);
180 return jtag_execute_queue();
183 int xtensa_dm_core_status_read(struct xtensa_debug_module
*dm
)
185 uint8_t dsr_buf
[sizeof(uint32_t)];
187 xtensa_dm_queue_enable(dm
);
188 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_DSR
, dsr_buf
);
189 xtensa_dm_queue_tdi_idle(dm
);
190 int res
= jtag_execute_queue();
193 dm
->core_status
.dsr
= buf_get_u32(dsr_buf
, 0, 32);
197 int xtensa_dm_core_status_clear(struct xtensa_debug_module
*dm
, xtensa_dsr_t bits
)
199 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_DSR
, bits
);
200 xtensa_dm_queue_tdi_idle(dm
);
201 return jtag_execute_queue();
204 int xtensa_dm_trace_start(struct xtensa_debug_module
*dm
, struct xtensa_trace_start_config
*cfg
)
206 /*Turn off trace unit so we can start a new trace. */
207 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_TRAXCTRL
, 0);
208 xtensa_dm_queue_tdi_idle(dm
);
209 int res
= jtag_execute_queue();
213 /*Set up parameters */
214 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_TRAXADDR
, 0);
215 if (cfg
->stopmask
!= XTENSA_STOPMASK_DISABLED
) {
216 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_PCMATCHCTRL
,
217 (cfg
->stopmask
<< PCMATCHCTRL_PCML_SHIFT
));
218 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_TRIGGERPC
, cfg
->stoppc
);
220 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_DELAYCNT
, cfg
->after
);
221 /*Options are mostly hardcoded for now. ToDo: make this more configurable. */
222 dm
->dbg_ops
->queue_reg_write(
226 ((cfg
->stopmask
!= XTENSA_STOPMASK_DISABLED
) ? TRAXCTRL_PCMEN
: 0) | TRAXCTRL_TMEN
|
227 (cfg
->after_is_words
? 0 : TRAXCTRL_CNTU
) | (0 << TRAXCTRL_SMPER_SHIFT
) | TRAXCTRL_PTOWS
);
228 xtensa_dm_queue_tdi_idle(dm
);
229 return jtag_execute_queue();
232 int xtensa_dm_trace_stop(struct xtensa_debug_module
*dm
, bool pto_enable
)
234 uint8_t traxctl_buf
[sizeof(uint32_t)];
236 struct xtensa_trace_status trace_status
;
238 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_TRAXCTRL
, traxctl_buf
);
239 xtensa_dm_queue_tdi_idle(dm
);
240 int res
= jtag_execute_queue();
243 traxctl
= buf_get_u32(traxctl_buf
, 0, 32);
246 traxctl
&= ~(TRAXCTRL_PTOWS
| TRAXCTRL_PTOWT
);
248 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_TRAXCTRL
, traxctl
| TRAXCTRL_TRSTP
);
249 xtensa_dm_queue_tdi_idle(dm
);
250 res
= jtag_execute_queue();
254 /*Check current status of trace hardware */
255 res
= xtensa_dm_trace_status_read(dm
, &trace_status
);
259 if (trace_status
.stat
& TRAXSTAT_TRACT
) {
260 LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status
.stat
);
266 int xtensa_dm_trace_status_read(struct xtensa_debug_module
*dm
, struct xtensa_trace_status
*status
)
268 uint8_t traxstat_buf
[sizeof(uint32_t)];
270 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_TRAXSTAT
, traxstat_buf
);
271 xtensa_dm_queue_tdi_idle(dm
);
272 int res
= jtag_execute_queue();
273 if (res
== ERROR_OK
&& status
)
274 status
->stat
= buf_get_u32(traxstat_buf
, 0, 32);
278 int xtensa_dm_trace_config_read(struct xtensa_debug_module
*dm
, struct xtensa_trace_config
*config
)
280 uint8_t traxctl_buf
[sizeof(uint32_t)];
281 uint8_t memadrstart_buf
[sizeof(uint32_t)];
282 uint8_t memadrend_buf
[sizeof(uint32_t)];
283 uint8_t adr_buf
[sizeof(uint32_t)];
288 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_TRAXCTRL
, traxctl_buf
);
289 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_MEMADDRSTART
, memadrstart_buf
);
290 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_MEMADDREND
, memadrend_buf
);
291 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_TRAXADDR
, adr_buf
);
292 xtensa_dm_queue_tdi_idle(dm
);
293 int res
= jtag_execute_queue();
294 if (res
== ERROR_OK
) {
295 config
->ctrl
= buf_get_u32(traxctl_buf
, 0, 32);
296 config
->memaddr_start
= buf_get_u32(memadrstart_buf
, 0, 32);
297 config
->memaddr_end
= buf_get_u32(memadrend_buf
, 0, 32);
298 config
->addr
= buf_get_u32(adr_buf
, 0, 32);
303 int xtensa_dm_trace_data_read(struct xtensa_debug_module
*dm
, uint8_t *dest
, uint32_t size
)
308 for (unsigned int i
= 0; i
< size
/ 4; i
++)
309 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_TRAXDATA
, &dest
[i
* 4]);
310 xtensa_dm_queue_tdi_idle(dm
);
311 return jtag_execute_queue();
314 int xtensa_dm_perfmon_enable(struct xtensa_debug_module
*dm
, int counter_id
,
315 const struct xtensa_perfmon_config
*config
)
320 uint8_t pmstat_buf
[4];
321 uint32_t pmctrl
= ((config
->tracelevel
) << 4) +
322 (config
->select
<< 8) +
323 (config
->mask
<< 16) +
324 (config
->kernelcnt
<< 3);
326 /* enable performance monitor */
327 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_PMG
, 0x1);
329 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_PM0
+ counter_id
, 0);
330 dm
->dbg_ops
->queue_reg_write(dm
, NARADR_PMCTRL0
+ counter_id
, pmctrl
);
331 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_PMSTAT0
+ counter_id
, pmstat_buf
);
332 xtensa_dm_queue_tdi_idle(dm
);
333 return jtag_execute_queue();
336 int xtensa_dm_perfmon_dump(struct xtensa_debug_module
*dm
, int counter_id
,
337 struct xtensa_perfmon_result
*out_result
)
339 uint8_t pmstat_buf
[4];
340 uint8_t pmcount_buf
[4];
342 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_PMSTAT0
+ counter_id
, pmstat_buf
);
343 dm
->dbg_ops
->queue_reg_read(dm
, NARADR_PM0
+ counter_id
, pmcount_buf
);
344 xtensa_dm_queue_tdi_idle(dm
);
345 int res
= jtag_execute_queue();
346 if (res
== ERROR_OK
) {
347 uint32_t stat
= buf_get_u32(pmstat_buf
, 0, 32);
348 uint64_t result
= buf_get_u32(pmcount_buf
, 0, 32);
350 /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
351 * high 32 bits of the counter. */
353 out_result
->overflow
= ((stat
& 1) != 0);
354 out_result
->value
= result
;
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)