target/mips: Use 'bool' data type
[openocd.git] / src / target / armv7m_trace.c
1 /***************************************************************************
2 * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <target/target.h>
23 #include <target/armv7m.h>
24 #include <target/cortex_m.h>
25 #include <target/armv7m_trace.h>
26 #include <jtag/interface.h>
27
28 #define TRACE_BUF_SIZE 4096
29
30 static int armv7m_poll_trace(void *target)
31 {
32 struct armv7m_common *armv7m = target_to_armv7m(target);
33 uint8_t buf[TRACE_BUF_SIZE];
34 size_t size = sizeof(buf);
35 int retval;
36
37 retval = adapter_poll_trace(buf, &size);
38 if (retval != ERROR_OK || !size)
39 return retval;
40
41 target_call_trace_callbacks(target, size, buf);
42
43 if (armv7m->trace_config.trace_file != NULL) {
44 if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
45 fflush(armv7m->trace_config.trace_file);
46 else {
47 LOG_ERROR("Error writing to the trace destination file");
48 return ERROR_FAIL;
49 }
50 }
51
52 return ERROR_OK;
53 }
54
55 int armv7m_trace_tpiu_config(struct target *target)
56 {
57 struct armv7m_common *armv7m = target_to_armv7m(target);
58 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
59 int prescaler;
60 int retval;
61
62 target_unregister_timer_callback(armv7m_poll_trace, target);
63
64
65 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
66 trace_config->pin_protocol,
67 trace_config->port_size,
68 &trace_config->trace_freq);
69 if (retval != ERROR_OK)
70 return retval;
71
72 if (!trace_config->trace_freq) {
73 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
74 return ERROR_FAIL;
75 }
76
77 prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
78
79 if (trace_config->traceclkin_freq % trace_config->trace_freq) {
80 prescaler++;
81 int trace_freq = trace_config->traceclkin_freq / prescaler;
82 LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead",
83 trace_config->trace_freq, trace_config->traceclkin_freq,
84 trace_freq);
85 trace_config->trace_freq = trace_freq;
86 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
87 trace_config->pin_protocol,
88 trace_config->port_size,
89 &trace_config->trace_freq);
90 if (retval != ERROR_OK)
91 return retval;
92 }
93
94 retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
95 if (retval != ERROR_OK)
96 return retval;
97
98 retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
99 if (retval != ERROR_OK)
100 return retval;
101
102 retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
103 if (retval != ERROR_OK)
104 return retval;
105
106 uint32_t ffcr;
107 retval = target_read_u32(target, TPIU_FFCR, &ffcr);
108 if (retval != ERROR_OK)
109 return retval;
110 if (trace_config->formatter)
111 ffcr |= (1 << 1);
112 else
113 ffcr &= ~(1 << 1);
114 retval = target_write_u32(target, TPIU_FFCR, ffcr);
115 if (retval != ERROR_OK)
116 return retval;
117
118 if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
119 target_register_timer_callback(armv7m_poll_trace, 1,
120 TARGET_TIMER_TYPE_PERIODIC, target);
121
122 target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
123
124 return ERROR_OK;
125 }
126
127 int armv7m_trace_itm_config(struct target *target)
128 {
129 struct armv7m_common *armv7m = target_to_armv7m(target);
130 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
131 int retval;
132
133 retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
134 if (retval != ERROR_OK)
135 return retval;
136
137 /* Enable ITM, TXENA, set TraceBusID and other parameters */
138 retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
139 (trace_config->itm_diff_timestamps << 1) |
140 (trace_config->itm_synchro_packets << 2) |
141 (trace_config->itm_async_timestamps << 4) |
142 (trace_config->itm_ts_prescale << 8) |
143 (trace_config->trace_bus_id << 16));
144 if (retval != ERROR_OK)
145 return retval;
146
147 for (unsigned int i = 0; i < 8; i++) {
148 retval = target_write_u32(target, ITM_TER0 + i * 4,
149 trace_config->itm_ter[i]);
150 if (retval != ERROR_OK)
151 return retval;
152 }
153
154 return ERROR_OK;
155 }
156
157 static void close_trace_file(struct armv7m_common *armv7m)
158 {
159 if (armv7m->trace_config.trace_file)
160 fclose(armv7m->trace_config.trace_file);
161 armv7m->trace_config.trace_file = NULL;
162 }
163
164 COMMAND_HANDLER(handle_tpiu_config_command)
165 {
166 struct target *target = get_current_target(CMD_CTX);
167 struct armv7m_common *armv7m = target_to_armv7m(target);
168
169 unsigned int cmd_idx = 0;
170
171 if (CMD_ARGC == cmd_idx)
172 return ERROR_COMMAND_SYNTAX_ERROR;
173 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
174 if (CMD_ARGC == cmd_idx + 1) {
175 close_trace_file(armv7m);
176
177 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
178 if (CMD_CTX->mode == COMMAND_EXEC)
179 return armv7m_trace_tpiu_config(target);
180 else
181 return ERROR_OK;
182 }
183 } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
184 !strcmp(CMD_ARGV[cmd_idx], "internal")) {
185 close_trace_file(armv7m);
186
187 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
188 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
189 cmd_idx++;
190 if (CMD_ARGC == cmd_idx)
191 return ERROR_COMMAND_SYNTAX_ERROR;
192
193 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
194
195 if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
196 armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
197 if (!armv7m->trace_config.trace_file) {
198 LOG_ERROR("Can't open trace destination file");
199 return ERROR_FAIL;
200 }
201 }
202 }
203 cmd_idx++;
204 if (CMD_ARGC == cmd_idx)
205 return ERROR_COMMAND_SYNTAX_ERROR;
206
207 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
208 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
209
210 cmd_idx++;
211 if (CMD_ARGC == cmd_idx)
212 return ERROR_COMMAND_SYNTAX_ERROR;
213
214 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
215 } else {
216 if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
217 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
218 else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
219 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
220 else
221 return ERROR_COMMAND_SYNTAX_ERROR;
222
223 cmd_idx++;
224 if (CMD_ARGC == cmd_idx)
225 return ERROR_COMMAND_SYNTAX_ERROR;
226
227 COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
228 }
229
230 cmd_idx++;
231 if (CMD_ARGC == cmd_idx)
232 return ERROR_COMMAND_SYNTAX_ERROR;
233
234 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
235
236 cmd_idx++;
237 if (CMD_ARGC != cmd_idx) {
238 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
239 cmd_idx++;
240 } else {
241 if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
242 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
243 return ERROR_COMMAND_SYNTAX_ERROR;
244 }
245 armv7m->trace_config.trace_freq = 0;
246 }
247
248 if (CMD_ARGC == cmd_idx) {
249 if (CMD_CTX->mode == COMMAND_EXEC)
250 return armv7m_trace_tpiu_config(target);
251 else
252 return ERROR_OK;
253 }
254 }
255
256 return ERROR_COMMAND_SYNTAX_ERROR;
257 }
258
259 COMMAND_HANDLER(handle_itm_port_command)
260 {
261 struct target *target = get_current_target(CMD_CTX);
262 struct armv7m_common *armv7m = target_to_armv7m(target);
263 unsigned int reg_idx;
264 uint8_t port;
265 bool enable;
266
267 if (CMD_ARGC != 2)
268 return ERROR_COMMAND_SYNTAX_ERROR;
269
270 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
271 COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
272 reg_idx = port / 32;
273 port = port % 32;
274 if (enable)
275 armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
276 else
277 armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
278
279 if (CMD_CTX->mode == COMMAND_EXEC)
280 return armv7m_trace_itm_config(target);
281 else
282 return ERROR_OK;
283 }
284
285 COMMAND_HANDLER(handle_itm_ports_command)
286 {
287 struct target *target = get_current_target(CMD_CTX);
288 struct armv7m_common *armv7m = target_to_armv7m(target);
289 bool enable;
290
291 if (CMD_ARGC != 1)
292 return ERROR_COMMAND_SYNTAX_ERROR;
293
294 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
295 memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
296 sizeof(armv7m->trace_config.itm_ter));
297
298 if (CMD_CTX->mode == COMMAND_EXEC)
299 return armv7m_trace_itm_config(target);
300 else
301 return ERROR_OK;
302 }
303
304 static const struct command_registration tpiu_command_handlers[] = {
305 {
306 .name = "config",
307 .handler = handle_tpiu_config_command,
308 .mode = COMMAND_ANY,
309 .help = "Configure TPIU features",
310 .usage = "(disable | "
311 "((external | internal <filename>) "
312 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
313 "<TRACECLKIN freq> [<trace freq>]))",
314 },
315 COMMAND_REGISTRATION_DONE
316 };
317
318 static const struct command_registration itm_command_handlers[] = {
319 {
320 .name = "port",
321 .handler = handle_itm_port_command,
322 .mode = COMMAND_ANY,
323 .help = "Enable or disable ITM stimulus port",
324 .usage = "<port> (0|1|on|off)",
325 },
326 {
327 .name = "ports",
328 .handler = handle_itm_ports_command,
329 .mode = COMMAND_ANY,
330 .help = "Enable or disable all ITM stimulus ports",
331 .usage = "(0|1|on|off)",
332 },
333 COMMAND_REGISTRATION_DONE
334 };
335
336 const struct command_registration armv7m_trace_command_handlers[] = {
337 {
338 .name = "tpiu",
339 .mode = COMMAND_ANY,
340 .help = "tpiu command group",
341 .usage = "",
342 .chain = tpiu_command_handlers,
343 },
344 {
345 .name = "itm",
346 .mode = COMMAND_ANY,
347 .help = "itm command group",
348 .usage = "",
349 .chain = itm_command_handlers,
350 },
351 COMMAND_REGISTRATION_DONE
352 };

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)