diff --git a/README.md b/README.md index e37f21e..6482fa7 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ sootty "waveform.vcd" -o > image.svg with a Value Change Dump (VCD) or Extended VCD (EVCD) file to produce an svg waveform diagram. Optional arguments include: - `-b | --break FORMULA` Specify the formula for the points in time to be highlighted. +- `--btable` Print the wire value table at breakpoints to `stdout` (`-b` is required). - `-e | --end FORMULA` Specify the end of the window. - `-h | --help` Show the help message and exit. - `-l | --length N` Specify the number of ticks in the window (mutually exclusive with `-e`). @@ -57,6 +58,12 @@ Reloading a saved query: sootty -R "save.txt" ``` +Add breakpoints at time 9, 11, and 16 - 17 and print wire values at breakpoints: + +```bash +sootty "example/example5.evcd" -b "time 9 || time 11 || after time 15 && before time 18" --btable +``` + How to run in python (using the repl): ```python diff --git a/example/example5.evcd b/example/example5.evcd new file mode 100644 index 0000000..e669846 --- /dev/null +++ b/example/example5.evcd @@ -0,0 +1,67 @@ +$comment + File created using the following command: + vcd file opt3.evcd -dumpports +$end +$date + Sat Sep 3 13:11:39 2022 +$end +$version + dumpports ModelSim Version 10.2c +$end +$timescale + 1ps +$end + +$scope module testbench $end + +$scope module pe8 $end +$var port [7:0] <0 req $end +$var port 1 <1 en $end +$upscope $end + +$scope module pe4 $end +$var port [3:0] <2 req $end +$var port 1 <3 en $end +$upscope $end +$upscope $end +$enddefinitions $end +#0 +$dumpports +pU 0 6 <1 +pU 0 6 <3 +pDDDDDDDD 66666666 00000000 <0 +pDDDD 6666 0000 <2 +$end +#5 +pUDDDDDDD 06666666 60000000 <0 +pUDDD 0666 6000 <2 +#10 +pDDDUDDDD 66606666 00060000 <0 +pDUDD 6066 0600 <2 +#15 +pDDDDDUDD 66666066 00000600 <0 +pDDUD 6606 0060 <2 +#20 +pDDDDDDDU 66666660 00000006 <0 +pDDDU 6660 0006 <2 +#25 +pDUDUDUDU 60606060 06060606 <0 +pDUDU 6060 0606 <2 +#30 +pDUUDDUUD 60066006 06600660 <0 +pDUUD 6006 0660 <2 +#35 +pUUUDUUUD 00060006 66606660 <0 +pUUUD 0006 6660 <2 +#40 +pUUUUUUUU 00000000 66666666 <0 +pUUUU 0000 6666 <2 +#45 +pD 6 0 <3 +pD 6 0 <1 +#50 +pDUUDDUUD 60066006 06600660 <0 +pDUUD 6006 0660 <2 +$vcdclose +#55 +$end diff --git a/sootty/__main__.py b/sootty/__main__.py index 625864b..2a6343e 100644 --- a/sootty/__main__.py +++ b/sootty/__main__.py @@ -1,6 +1,5 @@ import argparse -import os -import yaml +import sys from sootty.exceptions import SoottyError from .save import save_query, reload_query from .storage import WireTrace @@ -17,7 +16,7 @@ def parse_args(): default=None, metavar="FILENAME", type=str, - help="input .vcd file (required unless -R flag is provided)", + help="input .vcd or .evcd file (required unless -R flag is provided)", ) parser.add_argument( "-s", @@ -41,13 +40,23 @@ def parse_args(): parser.add_argument( "-b", "--break", + required='--btable' in sys.argv, type=str, metavar="FORMULA", dest="breakpoints", help="formula for the points in time to be highlighted", ) parser.add_argument( - "-l", "--length", type=int, dest="length", help="number of cycles to display" + '--btable', + action="store_true", + help="print a breakpoint table to stdout", + ) + parser.add_argument( + "-l", + "--length", + type=int, + dest="length", + help="number of cycles to display", ) parser.add_argument( "-o", @@ -102,6 +111,7 @@ def parse_args(): args.filename, args.wires, args.breakpoints, + args.btable, args.length, args.start, args.end, @@ -111,7 +121,7 @@ def parse_args(): def main(): - filename, wires, breakpoints, length, start, end, output, radix = parse_args() + filename, wires, breakpoints, btable, length, start, end, output, radix = parse_args() if filename is None: raise SoottyError("Input file is required. See --help for more info.") @@ -161,10 +171,11 @@ def main(): if not output: image.display() # Show image in terminal (works in kitty, iterm) - else: print(image.source) + if btable: + wiretrace.print_breakpoints(breakpoints) if __name__ == "__main__": main() diff --git a/sootty/storage/valuechange.py b/sootty/storage/valuechange.py index 3166301..2130b53 100644 --- a/sootty/storage/valuechange.py +++ b/sootty/storage/valuechange.py @@ -1,4 +1,3 @@ -import sys from vcd.reader import * from itertools import islice from sortedcontainers import SortedDict, SortedList, SortedSet diff --git a/sootty/storage/wire.py b/sootty/storage/wire.py index 54f987d..864ee5d 100644 --- a/sootty/storage/wire.py +++ b/sootty/storage/wire.py @@ -1,4 +1,3 @@ -import sys from itertools import compress, chain from ..exceptions import * diff --git a/sootty/storage/wiregroup.py b/sootty/storage/wiregroup.py index e44d33b..a82b5f2 100644 --- a/sootty/storage/wiregroup.py +++ b/sootty/storage/wiregroup.py @@ -1,5 +1,3 @@ -import sys - from ..exceptions import * from .wire import Wire @@ -46,3 +44,15 @@ def get_names(self): for group in self.groups: names.update(group.get_names()) return names + + def get_wires(self): + """Returns a dictionary of all wires of this wiregroup or a list if this wiregroup is the innermost one.""" + if self.groups: + wires = dict() + if self.wires: + wires[self.name] = self.wires + for group in self.groups: + wires[group.name] = group.get_wires() + else: + wires = self.wires + return wires diff --git a/sootty/storage/wiretrace.py b/sootty/storage/wiretrace.py index feee377..5b52388 100644 --- a/sootty/storage/wiretrace.py +++ b/sootty/storage/wiretrace.py @@ -1,4 +1,4 @@ -import json, sys +import sys from vcd.reader import * from ..exceptions import * @@ -290,3 +290,23 @@ def compute_limits(self, start_expr: str, end_expr: str): ends = list(filter(lambda time: time > start, self.evaluate(end_expr))) end = ends[0] if len(ends) else self.length() return (start, end) + + def print_breakpoints(self, breakpoints: list): + """ + Print a table of wires and their values. + """ + def rec_print(wires): + for scope, sub in wires.items(): + if type(sub) is dict: + print("scope\t" + scope) + rec_print(sub) + else: # is list + print("scope\t" + scope) + for wire in sub: + print(wire.name, end="\t") + for breakpoint in breakpoints: + print(str(wire._data.get(breakpoint)), end="\t") + print() + + print("time", *breakpoints, sep="\t") + rec_print(self.root.get_wires()) diff --git a/sootty/utils.py b/sootty/utils.py index b2897b9..9c0715f 100644 --- a/sootty/utils.py +++ b/sootty/utils.py @@ -14,7 +14,7 @@ def dec2anybase(input, base, width): res += chr(rem + ord("0")) else: res += chr(rem - 10 + ord("A")) - input = int(input / base) + input = input // base return res[::-1].zfill(ceil(log(2**width - 1, base))) @@ -129,12 +129,12 @@ def evcd2vcd(stream): while True: # Basic formatter and syntax checker if tok == b'$comment' or tok == b'$date' or tok == b'$timescale' or tok == b'$version': - vcd.write(tok + b' ') + vcd.write(tok + b'\n ') body = next(tokit) while body != b'$end': - vcd.write(body + b' ') + vcd.write(b' ' + body) body = next(tokit) - vcd.write(b'$end\n') # body + \n + vcd.write(b'\n$end\n') # body + \n tok = next(tokit) elif tok == b'$enddefinitions': if next(tokit) != b'$end': diff --git a/sootty/visualizer.py b/sootty/visualizer.py index 502761b..6720719 100644 --- a/sootty/visualizer.py +++ b/sootty/visualizer.py @@ -1,4 +1,4 @@ -import sys, html +import html from enum import Enum from .display import VectorImage