Merge pull request #40 from jevinskie/jev/vcd-timescale-fix

VCD: Add samplerate support to fix displayed timestamps
This commit is contained in:
enjoy-digital 2022-01-31 16:55:12 +01:00 committed by GitHub
commit 71187f8bd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 9 deletions

View File

@ -48,6 +48,7 @@ class LiteScopeSoC(BaseSoC):
self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals,
depth = 1024, depth = 1024,
clock_domain = "sys", clock_domain = "sys",
samplerate = self.sys_clk_freq,
csr_csv = "analyzer.csv") csr_csv = "analyzer.csv")
self.add_csr("analyzer") self.add_csr("analyzer")

View File

@ -226,9 +226,10 @@ class _Storage(Module, AutoCSR):
class LiteScopeAnalyzer(Module, AutoCSR): class LiteScopeAnalyzer(Module, AutoCSR):
def __init__(self, groups, depth, clock_domain="sys", trigger_depth=16, register=False, csr_csv="analyzer.csv"): def __init__(self, groups, depth, samplerate=1e-12, clock_domain="sys", trigger_depth=16, register=False, csr_csv="analyzer.csv"):
self.groups = groups = self.format_groups(groups) self.groups = groups = self.format_groups(groups)
self.depth = depth self.depth = depth
self.samplerate = samplerate
self.data_width = data_width = max([sum([len(s) for s in g]) for g in groups.values()]) self.data_width = data_width = max([sum([len(s) for s in g]) for g in groups.values()])
@ -294,6 +295,7 @@ class LiteScopeAnalyzer(Module, AutoCSR):
return ",".join(args) + "\n" return ",".join(args) + "\n"
r = format_line("config", "None", "data_width", str(self.data_width)) r = format_line("config", "None", "data_width", str(self.data_width))
r += format_line("config", "None", "depth", str(self.depth)) r += format_line("config", "None", "depth", str(self.depth))
r += format_line("config", "None", "samplerate", str(self.samplerate))
for i, signals in self.groups.items(): for i, signals in self.groups.items():
for s in signals: for s in signals:
r += format_line("signal", str(i), vns.get_name(s), str(len(s))) r += format_line("signal", str(i), vns.get_name(s), str(len(s)))

View File

@ -118,6 +118,7 @@ class LiteScopeAnalyzerDriver:
self.add_trigger(value, mask, cond) self.add_trigger(value, mask, cond)
def configure_subsampler(self, value): def configure_subsampler(self, value):
self.subsampling = value
self.subsampler_value.write(value-1) self.subsampler_value.write(value-1)
def run(self, offset=0, length=None): def run(self, offset=0, length=None):
@ -166,11 +167,13 @@ class LiteScopeAnalyzerDriver:
return self.data return self.data
def save(self, filename, samplerate=None, flatten=False): def save(self, filename, samplerate=None, flatten=False):
if samplerate is None:
samplerate = self.samplerate / self.subsampling
if self.debug: if self.debug:
print("[writing to " + filename + "]...") print("[writing to " + filename + "]...")
name, ext = os.path.splitext(filename) name, ext = os.path.splitext(filename)
if ext == ".vcd": if ext == ".vcd":
dump = VCDDump() dump = VCDDump(samplerate=samplerate)
elif ext == ".csv": elif ext == ".csv":
dump = CSVDump() dump = CSVDump()
elif ext == ".py": elif ext == ".py":

View File

@ -6,6 +6,7 @@
from itertools import count from itertools import count
import datetime import datetime
import re
from litescope.software.dump.common import Dump, dec2bin from litescope.software.dump.common import Dump, dec2bin
@ -19,14 +20,37 @@ def vcd_codes():
code = codechars[r] + code code = codechars[r] + code
yield code yield code
_si_prefix2exp = {
"": 0,
"m": -3,
"u": -6,
"n": -9,
"p": -12,
"f": -15,
}
def _timescale_str2num(timescale):
match = re.fullmatch("(\d+)(\w{0,1})s", timescale)
num = int(match.group(1))
si_prefix = match.group(2)
exp = _si_prefix2exp[si_prefix]
return num * 10**exp, si_prefix
class VCDDump(Dump): class VCDDump(Dump):
def __init__(self, dump=None, timescale="1ps", comment=""): def __init__(self, dump=None, samplerate=1e-12, timescale="1ps", comment=""):
Dump.__init__(self) Dump.__init__(self)
self.variables = [] if dump is None else dump.variables self.variables = [] if dump is None else dump.variables
self.timescale = timescale self.timescale = timescale
self.comment = comment self.comment = comment
self.cnt = -1 self.cnt = -1
# rescale the timescale from the provided one to one where it is equal to the samplerate
# this lets us output sequential change timestamps which helps with software like PulseView
# that slow down if a much smaller timescale than necessary is used
timescale_seconds, si_prefix = _timescale_str2num(timescale)
# factor of 2 scale is because of 2x samples from fake clock
self.count_timescale = int(1 / (timescale_seconds * samplerate * 2))
self.timescale_unit_str = si_prefix + "s"
def change(self): def change(self):
r = "" r = ""
@ -65,14 +89,12 @@ class VCDDump(Dump):
def generate_timescale(self): def generate_timescale(self):
r = "$timescale " r = "$timescale "
r += self.timescale r += str(self.count_timescale) + self.timescale_unit_str
r += " $end\n" r += " $end\n"
return r return r
def generate_vars(self): def generate_vars(self):
r = "$scope " r = "$scope dumped_signals $end\n"
r += self.timescale
r += " $end\n"
for v in self.variables: for v in self.variables:
r += "$var wire " r += "$var wire "
r += str(v.width) r += str(v.width)