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 ***************************************************************************/
24 #include "oocd_trace.h"
25 #include "arm7_9_common.h"
28 * This is "proof of concept" code, for prototype hardware:
29 * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html
33 static int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
);
35 static int oocd_trace_read_reg(oocd_trace_t
*oocd_trace
, int reg
, uint32_t *value
)
37 size_t bytes_written
, bytes_read
, bytes_to_read
;
40 cmd
= 0x10 | (reg
& 0x7);
41 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
44 while (bytes_to_read
> 0)
46 bytes_read
= read(oocd_trace
->tty_fd
, ((uint8_t*)value
) + 4 - bytes_to_read
, bytes_to_read
);
47 bytes_to_read
-= bytes_read
;
50 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, *value
);
55 static int oocd_trace_write_reg(oocd_trace_t
*oocd_trace
, int reg
, uint32_t value
)
60 data
[0] = 0x18 | (reg
& 0x7);
61 data
[1] = value
& 0xff;
62 data
[2] = (value
& 0xff00) >> 8;
63 data
[3] = (value
& 0xff0000) >> 16;
64 data
[4] = (value
& 0xff000000) >> 24;
66 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
67 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, value
);
72 static int oocd_trace_read_memory(oocd_trace_t
*oocd_trace
, uint8_t *data
, uint32_t address
, uint32_t size
)
74 size_t bytes_written
, bytes_to_read
;
78 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
79 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
82 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
84 bytes_to_read
= size
* 16;
85 while (bytes_to_read
> 0)
87 if ((bytes_read
= read(oocd_trace
->tty_fd
,
88 ((uint8_t*)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
)) < 0)
90 LOG_DEBUG("read() returned %zi (%s)", bytes_read
, strerror(errno
));
93 bytes_to_read
-= bytes_read
;
99 static int oocd_trace_init(etm_context_t
*etm_ctx
)
102 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
105 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
107 if (oocd_trace
->tty_fd
< 0)
109 LOG_ERROR("can't open tty");
110 return ERROR_ETM_CAPTURE_INIT_FAILED
;
113 /* clear input & output buffers, then switch to "blocking mode" */
114 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
115 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
116 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
118 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
120 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
121 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
123 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
124 oocd_trace
->newtio
.c_oflag
= 0;
126 /* set input mode (non-canonical, no echo,...) */
127 oocd_trace
->newtio
.c_lflag
= 0;
129 cfmakeraw(&oocd_trace
->newtio
);
130 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
131 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
133 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
134 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
136 /* occasionally one bogus character is left in the input buffer
137 * read up any leftover characters to ensure communication is in sync */
138 while ((bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
))) > 0)
140 LOG_DEBUG("%zi bytes read\n", bytes_read
);
146 static trace_status_t
oocd_trace_status(etm_context_t
*etm_ctx
)
148 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
151 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
153 /* if tracing is currently idle, return this information */
154 if (etm_ctx
->capture_status
== TRACE_IDLE
)
156 return etm_ctx
->capture_status
;
158 else if (etm_ctx
->capture_status
& TRACE_RUNNING
)
160 /* check Full bit to identify an overflow */
162 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
164 /* check Triggered bit to identify trigger condition */
166 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
170 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
171 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
175 return etm_ctx
->capture_status
;
178 static int oocd_trace_read_trace(etm_context_t
*etm_ctx
)
180 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
181 uint32_t status
, address
;
182 uint32_t first_frame
= 0x0;
183 uint32_t num_frames
= 1048576;
187 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
188 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
190 /* check if we overflowed, and adjust first frame of the trace accordingly
191 * if we didn't overflow, read only up to the frame that would be written next,
192 * i.e. don't read invalid entries
195 first_frame
= address
;
197 num_frames
= address
;
199 /* read data into temporary array for unpacking
200 * one frame from OpenOCD + trace corresponds to 16 trace cycles
202 trace_data
= malloc(sizeof(uint8_t) * num_frames
* 16);
203 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
205 if (etm_ctx
->trace_depth
> 0)
207 free(etm_ctx
->trace_data
);
210 etm_ctx
->trace_depth
= num_frames
* 16;
211 etm_ctx
->trace_data
= malloc(sizeof(etmv1_trace_data_t
) * etm_ctx
->trace_depth
);
213 for (i
= 0; i
< num_frames
* 16; i
++)
215 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
216 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
217 etm_ctx
->trace_data
[i
].flags
= 0;
219 if ((trace_data
[i
] & 0x80) >> 7)
221 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
224 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
)
226 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
227 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
236 static int oocd_trace_start_capture(etm_context_t
*etm_ctx
)
238 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
239 uint32_t control
= 0x1; /* 0x1: enabled */
240 uint32_t trigger_count
;
242 if (((etm_ctx
->portmode
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
243 || ((etm_ctx
->portmode
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
))
245 LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode");
246 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
249 if ((etm_ctx
->portmode
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
251 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
254 /* OpenOCD + trace holds up to 16 million samples,
255 * but trigger counts is set in multiples of 16 */
256 trigger_count
= (1048576 * etm_ctx
->trigger_percent
) / 100;
258 /* capturing always starts at address zero */
259 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
260 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
261 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
263 /* we're starting a new trace, initialize capture status */
264 etm_ctx
->capture_status
= TRACE_RUNNING
;
269 static int oocd_trace_stop_capture(etm_context_t
*etm_ctx
)
271 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
273 /* trace stopped, just clear running flag, but preserve others */
274 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
276 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
281 etm_capture_driver_t oocd_trace_capture_driver
=
283 .name
= "oocd_trace",
284 .register_commands
= oocd_trace_register_commands
,
285 .init
= oocd_trace_init
,
286 .status
= oocd_trace_status
,
287 .start_capture
= oocd_trace_start_capture
,
288 .stop_capture
= oocd_trace_stop_capture
,
289 .read_trace
= oocd_trace_read_trace
,
292 static int handle_oocd_trace_config_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
295 armv4_5_common_t
*armv4_5
;
296 arm7_9_common_t
*arm7_9
;
300 LOG_ERROR("incomplete 'oocd_trace config <target> <tty>' command");
304 target
= get_current_target(cmd_ctx
);
306 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
308 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
314 oocd_trace_t
*oocd_trace
= malloc(sizeof(oocd_trace_t
));
316 arm7_9
->etm_ctx
->capture_driver_priv
= oocd_trace
;
317 oocd_trace
->etm_ctx
= arm7_9
->etm_ctx
;
319 /* copy name of TTY device used to communicate with OpenOCD + trace */
320 oocd_trace
->tty
= strndup(args
[1], 256);
324 LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured");
330 static int handle_oocd_trace_status_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
333 armv4_5_common_t
*armv4_5
;
334 arm7_9_common_t
*arm7_9
;
335 oocd_trace_t
*oocd_trace
;
338 target
= get_current_target(cmd_ctx
);
340 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
342 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
346 if (!arm7_9
->etm_ctx
)
348 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
352 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
354 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
358 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
360 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
363 command_print(cmd_ctx
, "trace clock locked");
365 command_print(cmd_ctx
, "no trace clock");
370 static int handle_oocd_trace_resync_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
373 armv4_5_common_t
*armv4_5
;
374 arm7_9_common_t
*arm7_9
;
375 oocd_trace_t
*oocd_trace
;
376 size_t bytes_written
;
377 uint8_t cmd_array
[1];
379 target
= get_current_target(cmd_ctx
);
381 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
383 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
387 if (!arm7_9
->etm_ctx
)
389 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
393 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
395 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
399 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
403 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
405 command_print(cmd_ctx
, "requesting traceclock resync");
406 LOG_DEBUG("resyncing traceclk pll");
411 int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
)
413 command_t
*oocd_trace_cmd
;
415 oocd_trace_cmd
= register_command(cmd_ctx
, NULL
, "oocd_trace", NULL
, COMMAND_ANY
, "OpenOCD + trace");
417 register_command(cmd_ctx
, oocd_trace_cmd
, "config", handle_oocd_trace_config_command
, COMMAND_CONFIG
, NULL
);
419 register_command(cmd_ctx
, oocd_trace_cmd
, "status", handle_oocd_trace_status_command
, COMMAND_EXEC
, "display OpenOCD + trace status");
420 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)