#!/usr/bin/env python3
from migen import *
from migen.genlib import cdc
from migen.fhdl.decorators import ResetInserter
from ..test.common import BaseUsbTestCase
import unittest
[docs]@ResetInserter()
class RxPacketDetect(Module):
"""Packet Detection
Full Speed packets begin with the following sequence:
KJKJKJKK
This raw sequence corresponds to the following data:
00000001
The bus idle condition is signaled with the J state:
JJJJJJJJ
This translates to a series of '1's since there are no transitions. Given
this information, it is easy to detect the beginning of a packet by looking
for 00000001.
The end of a packet is even easier to detect. The end of a packet is
signaled with two SE0 and one J. We can just look for the first SE0 to
detect the end of the packet.
Packet detection can occur in parallel with bitstuff removal.
https://www.pjrc.com/teensy/beta/usb20.pdf, USB2 Spec, 7.1.10
Input Ports
------------
i_valid : Signal(1)
Qualifier for all of the input signals. Indicates one bit of valid
data is present on the inputs.
i_data : Signal(1)
Decoded data bit from USB bus.
Qualified by valid.
i_se0 : Signal(1)
Indicator for SE0 from USB bus.
Qualified by valid.
Output Ports
------------
o_pkt_start : Signal(1)
Asserted for one clock on the last bit of the sync.
o_pkt_active : Signal(1)
Asserted while in the middle of a packet.
o_pkt_end : Signal(1)
Asserted for one clock after the last data bit of a packet was received.
"""
def __init__(self):
self.i_valid = Signal()
self.i_data = Signal()
self.i_se0 = Signal()
self.submodules.pkt = pkt = FSM()
pkt_start = Signal()
pkt_active = Signal()
pkt_end = Signal()
for i in range(5):
pkt.act("D%d" % i,
If(self.i_valid,
If(self.i_data | self.i_se0,
# Receiving '1' or SE0 early resets the packet start counter.
NextState("D0")
).Else(
# Receiving '0' increments the packet start counter.
NextState("D%d" % (i + 1))
)
)
)
pkt.act("D5",
If(self.i_valid,
If(self.i_se0,
NextState("D0")
# once we get a '1', the packet is active
).Elif(self.i_data,
pkt_start.eq(1),
NextState("PKT_ACTIVE")
)
)
)
pkt.act("PKT_ACTIVE",
pkt_active.eq(1),
If(self.i_valid & self.i_se0,
NextState("D0"),
pkt_active.eq(0),
pkt_end.eq(1)
)
)
# pass all of the outputs through a pipe stage
self.o_pkt_start = Signal()
self.o_pkt_active = Signal()
self.o_pkt_end = Signal()
self.comb += [
self.o_pkt_start.eq(pkt_start),
self.o_pkt_active.eq(pkt_active),
self.o_pkt_end.eq(pkt_end),
]