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

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)