1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
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, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
27 #include "oocd_trace.h"
30 * This is "proof of concept" code, for prototype hardware:
31 * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html
34 static int oocd_trace_read_reg(struct oocd_trace
*oocd_trace
, int reg
, uint32_t *value
)
36 size_t bytes_written
, bytes_read
, bytes_to_read
;
39 cmd
= 0x10 | (reg
& 0x7);
40 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
43 while (bytes_to_read
> 0) {
44 bytes_read
= read(oocd_trace
->tty_fd
, ((uint8_t *)value
) + 4 - bytes_to_read
, bytes_to_read
);
45 bytes_to_read
-= bytes_read
;
48 LOG_DEBUG("reg #%i: 0x%8.8x", reg
, *value
);
53 static int oocd_trace_write_reg(struct oocd_trace
*oocd_trace
, int reg
, uint32_t value
)
58 data
[0] = 0x18 | (reg
& 0x7);
59 data
[1] = value
& 0xff;
60 data
[2] = (value
& 0xff00) >> 8;
61 data
[3] = (value
& 0xff0000) >> 16;
62 data
[4] = (value
& 0xff000000) >> 24;
64 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
65 LOG_DEBUG("reg #%i: 0x%8.8x", reg
, value
);
70 static int oocd_trace_read_memory(struct oocd_trace
*oocd_trace
, uint8_t *data
, uint32_t address
, uint32_t size
)
72 size_t bytes_written
, bytes_to_read
;
76 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
77 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
80 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
82 bytes_to_read
= size
* 16;
83 while (bytes_to_read
> 0) {
84 bytes_read
= read(oocd_trace
->tty_fd
,
85 ((uint8_t *)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
);
87 LOG_DEBUG("read() returned %zi (%s)", bytes_read
, strerror(errno
));
89 bytes_to_read
-= bytes_read
;
95 static int oocd_trace_init(struct etm_context
*etm_ctx
)
98 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
101 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
103 if (oocd_trace
->tty_fd
< 0) {
104 LOG_ERROR("can't open tty");
105 return ERROR_ETM_CAPTURE_INIT_FAILED
;
108 /* clear input & output buffers, then switch to "blocking mode" */
109 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
110 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
111 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
113 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
115 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
116 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
118 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
119 oocd_trace
->newtio
.c_oflag
= 0;
121 /* set input mode (non-canonical, no echo,...) */
122 oocd_trace
->newtio
.c_lflag
= 0;
124 cfmakeraw(&oocd_trace
->newtio
);
125 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
126 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
128 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
129 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
131 /* occasionally one bogus character is left in the input buffer
132 * read up any leftover characters to ensure communication is in sync */
134 bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
));
136 LOG_DEBUG("%zi bytes read", bytes_read
);
137 } while (bytes_read
> 0);
142 static trace_status_t
oocd_trace_status(struct etm_context
*etm_ctx
)
144 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
147 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
149 /* if tracing is currently idle, return this information */
150 if (etm_ctx
->capture_status
== TRACE_IDLE
)
151 return etm_ctx
->capture_status
;
152 else if (etm_ctx
->capture_status
& TRACE_RUNNING
) {
153 /* check Full bit to identify an overflow */
155 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
157 /* check Triggered bit to identify trigger condition */
159 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
162 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
163 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
167 return etm_ctx
->capture_status
;
170 static int oocd_trace_read_trace(struct etm_context
*etm_ctx
)
172 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
173 uint32_t status
, address
;
174 uint32_t first_frame
= 0x0;
175 uint32_t num_frames
= 1048576;
179 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
180 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
182 /* check if we overflowed, and adjust first frame of the trace accordingly
183 * if we didn't overflow, read only up to the frame that would be written next,
184 * i.e. don't read invalid entries
187 first_frame
= address
;
189 num_frames
= address
;
191 /* read data into temporary array for unpacking
192 * one frame from OpenOCD + trace corresponds to 16 trace cycles
194 trace_data
= malloc(sizeof(uint8_t) * num_frames
* 16);
195 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
197 if (etm_ctx
->trace_depth
> 0)
198 free(etm_ctx
->trace_data
);
200 etm_ctx
->trace_depth
= num_frames
* 16;
201 etm_ctx
->trace_data
= malloc(sizeof(struct etmv1_trace_data
) * etm_ctx
->trace_depth
);
203 for (i
= 0; i
< num_frames
* 16; i
++) {
204 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
205 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
206 etm_ctx
->trace_data
[i
].flags
= 0;
208 if ((trace_data
[i
] & 0x80) >> 7)
209 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
211 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
) {
212 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
213 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
222 static int oocd_trace_start_capture(struct etm_context
*etm_ctx
)
224 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
225 uint32_t control
= 0x1; /* 0x1: enabled */
226 uint32_t trigger_count
;
228 if (((etm_ctx
->control
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
229 || ((etm_ctx
->control
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
)) {
230 LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode");
231 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
234 if ((etm_ctx
->control
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
235 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
237 /* OpenOCD + trace holds up to 16 million samples,
238 * but trigger counts is set in multiples of 16 */
239 trigger_count
= (1048576 * /* trigger_percent */ 50) / 100;
241 /* capturing always starts at address zero */
242 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
243 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
244 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
246 /* we're starting a new trace, initialize capture status */
247 etm_ctx
->capture_status
= TRACE_RUNNING
;
252 static int oocd_trace_stop_capture(struct etm_context
*etm_ctx
)
254 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
256 /* trace stopped, just clear running flag, but preserve others */
257 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
259 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
264 COMMAND_HANDLER(handle_oocd_trace_config_command
)
266 struct target
*target
;
270 return ERROR_COMMAND_SYNTAX_ERROR
;
272 target
= get_current_target(CMD_CTX
);
273 arm
= target_to_arm(target
);
275 command_print(CMD_CTX
, "current target isn't an ARM");
280 struct oocd_trace
*oocd_trace
= malloc(sizeof(struct oocd_trace
));
282 arm
->etm
->capture_driver_priv
= oocd_trace
;
283 oocd_trace
->etm_ctx
= arm
->etm
;
285 /* copy name of TTY device used to communicate with OpenOCD + trace */
286 oocd_trace
->tty
= strndup(CMD_ARGV
[1], 256);
288 LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured");
293 COMMAND_HANDLER(handle_oocd_trace_status_command
)
295 struct target
*target
;
297 struct oocd_trace
*oocd_trace
;
300 target
= get_current_target(CMD_CTX
);
302 arm
= target_to_arm(target
);
304 command_print(CMD_CTX
, "current target isn't an ARM");
309 command_print(CMD_CTX
, "current target doesn't have an ETM configured");
313 if (strcmp(arm
->etm
->capture_driver
->name
, "oocd_trace") != 0) {
314 command_print(CMD_CTX
, "current target's ETM capture driver isn't 'oocd_trace'");
318 oocd_trace
= (struct oocd_trace
*)arm
->etm
->capture_driver_priv
;
320 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
323 command_print(CMD_CTX
, "trace clock locked");
325 command_print(CMD_CTX
, "no trace clock");
330 COMMAND_HANDLER(handle_oocd_trace_resync_command
)
332 struct target
*target
;
334 struct oocd_trace
*oocd_trace
;
335 size_t bytes_written
;
336 uint8_t cmd_array
[1];
338 target
= get_current_target(CMD_CTX
);
340 arm
= target_to_arm(target
);
342 command_print(CMD_CTX
, "current target isn't an ARM");
347 command_print(CMD_CTX
, "current target doesn't have an ETM configured");
351 if (strcmp(arm
->etm
->capture_driver
->name
, "oocd_trace") != 0) {
352 command_print(CMD_CTX
, "current target's ETM capture driver isn't 'oocd_trace'");
356 oocd_trace
= (struct oocd_trace
*)arm
->etm
->capture_driver_priv
;
360 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
362 command_print(CMD_CTX
, "requesting traceclock resync");
363 LOG_DEBUG("resyncing traceclk pll");
368 static const struct command_registration oocd_trace_all_command_handlers
[] = {
371 .handler
= handle_oocd_trace_config_command
,
372 .mode
= COMMAND_CONFIG
,
373 .usage
= "<target> <tty>",
377 .handler
= handle_oocd_trace_status_command
,
378 .mode
= COMMAND_EXEC
,
380 .help
= "display OpenOCD + trace status",
384 .handler
= handle_oocd_trace_resync_command
,
385 .mode
= COMMAND_EXEC
,
387 .help
= "resync OpenOCD + trace capture clock",
389 COMMAND_REGISTRATION_DONE
391 static const struct command_registration oocd_trace_command_handlers
[] = {
393 .name
= "oocd_trace",
395 .help
= "OpenOCD trace capture driver command group",
397 .chain
= oocd_trace_all_command_handlers
,
399 COMMAND_REGISTRATION_DONE
402 struct etm_capture_driver oocd_trace_capture_driver
= {
403 .name
= "oocd_trace",
404 .commands
= oocd_trace_command_handlers
,
405 .init
= oocd_trace_init
,
406 .status
= oocd_trace_status
,
407 .start_capture
= oocd_trace_start_capture
,
408 .stop_capture
= oocd_trace_stop_capture
,
409 .read_trace
= oocd_trace_read_trace
,
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)