Added option for reduction of long clock sequences in wavedrom converter

Signed-off-by: Wojciech Gryncewicz <wgryncewicz@antmicro.com>
This commit is contained in:
Wojciech Gryncewicz 2020-12-01 15:26:39 +01:00
parent adea4260e7
commit c5bd980a84
1 changed files with 53 additions and 17 deletions

View File

@ -18,6 +18,7 @@ import sys
import argparse import argparse
import pathlib import pathlib
import wavedrom import wavedrom
import re
from contextlib import contextmanager from contextlib import contextmanager
@ -44,7 +45,7 @@ def file_or_stdout(file):
def readVCD (file): def readVCD (file):
''' Parses VCD file. ''' Parses VCD file.
Args: Args:
file - path to a VCD file [pathlib.Path] file - path to a VCD file [pathlib.Path]
@ -67,12 +68,12 @@ def readVCD (file):
# tag, other than end # tag, other than end
if not line.startswith('$end'): if not line.startswith('$end'):
currtag = line.partition(' ')[0].lstrip('$').rstrip() currtag = line.partition(' ')[0].lstrip('$').rstrip()
vcd[currtag] = vcd.setdefault(currtag, '') + line.partition(' ')[2].rpartition('$')[0] vcd[currtag] = vcd.setdefault(currtag, '') + line.partition(' ')[2].rpartition('$')[0]
# line ends with end tag # line ends with end tag
if not vcd[currtag].endswith('\n'): if not vcd[currtag].endswith('\n'):
vcd[currtag] += '\n' vcd[currtag] += '\n'
if line.split()[-1]=='$end': if line.split()[-1]=='$end':
currtag = 'body' currtag = 'body'
vcd[currtag] = '' vcd[currtag] = ''
if 'var' not in vcd: if 'var' not in vcd:
@ -83,13 +84,39 @@ def readVCD (file):
return vcd return vcd
def parsetowavedrom (file, savetofile = False):
def reduce_clock_sequences (wave) :
''' Remove clock seqnces longer than 2 cycles
not accompanied by other signals changes
Parameters:
wave - dictionary 'signal'->['list of states'] [dict]
'''
for v in wave:
sig = wave[v] # analized signal
other = [wave[i] for i in wave if i!=v] # list of other signals
other = [''.join(s) for s in zip(*other)] # list of concatenated states
other = [len(s.replace('.','')) for s in other] # list of state changes count
sig = [s if o==0 else ' ' for s,o in zip(sig,other)] # keep only when no changes in other
sig = "".join(sig)
cuts = []
for m in re.finditer("(10){2,}",sig):
cuts.append( (m.start()+1, m.end()-1) ) # area to be reduced, leave 1..0
cuts.reverse()
for cut in cuts:
for v,w in wave.items(): # reduce cuts from all signals
wave[v] = w[ :cut[0]] + w[cut[1]: ]
return wave
def parsetowavedrom (file, savetofile = False, reduce_clock = False):
''' Reads and simplifies VCD waveform ''' Reads and simplifies VCD waveform
Generates wavedrom notation. Generates wavedrom notation.
Args: Args:
file - path to a VCD file [pathlib.Path] file - path to a VCD file [pathlib.Path]
''' '''
varsubst = {} # var substitution varsubst = {} # var substitution
reg = [] # list of signals reg = [] # list of signals
@ -117,21 +144,21 @@ def parsetowavedrom (file, savetofile = False):
# set initial states # set initial states
event.append(0) event.append(0)
#default #default
for v in reg+wire: for v in reg+wire:
wave[v] = ['x'] wave[v] = ['x']
#defined #defined
for line in vcd['dumpvars'].split('\n'): for line in vcd['dumpvars'].split('\n'):
if len(line)>=2: if len(line)>=2:
wave[ varsubst[line[1]] ] = [line[0]] wave[ varsubst[line[1]] ] = [line[0]]
# parse wave body # parse wave body
for line in vcd['body'].split('\n'): for line in vcd['body'].split('\n'):
#timestamp line #timestamp line
if line.startswith('#'): if line.startswith('#'):
line = line.strip().lstrip('#') line = line.strip().lstrip('#')
if not line.isnumeric(): if not line.isnumeric():
raise SyntaxError("Invalid VCD timestamp") raise SyntaxError("Invalid VCD timestamp")
event.append(int(line)) event.append(int(line))
for v in wave.keys(): for v in wave.keys():
wave[v].append('.') wave[v].append('.')
@ -139,11 +166,12 @@ def parsetowavedrom (file, savetofile = False):
else : else :
if len(line)>=2: if len(line)>=2:
wave [ varsubst[line[1]] ][-1] = line[0] wave [ varsubst[line[1]] ][-1] = line[0]
# TODO: add "double interval support" if reduce_clock:
wave = reduce_clock_sequences(wave)
signals = [] signals = []
for v in wave.keys(): for v in wave.keys():
fill = ' ' * (max( [len(s) for s in wave.keys()] ) - len(v)) fill = ' ' * (max( [len(s) for s in wave.keys()] ) - len(v))
wavestr = ''.join(wave[v]) wavestr = ''.join(wave[v])
signals.append( signal_template.format( name = v, wave = wavestr, fill = fill ) ) signals.append( signal_template.format( name = v, wave = wavestr, fill = fill ) )
@ -151,15 +179,18 @@ def parsetowavedrom (file, savetofile = False):
wavedrom = wavedrom_template.format ( signals = signals ) wavedrom = wavedrom_template.format ( signals = signals )
outfile = file.with_suffix(".wdr.json") if savetofile else None outfile = file.with_suffix(".wdr.json") if savetofile else None
with file_or_stdout(outfile) as f: with file_or_stdout(outfile) as f:
f.write(wavedrom) f.write(wavedrom)
return wavedrom return wavedrom
def quoted_strings_wavedrom (wdr) : def quoted_strings_wavedrom (wdr) :
''' Convert wavedrom script to more restrictive ''' Convert wavedrom script to more restrictive
version of JSON with quoted keywords version of JSON with quoted keywords
Parameters:
wdr - wavedrom script [str]
''' '''
wdr = wdr.replace(' signal:',' "signal":') wdr = wdr.replace(' signal:',' "signal":')
wdr = wdr.replace(' name:',' "name":') wdr = wdr.replace(' name:',' "name":')
@ -190,6 +221,11 @@ def main():
"--savesvg", "--savesvg",
help="generate .svg image", help="generate .svg image",
action="store_true") action="store_true")
parser.add_argument(
"-r",
"--reduceclk",
help="reduce clock sequences",
action="store_true")
parser.add_argument( parser.add_argument(
"infile", "infile",
help="VCD waveform file", help="VCD waveform file",
@ -209,10 +245,10 @@ def main():
errors = 0 errors = 0
for f in infile: for f in infile:
try: try:
wdr = parsetowavedrom(f, args.wavedrom) wdr = parsetowavedrom(f, args.wavedrom, args.reduceclk)
if args.savesvg: if args.savesvg:
svg = wavedrom.render( quoted_strings_wavedrom(wdr) ) svg = wavedrom.render( quoted_strings_wavedrom(wdr) )
outfile = f.with_suffix(".svg") outfile = f.with_suffix(".svg")
svg.saveas(outfile) svg.saveas(outfile)
except KeyboardInterrupt: except KeyboardInterrupt:
sys.exit(1) sys.exit(1)