def _parse(self):
        """! @brief SWO parser as generator function coroutine.
        
        The generator yields every time it needs a byte of SWO data. The caller must use the
        generator's send() method to provide the next byte.
        """
        timestamp = 0
        invalid = False
        while True:
            byte = yield
            hdr = byte
            
            # Sync packet.
            if hdr == 0:
                packets = 0
                while True:
                    # Check for final 1 bit after at least 5 all-zero sync packets
                    if (packets >= 5) and (byte == 0x80):
                        break
                    elif byte == 0:
                        packets += 1
                    else:
                        # Get early non-zero packet, reset sync packet counter.
                        #packets = 0
                        invalid = True
                        break
                    byte = yield
                self._itm_page = 0
            # Overflow packet.
            elif hdr == 0x70:
                self._send_event(events.TraceOverflow(timestamp))
            # Protocol packet.
            elif (hdr & 0x3) == 0:
                c = (hdr >> 7) & 0x1
                d = (hdr >> 4) & 0b111
                # Local timestamp.
                if (hdr & 0xf) == 0 and d not in (0x0, 0x3):
                    ts = 0
                    tc = 0
                    # Local timestamp packet format 1.
                    if c == 1:
                        tc = (hdr >> 4) & 0x3
                        while c == 1:
                            byte = yield
                            ts = (ts << 7) | (byte & 0x7f)
                            c = (byte >> 7) & 0x1
                    # Local timestamp packet format 2.
                    else:
                        ts = (hdr >> 4) & 0x7
                    timestamp += ts
                    self._send_event(events.TraceTimestamp(tc, timestamp))
                # Global timestamp.
                elif hdr in (0b10010100, 0b10110100):
                    t = (hdr >> 5) & 0x1
                    # TODO handle global timestamp
                # Extension.
                elif (hdr & 0x8) == 0x8:
                    sh = (hdr >> 2) & 0x1
                    if c == 0:
                        ex = (hdr >> 4) & 0x7
                    else:
                        ex = 0
                        while c == 1:
                            byte = yield
                            ex = (ex << 7) | (byte & 0x7f)
                            c = (byte >> 7) & 0x1
                    if sh == 0:
                        # Extension packet with sh==0 sets ITM stimulus page.
                        self._itm_page = ex
                    else:
                        #self._send_event(events.TraceEvent("Extension: SH={:d} EX={:#x}\n".format(sh, ex), timestamp))
                        invalid = True
                # Reserved packet.
                else:
                    invalid = True
            # Source packet.
            else:
                ss = hdr & 0x3
                l = 1 << (ss - 1)
                a = (hdr >> 3) & 0x1f
                if l == 1:
                    payload = yield
                elif l == 2:
                    byte1 = yield
                    byte2 = yield
                    payload = (byte1 | 
                                (byte2 << 8))
                else:
                    byte1 = yield
                    byte2 = yield
                    byte3 = yield
                    byte4 = yield
                    payload = (byte1 | 
                                (byte2 << 8) |
                                (byte3 << 16) |
                                (byte4 << 24))
                
                # Instrumentation packet.
                if (hdr & 0x4) == 0:
                    port = (self._itm_page * 32) + a
                    self._send_event(events.TraceITMEvent(port, payload, l, timestamp))
                # Hardware source packets...
                # Event counter
                elif a == 0:
                    self._send_event(events.TraceEventCounter(payload, timestamp))
                # Exception trace
                elif a == 1:
                    exceptionNumber = payload & 0x1ff
                    exceptionName = self._core.exception_number_to_name(exceptionNumber, True)
                    fn = (payload >> 12) & 0x3
                    if 1 <= fn <= 3:
                        self._send_event(events.TraceExceptionEvent(exceptionNumber, exceptionName, fn, timestamp))
                    else:
                        invalid = True
                # Periodic PC
                elif a == 2:                        
                    # A payload of 0 indicates a period PC sleep event.
                    self._send_event(events.TracePeriodicPC(payload, timestamp))
                # Data trace
                elif 8 <= a <= 23:
                    type = (hdr >> 6) & 0x3
                    cmpn = (hdr >> 4) & 0x3
                    bit3 = (hdr >> 3) & 0x1
                    # PC value
                    if type == 0b01 and bit3 == 0:
                        self._send_event(events.TraceDataTraceEvent(cmpn=cmpn, pc=payload, ts=timestamp))
                    # Address
                    elif type == 0b01 and bit3 == 1:
                        self._send_event(events.TraceDataTraceEvent(cmpn=cmpn, addr=payload, ts=timestamp))
                    # Data value
                    elif type == 0b10:
                        self._send_event(events.TraceDataTraceEvent(cmpn=cmpn, value=payload, rnw=(bit3 == 0), sz=l, ts=timestamp))
                    else:
                        invalid = True
                # Invalid DWT 'a' value.
                else:
                    invalid = True