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"
32 #include "binarybuffer.h"
36 #include "arm7_9_common.h"
40 int oocd_trace_read_reg(oocd_trace_t
*oocd_trace
, int reg
, u32
*value
)
42 size_t bytes_written
, bytes_read
, bytes_to_read
;
45 cmd
= 0x10 | (reg
& 0x7);
46 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
49 while (bytes_to_read
> 0)
51 bytes_read
= read(oocd_trace
->tty_fd
, ((u8
*)value
) + 4 - bytes_to_read
, bytes_to_read
);
52 bytes_to_read
-= bytes_read
;
55 DEBUG("reg #%i: 0x%8.8x\n", reg
, *value
);
60 int oocd_trace_write_reg(oocd_trace_t
*oocd_trace
, int reg
, u32 value
)
65 data
[0] = 0x18 | (reg
& 0x7);
66 data
[1] = value
& 0xff;
67 data
[2] = (value
& 0xff00) >> 8;
68 data
[3] = (value
& 0xff0000) >> 16;
69 data
[4] = (value
& 0xff000000) >> 24;
71 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
72 DEBUG("reg #%i: 0x%8.8x\n", reg
, value
);
77 int oocd_trace_read_memory(oocd_trace_t
*oocd_trace
, u8
*data
, u32 address
, u32 size
)
79 size_t bytes_written
, bytes_read
, bytes_to_read
;
83 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
84 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
87 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
89 bytes_to_read
= size
* 16;
90 while (bytes_to_read
> 0)
92 if ((bytes_read
= read(oocd_trace
->tty_fd
,
93 ((u8
*)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
)) < 0)
95 DEBUG("read() returned %i (%s)", bytes_read
, strerror(errno
));
98 bytes_to_read
-= bytes_read
;
104 int oocd_trace_init(etm_context_t
*etm_ctx
)
107 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
108 size_t bytes_written
, bytes_read
, bytes_to_read
;
110 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
112 if(oocd_trace
->tty_fd
< 0)
114 ERROR("can't open tty");
115 return ERROR_ETM_CAPTURE_INIT_FAILED
;
118 /* clear input & output buffers, then switch to "blocking mode" */
119 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
120 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
121 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
123 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
125 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
126 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
128 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
129 oocd_trace
->newtio
.c_oflag
= 0;
131 /* set input mode (non-canonical, no echo,...) */
132 oocd_trace
->newtio
.c_lflag
= 0;
134 cfmakeraw(&oocd_trace
->newtio
);
135 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
136 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
138 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
139 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
141 /* occasionally one bogus character is left in the input buffer
142 * read up any leftover characters to ensure communication is in sync */
143 while ((bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
))) > 0)
145 DEBUG("%i bytes read\n", bytes_read
);
151 trace_status_t
oocd_trace_status(etm_context_t
*etm_ctx
)
153 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
156 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
158 /* if tracing is currently idle, return this information */
159 if (etm_ctx
->capture_status
== TRACE_IDLE
)
161 return etm_ctx
->capture_status
;
163 else if (etm_ctx
->capture_status
& TRACE_RUNNING
)
165 /* check Full bit to identify an overflow */
167 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
169 /* check Triggered bit to identify trigger condition */
171 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
175 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
176 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
180 return etm_ctx
->capture_status
;
183 int oocd_trace_read_trace(etm_context_t
*etm_ctx
)
185 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
187 u32 first_frame
= 0x0;
188 u32 num_frames
= 1048576;
192 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
193 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
195 /* check if we overflowed, and adjust first frame of the trace accordingly
196 * if we didn't overflow, read only up to the frame that would be written next,
197 * i.e. don't read invalid entries
200 first_frame
= address
;
202 num_frames
= address
;
204 /* read data into temporary array for unpacking
205 * one frame from OpenOCD+trace corresponds to 16 trace cycles
207 trace_data
= malloc(sizeof(u8
) * num_frames
* 16);
208 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
210 if (etm_ctx
->trace_depth
> 0)
212 free(etm_ctx
->trace_data
);
215 etm_ctx
->trace_depth
= num_frames
* 16;
216 etm_ctx
->trace_data
= malloc(sizeof(etmv1_trace_data_t
) * etm_ctx
->trace_depth
);
218 for (i
= 0; i
< num_frames
* 16; i
++)
220 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
221 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
222 etm_ctx
->trace_data
[i
].flags
= 0;
224 if ((trace_data
[i
] & 0x80) >> 7)
226 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
229 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
)
231 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
232 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
241 int oocd_trace_start_capture(etm_context_t
*etm_ctx
)
243 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
244 u32 control
= 0x1; /* 0x1: enabled */
247 if (((etm_ctx
->portmode
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
248 || ((etm_ctx
->portmode
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
))
250 DEBUG("OpenOCD+trace only supports normal 4-bit ETM mode");
251 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
254 if ((etm_ctx
->portmode
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
256 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
259 /* OpenOCD+trace holds up to 16 million samples,
260 * but trigger counts is set in multiples of 16 */
261 trigger_count
= (1048576 * etm_ctx
->trigger_percent
) / 100;
263 /* capturing always starts at address zero */
264 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
265 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
266 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
268 /* we're starting a new trace, initialize capture status */
269 etm_ctx
->capture_status
= TRACE_RUNNING
;
274 int oocd_trace_stop_capture(etm_context_t
*etm_ctx
)
276 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
278 /* trace stopped, just clear running flag, but preserve others */
279 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
281 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
286 etm_capture_driver_t oocd_trace_capture_driver
=
288 .name
= "oocd_trace",
289 .register_commands
= oocd_trace_register_commands
,
290 .init
= oocd_trace_init
,
291 .status
= oocd_trace_status
,
292 .start_capture
= oocd_trace_start_capture
,
293 .stop_capture
= oocd_trace_stop_capture
,
294 .read_trace
= oocd_trace_read_trace
,
297 int handle_oocd_trace_config_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
300 armv4_5_common_t
*armv4_5
;
301 arm7_9_common_t
*arm7_9
;
305 ERROR("incomplete 'oocd_trace config <target> <tty>' command");
309 target
= get_current_target(cmd_ctx
);
311 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
313 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
319 oocd_trace_t
*oocd_trace
= malloc(sizeof(oocd_trace_t
));
321 arm7_9
->etm_ctx
->capture_driver_priv
= oocd_trace
;
322 oocd_trace
->etm_ctx
= arm7_9
->etm_ctx
;
324 /* copy name of TTY device used to communicate with OpenOCD+trace */
325 oocd_trace
->tty
= strndup(args
[1], 256);
329 ERROR("target has no ETM defined, OpenOCD+trace left unconfigured");
335 int handle_oocd_trace_status_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
338 armv4_5_common_t
*armv4_5
;
339 arm7_9_common_t
*arm7_9
;
340 oocd_trace_t
*oocd_trace
;
343 target
= get_current_target(cmd_ctx
);
345 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
347 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
351 if (!arm7_9
->etm_ctx
)
353 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
357 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
359 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
363 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
365 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
368 command_print(cmd_ctx
, "trace clock locked");
370 command_print(cmd_ctx
, "no trace clock");
375 int handle_oocd_trace_resync_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
378 armv4_5_common_t
*armv4_5
;
379 arm7_9_common_t
*arm7_9
;
380 oocd_trace_t
*oocd_trace
;
382 size_t bytes_written
;
385 target
= get_current_target(cmd_ctx
);
387 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
389 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
393 if (!arm7_9
->etm_ctx
)
395 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
399 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
401 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
405 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
409 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
411 command_print(cmd_ctx
, "requesting traceclock resync");
412 DEBUG("resyncing traceclk pll");
417 int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
)
419 command_t
*oocd_trace_cmd
;
421 oocd_trace_cmd
= register_command(cmd_ctx
, NULL
, "oocd_trace", NULL
, COMMAND_ANY
, "OpenOCD+trace");
423 register_command(cmd_ctx
, oocd_trace_cmd
, "config", handle_oocd_trace_config_command
, COMMAND_CONFIG
, NULL
);
425 register_command(cmd_ctx
, oocd_trace_cmd
, "status", handle_oocd_trace_status_command
, COMMAND_EXEC
, "display OpenOCD+trace status");
426 register_command(cmd_ctx
, oocd_trace_cmd
, "resync", handle_oocd_trace_resync_command
, COMMAND_EXEC
, "resync OpenOCD+trace capture clock");
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)