From f1f963ce9afcd478835136fffd3b00f24e4484ac Mon Sep 17 00:00:00 2001 From: Yihua Liu Date: Sun, 4 Sep 2022 13:06:16 +0800 Subject: [PATCH 1/5] feat: get wires prototype --- .vscode/launch.json | 20 +++++++++++ README.md | 6 ++++ example/example5.evcd | 67 +++++++++++++++++++++++++++++++++++++ sootty/__main__.py | 2 ++ sootty/storage/wiregroup.py | 14 ++++++-- sootty/storage/wiretrace.py | 9 +++++ 6 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 example/example5.evcd diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7ef02d1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Module", + "type": "python", + "request": "launch", + "module": "sootty", + "justMyCode": true, + "args": [ + "\"example/example5.evcd\"", + // "-b", + // "\"time 10 || time 11 || before time 18 && after time 14\"" + ] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index e6bc72b..5211f05 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,12 @@ Reloading a saved query: sootty -R "save.txt" ``` +Add breakpoints at time 9, 11, and 17 - 18: + +```bash +sootty "example/example1.vcd" -b "time 9 || time 11 || after time 16 && before time 18" +``` + 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 375c231..77d0b98 100644 --- a/sootty/__main__.py +++ b/sootty/__main__.py @@ -161,6 +161,8 @@ def main(): if not output: image.display() # Show image in terminal (works in kitty, iterm) + if breakpoints is not None: + wiretrace.print(breakpoints) else: print(image.source) diff --git a/sootty/storage/wiregroup.py b/sootty/storage/wiregroup.py index e44d33b..e21fdbe 100644 --- a/sootty/storage/wiregroup.py +++ b/sootty/storage/wiregroup.py @@ -40,9 +40,17 @@ def find(self, name: str): def get_names(self): """Returns list of all wire names.""" - names = set() + names = dict() + names[self.name] = list() for wire in self.wires: - names.add(wire.name) + names[self.name].append(wire.name) for group in self.groups: - names.update(group.get_names()) + names[group.name] = group.get_names() return names + + def get_wires(self): + wires = dict() + wires[self.name] = self.wires + for group in self.groups: + wires[group.name] = group.get_wires() + return wires diff --git a/sootty/storage/wiretrace.py b/sootty/storage/wiretrace.py index aec65d3..5957990 100644 --- a/sootty/storage/wiretrace.py +++ b/sootty/storage/wiretrace.py @@ -265,3 +265,12 @@ 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(self, breakpoints: list): + """ + Print a table of wires and their values. + """ + wires = self.root.get_wires() + col_widths = [len(str(max(wires.keys())))] + for i in range(len(wires)): + col_widths.append(max(wires)) From 10cc2e43f2f066f1f56b594a470133a7759aa34a Mon Sep 17 00:00:00 2001 From: Yihua Liu Date: Mon, 5 Sep 2022 23:30:23 +0800 Subject: [PATCH 2/5] feat: --btable print breakpoints table --- .vscode/launch.json | 20 -------------------- README.md | 4 ++-- sootty/__main__.py | 25 +++++++++++++++++-------- sootty/storage/valuechange.py | 1 - sootty/storage/wire.py | 1 - sootty/storage/wiregroup.py | 32 ++++++++++++++++++++------------ sootty/storage/wiretrace.py | 23 +++++++++++++++++------ sootty/utils.py | 8 ++++---- sootty/visualizer.py | 2 +- 9 files changed, 61 insertions(+), 55 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7ef02d1..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Module", - "type": "python", - "request": "launch", - "module": "sootty", - "justMyCode": true, - "args": [ - "\"example/example5.evcd\"", - // "-b", - // "\"time 10 || time 11 || before time 18 && after time 14\"" - ] - } - ] -} \ No newline at end of file diff --git a/README.md b/README.md index eff1c1a..b837522 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ Reloading a saved query: sootty -R "save.txt" ``` -Add breakpoints at time 9, 11, and 17 - 18: +Add breakpoints at time 9, 11, and 16 - 17 and print wire values at breakpoints: ```bash -sootty "example/example1.vcd" -b "time 9 || time 11 || after time 16 && before time 18" +sootty "example/example5.evcd" -b "time 9 || time 11 || after time 15 && before time 18" --btable ``` How to run in python (using the repl): diff --git a/sootty/__main__.py b/sootty/__main__.py index ea60309..2365e46 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", @@ -47,7 +46,17 @@ def parse_args(): 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", + required='-b' in sys.argv, + 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,12 +171,11 @@ def main(): if not output: image.display() # Show image in terminal (works in kitty, iterm) - if breakpoints is not None: - wiretrace.print(breakpoints) - 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 e21fdbe..c0f73fb 100644 --- a/sootty/storage/wiregroup.py +++ b/sootty/storage/wiregroup.py @@ -1,5 +1,3 @@ -import sys - from ..exceptions import * from .wire import Wire @@ -40,17 +38,27 @@ def find(self, name: str): def get_names(self): """Returns list of all wire names.""" - names = dict() - names[self.name] = list() - for wire in self.wires: - names[self.name].append(wire.name) - for group in self.groups: - names[group.name] = group.get_names() + if self.groups: + names = dict() + if self.wires: + names[self.name] = list() + for wire in self.wires: + names[self.name].append(wire.name) + for group in self.groups: + names[group.name] = group.get_names() + else: + names = list() + for wire in self.wires: + names.append(wire.name) return names def get_wires(self): - wires = dict() - wires[self.name] = self.wires - for group in self.groups: - wires[group.name] = group.get_wires() + 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 55a3469..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 * @@ -291,11 +291,22 @@ def compute_limits(self, start_expr: str, end_expr: str): end = ends[0] if len(ends) else self.length() return (start, end) - def print(self, breakpoints: list): + def print_breakpoints(self, breakpoints: list): """ Print a table of wires and their values. """ - wires = self.root.get_wires() - col_widths = [len(str(max(wires.keys())))] - for i in range(len(wires)): - col_widths.append(max(wires)) + 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 From f8ed06c87cb0ce3cefe1dd490ba2403eb3247d91 Mon Sep 17 00:00:00 2001 From: Yihua Liu Date: Mon, 5 Sep 2022 23:54:40 +0800 Subject: [PATCH 3/5] fix: python argparse required --btable --- README.md | 1 + sootty/__main__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b837522..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`). diff --git a/sootty/__main__.py b/sootty/__main__.py index 2365e46..2a6343e 100644 --- a/sootty/__main__.py +++ b/sootty/__main__.py @@ -40,6 +40,7 @@ def parse_args(): parser.add_argument( "-b", "--break", + required='--btable' in sys.argv, type=str, metavar="FORMULA", dest="breakpoints", @@ -48,7 +49,6 @@ def parse_args(): parser.add_argument( '--btable', action="store_true", - required='-b' in sys.argv, help="print a breakpoint table to stdout", ) parser.add_argument( From a5bbe537172da972495e6b39c097dd9ad0c1822c Mon Sep 17 00:00:00 2001 From: Yihua Liu Date: Wed, 7 Sep 2022 23:24:03 +0800 Subject: [PATCH 4/5] doc: add docstring for get_wires --- sootty/storage/wiregroup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sootty/storage/wiregroup.py b/sootty/storage/wiregroup.py index c0f73fb..162f890 100644 --- a/sootty/storage/wiregroup.py +++ b/sootty/storage/wiregroup.py @@ -37,7 +37,7 @@ def find(self, name: str): raise SoottyError(f"Wire '{name}' does not exist.") def get_names(self): - """Returns list of all wire names.""" + """Returns a dictionary of all wire names of this wiregroup or a list if this wiregroup is the innermost one.""" if self.groups: names = dict() if self.wires: @@ -53,6 +53,7 @@ def get_names(self): 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: From 200fa982270d24c891b822c1a37237cf9a57b4b1 Mon Sep 17 00:00:00 2001 From: Yihua Liu Date: Sun, 11 Sep 2022 21:29:54 +0800 Subject: [PATCH 5/5] remove the duplicate changes from PR #64 --- sootty/storage/wiregroup.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/sootty/storage/wiregroup.py b/sootty/storage/wiregroup.py index 162f890..a82b5f2 100644 --- a/sootty/storage/wiregroup.py +++ b/sootty/storage/wiregroup.py @@ -37,19 +37,12 @@ def find(self, name: str): raise SoottyError(f"Wire '{name}' does not exist.") def get_names(self): - """Returns a dictionary of all wire names of this wiregroup or a list if this wiregroup is the innermost one.""" - if self.groups: - names = dict() - if self.wires: - names[self.name] = list() - for wire in self.wires: - names[self.name].append(wire.name) - for group in self.groups: - names[group.name] = group.get_names() - else: - names = list() - for wire in self.wires: - names.append(wire.name) + """Returns list of all wire names.""" + names = set() + for wire in self.wires: + names.add(wire.name) + for group in self.groups: + names.update(group.get_names()) return names def get_wires(self):