├── tests ├── __init__.py ├── example0.vcd ├── multiscope.vcd ├── verilog2005-sample0.vcd ├── example0.json ├── verilog2005-sample1.vcd ├── all.py ├── jsonWriter_test.py ├── vcdParser_test.py ├── vcdWriter_test.py └── AxiRegTC_test_write.vcd ├── pyDigitalWaveTools ├── __init__.py ├── vcd │ ├── __init__.py │ ├── value_format.py │ ├── common.py │ ├── writer.py │ └── parser.py └── json │ ├── __init__.py │ ├── value_format.py │ └── writer.py ├── doc ├── requirements.doc.txt ├── .gitignore ├── build.py ├── index.rst └── conf.py ├── setup.cfg ├── MANIFEST.in ├── .coveragerc ├── .readthedocs.yml ├── .circleci └── config.yml ├── LICENSE ├── pyproject.toml ├── .gitignore └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyDigitalWaveTools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/requirements.doc.txt: -------------------------------------------------------------------------------- 1 | sphinx_bootstrap_theme -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | _build/ 3 | *.rst 4 | make.bat 5 | Makefile 6 | !index.rst 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description_file = README.md 3 | 4 | [options] 5 | zip_safe = True -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include pyDigitalWaveTools *.vcd 2 | include README.md 3 | include MANIFEST.in -------------------------------------------------------------------------------- /pyDigitalWaveTools/vcd/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A module for parsing and writing of Value Change Dump (VCD) files 3 | """ 4 | -------------------------------------------------------------------------------- /pyDigitalWaveTools/json/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A module for loading and producing of wave data in json format 3 | (json equivalent to vcd module) 4 | """ 5 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | 4 | source = 5 | pyDigitalWaveTools 6 | 7 | [report] 8 | exclude_lines = 9 | pragma: no cover 10 | def __repr__ 11 | raise AssertionError 12 | raise NotImplementedError 13 | if __name__ == .__main__.: 14 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | build: 3 | os: ubuntu-lts-latest 4 | tools: 5 | python: "3.12" 6 | apt_packages: 7 | - graphviz 8 | python: 9 | install: 10 | - requirements: doc/requirements.doc.txt 11 | sphinx: 12 | configuration: doc/conf.py 13 | 14 | -------------------------------------------------------------------------------- /doc/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | An equivalent of `sphinx-build -b html . build` 6 | Used for simple debugger execution for doc build. 7 | """ 8 | 9 | from sphinx.cmd.build import build_main 10 | build_main(["-b", "html", ".", "_build"]) 11 | -------------------------------------------------------------------------------- /tests/example0.vcd: -------------------------------------------------------------------------------- 1 | $date 2 | 2018-04-12 18:04:03.652880 3 | $end 4 | $timescale 1ps $end 5 | $scope module unit0 $end 6 | $var wire 1 ! sig0 $end 7 | $var wire 1 " sig1 $end 8 | $var wire 16 # vect0 $end 9 | $upscope $end 10 | $enddefinitions $end 11 | #0 12 | X! 13 | X" 14 | bXXXXXXXXXXXXXXXX # 15 | #1 16 | 0! 17 | #2 18 | 1" 19 | #3 20 | b0000000000001010 # 21 | #4 22 | b0000000000010100 # 23 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to pyDigitalWaveTools's documentation! 2 | ========================================== 3 | 4 | Readme File 5 | =========== 6 | 7 | This is a python library for operations with VCD and other digital wave files. 8 | 9 | .. toctree:: 10 | :maxdepth: 3 11 | :caption: Contents: 12 | 13 | pyDigitalWaveTools 14 | 15 | 16 | 17 | Indices and tables 18 | ================== 19 | 20 | * :ref:`genindex` 21 | * :ref:`modindex` 22 | * :ref:`search` 23 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | python: circleci/python@3.1.0 5 | py: nic30/python-all-in-1@0.3.1 6 | 7 | jobs: 8 | install-test-deploy: 9 | executor: 10 | name: python/default 11 | tag: '3.13.7' 12 | resource_class: small 13 | steps: 14 | - checkout 15 | # - python/load-cache 16 | - py/install-setup-py 17 | # - python/save-cache 18 | - py/test-and-coverage 19 | - py/deploy-pypi-on-tag 20 | 21 | workflows: 22 | main: 23 | jobs: 24 | - install-test-deploy: 25 | context: 26 | - pypi 27 | filters: 28 | tags: 29 | only: /.*/ -------------------------------------------------------------------------------- /tests/multiscope.vcd: -------------------------------------------------------------------------------- 1 | $date 2 | Tue Mar 16 16:28:35 2021 3 | $end 4 | $version 5 | Icarus Verilog 6 | $end 7 | $timescale 8 | 1s 9 | $end 10 | $scope module testbench $end 11 | $var reg 1 ! sel $end 12 | $upscope $end 13 | $scope module testbench $end 14 | $var reg 1 " a $end 15 | $upscope $end 16 | $scope module testbench $end 17 | $var reg 1 # b $end 18 | $upscope $end 19 | $scope module testbench $end 20 | $var wire 1 $ out $end 21 | $upscope $end 22 | $enddefinitions $end 23 | #0 24 | $dumpvars 25 | x$ 26 | x# 27 | x" 28 | x! 29 | $end 30 | #1 31 | 0$ 32 | 0# 33 | 0" 34 | 0! 35 | #2 36 | 1$ 37 | 1" 38 | #3 39 | 1# 40 | #4 41 | 0$ 42 | 0" 43 | #5 44 | 0# 45 | 1! 46 | #6 47 | 1" 48 | #7 49 | 1$ 50 | 1# 51 | #8 52 | 0" 53 | -------------------------------------------------------------------------------- /tests/verilog2005-sample0.vcd: -------------------------------------------------------------------------------- 1 | $date June 26, 1989 10:05:41 2 | $end 3 | $version VERILOG-SIMULATOR 1.0a 4 | $end 5 | $timescale 1 ns 6 | $end 7 | $scope module top $end 8 | $scope module m1 $end 9 | $var trireg 1 *@ net1 $end 10 | $var trireg 1 *# net2 $end 11 | $var trireg 1 *$ net3 $end 12 | $upscope $end 13 | $scope task t1 $end 14 | $var reg 32 (k accumulator[31:0] $end 15 | $var integer 32 {2 index $end 16 | $upscope $end 17 | $upscope $end 18 | $enddefinitions $end 19 | #500 20 | $dumpvars 21 | x*@ 22 | x*# 23 | x*$ 24 | bx (k 25 | bx {2 26 | $end 27 | #505 28 | 0*@ 29 | 1*# 30 | 1*$ 31 | b10zx1110x11100 (k 32 | b1111000101z01x {2 33 | #510 34 | 0*$ 35 | #520 36 | 1*$ 37 | #530 38 | 0*$ 39 | bz (k 40 | #535 41 | $dumpall 0*@ 1*# 0*$ 42 | bz (k 43 | b1111000101z01x {2 44 | $end 45 | #540 46 | 1*$ 47 | #1000 48 | $dumpoff 49 | x*@ 50 | x*# 51 | x*$ 52 | bx (k 53 | bx {2 54 | $end 55 | #2000 56 | $dumpon 57 | z*@ 58 | 1*# 59 | 0*$ 60 | b0 (k 61 | bx {2 62 | $end 63 | #2010 64 | 1*$ -------------------------------------------------------------------------------- /tests/example0.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "data": [ 5 | [ 6 | 0, 7 | "X" 8 | ], 9 | [ 10 | 1, 11 | "0" 12 | ] 13 | ], 14 | "name": "sig0", 15 | "type": { 16 | "name": "wire", 17 | "width": 1 18 | } 19 | }, 20 | { 21 | "data": [ 22 | [ 23 | 0, 24 | "X" 25 | ], 26 | [ 27 | 2, 28 | "1" 29 | ] 30 | ], 31 | "name": "sig1", 32 | "type": { 33 | "name": "wire", 34 | "width": 1 35 | } 36 | }, 37 | { 38 | "data": [ 39 | [ 40 | 0, 41 | "bXXXXXXXXXXXXXXXX" 42 | ], 43 | [ 44 | 3, 45 | "b0000000000001010" 46 | ], 47 | [ 48 | 4, 49 | "b0000000000010100" 50 | ] 51 | ], 52 | "name": "vect0", 53 | "type": { 54 | "name": "wire", 55 | "width": 16 56 | } 57 | } 58 | ], 59 | "name": "unit0", 60 | "type": { 61 | "name": "struct" 62 | } 63 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Nic30 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/verilog2005-sample1.vcd: -------------------------------------------------------------------------------- 1 | $date June 26, 1989 10:05:41 2 | $end 3 | $version VERILOG-SIMULATOR 1.0a 4 | $end 5 | $timescale 1 ns 6 | $end 7 | $scope module top 8 | $end 9 | $scope module m1 10 | $end 11 | $var trireg 1 *@ net1 12 | $end 13 | $var trireg 1 *# net2 14 | $end 15 | $var trireg 1 * 16 | $ net3 17 | $end 18 | $upscope 19 | $end 20 | $scope task t1 21 | $end 22 | $var reg 32 (k accumulator[31:0] 23 | $end 24 | $var integer 32 {2 index 25 | $end 26 | $upscope 27 | $end 28 | $upscope 29 | $end 30 | $enddefinitions 31 | $end 32 | $comment 33 | $dumpvars was executed at time '#500'. All initial values are dumped at this time. 34 | $end 35 | 36 | #500 37 | $dumpvars 38 | x*@ 39 | x*# 40 | x*$ 41 | bx (k 42 | bx {2 43 | $end 44 | #505 45 | 0*@ 46 | 1*# 47 | 1*$ 48 | b10zx1110x11100 (k 49 | b1111000101z01x {2 50 | #510 51 | 0*$ 52 | #520 53 | 1*$ 54 | #530 55 | 0*$ 56 | bz (k 57 | #535 58 | $dumpall 0*@ 1*# 0*$ 59 | 60 | bz (k 61 | b1111000101z01x {2 62 | $end 63 | #540 64 | 1*$ 65 | #1000 66 | $dumpoff 67 | x*@ 68 | x*# 69 | x*$ 70 | bx (k 71 | bx {2 72 | $end 73 | #2000 74 | $dumpon 75 | z*@ 76 | 1*# 77 | 0*$ 78 | b0 (k 79 | bx {2 80 | $end 81 | #2010 82 | 1*$ 83 | 84 | -------------------------------------------------------------------------------- /tests/all.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | from unittest import TestLoader, TextTestRunner, TestSuite 6 | from tests.jsonWriter_test import JsonWriterTC 7 | from tests.vcdParser_test import VcdParserTC 8 | from tests.vcdWriter_test import VcdWriterTC 9 | 10 | 11 | 12 | def testSuiteFromTCs(*tcs): 13 | loader = TestLoader() 14 | loadedTcs = [loader.loadTestsFromTestCase(tc) for tc in tcs] 15 | suite = TestSuite(loadedTcs) 16 | return suite 17 | 18 | 19 | suite = testSuiteFromTCs( 20 | JsonWriterTC, 21 | VcdParserTC, 22 | VcdWriterTC, 23 | ) 24 | 25 | 26 | if __name__ == '__main__': 27 | runner = TextTestRunner(verbosity=2) 28 | 29 | try: 30 | from concurrencytest import ConcurrentTestSuite, fork_for_tests 31 | useParallelTest = True 32 | except ImportError: 33 | # concurrencytest is not installed, use regular test runner 34 | useParallelTest = False 35 | 36 | if useParallelTest: 37 | # Run same tests across 4 processes 38 | concurrent_suite = ConcurrentTestSuite(suite, fork_for_tests()) 39 | runner.run(concurrent_suite) 40 | else: 41 | sys.exit(not runner.run(suite).wasSuccessful()) 42 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 77.0.3"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "pyDigitalWaveTools" 7 | version = "1.2" 8 | dependencies = [] 9 | requires-python = ">=3.8" 10 | authors = [ 11 | {name = "Michal Orsak", email = "Nic30original@gmail.com"}, 12 | ] 13 | 14 | description = "A library for operations with VCD and other digital wave files" 15 | readme = "README.md" 16 | license = "MIT" 17 | license-files = ["LICENSE"] 18 | keywords = [ 19 | 'parser', 'vcd-writter', 'vcd', 'value-change-dump', 'simulation'] 20 | classifiers = [ 21 | "Development Status :: 4 - Beta", 22 | "Intended Audience :: Developers", 23 | "Operating System :: OS Independent", 24 | "Programming Language :: Python :: 3", 25 | "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", 26 | "Topic :: System :: Hardware", 27 | "Topic :: System :: Emulators", 28 | "Topic :: Utilities", 29 | ] 30 | 31 | 32 | [project.urls] 33 | Homepage = "https://github.com/Nic30/pyDigitalWaveTools" 34 | Documentation = "https://pyDigitalWaveTools.readthedocs.io/en/latest/?badge=latest" 35 | Repository = "https://github.com/Nic30/pyDigitalWaveTools.git" 36 | "Bug Tracker" = "https://github.com/Nic30/pyDigitalWaveTools/issues" 37 | -------------------------------------------------------------------------------- /tests/jsonWriter_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | import os 6 | import unittest 7 | 8 | from pyDigitalWaveTools.json.value_format import JsonBitsFormatter 9 | from pyDigitalWaveTools.json.writer import JsonWriter 10 | from tests.vcdWriter_test import example_dump_values0 11 | 12 | 13 | BASE = os.path.dirname(os.path.realpath(__file__)) 14 | 15 | 16 | def value_tuples_to_lists(scope: dict): 17 | """ 18 | We need to convert all tuples to list because the tuple is serialized as list in json 19 | and after de-serialization the tuple objects will become lists 20 | """ 21 | data = scope.get("data", None) 22 | if data is not None: 23 | data = [list(d) for d in data] 24 | scope["data"] = data 25 | 26 | children = scope.get("children", None) 27 | if children is not None: 28 | for c in children: 29 | value_tuples_to_lists(c) 30 | return scope 31 | 32 | 33 | class JsonWriterTC(unittest.TestCase): 34 | 35 | def test_example0(self): 36 | 37 | res = {} 38 | w = JsonWriter(res) 39 | example_dump_values0(w, JsonBitsFormatter) 40 | 41 | # with open(os.path.join(BASE, "example0.json"), "w") as f: 42 | # json.dump(res, f, indent=2, sort_keys=True) 43 | 44 | res = value_tuples_to_lists(res) 45 | with open(os.path.join(BASE, "example0.json")) as f: 46 | ref = json.load(f) 47 | self.assertDictEqual(ref, res) 48 | 49 | 50 | if __name__ == "__main__": 51 | testLoader = unittest.TestLoader() 52 | # suite = unittest.TestSuite([JsonWriterTC("test_example0")]) 53 | suite = testLoader.loadTestsFromTestCase(JsonWriterTC) 54 | runner = unittest.TextTestRunner(verbosity=3) 55 | runner.run(suite) 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | doc/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # eclipse project 104 | .project 105 | .pydevproject 106 | .settings/ 107 | 108 | -------------------------------------------------------------------------------- /pyDigitalWaveTools/vcd/value_format.py: -------------------------------------------------------------------------------- 1 | from io import StringIO 2 | from typing import Optional 3 | 4 | 5 | def bitVectorToStr(val: int, width: int, vld_mask: int, prefix: Optional[str], suffix: Optional[str]): 6 | buff = [] 7 | if prefix is not None: 8 | buff.append(prefix) 9 | 10 | for i in range(width - 1, -1, -1): 11 | mask = (1 << i) 12 | b = val & mask 13 | 14 | if vld_mask & mask: 15 | s = "1" if b else "0" 16 | else: 17 | s = "X" 18 | buff.append(s) 19 | 20 | if suffix is not None: 21 | buff.append(suffix) 22 | 23 | return ''.join(buff) 24 | 25 | 26 | def bitToStr(val: int, vld_mask: int): 27 | if vld_mask: 28 | return "1" if val else "0" 29 | else: 30 | return "X" 31 | 32 | 33 | class LogValueFormatter(): 34 | 35 | def bind_var_info(self, varInfo: "VcdVarWritingInfo"): 36 | pass 37 | 38 | def format(self, newVal: "Value", updater, t: int, out: StringIO): 39 | pass 40 | 41 | 42 | class VcdEnumFormatter(LogValueFormatter): 43 | 44 | def bind_var_info(self, varInfo: "VcdVarWritingInfo"): 45 | self.vcdId = varInfo.vcdId 46 | 47 | def format(self, newVal: "Value", updater, t: int, out: StringIO): 48 | if newVal.vld_mask: 49 | val = newVal.val 50 | else: 51 | val = "UNDEF" 52 | 53 | out.write(f"s{val:s} {self.vcdId:s}\n") 54 | 55 | 56 | class VcdBitsFormatter(LogValueFormatter): 57 | 58 | def bind_var_info(self, varInfo: "VcdVarWritingInfo"): 59 | self.width = varInfo.width 60 | self.vcdId = varInfo.vcdId 61 | if self.width == 1: 62 | self.format = self._format_bit 63 | self.suffix = f"{self.vcdId:s}\n" 64 | else: 65 | self.format = self._format_bits 66 | self.suffix = f" {self.vcdId:s}\n" 67 | 68 | def _format_bit(self, newVal: "Value", updater, t: int, out: StringIO): 69 | v = bitToStr(newVal.val, newVal.vld_mask) 70 | out.write(v + self.suffix) 71 | 72 | def _format_bits(self, newVal: "Value", updater, t: int, out: StringIO): 73 | out.write(bitVectorToStr(newVal.val, self.width, newVal.vld_mask, "b", self.suffix)) 74 | 75 | def format(self, newVal: "Value", updater): 76 | raise AssertionError("Should have been replaced in bind_var_info") 77 | 78 | -------------------------------------------------------------------------------- /pyDigitalWaveTools/vcd/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from typing import Union 4 | 5 | 6 | class VCD_SIG_TYPE(): 7 | WIRE = "wire" 8 | REAL = "real" 9 | # not part of vcd 10 | ENUM = "enum" 11 | ARRAY = "array" 12 | 13 | 14 | class VcdVarInfo(): 15 | """ 16 | Common part of VcdParsingVarInfo and VcdVarWritingInfo 17 | Container of informations about variable in VCD 18 | 19 | :ivar ~.vcdId: id in VCD file or the first VcdVarInfo which uses the same id (in this case this var is just reference to it) 20 | :ivar ~.name: name in VCD file 21 | :ivar ~.width: width in VCD file (int) 22 | :ivar ~.sigType: VCD var type name (from VCD_SIG_TYPE) 23 | :ivar ~.parent: parent VcdSignalScope object 24 | """ 25 | 26 | def __init__(self, vcdId: Union[str, 'VcdVarInfo'], name: str, width, sigType, parent): 27 | self.vcdId = vcdId 28 | self.name = name 29 | self.width = width 30 | self.sigType = sigType 31 | self.parent = parent 32 | 33 | def __repr__(self): 34 | return "<%s %s vcdId:%r>" % ( 35 | self.__class__.__name__, 36 | VcdVarScope._getDebugName(self), 37 | self.vcdId) 38 | 39 | 40 | class VcdVarScope(): 41 | """ 42 | VCD module - container for variables 43 | 44 | :ivar ~.name: name of this scope 45 | :ivar ~.parent: parent scope of this scope or None 46 | :ivar ~.children: dict {name: } 47 | """ 48 | 49 | def __init__(self, name, parent=None): 50 | self.name = name 51 | self.parent = parent 52 | self.children = {} 53 | 54 | def _getDebugName(self): 55 | buff = [] 56 | o = self 57 | while True: 58 | try: 59 | n = o.name 60 | except AttributeError: 61 | buff.append(repr(o)) 62 | break 63 | 64 | buff.append(n) 65 | o = o.parent 66 | if o is None: 67 | break 68 | return ".".join(reversed(buff)) 69 | 70 | def toJson(self): 71 | return { 72 | "name": self.name, 73 | "type": {"name": "struct"}, 74 | "children": [ch.toJson() for ch in self.children.values()] 75 | } 76 | 77 | def __repr__(self): 78 | return "<%s %s>" % (self.__class__.__name__, self._getDebugName()) 79 | -------------------------------------------------------------------------------- /pyDigitalWaveTools/json/value_format.py: -------------------------------------------------------------------------------- 1 | from copy import copy 2 | from typing import List, Tuple 3 | 4 | from pyDigitalWaveTools.vcd.value_format import bitToStr, bitVectorToStr, \ 5 | LogValueFormatter 6 | from pyDigitalWaveTools.vcd.writer import VcdVarWritingInfo 7 | 8 | 9 | class JsonArrayFormatter(LogValueFormatter): 10 | def __init__(self, dimmensions, elm_formatter): 11 | self.dimmensions = dimmensions 12 | self.elm_formatter = elm_formatter 13 | 14 | def bind_var_info(self, varInfo: VcdVarWritingInfo): 15 | vi = copy(varInfo) 16 | vi.width = vi.width[-1] 17 | self.elm_formatter.bind_var_info(vi) 18 | 19 | def format(self, newVal: "Value", updater, t: int, out: List[Tuple]): 20 | # updater can assign value of whole array, that is why it does not 21 | # need to have indexes 22 | indexes = getattr(updater, "indexes", None) 23 | if indexes: 24 | indexes = [int(i) for i in updater.indexes] 25 | for i in indexes: 26 | newVal = newVal[i] 27 | self.elm_formatter.format(newVal, updater, t, out) 28 | v = out.pop() 29 | v = (t, (indexes, v[1])) 30 | out.append(v) 31 | else: 32 | for i, v in enumerate(newVal): 33 | self.elm_formatter.format(v, updater, t, out) 34 | v = out.pop() 35 | v = (t, ([i,], v[1])) 36 | out.append(v) 37 | 38 | 39 | class JsonEnumFormatter(LogValueFormatter): 40 | 41 | def format(self, newVal: "Value", updater, t: int, out: List[Tuple]): 42 | if newVal.vld_mask: 43 | v = newVal.val 44 | else: 45 | v = "" 46 | out.append((t, v)) 47 | 48 | 49 | class JsonBitsFormatter(LogValueFormatter): 50 | 51 | def bind_var_info(self, varInfo: VcdVarWritingInfo): 52 | self.width = varInfo.width 53 | if self.width == 1: 54 | self.format = self._format_bit 55 | else: 56 | self.format = self._format_bits 57 | 58 | def _format_bit(self, newVal: "Value", updater, t: int, out: List[Tuple]): 59 | out.append((t, bitToStr(newVal.val, newVal.vld_mask))) 60 | 61 | def _format_bits(self, newVal: "Value", updater, t: int, out: List[Tuple]): 62 | out.append((t, bitVectorToStr(newVal.val, self.width, newVal.vld_mask, 'b', None))) 63 | 64 | def format(self, newVal: "Value", updater, t: int, out: List[Tuple]): 65 | raise Exception("Should have been replaced in bind_var_info") 66 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # This file only contains a selection of the most common options. For a full 2 | # list see the documentation: 3 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 4 | from datetime import datetime 5 | import glob 6 | import os 7 | from sphinx.ext.apidoc import main as apidoc_main 8 | import sys 9 | import sphinx_bootstrap_theme 10 | # -- Path setup -------------------------------------------------------------- 11 | 12 | # If extensions (or modules to document with autodoc) are in another directory, 13 | # add these directories to sys.path here. If the directory is relative to the 14 | # documentation root, use os.path.abspath to make it absolute, like shown here. 15 | # 16 | # sys.path.insert(0, os.path.abspath('.')) 17 | sys.path.insert(0, os.path.abspath('../')) 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = 'pyDigitalWaveTools' 22 | copyright = '2017-%d, Michal Orsak' % datetime.now().year 23 | author = 'Michal Orsak' 24 | 25 | 26 | # -- General configuration --------------------------------------------------- 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 30 | # ones. 31 | extensions = [ 32 | 'sphinx.ext.autodoc', 33 | ] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # List of patterns, relative to source directory, that match files and 39 | # directories to ignore when looking for source files. 40 | # This pattern also affects html_static_path and html_extra_path. 41 | exclude_patterns = [] 42 | 43 | 44 | # -- Options for HTML output ------------------------------------------------- 45 | 46 | # The theme to use for HTML and HTML Help pages. See the documentation for 47 | # a list of builtin themes. 48 | # 49 | html_theme = 'bootstrap' 50 | html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() 51 | 52 | 53 | # Add any paths that contain custom static files (such as style sheets) here, 54 | # relative to this directory. They are copied after the builtin static files, 55 | # so a file named "default.css" will overwrite the builtin "default.css". 56 | html_static_path = ['_static'] 57 | 58 | # update generated *.rst pages 59 | for file in glob.glob("*.rst"): 60 | if file != "index.rst": 61 | print("removing: ", file) 62 | os.remove(file) 63 | 64 | 65 | apidoc_main(["--module-first", "--full", "--maxdepth", "-1", 66 | "--output-dir", "../doc", "../pyDigitalWaveTools"]) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyDigitalWaveTools 2 | [![CircleCI](https://circleci.com/gh/Nic30/pyDigitalWaveTools.svg?style=svg)](https://circleci.com/gh/Nic30/pyDigitalWaveTools) 3 | [![Coverage Status](https://coveralls.io/repos/github/Nic30/pyDigitalWaveTools/badge.svg?branch=master)](https://coveralls.io/github/Nic30/pyDigitalWaveTools?branch=master) 4 | [![PyPI version](https://badge.fury.io/py/pyDigitalWaveTools.svg)](http://badge.fury.io/py/pyDigitalWaveTools) 5 | [![Documentation Status](https://readthedocs.org/projects/pydigitalwavetools/badge/?version=latest)](http://pydigitalwavetools.readthedocs.io/en/latest/?badge=latest) 6 | [![Python version](https://img.shields.io/pypi/pyversions/pyDigitalWaveTools.svg)](https://img.shields.io/pypi/pyversions/pyDigitalWaveTools.svg) 7 | 8 | Python library for operations with VCD and other digital wave files. The VCD spec is a part of verilog standard e.g. IEEE.1364-2005, IEEE.1800-2017 9 | 10 | ## Feature list 11 | * parse VCD (std 2009) files to intermediate format 12 | * write VCD files, user specified formatters for user types, predefined formatters for vectors, bits and enum values 13 | * dump intermediate format as simple json 14 | 15 | ## Hello pyDigitalWaveTools 16 | 17 | Here is a simple example how to use the VCD parser: 18 | 19 | ```python 20 | #!/usr/bin/env python3 21 | import json 22 | import sys 23 | from pyDigitalWaveTools.vcd.parser import VcdParser 24 | 25 | if len(sys.argv) > 1: 26 | fname = sys.argv[1] 27 | else: 28 | print('Give me a vcd file to parse') 29 | sys.exit(-1) 30 | 31 | with open(fname) as vcd_file: 32 | vcd = VcdParser() 33 | vcd.parse(vcd_file) 34 | data = vcd.scope.toJson() 35 | print(json.dumps(data, indent=4, sort_keys=True)) 36 | ``` 37 | 38 | 39 | ## Output json format 40 | ``` 41 | scope 42 | { "name": "" 43 | "children" : {"" : child} 44 | } 45 | 46 | child can be scope or signal record 47 | 48 | signal record 49 | { "name": "" 50 | "type": {"sigType": "", 51 | "width": }, 52 | "data": [], 53 | } 54 | 55 | data record format 56 | [