VCD: Add samplerate support to fix displayed timestamps

To use this, pass the samplerate kwarg to LiteScopeAnalyzer(). If using the sys domain, soc_obj.sys_clk_freq works.
This commit is contained in:
Jevin Sweval 2022-01-29 13:44:17 -08:00
parent 42a357714b
commit 21f6fcaa28
4 changed files with 37 additions and 9 deletions

View File

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

View File

@ -226,9 +226,10 @@ class _Storage(Module, AutoCSR):
class LiteScopeAnalyzer(Module, AutoCSR):
def __init__(self, groups, depth, clock_domain="sys", trigger_depth=16, register=False, csr_csv="analyzer.csv"):
self.groups = groups = self.format_groups(groups)
self.depth = depth
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.depth = depth
self.samplerate = samplerate
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"
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", "samplerate", str(self.samplerate))
for i, signals in self.groups.items():
for s in signals:
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)
def configure_subsampler(self, value):
self.subsampling = value
self.subsampler_value.write(value-1)
def run(self, offset=0, length=None):
@ -166,11 +167,13 @@ class LiteScopeAnalyzerDriver:
return self.data
def save(self, filename, samplerate=None, flatten=False):
if samplerate is None:
samplerate = self.samplerate / self.subsampling
if self.debug:
print("[writing to " + filename + "]...")
name, ext = os.path.splitext(filename)
if ext == ".vcd":
dump = VCDDump()
dump = VCDDump(samplerate=samplerate)
elif ext == ".csv":
dump = CSVDump()
elif ext == ".py":

View File

@ -6,6 +6,7 @@
from itertools import count
import datetime
import re
from litescope.software.dump.common import Dump, dec2bin
@ -19,14 +20,37 @@ def vcd_codes():
code = codechars[r] + 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):
def __init__(self, dump=None, timescale="1ps", comment=""):
def __init__(self, dump=None, samplerate=1e-12, timescale="1ps", comment=""):
Dump.__init__(self)
self.variables = [] if dump is None else dump.variables
self.timescale = timescale
self.comment = comment
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):
r = ""
@ -65,14 +89,12 @@ class VCDDump(Dump):
def generate_timescale(self):
r = "$timescale "
r += self.timescale
r += str(self.count_timescale) + self.timescale_unit_str
r += " $end\n"
return r
def generate_vars(self):
r = "$scope "
r += self.timescale
r += " $end\n"
r = "$scope dumped_signals $end\n"
for v in self.variables:
r += "$var wire "
r += str(v.width)