litescope: add support for groups of signals and dynamic muxing between them

allow multiple debug configuration in a single bitstream
This commit is contained in:
Florent Kermarrec 2017-06-09 12:06:53 +02:00
parent 2f625c58b2
commit cf7ea12ec8
2 changed files with 66 additions and 29 deletions

View File

@ -66,6 +66,21 @@ class FrontendSubSampler(Module, AutoCSR):
] ]
class AnalyzerMux(Module, AutoCSR):
def __init__(self, dw, n):
self.sinks = [stream.Endpoint(core_layout(dw)) for i in range(n)]
self.source = stream.Endpoint(core_layout(dw))
self.value = CSRStorage(bits_for(n))
# # #
cases = {}
for i in range(n):
cases[i] = self.sinks[i].connect(self.source)
self.comb += Case(self.value.storage, cases)
class AnalyzerFrontend(Module, AutoCSR): class AnalyzerFrontend(Module, AutoCSR):
def __init__(self, dw, cd, cd_ratio): def __init__(self, dw, cd, cd_ratio):
self.sink = stream.Endpoint(core_layout(dw)) self.sink = stream.Endpoint(core_layout(dw))
@ -160,8 +175,11 @@ class LiteScopeIO(Module, AutoCSR):
return self.gpio.get_csrs() return self.gpio.get_csrs()
class LiteScopeAnalyzer(Module, AutoCSR): def _format_groups(groups):
def __init__(self, signals, depth, cd="sys", cd_ratio=1): if not isinstance(groups, dict):
groups = {0 : groups}
new_groups = {}
for n, signals in groups.items():
if not isinstance(signals, list): if not isinstance(signals, list):
signals = [signals] signals = [signals]
@ -171,32 +189,40 @@ class LiteScopeAnalyzer(Module, AutoCSR):
split_signals.extend(s.flatten()) split_signals.extend(s.flatten())
else: else:
split_signals.append(s) split_signals.append(s)
signals = split_signals new_groups[n] = split_signals
return new_groups
self.signals = signals
self.dw = sum([len(s) for s in signals]) class LiteScopeAnalyzer(Module, AutoCSR):
self.core_dw = self.dw*cd_ratio def __init__(self, groups, depth, cd="sys", cd_ratio=1):
self.groups = _format_groups(groups)
self.dw = max([sum([len(s) for s in g]) for g in self.groups.values()])
self.depth = depth self.depth = depth
self.cd_ratio = cd_ratio self.cd_ratio = cd_ratio
# # # # # #
self.submodules.mux = AnalyzerMux(self.dw, len(self.groups))
for i, signals in self.groups.items():
self.comb += [
self.mux.sinks[i].valid.eq(1),
self.mux.sinks[i].data.eq(Cat(signals))
]
self.submodules.frontend = AnalyzerFrontend(self.dw, cd, cd_ratio) self.submodules.frontend = AnalyzerFrontend(self.dw, cd, cd_ratio)
self.submodules.storage = AnalyzerStorage(self.core_dw, depth, cd_ratio) self.submodules.storage = AnalyzerStorage(self.dw*cd_ratio, depth, cd_ratio)
self.comb += [ self.comb += [
self.frontend.sink.valid.eq(1), self.mux.source.connect(self.frontend.sink),
self.frontend.sink.data.eq(Cat(self.signals)),
self.frontend.source.connect(self.storage.sink) self.frontend.source.connect(self.storage.sink)
] ]
def export_csv(self, vns, filename): def export_csv(self, vns, filename):
def format_line(*args): def format_line(*args):
return ",".join(args) + "\n" return ",".join(args) + "\n"
r = format_line("config", "dw", str(self.dw)) r = format_line("config", "None", "dw", str(self.dw))
r += format_line("config", "depth", str(self.depth)) r += format_line("config", "None", "depth", str(self.depth))
r += format_line("config", "cd_ratio", str(int(self.cd_ratio))) r += format_line("config", "None", "cd_ratio", str(int(self.cd_ratio)))
for s in self.signals: for i, signals in self.groups.items():
r += format_line("signal", vns.get_name(s), str(len(s))) for s in signals:
r += format_line("signal", str(i), vns.get_name(s), str(len(s)))
write_to_file(filename, r) write_to_file(filename, r)

View File

@ -6,7 +6,8 @@ from litescope.software.dump import *
import csv import csv
class LiteScopeAnalyzerDriver():
class LiteScopeAnalyzerDriver:
def __init__(self, regs, name, config_csv=None, clk_freq=None, debug=False): def __init__(self, regs, name, config_csv=None, clk_freq=None, debug=False):
self.regs = regs self.regs = regs
self.name = name self.name = name
@ -21,24 +22,28 @@ class LiteScopeAnalyzerDriver():
self.samplerate = clk_freq self.samplerate = clk_freq
self.debug = debug self.debug = debug
self.get_config() self.get_config()
self.get_layout() self.get_layouts()
self.build() self.build()
self.group = 0
self.data = DumpData(self.dw) self.data = DumpData(self.dw)
def get_config(self): def get_config(self):
csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#') csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
for item in csv_reader: for item in csv_reader:
t, n, v = item t, g, n, v = item
if t == "config": if t == "config":
setattr(self, n, int(v)) setattr(self, n, int(v))
def get_layout(self): def get_layouts(self):
self.layout = [] self.layouts = {}
csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#') csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
for item in csv_reader: for item in csv_reader:
t, n, v = item t, g, n, v = item
if t == "signal": if t == "signal":
self.layout.append((n, int(v))) try:
self.layouts[int(g)].append((n, int(v)))
except:
self.layouts[int(g)] = [(n, int(v))]
def build(self): def build(self):
for key, value in self.regs.d.items(): for key, value in self.regs.d.items():
@ -46,13 +51,19 @@ class LiteScopeAnalyzerDriver():
key = key.replace(self.name + "_", "") key = key.replace(self.name + "_", "")
setattr(self, key, value) setattr(self, key, value)
value = 1 value = 1
for name, length in self.layout: for signals in self.layouts.values():
setattr(self, name + "_o", value) for name, length in signals:
value = value*(2**length) setattr(self, name + "_o", value)
value = value*(2**length)
value = 0 value = 0
for name, length in self.layout: for signals in self.layouts.values():
setattr(self, name + "_m", (2**length-1) << value) for name, length in signals:
value += length setattr(self, name + "_m", (2**length-1) << value)
value += length
def configure_group(self, value):
self.group = value
self.mux_value.write(value)
def configure_trigger(self, value=0, mask=0, cond=None): def configure_trigger(self, value=0, mask=0, cond=None):
if cond is not None: if cond is not None:
@ -113,5 +124,5 @@ class LiteScopeAnalyzerDriver():
dump = SigrokDump(samplerate=self.samplerate) dump = SigrokDump(samplerate=self.samplerate)
else: else:
raise NotImplementedError raise NotImplementedError
dump.add_from_layout(self.layout, self.data) dump.add_from_layout(self.layouts[self.group], self.data)
dump.write(filename) dump.write(filename)