2 * This file is part of the swodec project.
4 * Copyright (C) 2014-2015 Marc Schink <swo-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /* Event counter packet discriminator ID. */
29 /* Size of an event counter packet in bytes. */
32 /* Bitmask for the CPI flag of an event counter packet. */
33 #define EVCNT_CPI_MASK 0x01
35 /* Bitmask for the Exc flag of an event counter packet. */
36 #define EVCNT_EXC_MASK 0x02
38 /* Bitmask for the Sleep flag of an event counter packet. */
39 #define EVCNT_SLEEP_MASK 0x04
41 /* Bitmask for the LSU flag of an event counter packet. */
42 #define EVCNT_LSU_MASK 0x08
44 /* Bitmask for the Fold flag of an event counter packet. */
45 #define EVCNT_FOLD_MASK 0x10
47 /* Bitmask for the Cyc flag of an event counter packet. */
48 #define EVCNT_CYC_MASK 0x20
50 /* Exception trace packet discriminator ID. */
53 /* Size of an exception trace packet in bytes. */
54 #define EXTRACE_SIZE 3
56 /* Bitmask for the exception number of an exception trace packet. */
57 #define EXTRACE_EX_MASK 0x01
59 /* Offset of the exception number of an exception trace packet. */
60 #define EXTRACE_EX_OFFSET 8
62 /* Bitmask for the function of an exception trace packet. */
63 #define EXTRACE_FN_MASK 0x30
65 /* Offset of the function of an exception trace packet. */
66 #define EXTRACE_FN_OFFSET 4
68 /* Periodic PC sample packet discriminator ID. */
69 #define PC_SAMPLE_ID 2
71 /* Size of a periodic PC sleep packet in bytes. */
72 #define PC_SAMPLE_SLEEP_SIZE 2
74 /* Size of a periodic PC sample packet in bytes. */
75 #define PC_SAMPLE_SIZE 5
77 /* Bitmask for the comparator number of a data trace packet. */
78 #define CMPN_MASK 0x06
80 /* Offset of the comparator number of a data trace packet. */
83 /* Bitmask for the WnR flag of a data trace data value packet. */
86 /* Bitmask for the data trace PC value packet header. */
87 #define PC_VALUE_HEADER_MASK 0x19
89 /* Data trace PC value packet header. */
90 #define PC_VALUE_HEADER 0x08
92 /* Size of a data trace PC value packet in bytes. */
93 #define PC_VALUE_SIZE 5
95 /* Bitmask for the data trace address offset packet header. */
96 #define ADDR_OFFSET_HEADER_MASK 0x19
98 /* Data trace address offset packet header. */
99 #define ADDR_OFFSET_HEADER 0x09
101 /* Size of a data trace address offset packet in bytes. */
102 #define ADDR_OFFSET_SIZE 3
104 /* Bitmask for the data trace data value packet header. */
105 #define DATA_VALUE_HEADER_MASK 0x18
107 /* Data trace data value packet header. */
108 #define DATA_VALUE_HEADER 0x10
111 * Exception names according to section B1.5 of ARMv7-M Architecture Reference
114 static const char *exception_names
[] = {
133 /* Number of exception names. */
134 #define NUM_EXCEPTION_NAMES 16
136 /* Exception trace functions. */
137 enum extrace_function
{
138 /* Enter exception. */
139 EXTRACE_FN_ENTER
= 1,
140 /* Exit exception. */
142 /* Return to exception. */
143 EXTRACE_FN_RETURN
= 3
146 static void handle_evcnt_packet(const struct libswo_packet_hw
*packet
)
155 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_EVENT_COUNTER
)))
158 if (packet
->size
!= EVCNT_SIZE
) {
159 g_warning("Event counter packet with invalid size of "
160 "%zu bytes.", packet
->size
);
164 if (packet
->payload
[0] & EVCNT_CPI_MASK
)
169 if (packet
->payload
[0] & EVCNT_EXC_MASK
)
174 if (packet
->payload
[0] & EVCNT_SLEEP_MASK
)
179 if (packet
->payload
[0] & EVCNT_LSU_MASK
)
184 if (packet
->payload
[0] & EVCNT_FOLD_MASK
)
189 if (packet
->payload
[0] & EVCNT_CYC_MASK
)
194 printf("Event counter (CPI = %u, exc = %u, sleep = %u, LSU = %u, "
195 "fold = %u, cyc = %u)\n", cpi
, exc
, sleep
, lsu
, fold
, cyc
);
198 static void handle_extrace_packet(const struct libswo_packet_hw
*packet
)
206 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_EXCEPTION_TRACE
)))
209 if (packet
->size
!= EXTRACE_SIZE
) {
210 g_warning("Exception trace packet with invalid size of "
211 "%zu bytes.", packet
->size
);
215 exception
= packet
->payload
[0];
216 exception
|= (packet
->payload
[1] & EXTRACE_EX_MASK
) << \
218 tmp
= (packet
->payload
[1] & EXTRACE_FN_MASK
) >> EXTRACE_FN_OFFSET
;
221 case EXTRACE_FN_ENTER
:
224 case EXTRACE_FN_EXIT
:
227 case EXTRACE_FN_RETURN
:
234 if (exception
< NUM_EXCEPTION_NAMES
) {
235 name
= exception_names
[exception
];
237 snprintf(buf
, sizeof(buf
), "External interrupt %u",
238 exception
- NUM_EXCEPTION_NAMES
);
242 printf("Exception trace (function = %s, exception = %s)\n", func
, name
);
245 static void handle_pc_sample_packet(const struct libswo_packet_hw
*packet
)
248 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_PC_SAMPLE
)))
251 if (packet
->size
== PC_SAMPLE_SLEEP_SIZE
) {
252 if (packet
->value
> 0) {
253 g_warning("Periodic PC sleep packet contains invalid "
254 "value: %x.", packet
->value
);
258 printf("Periodic PC sleep\n");
259 } else if (packet
->size
== PC_SAMPLE_SIZE
) {
260 printf("Periodic PC sample (value = %x)\n", packet
->value
);
262 g_warning("Periodic PC sample packet with invalid size of "
263 "%zu bytes.", packet
->size
);
267 static void handle_pc_value_packet(const struct libswo_packet_hw
*packet
)
271 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_DT_PC_VALUE
)))
274 if (packet
->size
!= PC_VALUE_SIZE
) {
275 g_warning("Data trace PC value packet with invalid size of "
276 "%zu bytes.", packet
->size
);
280 cmpn
= (packet
->address
& CMPN_MASK
) >> CMPN_OFFSET
;
282 printf("Data trace PC value (comparator = %u, value = %x)\n", cmpn
,
286 static void handle_address_offset_packet(const struct libswo_packet_hw
*packet
)
290 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_DT_ADDR_OFFSET
)))
293 if (packet
->size
!= ADDR_OFFSET_SIZE
) {
294 g_warning("Data trace address offset packet with invalid size "
295 "of %zu bytes.", packet
->size
);
299 cmpn
= (packet
->address
& CMPN_MASK
) >> CMPN_OFFSET
;
301 printf("Data trace address offset (comparator = %u, value = %x)\n",
302 cmpn
, packet
->value
);
305 static void handle_data_value_packet(const struct libswo_packet_hw
*packet
)
310 if (!(packet_type_filter
& (1 << DWT_PACKET_TYPE_DT_DATA_VALUE
)))
313 wnr
= packet
->address
& WNR_MASK
;
314 cmpn
= (packet
->address
& CMPN_MASK
) >> CMPN_OFFSET
;
316 printf("Data trace data value (comparator = %u, WnR = %u, value = %x, "
317 "size = %zu bytes)\n", cmpn
, wnr
, packet
->value
,
321 gboolean
dwt_handle_packet(const struct libswo_packet_hw
*packet
)
325 addr
= packet
->address
;
327 if (addr
== EVCNT_ID
)
328 handle_evcnt_packet(packet
);
329 else if (addr
== EXTRACE_ID
)
330 handle_extrace_packet(packet
);
331 else if (addr
== PC_SAMPLE_ID
)
332 handle_pc_sample_packet(packet
);
333 else if ((addr
& PC_VALUE_HEADER_MASK
) == PC_VALUE_HEADER
)
334 handle_pc_value_packet(packet
);
335 else if ((addr
& ADDR_OFFSET_HEADER_MASK
) == ADDR_OFFSET_HEADER
)
336 handle_address_offset_packet(packet
);
337 else if ((addr
& DATA_VALUE_HEADER_MASK
) == DATA_VALUE_HEADER
)
338 handle_data_value_packet(packet
);