Add filter support for DWT packets
[swodec.git] / src / dwt.c
blobc0b34117d54f154a6f94a2e82913e4fa0e6b65ce
1 /*
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/>.
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <glib.h>
24 #include "swodec.h"
26 /* Event counter packet discriminator ID. */
27 #define EVCNT_ID 0
29 /* Size of an event counter packet in bytes. */
30 #define EVCNT_SIZE 2
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. */
51 #define EXTRACE_ID 1
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. */
81 #define CMPN_OFFSET 1
83 /* Bitmask for the WnR flag of a data trace data value packet. */
84 #define WNR_MASK 0x01
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
112 * Manual.
114 static const char *exception_names[] = {
115 "Thread",
116 "Reset",
117 "NMI",
118 "HardFault",
119 "MemManage",
120 "BusFault",
121 "UsageFault",
122 "Reserved",
123 "Reserved",
124 "Reserved",
125 "Reserved",
126 "SVCall",
127 "Debug Monitor",
128 "Reserved",
129 "PendSV",
130 "SysTick"
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. */
141 EXTRACE_FN_EXIT = 2,
142 /* Return to exception. */
143 EXTRACE_FN_RETURN = 3
146 static void handle_evcnt_packet(const struct libswo_packet_hw *packet)
148 unsigned int cpi;
149 unsigned int exc;
150 unsigned int sleep;
151 unsigned int lsu;
152 unsigned int fold;
153 unsigned int cyc;
155 if (!(packet_type_filter & (1 << DWT_PACKET_TYPE_EVENT_COUNTER)))
156 return;
158 if (packet->size != EVCNT_SIZE) {
159 g_warning("Event counter packet with invalid size of "
160 "%zu bytes.", packet->size);
161 return;
164 if (packet->payload[0] & EVCNT_CPI_MASK)
165 cpi = 1;
166 else
167 cpi = 0;
169 if (packet->payload[0] & EVCNT_EXC_MASK)
170 exc = 1;
171 else
172 exc = 0;
174 if (packet->payload[0] & EVCNT_SLEEP_MASK)
175 sleep = 1;
176 else
177 sleep = 0;
179 if (packet->payload[0] & EVCNT_LSU_MASK)
180 lsu = 1;
181 else
182 lsu = 0;
184 if (packet->payload[0] & EVCNT_FOLD_MASK)
185 fold = 1;
186 else
187 fold = 0;
189 if (packet->payload[0] & EVCNT_CYC_MASK)
190 cyc = 1;
191 else
192 cyc = 0;
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)
200 uint16_t exception;
201 uint8_t tmp;
202 const char *func;
203 const char *name;
204 char buf[23];
206 if (!(packet_type_filter & (1 << DWT_PACKET_TYPE_EXCEPTION_TRACE)))
207 return;
209 if (packet->size != EXTRACE_SIZE) {
210 g_warning("Exception trace packet with invalid size of "
211 "%zu bytes.", packet->size);
212 return;
215 exception = packet->payload[0];
216 exception |= (packet->payload[1] & EXTRACE_EX_MASK) << \
217 EXTRACE_EX_OFFSET;
218 tmp = (packet->payload[1] & EXTRACE_FN_MASK) >> EXTRACE_FN_OFFSET;
220 switch (tmp) {
221 case EXTRACE_FN_ENTER:
222 func = "enter";
223 break;
224 case EXTRACE_FN_EXIT:
225 func = "exit";
226 break;
227 case EXTRACE_FN_RETURN:
228 func = "return";
229 break;
230 default:
231 func = "reserved";
234 if (exception < NUM_EXCEPTION_NAMES) {
235 name = exception_names[exception];
236 } else {
237 snprintf(buf, sizeof(buf), "External interrupt %u",
238 exception - NUM_EXCEPTION_NAMES);
239 name = buf;
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)))
249 return;
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);
255 return;
258 printf("Periodic PC sleep\n");
259 } else if (packet->size == PC_SAMPLE_SIZE) {
260 printf("Periodic PC sample (value = %x)\n", packet->value);
261 } else {
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)
269 unsigned int cmpn;
271 if (!(packet_type_filter & (1 << DWT_PACKET_TYPE_DT_PC_VALUE)))
272 return;
274 if (packet->size != PC_VALUE_SIZE) {
275 g_warning("Data trace PC value packet with invalid size of "
276 "%zu bytes.", packet->size);
277 return;
280 cmpn = (packet->address & CMPN_MASK) >> CMPN_OFFSET;
282 printf("Data trace PC value (comparator = %u, value = %x)\n", cmpn,
283 packet->value);
286 static void handle_address_offset_packet(const struct libswo_packet_hw *packet)
288 unsigned int cmpn;
290 if (!(packet_type_filter & (1 << DWT_PACKET_TYPE_DT_ADDR_OFFSET)))
291 return;
293 if (packet->size != ADDR_OFFSET_SIZE) {
294 g_warning("Data trace address offset packet with invalid size "
295 "of %zu bytes.", packet->size);
296 return;
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)
307 unsigned int wnr;
308 unsigned int cmpn;
310 if (!(packet_type_filter & (1 << DWT_PACKET_TYPE_DT_DATA_VALUE)))
311 return;
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,
318 packet->size - 1);
321 gboolean dwt_handle_packet(const struct libswo_packet_hw *packet)
323 uint8_t addr;
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);
339 else
340 return FALSE;
342 return TRUE;