Skip to content

Commit 0d6cbda

Browse files
committed
wip: Add COBS encoder and test it by having it output delimited TPIU frames.
1 parent 85b66b9 commit 0d6cbda

File tree

2 files changed

+208
-1
lines changed

2 files changed

+208
-1
lines changed

orbtrace/trace/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from .swo import ManchesterDecoder, PulseLengthCapture, BitsToBytes, NRZDecoder, UARTDecoder
88

9+
from . import cobs
10+
911
class TracePHY(Module):
1012
def __init__(self, pads):
1113
self.source = source = Endpoint([('data', 128)])
@@ -307,10 +309,15 @@ def __init__(self, platform):
307309
ClockDomainsRenamer({'write': 'trace', 'read': 'sys'})(AsyncFIFO([('data', 128)], 4)),
308310
ByteSwap(16),
309311
injector := Injector(),
310-
PipeValid([('data', 128)]),
312+
pv := PipeValid([('data', 128)]),
311313
Converter(128, 8),
314+
cobs.COBSEncoder(),
315+
cobs.DelimiterAppender(),
316+
cobs.SuperFramer(7500000, 65536),
312317
]
313318

319+
pv.comb += pv.source.last.eq(1)
320+
314321
trace_stream = Endpoint([('data', 8)])
315322

316323
self.submodules += [*trace_pipeline, Pipeline(*trace_pipeline, trace_stream)]

orbtrace/trace/cobs.py

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
from migen import *
2+
3+
from litex.soc.interconnect import stream
4+
5+
class GroupSplitter(Module):
6+
def __init__(self, delimiter = 0):
7+
self.sink = sink = stream.Endpoint([('data', 8)])
8+
self.source_data = source_data = stream.Endpoint([('data', 8)])
9+
self.source_len = source_len = stream.Endpoint([('len', 8)])
10+
11+
cnt = Signal(8)
12+
cnt_inc = Signal()
13+
cnt_reset = Signal()
14+
15+
last = Signal()
16+
17+
self.comb += [
18+
sink.ready.eq(source_data.ready & source_len.ready & (cnt < 254) & ~last),
19+
source_data.data.eq(sink.data),
20+
source_len.len.eq(cnt),
21+
source_len.last.eq(last),
22+
23+
If((sink.ready & sink.valid) | (cnt == 254) | last,
24+
If((sink.data == delimiter) | (cnt == 254) | last,
25+
source_len.valid.eq(1),
26+
cnt_reset.eq(source_len.ready),
27+
),
28+
If((sink.data != delimiter) & (cnt < 254) & ~last,
29+
source_data.valid.eq(1),
30+
cnt_inc.eq(1),
31+
),
32+
),
33+
]
34+
35+
self.sync += [
36+
If(cnt_inc,
37+
cnt.eq(cnt + 1),
38+
),
39+
If(cnt_reset,
40+
cnt.eq(source_data.valid),
41+
),
42+
If(sink.ready & sink.valid & sink.last,
43+
last.eq(1),
44+
),
45+
If(source_len.ready & last,
46+
last.eq(0),
47+
),
48+
]
49+
50+
class GroupCombiner(Module):
51+
def __init__(self, delimiter = 0):
52+
self.sink_data = sink_data = stream.Endpoint([('data', 8)])
53+
self.sink_len = sink_len = stream.Endpoint([('len', 8)])
54+
self.source = source = stream.Endpoint([('data', 8)])
55+
56+
self.submodules.fsm = fsm = FSM()
57+
58+
header = Signal(8)
59+
cnt = Signal(8)
60+
last = Signal()
61+
62+
self.comb += [
63+
header.eq(sink_len.len),
64+
If(sink_len.len >= delimiter,
65+
header.eq(sink_len.len + 1),
66+
),
67+
]
68+
69+
fsm.act('HEADER',
70+
sink_len.ready.eq(source.ready),
71+
source.valid.eq(sink_len.valid),
72+
source.last.eq(sink_len.last & (sink_len.len == 0)),
73+
source.data.eq(header),
74+
75+
If(source.ready & source.valid & (sink_len.len > 0),
76+
NextState('DATA'),
77+
NextValue(cnt, sink_len.len - 1),
78+
NextValue(last, sink_len.last),
79+
),
80+
)
81+
82+
fsm.act('DATA',
83+
sink_data.ready.eq(source.ready),
84+
source.valid.eq(sink_data.valid),
85+
source.last.eq(last & (cnt == 0)),
86+
source.data.eq(sink_data.data),
87+
88+
If(source.ready & source.valid,
89+
NextValue(cnt, cnt - 1),
90+
91+
If(cnt == 0,
92+
NextState('HEADER'),
93+
),
94+
),
95+
)
96+
97+
class COBSEncoder(Module):
98+
def __init__(self, delimiter = 0):
99+
self.sink = stream.Endpoint([('data', 8)])
100+
self.source = stream.Endpoint([('data', 8)])
101+
102+
self.submodules.group_splitter = GroupSplitter(delimiter)
103+
self.submodules.fifo_data = stream.SyncFIFO([('data', 8)], 256)
104+
self.submodules.fifo_len = stream.SyncFIFO([('len', 8)], 256)
105+
self.submodules.group_combiner = GroupCombiner(delimiter)
106+
107+
self.comb += [
108+
self.sink.connect(self.group_splitter.sink),
109+
110+
self.group_splitter.source_data.connect(self.fifo_data.sink),
111+
self.group_splitter.source_len.connect(self.fifo_len.sink),
112+
113+
self.fifo_data.source.connect(self.group_combiner.sink_data),
114+
self.fifo_len.source.connect(self.group_combiner.sink_len),
115+
116+
self.group_combiner.source.connect(self.source),
117+
]
118+
119+
class DelimiterAppender(Module):
120+
def __init__(self, delimiter = 0):
121+
self.sink = stream.Endpoint([('data', 8)])
122+
self.source = stream.Endpoint([('data', 8)])
123+
124+
self.submodules.fsm = fsm = FSM()
125+
126+
fsm.act('DATA',
127+
self.sink.connect(self.source, omit = {'last'}),
128+
129+
If(self.sink.valid & self.sink.ready & self.sink.last,
130+
NextState('DELIMITER'),
131+
),
132+
)
133+
134+
fsm.act('DELIMITER',
135+
self.source.data.eq(delimiter),
136+
self.source.last.eq(1),
137+
self.source.valid.eq(1),
138+
139+
If(self.source.ready,
140+
NextState('DATA'),
141+
),
142+
)
143+
144+
class SuperFramer(Module):
145+
def __init__(self, interval, threshold):
146+
self.sink = sink = stream.Endpoint([('data', 8)])
147+
self.source = source = stream.Endpoint([('data', 8)])
148+
149+
interval_cnt = Signal(max = interval + 1)
150+
byte_cnt = Signal(max = threshold + 1)
151+
152+
flush = Signal()
153+
154+
data = Signal(8)
155+
first = Signal(reset = 1)
156+
last = Signal()
157+
valid = Signal()
158+
159+
self.comb += [
160+
sink.ready.eq(~valid | (source.ready & source.valid)),
161+
162+
source.data.eq(data),
163+
source.first.eq(first),
164+
source.last.eq(last & flush),
165+
source.valid.eq(valid & (sink.valid | flush)),
166+
]
167+
168+
self.sync += [
169+
If(source.ready & source.valid,
170+
first.eq(source.last),
171+
valid.eq(0),
172+
173+
If(last & flush,
174+
flush.eq(0),
175+
),
176+
177+
If(byte_cnt < threshold,
178+
byte_cnt.eq(byte_cnt + 1),
179+
),
180+
),
181+
182+
If(sink.ready & sink.valid,
183+
data.eq(sink.data),
184+
last.eq(sink.last),
185+
valid.eq(1),
186+
),
187+
188+
If(valid & (interval_cnt < interval),
189+
interval_cnt.eq(interval_cnt + 1),
190+
),
191+
192+
If(interval_cnt == interval,
193+
byte_cnt.eq(0),
194+
interval_cnt.eq(0),
195+
196+
If(byte_cnt < threshold,
197+
flush.eq(1),
198+
),
199+
),
200+
]

0 commit comments

Comments
 (0)