[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2.1\n\norbs:\n  python: circleci/python@3.1.0\n  py: nic30/python-all-in-1@0.3.1\n\njobs:\n  install-test-deploy:\n    executor:\n      name: python/default\n      tag: '3.13.7'\n    resource_class: small\n    steps:\n      - checkout\n      # - python/load-cache\n      - py/install-package-git:\n          cwd: ..\n          url: https://github.com/Nic30/hwtLib\n      - py/install-setup-py\n      # - python/save-cache\n      - py/test-and-coverage\n      - py/deploy-pypi-on-tag\n\nworkflows:\n  main:\n    jobs:\n      - install-test-deploy:\n          context:\n            - pypi\n          filters:\n            tags:\n              only: /.*/\n"
  },
  {
    "path": ".coveragerc",
    "content": "[run]\nbranch = True\n\nsource =\n    hwt\n\n[report]\nexclude_lines =\n    pragma: no cover\n    def __repr__\n    raise AssertionError\n    raise NotImplementedError\n    if __name__ == .__main__.:\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.dill\n*.class\n\n# python egg folders\nbuild/\ndist/\nhwt.egg-info/\n\n# eclipse project files\n.project\n.pydevproject\n.settings/\n\n#log files\n*.jou\n*.log\n\n"
  },
  {
    "path": ".readthedocs.yml",
    "content": "version: 2\nbuild:\n  os: ubuntu-lts-latest\n  tools:\n    python: \"3.12\"\n  apt_packages:\n    - graphviz\npython:\n  install:\n    - requirements: doc/requirements.doc.txt\nsphinx:\n  configuration: doc/conf.py\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Nic30\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include README.md\ninclude MANIFEST.in"
  },
  {
    "path": "README.md",
    "content": "# HWToolkit (hwt),\n# the library for hardware development in Python\n[![CircleCI](https://circleci.com/gh/Nic30/hwt.svg?style=svg)](https://circleci.com/gh/Nic30/hwt)\n[![Coverage Status](https://coveralls.io/repos/github/Nic30/hwt/badge.svg?branch=master)](https://coveralls.io/github/Nic30/hwt?branch=master)\n[![PyPI version](https://badge.fury.io/py/hwt.svg)](https://badge.fury.io/py/hwt)\n[![Documentation Status](https://readthedocs.org/projects/hwtoolkit/badge/?version=latest)](https://hwtoolkit.readthedocs.io/en/latest/?badge=latest)\n[![](https://img.shields.io/github/license/Nic30/hwt.svg)](https://github.com/Nic30/hwt)\n[![Python version](https://img.shields.io/pypi/pyversions/hwt.svg)](https://img.shields.io/pypi/pyversions/hwt.svg)\n[![Join the chat at https://gitter.im/hwt-community/community](https://badges.gitter.im/hwt-community/community.svg)](https://gitter.im/hwt-community/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\n## Keywords\n\n* Metaprogramming (Hardware Construction Language HCL, templatization) + HLS.\n* Simulator API, UVM\n* Buildtool, IP core generator\n\n## How HWT can help you?\n\n* The lower layer (IR, HDL serializers) is a shield against a problems related to VHDL/Verilog. It is checking for correctness and synthetisability and removing specific of HDLs.\n* The system level and HLS layer allows you to quickly build desing generators with advance optimisation techniques of your choice.\n* Simulator API and it's UVM simulation environment is just python object with C++ binding. This makes it easy to use while not sacrificing performance.\n* Rich type system can describe also data locality and packet features. This significantly simplifies configuration of component which are working with packets or any data over remote bus.\n* HWT is not compiler nor transpiler but it is actually a core library. It contains only necessary stuff and you can can modify/extend any part any time.\n  Because the word of HW developement is always full of unexpected situations.\n\n\n## Features\n\n* Hardware Construction Language (HCL) (example [simple](https://github.com/Nic30/hwtLib/blob/master/hwtLib/examples/simple.py), [showcase](https://github.com/Nic30/hwtLib/blob/master/hwtLib/examples/showcase0.py)). It is somewhere between HLS and HDL. It offers HLS style of coding but at the same time it allows you to manipulate HDL objects. This means it is a little bit slower to write a prototype than you would in HLS, but you always know what, how and why is happening.\n* Digital circuit simulator with UVM like verification environment (example usage [CAM](https://github.com/Nic30/hwtLib/blob/master/hwtLib/mem/cam_test.py), [structWriter_test.py](https://github.com/Nic30/hwtLib/blob/master/hwtLib/structManipulators/structWriter_test.py))\n* Tools for static analysis ([resourceAnalyzer](https://github.com/Nic30/hwt/blob/master/hwt/serializer/resourceAnalyzer/analyzer.py), example usage [cntr_test.py](https://github.com/Nic30/hwtLib/blob/master/hwtLib/examples/arithmetic/cntr_test.py))\n* Serializers to export HWT designs into multiple target HDLs ([verilog, VHDL, system-c, IP-core packager, hwt itself...](https://github.com/Nic30/hwt/tree/master/hwt/serializer))\n\nHWT uses hilevel-netlists for internal representation of target design. Optimized netlists are generated from usual code statements, function calls, statements etc (hw processes are automatically resolved). This netlist is easy to use and easy to modify or analyse by user if there is something missing in main library.\nAlso [serialization modes](https://github.com/Nic30/hwt/blob/master/hwt/serializer/mode.py) allows to tweaks how component should behave during serialization.\n\nHWT performs no HLS planing or schedueling. HWT is also good as API for code generating by more advanced tools. Hierarchy of components/interfaces/types is not limited. User specifed names are checked for collision with target language.\n\nHWT designs are objects. No specific compiler execution is required, just run `python3`, import the thing and use `to_rtl` metod or other (take a look at [examples](https://github.com/Nic30/hwtLib/blob/master/hwtLib/)).\n\n\n## HWT ecosystem\n\n![hwt_ecosystem_packages.png](doc/_static/hwt_ecosystem_packages.png)\n\n\n## Installation\n\nThis library is a regular python package. You can install it using:\n```\n# system-wide, use -u for local use only\nsudo pip3 install hwt\n\n# or directly from git\npip3 install --upgrade --force-reinstall --no-cache-dir -r https://raw.githubusercontent.com/Nic30/hwt/master/doc/requirements.txt git+https://github.com/Nic30/hwt.git@master#egg=hwt\n```\n\nThen you are able to use functions and classes defined in the hwt library from a python console or script.\nInstallation of [hwtLib](https://github.com/Nic30/hwtLib) is recomended as it contains common interfaces, agents, components etc...\n\n## FAQ\n\n* Where is the entry point of the compiler?\n  * This is not a compiler, it is library of the objects which can be converted to Verilog/VHDL and back.\n* How do I get Verilog/VHDL?\n  * Use `to_rtl` method [example](https://github.com/Nic30/hwtLib/blob/master/hwtLib/examples/simple.py)\n* How do I define my interface type, protocol and simulation agent?\n  * Derive from any Interface class. [example](https://github.com/Nic30/hwt/blob/master/hwt/interfaces/std.py#L107)\n* I do have c structure of UDP header, how do I send/receive UDP packet over AXI-stream interface?\n  * Define HStruct type composed of eth_header_t, IPv4_header_t and HStream(uint8_t) and use [AxisFrameGen](https://github.com/Nic30/hwtLib/blob/master/hwtLib/amba/axis_comp/frameGen.py). There is and example of [ping responder](https://github.com/Nic30/hwtLib/blob/master/hwtLib/examples/builders/pingResponder.py)\n\n\n## Similar projects\n\n* [autofpga](https://github.com/ZipCPU/autofpga) - C++, A utility for Composing FPGA designs from Peripherals\n* :skull: [baremetal](https://github.com/dawsonjon/baremetal) - Python, simple HCL\n* [BinPy](https://github.com/BinPy/BinPy) - Python, An electronic simulation library\n* :skull: [pervognsen/Bitwise](https://github.com/pervognsen/bitwise) - Python, HDL which translates python directly\n* :skull: [jamesjiang52/Bitwise](https://github.com/jamesjiang52/Bitwise) - Python, simple HCL.\n* [blarney](https://github.com/blarney-lang/blarney) - Haskell, HCL\n* [bsc](https://github.com/B-Lang-org/bsc) - Haskell, C++, BSV - Bluespec Compiler\n* [Cement HDL/CmtHDL](https://github.com/pku-liang/Cement) - Rust, eHDL\n* [chisel](https://chisel.eecs.berkeley.edu/) - 2012-?, Scala, HCL\n* [Chips-2.0](https://github.com/dawsonjon/Chips-2.0) - , , FPGA Design Suite based on C to Verilog design flow\n* [circt](https://github.com/llvm/circt) - 2020-?, C++/LLVM, compiler infrastructure\n* [circuitgraph](https://github.com/circuitgraph/circuitgraph) - Tools for working with circuits as graphs in python\n* [concat](https://github.com/conal/concat) - 2016-?, Haskell, Haskell to hardware\n* [DUH](https://github.com/sifive/duh) - JS, simple convertor between verilog/scala/ipxact\n* [DFiant](https://github.com/DFiantHDL/DFiant) 2019-?, Scala, dataflow based HDL\n* [edalize](https://github.com/olofk/edalize) - 2018-?, Python, abstraction layer for eda tools\n* [garnet](https://github.com/StanfordAHA/garnet) -2018-?, Python, Coarse-Grained Reconfigurable Architecture generator based on magma\n* [hammer](https://github.com/ucb-bar/hammer) - 2017-?, Python, Highly Agile Masks Made Effortlessly from RTL\n* [heterocl](https://github.com/cornell-zhang/heterocl) - 2017-?, C++, A Multi-Paradigm Programming Infrastructure for Software-Defined Reconfigurable Computing\n* [hoodlum](https://github.com/tcr/hoodlum) - 2016-?, Rust, HCL\n* [ILAng](https://github.com/Bo-Yuan-Huang/ILAng) - modeling and verification platform for SoCs where Instruction-Level Abstraction (ILA) is used as the formal model for hardware components.\n* :skull: [jhdl](https://github.com/larsjoost/jhdl) - ?-2017, C++ Verilog/VHDL -> systemC, prototype\n* [Kactus2](http://funbase.cs.tut.fi) - IP-core packager\n* [kratos](https://github.com/Kuree/kratos) - C++/Python, hardware generator/simulator\n* [lgraph](https://github.com/masc-ucsc/lgraph) - C, generic graph library\n* [llhd](https://github.com/fabianschuiki/llhd) - Rust, HCL\n* [livehd](https://github.com/masc-ucsc/livehd) - mainly C++, An infrastructure designed for Live Hardware Development.\n* [Lucid HDL in Alchitry-Labs](https://github.com/alchitry/Alchitry-Labs) - Custom language and IDE inspired by Verilog\n* [magma](https://github.com/phanrahan/magma/) - 2017-?, Python, HCL\n* [amaranth](https://github.com/amaranth-lang/amaranth)/[migen](https://github.com/m-labs/migen) - 2013-?, Python, HCL\n* [mockturtle](https://github.com/lsils/mockturtle) - logic network library\n* [moore](https://github.com/fabianschuiki/moore) - Rust, HDL -> model compiler\n* [msdsl](https://github.com/sgherbst/msdsl) - Python, real number model -> verilog\n* [MyHDL](https://github.com/myhdl/myhdl) - 2004-?, Python, Process based HDL\n* [Amaranth HDL](https://github.com/amaranth-lang/amaranth) -, Python, (previously nMigen) A refreshed Python toolbox for building complex digital hardware\n* [OpenTimer](https://github.com/OpenTimer/OpenTimer) - , C++,  A High-Performance Timing Analysis Tool for VLSI Systems\n* [percy](https://github.com/whaaswijk/percy) - Collection of different synthesizers and exact synthesis methods for use in applications such as circuit resynthesis and design exploration.\n* [PyChip-py-hcl](https://github.com/scutdig/PyChip-py-hcl) - , Python, Chisel3 like HCL\n* [pygears](https://github.com/bogdanvuk/pygears) - , Python, function style HDL generator\n* [PyMTL3](https://github.com/cornell-brg/pymtl3) 2018-?\n* [PyMTL](https://github.com/cornell-brg/pymtl) - 2014-?, Python, Process based HDL\n* [PipelineC](https://github.com/JulianKemmerer/PipelineC) - 2018-?, Python, C++ HLS-like automatic pipelining as a language construct/compiler\n* [PyRTL](https://github.com/UCSBarchlab/PyRTL) - 2015-?, Python, HCL\n* [Pyverilog](https://github.com/PyHDI/Pyverilog) - 2013-? Python-based Hardware Design Processing Toolkit for Verilog HDL\n* [rogue](https://github.com/slaclab/rogue) , C++/Python - Hardware Abstraction & Data Acquisition System\n* [rohd](https://github.com/intel/rohd), 2023-?, dart, HCL\n* [sail](https://github.com/rems-project/sail) 2018-?, (OCaml, Standard ML, Isabelle) - architecture definition language\n* :skull: [SFGen](https://github.com/dillonhuff/SFGen) - Python, arithmetic function generator\n* [spatial](https://github.com/stanford-ppl/spatial) - Scala, an Argon DSL like, high level abstraction\n* [SpinalHDL](https://github.com/SpinalHDL/SpinalHDL) - 2015-?, Scala, HCL\n* [Silice](https://github.com/sylefeb/Silice) - ?, C++, Custom HDL\n* :skull: [SyDpy](https://github.com/bogdanvuk/sydpy) - ?-2016, Python, HCL and verif. framework operating on TML/RTL level\n* [systemrdl-compiler](https://github.com/SystemRDL/systemrdl-compiler) - Python,c++, register description language compiler\n* [UHDM](https://github.com/alainmarcel/UHDM) - C++ SystemVerilog -> C++ model\n* :skull: [Verilog.jl](https://github.com/interplanetary-robot/Verilog.jl) - 2017-2017, Julia, simple Julia to Verilog transpiler\n* [veriloggen](https://github.com/PyHDI/veriloggen) - 2015-?, Python, Verilog centric HCL with HLS like features\n* :skull:  [wyre](https://github.com/nickmqb/wyre) - 2020-2020, Mupad, Minimalistic HDL\n* [phi](https://github.com/donn/Phi) - 2019-?, custom language, llvm based compiler of custom hdl\n* [prga](https://github.com/PrincetonUniversity/prga) - 2019-?. Python, prototyping platform with integrated yosys\n* [Hardcaml](https://github.com/janestreet/hardcaml) - OCaml, HCL\n* [magia-hdl](https://github.com/magia-hdl/magia) - 2023-?, Python, HCL\n* [Metron](https://github.com/aappleby/Metron) - C++, C++ -> SystemVerilog syntax translator\n* [librelane](https://github.com/librelane/librelane) - python, ASIC implementation flow infrastructure \n\n### Dictionary\n* IR - Internal Representation\n* HDL - Hardware Design Languge (Lang. construct maps directly to specific HW part)\n* eHDL - Embedded HDL (HDL construct avare source code generator)\n* HCL - Hardware Construction Language (User code constructs IR. IR can be directly transipled to HDL)\n* HLS - High Level Synthesis (User code is translated to IR. IR is compiled\n to HDL IR in multiple complex steps, typically contains scheduling, arch. mapping etc.)\n\n## Related open-source\n\n* [fusesoc](https://github.com/olofk/fusesoc) - package manager and a set of build tools for FPGA/ASIC development\n* [OpenSTA](https://github.com/abk-openroad/OpenSTA) - a gate level static timing verifier\n* [RePlAce](https://github.com/abk-openroad/RePlAce) - global placement tool\n* [verilator](https://www.veripool.org/wiki/verilator) - Verilog -> C/C++ simulator\n* [vtr-verilog-to-routing](https://github.com/verilog-to-routing/vtr-verilog-to-routing)\n* [yosys](https://github.com/YosysHQ/yosys) - RTL synthesis framework\n* [UHDM](https://github.com/alainmarcel/UHDM) - SV -> C++\n\n\n## Board support libraries (Potential candidates for public integration)\n\n* [litex](https://github.com/enjoy-digital/litex) - Buildsystem for migen\n* [loam](https://github.com/phanrahan/loam) - Buildsystem for magma\n* [vivado-boards](https://github.com/Digilent/vivado-boards) - Vivado XML/TCL files with board description\n* [nmigen-boards](https://github.com/nmigen/nmigen-boards) - board and connector meta fo nmigen\n\n\n## Sources of informations in this area\n\n* [computer-engineering-resources](https://github.com/rajesh-s/computer-engineering-resources) - list of conferences and hardware projects\n"
  },
  {
    "path": "doc/conf.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\nfrom datetime import datetime\nimport os\nimport re\nimport sys\n\nfrom sphinx.ext.apidoc import main as apidoc_main\nimport sphinx_bootstrap_theme\n\n\nsys.path.insert(0, os.path.abspath('../'))\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#\n# needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    'sphinx.ext.autodoc',\n    'sphinx.ext.todo',\n    'sphinx.ext.viewcode',\n    # 'sphinx.ext.napoleon',\n    'sphinx.ext.graphviz',\n    'sphinx.ext.intersphinx',\n]\n\nintersphinx_mapping = {\n    'ipCorePackager': (\"https://ipcorepackager.readthedocs.io/en/latest/\", None),\n}\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\n#\n# source_suffix = ['.rst', '.md']\nsource_suffix = '.rst'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = 'hwt'\ncopyright = '2017-%d, Michal Orsak' % datetime.now().year\nauthor = 'Michal Orsak'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = 'latest'\n# The full version, including alpha/beta/rc tags.\nrelease = ''\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = 'en'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This patterns also effect to html_static_path and html_extra_path\nexclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = True\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\n# html_theme = 'alabaster'\n\nhtml_theme = 'bootstrap'\nhtml_theme_path = sphinx_bootstrap_theme.get_html_theme_path()\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#\n# html_theme_options = {}\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# -- Options for HTMLHelp output ------------------------------------------\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'hwtdoc'\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    #\n    # 'papersize': 'letterpaper',\n\n    # The font size ('10pt', '11pt' or '12pt').\n    #\n    # 'pointsize': '10pt',\n\n    # Additional stuff for the LaTeX preamble.\n    #\n    # 'preamble': '',\n\n    # Latex figure (float) alignment\n    #\n    # 'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [\n    (master_doc, 'hwt.tex', 'HWToolkit generated documentation',\n     'Michal Orsak', 'manual'),\n]\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (master_doc, 'hwt', 'HWToolikt Documentation',\n     [author], 1)\n]\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (master_doc, 'hwt', 'HWToolikt Documentation',\n     author, 'hwt', 'Collection of tools for hardware generation.',\n     'Miscellaneous'),\n]\n\n# -- Options for Epub output ----------------------------------------------\n\n# Bibliographic Dublin Core info.\nepub_title = project\nepub_author = author\nepub_publisher = author\nepub_copyright = copyright\n\n# The unique identifier of the text. This can be a ISBN number\n# or the project homepage.\n#\n# epub_identifier = ''\n\n# A unique identification for the text.\n#\n# epub_uid = ''\n\n# A list of files that should not be packed into the epub file.\nepub_exclude_files = ['search.html']\n\nnotskipregex = re.compile(\"_[^_]+\")\n\n\ndef skip(app, what, name, obj, skip, options):\n    if name == \"__init__\" or notskipregex.match(name):\n        return False\n    return skip\n\n\ndef setup(app):\n    app.connect(\"autodoc-skip-member\", skip)\n\n\n# update *.rst pages\napidoc_main([\"--module-first\", \"--full\",\n             \"--output-dir\", \"../doc\", \"../hwt\"])\n"
  },
  {
    "path": "doc/gtkwave.rst",
    "content": "GTKWave useful tweaks\n======================\n\n.. code-block:: text\n\n    echo splash_disable 1 >> ~/.gtkwaverc"
  },
  {
    "path": "doc/hwtCircuitNormalForm.rst",
    "content": "HWT Circuit normal form (hwtCircuitNF)\n======================================\n\nHWT Circuit normal form (hwtCircuitNF) is a format of the netlist which is meant as a most simple and compact format of netlist\nfor circuit analysis. It is supposed to be human and programmatically readable.\n\nhwtCircuitNF is not dependent on HWT and it is rather a specification of the code-style in Verilog/VHDL.\nIt specifies how statements and signals should be used in order to reduce number of possible descriptions of the same thing.\n\nE.g. a multiplexer can be described using assignment with indexed/conditional expr. and also using switch/if statement\namong other possibilities.\nA typical synthesis tool converts all this to a gates and it performs the further code analysis there.\nHowever if we want to perform circuit analysis on statement level we have to check every possible syntax.\n\nBy performing code analysis and optimization in place on syntax level on normalized circuit we can gain these advantages:\n\n* No need for further conversions with nice object traceability.\n* All optimizations would be nearly human readable in every step.\n* There is probably less objects in the circuit which would also improve the performance of the compiler.\n\nHowever there are also downsides of this approach:\n\n* Object have a complex internal structure which could cancel out performance gains.\n* The properties of hwtCircuitNF have to be maintained during the updates which add another performance hits.\n* For an efficient implementation of analysis the object have to\n\n\nhwtCircuitNF rules\n------------------\n\n(A definition of common netlist in EDIF/VHDL/SystemVerilog)\nThe netlist described in hwtCircuitNF is a set of components, statements and signals connecting them.\nThe signal can not cross the boundary of the component, instead it has to be connected to IO of component to achieve this functionality.\nThe components can be nested, each component has only a single parent, same applies to statements.\nStatement can not have nested component.\n\n(A hwtCircuitNF addition)\nThe signal is driven from component IO or from statement. The signal endpoint is a component IO or statement which is using this\nsignal to drive something else. Each signal has to drive something and has to be driven by something.\n\nThis implies:\n\n* hwtCircuitNF does not contain unconnected statements/components.\n* Each signal is somehow connected to some output of the top.\n\nIn addition there are several additional rules about statement syntax and signal usage.\n\n\nMultiplexer coding style\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nRationale: To avoid expression analysis during detection of enclosures, muxes and latches.\n\nno\n.. code-block:: verilog\n\n    x <= y[(i + 1)*8 - 1: i*8];\n\nno\n.. code-block:: verilog\n\n    x <= i == 0 ? y[8-1:0] : y[16-1:8];\n\nyes\n.. code-block:: verilog\n\n   if (i == 0)\n       x <= y[ 8 - 1: 0]\n   else if (i == 1)\n       x <= y[16 - 1: 8]\n   // ...\n\nyes, prefered\n.. code-block:: verilog\n\n   case (i)\n     1'b0: x <= y[ 8-1:0];\n     1'b1: x <= y[16-1:8];\n\nNote that the instanciation of the MUX as a component is not a MUX description.\n\n\nConst indexed assignment vs assignment of concatenation\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRationale: Merge all drivers of signal in to a single statement.\n\n\nno\n.. code-block:: verilog\n\n    s[1] <= y;\n    s[0] <= x;\n\nyes - all assignment with a constant part specification converted to an assignment of concatenation of all parts\n.. code-block:: verilog\n\n    s <= {y, x};\n\nyes - there is only a single part and this is actually a cast\n.. code-block:: verilog\n\n   wire s[0:0];\n   s[0] <= y;\n\n\nConst indexed drives of disjunctive parts of same signal\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRationale: Split independent parts of signal if possible.\n\n\nno\n.. code-block:: verilog\n\n    if (c0)\n        s[0] <= x;\n    if (c1)\n        s[1] <= y;\n\n\nyes - all separately driven parts of signal extracted as a signal and the original signal is driven from its parts\n.. code-block:: verilog\n\n    wire s_0_tmp;\n    wire s_1_tmp;\n    assign s <= {s_1_tmp, s_0_tmp};\n    if (c0)\n        s_0_tmp <= x;\n    if (c1)\n        s_1_tmp <= y;\n\nyes - the part specifier is not a constant expression\n.. code-block:: verilog\n\n    if (c0)\n        s[i][0] <= x;\n    if (c1)\n        s[i][1] <= y;\n\n\n\nEnclosure filed\n^^^^^^^^^^^^^^^\n\nRationale: To be able to analyze any statement without the need for an information from its parent.\n\nno\n.. code-block:: verilog\n    s <= x0;\n    if (c0)\n        if (c1) begin\n            s <= x1;\n        end\n    else if (c2)\n        s <= x2;\n\n\nyes - enclosure filled\n.. code-block:: verilog\n    if (c0)\n        if (c1) begin\n            s <= x1;\n        end else begin\n            s <= x0;\n        end\n    else if (c2)\n        s <= x2;\n    else\n        s <= x0;\n\n\nAssignment to concatenation\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRationale: To have assignments with a single output and to be able to separate them from statements easily.\n\nno\n.. code-block:: verilog\n    {a, b} <= {c, d};\n\n\nyes - assignment only to single destination\n.. code-block:: verilog\n    a <= c;\n    b <= d;\n\n\nConcatenations always on top of expression tree\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRationale: We need to move indexing operators under the concatenations\n    in order to make structural hashing as efficient as possible. We need to do this also for other\n    bitwise operators and not just for index operators.\n\nno: The indexing is at the top of operator tree and the concatenation is at bottom.\n.. code-block:: verilog\n    wire[4-1:0] b;\n    wire c;\n    ~({a, b, c}[2-1:0])\n\nyes: The indexing is at the bottom of operator tree and concatenation is on top.\n.. code-block:: verilog\n    {~b[1-1:0], ~c}\n"
  },
  {
    "path": "doc/index.rst",
    "content": "Welcome to hwt (HWToolkit) generated documentation!\n===================================================\n\nThis documentation is automatically generated from actual source code.\n\nWhat is hwt (HWToolkit)\n-----------------------\n\n* Is a Hardware Construction Framework. It is similar to a HCLs like Chisel3 but it is rather set of object with a normal\n  behavior rather than a new language. The objects represents signals and other RTL components and can be serialized to Verilog/VHDL/SystemC/...\n  (That means the hwt is not transpiler or compiler and there is also no entry point.)\n\n* HWT internal representation is graph database of statements and signals.\n  Hwt type system is made of several elemental datatypes templates which can be used for a type of signal:\n\n  * HBits - represents bit vector\n\n  * HStruct - structure/record datatype\n\n  * HUnion - union datatype\n\n  * HArray - array datatype\n\n  * TransTmpl metatype - transactional template which describes how data can be partitioned to memores, buses, streams etc.\n  \tThink of it like a object which tells how to build frames from potentially sparse data structure in memory.\n\n  * The type itself drives it's hw representation, that means the typesystem is user extensible.\n\n* HWT is build as abstraction layer over all HDL languages to shield users from tricky features of such a languages.\n  However nothings is sacrificed and everything can be overridden.\n\n* HWT uses UVM like verification environment implemented in hwtSimApi. hwtSimApi can use verilator or python based simulator\n  to achieve high-speed simulation or nearly-zero simulator spin-up.\n\n* Most of parts of HWT ecosystem are independent and you can use them separately.\n\nOther useful libraries\n-----------------------\n\n.. image:: _static/hwt_ecosystem_packages.png\n\nWhere to start\n--------------\n\nTutorial is in hwtLib.examples.*, every file in this module contains user-entry-level comments.\nE.g. hwtLib.examples.simple.SimpleHwModule is a good starting point.\n\nComponent in HWT is a class which inherits from HwModule class.\nObject of such a class can be converted to a vhdl/Verilog by from hwt.synth.to_rtl function.\nThat said, this library is regular python library without any non-pyhon dependencies,\nit does not have any executable file.\n\nYou can also download this doc in `PDF\n<https://media.readthedocs.org/pdf/hwtoolkit/latest/hwtoolkit.pdf>`_.\n\n\n.. toctree::\n   :maxdepth: 4\n   :caption: Contents:\n\n   hwt\n\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`modindex`\n* :ref:`search`\n"
  },
  {
    "path": "doc/requirements.doc.txt",
    "content": "-r requirements.txt\nsphinx_bootstrap_theme"
  },
  {
    "path": "doc/requirements.txt",
    "content": "git+https://github.com/Nic30/pyMathBitPrecise.git@master#egg=pyMathBitPrecise\ngit+https://github.com/Nic30/pyDigitalWaveTools.git@master#egg=pyDigitalWaveTools\ngit+https://github.com/Nic30/hdlConvertorAst.git@master#egg=hdlConvertorAst\ngit+https://github.com/Nic30/ipCorePackager.git@master#egg=ipCorePackager\ngit+https://github.com/Nic30/hwtSimApi.git@master#egg=hwtSimApi\n"
  },
  {
    "path": "hwt/__init__.py",
    "content": ""
  },
  {
    "path": "hwt/code.py",
    "content": "from operator import and_, or_, xor, add, eq\nfrom types import GeneratorType\nfrom typing import Union, Sequence, Optional, Tuple\n\nfrom hdlConvertorAst.to.hdlUtils import iter_with_last\nfrom hwt.code_utils import _mkOp, _HwIOToRtlSignal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operatorDefs import concatFn\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.statement import HwtSyntaxError, HdlStatement\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import HwIOBase, HwModuleBase\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.math import log2ceil\nfrom hwt.pyUtils.arrayQuery import arr_any\nfrom hwt.synthesizer.rtlLevel.rtlSignalWalkers import \\\n    discoverEventDependency\n\n\nclass CodeBlock(HdlStmCodeBlockContainer):\n    \"\"\"\n    Container for list of statements\n    \"\"\"\n\n    def __init__(self, *statements: Sequence[HdlStatement]):\n        super(CodeBlock, self).__init__()\n        self._register_stements(statements, self.statements)\n        self.rank = sum(map(lambda s: s.rank, statements))\n\n        if self._outputs:\n            ctx = self._get_rtl_context()\n            ctx.statements.add(self)\n\n\nclass If(IfContainer):\n    \"\"\"\n    If statement generator\n    \"\"\"\n\n    def __init__(self, cond: Union[RtlSignalBase, HwIOBase], *statements: Sequence[HdlStatement]):\n        \"\"\"\n        :param cond: condition in if statement\n        :param statements: list of statements which should be active\n            if condition is met\n        \"\"\"\n        cond_sig = _HwIOToRtlSignal(cond)\n        if not isinstance(cond_sig, RtlSignalBase):\n            raise HwtSyntaxError(\"Condition is not signal, it is not certain\"\n                                 \" if this is an error or desire \", cond_sig)\n\n        assert cond_sig._dtype.bit_length() == 1, cond_sig\n        super(If, self).__init__(cond_sig)\n        self.rank = 1\n        self._inputs.append(cond_sig)\n        cond_sig._rtlEndpoints.append(self)\n\n        ev_dep = arr_any(discoverEventDependency(cond_sig), lambda x: True)\n        self._event_dependent_from_branch = 0 if ev_dep else None\n\n        self._register_stements(statements, self.ifTrue)\n        self._get_rtl_context().statements.add(self)\n\n    def Elif(self, cond: Union[RtlSignalBase, HwIOBase], *statements: Sequence[HdlStatement]):\n        assert self.parentStm is None\n        self.rank += 1\n        cond_sig = _HwIOToRtlSignal(cond)\n\n        assert cond_sig._dtype.bit_length() == 1, cond_sig\n        ev_dep = arr_any(discoverEventDependency(cond_sig), lambda x: True)\n        self._event_dependent_from_branch = len(self.elIfs) + 1 if ev_dep else None\n\n        self._inputs.append(cond_sig)\n        cond_sig._rtlEndpoints.append(self)\n\n        stms = ListOfHdlStatement()\n        self.elIfs.append((cond_sig, stms))\n        self._register_stements(statements, stms)\n\n        return self\n\n    def Else(self, *statements: Sequence[HdlStatement]):\n        assert self.parentStm is None\n        if self.ifFalse is not None:\n            raise HwtSyntaxError(\n                \"Else on this if-then-else statement was already used\")\n\n        self.rank += 1\n\n        self.ifFalse = ListOfHdlStatement()\n        self._register_stements(statements, self.ifFalse)\n        return self\n\n\nclass Switch(SwitchContainer):\n    \"\"\"\n    Switch statement generator\n    \"\"\"\n\n    def __init__(self, switchOn: Union[RtlSignalBase, HwIOBase]):\n        switchOn = _HwIOToRtlSignal(switchOn)\n        if not isinstance(switchOn, RtlSignalBase):\n            raise HwtSyntaxError(\"Select is not signal, it is not certain\"\n                                 \" if this is an error or desire\")\n        if arr_any(discoverEventDependency(switchOn), lambda x: True):\n            raise HwtSyntaxError(\"Can not switch on result of event operator\")\n\n        super(Switch, self).__init__(switchOn, [])\n        switchOn._rtlCtx.statements.add(self)\n        self._inputs.append(switchOn)\n        switchOn._rtlEndpoints.append(self)\n\n    def add_cases(self, tupesValStms: Sequence[Tuple[Union[HConst, int], Sequence[HdlStatement]]]):\n        \"\"\"\n        Add multiple case statements from iterable of tuples\n        (caseVal, statements)\n        \"\"\"\n        s = self\n        for val, statements in tupesValStms:\n            s = s.Case(val, statements)\n        return s\n\n    def Case(self, caseVal: Union[HConst, int], *statements: Sequence[HdlStatement]):\n        \"c-like case of switch statement\"\n        assert self.parentStm is None\n        caseVal = toHVal(caseVal, self.switchOn._dtype)\n\n        assert isinstance(caseVal, HConst), caseVal\n        assert caseVal._is_full_valid(), \"Cmp with invalid value\"\n        assert caseVal not in self._case_value_index, (\n            \"Switch statement already has case for value \", caseVal)\n\n        self.rank += 1\n        stms = ListOfHdlStatement()\n        self._case_value_index[caseVal] = len(self.cases)\n        self.cases.append((caseVal, stms))\n        self._register_stements(statements, stms)\n\n        return self\n\n    def Default(self, *statements: Sequence[HdlStatement]):\n        \"\"\"c-like default of switch statement\n        \"\"\"\n        assert self.parentStm is None\n        self.rank += 1\n        self.default = ListOfHdlStatement()\n        self._register_stements(statements, self.default)\n        return self\n\n\ndef SwitchLogic(cases: Sequence[Tuple[Union[RtlSignalBase, HwIOBase, HConst, bool], Sequence[HdlStatement]]],\n                default: Optional[Sequence[HdlStatement]]=None):\n    \"\"\"\n    Generate if tree for cases like (syntax sugar for large generated elifs)\n\n    ..code-block:: python\n        if cond0:\n            statements0\n        elif cond1:\n            statements1\n        else:\n            default\n\n    :param case: iterable of tuples (condition, statements)\n    :param default: default statements\n    \"\"\"\n    assigTop = None\n    hasElse = False\n    for last, (cond, statements) in iter_with_last(cases):\n        if isinstance(cond, (RtlSignalBase, HwIOBase)):\n            if assigTop is None:\n                assigTop = If(cond,\n                             statements\n                           )\n            else:\n                assigTop = assigTop.Elif(cond, statements)\n        else:\n            if cond:\n                if assigTop is None:\n                    assigTop = statements\n                else:\n                    assigTop.Else(statements)\n                    hasElse = True\n\n                if last or isinstance(cases, GeneratorType):\n                    # allow True as a condition for default\n                    break\n\n            raise HwtSyntaxError(\"Condition is not a signal, it is not certain\"\n                                 \" if this is an error or desire \", cond, cases)\n\n    if assigTop is None:\n        if default is None:\n            return []\n        else:\n            return default\n    else:\n        if hasElse:\n            return assigTop\n        elif default is not None:\n            assigTop = assigTop.Else(default)\n\n        return assigTop\n\n\ndef In(sigOrConst: Union[RtlSignalBase, HwIOBase, HConst], iterable: Sequence[Union[RtlSignalBase, HwIOBase, HConst]]):\n    \"\"\"\n    HDL convertible \"in\" operator, check if any of items\n    in \"iterable\" equals \"sigOrConst\"\n    \"\"\"\n    res = None\n    for i in iterable:\n        i = toHVal(i)\n        if res is None:\n            res = sigOrConst._eq(i)\n        else:\n            res = res | sigOrConst._eq(i)\n\n    assert res is not None, \"argument iterable is empty\"\n    return res\n\n\ndef StaticForEach(parentModule: HwModuleBase, items, bodyFn, name=\"\"):\n    \"\"\"\n    Generate for loop for static items\n\n    :param parentModule: HwModule where this code should be instantiated\n    :param items: items which this \"for\" iterating on\n    :param bodyFn: function which fn(item, index) or fn(item)\n        returns (statementList, ack).\n        It's content is performed in every iteration.\n        When ack is high loop will fall to next iteration\n    \"\"\"\n\n    items = list(items)\n    itemsCnt = len(items)\n    if itemsCnt == 0:\n        # if there are no items there is nothing to generate\n        return []\n    elif itemsCnt == 1:\n        # if there is only one item do not generate counter logic generate\n        return bodyFn(items[0], 0)\n    else:\n        # if there is multiple items we have to generate counter logic\n        index = parentModule._reg(name + \"for_index\",\n                                HBits(log2ceil(itemsCnt + 1), signed=False),\n                                def_val=0)\n        ackSig = parentModule._sig(name + \"for_ack\")\n\n        statementLists = []\n        for i, (statementList, ack) in [(i, bodyFn(item, i))\n                                        for i, item in enumerate(items)]:\n            statementLists.append(statementList + [(ackSig(ack)), ])\n\n        If(ackSig,\n           If(index._eq(itemsCnt - 1),\n              index(0)\n              ).Else(\n               index(index + 1)\n           )\n           )\n\n        return Switch(index)\\\n            .add_cases(\n            enumerate(statementLists)\n        ).Default(\n            bodyFn(items[0], 0)[0],\n            ackSig(True)\n        )\n\n\nclass FsmBuilder(Switch):\n    \"\"\"\n    A syntax sugar which automatically construct the state transition switch and state register\n\n    :ivar ~.stateReg: register with state\n    \"\"\"\n\n    def __init__(self, parentModule: HwModuleBase, stateT, stateRegName=\"st\"):\n        \"\"\"\n        :param parentModule: parent HwModule where FSM should be builded\n        :param stateT: enum type of state\n        :param stateRegName: name of register where sate is stored\n        \"\"\"\n        if isinstance(stateT, HEnum):\n            beginVal = stateT.from_py(stateT._allValues[0])\n        else:\n            beginVal = 0\n\n        self.stateReg = parentModule._reg(stateRegName, stateT, beginVal)\n        Switch.__init__(self, self.stateReg)\n\n    def Trans(self, stateFrom, *condAndNextState):\n        \"\"\"\n        :param stateFrom: apply when FSM is in this state\n        :param condAndNextState: tuples (condition, newState),\n            last does not to have condition\n\n        :attention: transitions has priority, first has the biggest\n        :attention: if stateFrom is None it is evaluated as default\n        \"\"\"\n        top = []\n        last = True\n\n        for cAndS in reversed(condAndNextState):\n            if last is True:\n                last = False\n                # if this is last trans. it does not have to condition\n                try:\n                    condition, newvalue = cAndS\n                except TypeError:\n                    top = self.stateReg(cAndS)\n                    continue\n                top = []\n\n            else:\n                condition, newvalue = cAndS\n\n            # building decision tree\n            top = \\\n                If(condition,\n                   self.stateReg(newvalue)\n                ).Else(\n                    top\n                )\n        if stateFrom is None:\n            return Switch.Default(self, top)\n        else:\n            return Switch.Case(self, stateFrom, top)\n\n    def Default(self, *condAndNextState):\n        d = self.Trans(None, *condAndNextState)\n        d.stateReg = self.stateReg\n        return d\n\n\n# variadic operator functions\nAnd = _mkOp(and_)\nAdd = _mkOp(add)\nOr = _mkOp(or_)\nXor = _mkOp(xor)  # :note: xor is bitwise !=\nXnor = _mkOp(eq)  # :note: xnor is bitwise ==\nConcat = _mkOp(concatFn)\n\n\ndef ror(sig:Union[RtlSignalBase, HConst], howMany: int) -> RtlSignalBase:\n    \"Rotate right\"\n    if sig._dtype.bit_length() == 1:\n        return sig\n\n    if isinstance(howMany, int):\n        return sig[howMany:]._concat(sig[:howMany])\n    elif isinstance(howMany, HConst):\n        return ror(sig, int(howMany))\n    else:\n        t = howMany._dtype\n        if not isinstance(t, HBits) or t.signed:\n            raise NotImplementedError(t)\n        res = sig\n        for i in range(1, t.domain_size() - 1):\n            res = howMany._eq(i)._ternary(ror(sig, i), res)\n        return  res\n\n\ndef rol(sig:Union[RtlSignalBase, HConst], howMany:Union[RtlSignalBase, int]) -> RtlSignalBase:\n    \"Rotate left\"\n    if isinstance(howMany, int):\n        width = sig._dtype.bit_length()\n        if width == 1:\n            return sig\n        return sig[(width - howMany):]._concat(sig[:(width - howMany)])\n    elif isinstance(howMany, HConst):\n        return rol(sig, int(howMany))\n    else:\n        t = howMany._dtype\n        if not isinstance(t, HBits) or t.signed:\n            raise NotImplementedError(t)\n        res = sig\n        for i in range(1, t.domain_size() - 1):\n            res = howMany._eq(i)._ternary(rol(sig, i), res)\n        return  res\n\n\ndef replicate(n:int, v:Union[RtlSignalBase, HConst]):\n    assert n > 0, n\n    return Concat(*(v for _ in range(n)))\n\n\ndef segment_get(n:Union[RtlSignalBase, HConst],\n                segmentWidth:int,\n                segmentIndex:Union[RtlSignalBase, HConst, int]):\n    \"\"\"\n    This function gets bits from bit vector as if it was an array of items of \"segmentWidth\" bits\n    \"\"\"\n    return n[segmentWidth * (segmentIndex + 1): segmentWidth * segmentIndex]\n\n\ndef split_to_segments(n:Union[RtlSignalBase, HConst], maxSegmentWidth:int, allowLastToBeSmaller=False, extendLast=False):\n    \"\"\"\n    Split bit vector to a segments of up to maxSegmentWidth bits, lower bits first.\n    \"\"\"\n    offset = 0\n    segments = []\n    width = n._dtype.bit_length()\n    if not allowLastToBeSmaller and not extendLast:\n        assert width % maxSegmentWidth == 0, (width, maxSegmentWidth)\n\n    while True:\n        end = min(offset + maxSegmentWidth, width)\n        segments.append(n[end:offset])\n        if end == width:\n            if extendLast and end != offset + maxSegmentWidth:\n                segments[-1] = segments[-1]._ext(maxSegmentWidth)\n            break\n        offset = end\n    return segments\n\n"
  },
  {
    "path": "hwt/code_utils.py",
    "content": "from typing import Union\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.defs import BIT\nfrom hwt.mainBases import HwIOBase\nfrom hwt.mainBases import RtlSignalBase\nfrom ipCorePackager.constants import DIRECTION\n\n\ndef rename_signal(hwModule: \"HwModule\",\n                  sig: Union[RtlSignalBase, int, bool],\n                  name: str):\n    \"\"\"\n    Wrap signal or value in signal of specified name\n\n    :attention: output signal is driven by new signal of a specified name\n        this means that the assigning to a new signal does not drive a original signal\n    \"\"\"\n\n    if isinstance(sig, (int, bool)):\n        t = BIT\n    else:\n        t = sig._dtype\n\n    if isinstance(sig, (HConst, int, bool)):\n        s = hwModule._sig(name, t, def_val=sig, nop_val=sig)\n    else:\n        s = hwModule._sig(name, t)\n        s(sig)\n\n    return s\n\n\ndef connect_optional(src: HwIOBase, dst: HwIOBase,\n                     check_fn=lambda hwIO0, hwIO1: (True, [])):\n    \"\"\"\n    Connect interfaces and ignore all missing things\n\n    :param check_fn: filter function(hwIO0, hwIO1) which check if interfaces should be connected\n        returns tuple (do_check, extra_connection_list)\n    \"\"\"\n    return list(_connect_optional(src, dst, check_fn, False))\n\n\n@internal\ndef _connect_optional(src: HwIOBase, dst: HwIOBase, check_fn, dir_reverse):\n    do_connect, extra_connections = check_fn(src, dst)\n    yield from extra_connections\n    if not do_connect:\n        return\n\n    if not src._hwIOs:\n        assert not dst._hwIOs, (src, dst)\n        if dir_reverse:\n            yield src(dst)\n        else:\n            yield dst(src)\n\n    for _s in src._hwIOs:\n        _d = getattr(dst, _s._name, None)\n        if _d is None:\n            # if the interfaces does not have subinterface of same name\n            continue\n\n        if _d._masterDir == DIRECTION.IN:\n            rev = not dir_reverse\n        else:\n            rev = dir_reverse\n\n        yield from _connect_optional(_s, _d, check_fn, rev)\n\n\n@internal\ndef _HwIOToRtlSignal(obj):\n    if isinstance(obj, HwIOBase):\n        return obj._sig\n    else:\n        return obj\n\n\n@internal\ndef _mkOp(fn):\n    \"\"\"\n    Function to create variadic operator function\n\n    :param fn: function to perform binary operation\n    \"\"\"\n\n    def op(*operands, key=None) -> RtlSignalBase:\n        \"\"\"\n        :param operands: variadic parameter of input uperands\n        :param key: optional function applied on every operand\n            before processing\n        \"\"\"\n        assert operands, operands\n        top = None\n        if key is not None:\n            operands = map(key, operands)\n\n        for s in operands:\n            if top is None:\n                top = s\n            else:\n                top = fn(top, s)\n        return top\n\n    return op\n\n"
  },
  {
    "path": "hwt/constants.py",
    "content": "\"\"\"\nCommonly used constants during HW development.\n\"\"\"\n\n# import constants from other packages to have them on one place\nfrom ipCorePackager.constants import INTF_DIRECTION, DIRECTION\nfrom hwtSimApi.constants import Time, CLK_PERIOD\n\nREAD = \"READ\"\nWRITE = \"WRITE\"\nREAD_WRITE = \"RW\"\nNOP = \"NOP\"\n\n\nclass NOT_SPECIFIED():\n    \"\"\"\n    Constant which means that the thing is not specified\n\n    Used for optional arguments as a value which marks that the value of this\n    argument was not specified on the place where we can not just use None\n    \"\"\"\n\n    def __init__(self):\n        raise AssertionError(\"Use only a class a constant\")\n"
  },
  {
    "path": "hwt/constraints.py",
    "content": "\"\"\"\nThis module contains the objects to store hardware constraints.\nHardware constrains are usually stored in XDC/UCF files and they specify somethings\nwhich can not be described using HDL (SystemVerilog/VHDL) like relation between clock.\nPlacement of component if FPGA etc.\n\"\"\"\n\nfrom copy import copy\nfrom typing import Union, Tuple\n\nfrom hwt.hwIO import HwIO\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwt.hwModule import HwModule\nfrom hwt.synthesizer.componentPath import ComponentPath\n\n\nclass iHdlConstrain():\n\n    def _get_parent(self) -> HwModule:\n        raise NotImplementedError(self)\n\n    def _copy_with_root_upadate(self, old_path_prefix, new_path_prefix):\n        raise NotImplementedError()\n\n    def register_on_parent(self):\n        self._get_parent()._constraints.append(self)\n\n\ndef _get_parent_HwModule(path: Tuple[Union[HwModule, HwIO, RtlSignal, iHdlConstrain], ...]) -> HwModule:\n    \"\"\"\n    Search parent :class:`hwt.hwModule.HwModule` instance in path\n    \"\"\"\n    if isinstance(path, iHdlConstrain):\n        return path._get_parent()\n\n    for o in reversed(path):\n        if isinstance(o, HwModule):\n            return o\n\n    raise AssertionError(\"No parent HwModule in path\", path)\n\n\ndef _get_absolute_path(obj) -> Union[Tuple[Union[HwModule, HwIO, RtlSignal, iHdlConstrain], ...], None]:\n    \"\"\"\n    Get tuple containing a path of objects from top to this object\n    \"\"\"\n    if obj is None:\n        return None\n    elif isinstance(obj, iHdlConstrain):\n        return obj\n\n    return ComponentPath(obj).resolve()\n\n\ndef _apply_path_update(path: ComponentPath, old_path_prefix: ComponentPath, new_path_prefix: ComponentPath):\n    \"\"\"\n    Update prefix of the path tuple\n    \"\"\"\n    if isinstance(path, iHdlConstrain):\n        return path._copy_with_root_upadate(old_path_prefix, new_path_prefix)\n    return path.update_prefix(old_path_prefix, new_path_prefix)\n\n\nclass set_max_delay(iHdlConstrain):\n    \"\"\"\n    Object which represents the max_delay constrain\n\n    * usually used to set propagation time between two clock domains etc.\n\n    :ivar ~.start: start of the signal path\n    :ivar ~.end: end of the signal path\n    :ivar ~.time_ns: max delay of the specified path in ns\n    \"\"\"\n\n    def __init__(self,\n                 start: Union[HwIO, RtlSignal],\n                 end: Union[HwIO, RtlSignal],\n                 time_ns: float,\n                 datapath_only=True,\n                 ommit_registration=False):\n        self.start = _get_absolute_path(start)\n        self.end = _get_absolute_path(end)\n        self.time_ns = time_ns\n        self.datapath_only = datapath_only\n        if not ommit_registration:\n            self.register_on_parent()\n\n    def _copy_with_root_upadate(self, old_path_prefix: ComponentPath, new_path_prefix: ComponentPath):\n        new_o = copy(self)\n        new_o.start = _apply_path_update(\n            self.start, old_path_prefix, new_path_prefix)\n        new_o.end = _apply_path_update(\n            self.end, old_path_prefix, new_path_prefix)\n        return new_o\n\n    def _get_parent(self) -> HwModule:\n        return _get_parent_HwModule(self.end)\n\n\nclass set_false_path(iHdlConstrain):\n\n    def __init__(self, start: Union[None, HwIO, RtlSignal],\n                 end: Union[None, HwIO, RtlSignal],\n                 ommit_registration=False):\n        self.start = _get_absolute_path(start)\n        self.end = _get_absolute_path(end)\n        if not ommit_registration:\n            self.register_on_parent()\n\n    def _copy_with_root_upadate(self, old_path_prefix: ComponentPath, new_path_prefix: ComponentPath):\n        return set_max_delay._copy_with_root_upadate(self, old_path_prefix, new_path_prefix)\n\n    def _get_parent(self) -> HwModule:\n        o = self.start\n        if o is None:\n            o = self.end\n        return _get_parent_HwModule(o)\n\n\nclass get_clock_of(iHdlConstrain):\n\n    def __init__(self, obj: Union[HwIO, RtlSignal],\n                 ommit_registration=False):\n        self.obj = _get_absolute_path(obj)\n\n    def _copy_with_root_upadate(self, old_path_prefix: ComponentPath, new_path_prefix: ComponentPath):\n        new_o = copy(self)\n        new_o.obj = _apply_path_update(\n            self.obj, old_path_prefix, new_path_prefix)\n        return new_o\n\n    def _get_parent(self) -> HwModule:\n        return _get_parent_HwModule(self.obj)\n\n\nclass set_async_reg(iHdlConstrain):\n    \"\"\"\n    Placement constrain which tell that the register should be put as close as possible to it's src/dst\n\n    It should not be placed on the FF on the src domain,\n    but should be set on FFs (possibly more) on the destination domain.\n    \"\"\"\n\n    def __init__(self, sig: RtlSignal,\n                 ommit_registration=False):\n        self.sig = _get_absolute_path(sig)\n        if not ommit_registration:\n            self.register_on_parent()\n\n    def _copy_with_root_upadate(self, old_path_prefix: ComponentPath, new_path_prefix: ComponentPath):\n        new_o = copy(self)\n        new_o.sig = _apply_path_update(\n            self.sig, old_path_prefix, new_path_prefix)\n        return new_o\n\n    def _get_parent(self) -> HwModule:\n        return _get_parent_HwModule(self.sig)\n\n"
  },
  {
    "path": "hwt/doc_markers.py",
    "content": "\n\ndef internal(fn):\n    \"\"\"\n    Decorator which does not affect functionality but it is used as marker\n    which tells that this object is not interesting for users and it is only used internally \n    \"\"\"\n    return fn\n\ndef hwt_expr_producer(fn):\n    \"\"\"\n    Decorator which does not affect functionality.\n    For documentation purposes it specifies that the function produces hwt expression.\n    \"\"\"\n    return fn"
  },
  {
    "path": "hwt/hObjList.py",
    "content": "from typing import TypeVar, Iterable, List, Union, Tuple, Optional, \\\n    Self\n\nfrom hwt.mainBases import HwIOBase, HwModuleBase\n\n\nT = TypeVar(\"T\", HwIOBase, HwModuleBase, None)\n\n\nclass HObjList(list[T]):\n    \"\"\"\n    Regular list with some interface/unit methods delegated on items.\n\n    Main purpose of this class it let :class:`hwt.synthesizer.PropDeclrCollector.PropDeclrCollector`\n    know that this is not an regular python array and that items should be registered as HW objects.\n\n    :ivar _name: name of the property on parent\n    :ivar _parent: parent HwModule/HwIO object\n    :note: this object may be nested in HObjList instances but the parent and name will always corresponds\n        to a HwModule/HwIO object, if there is any\n\n    :note: :class:`hwt.synthesizer.PropDeclrCollector.PropDeclrCollector` is used by\n        :class:`hwt.hwIO.Interface` and :class:`hwt.hwModule.HwModule`\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        hdlNameOverride = kwargs.pop(\"hdlName\", None)\n        list.__init__(self, *args, **kwargs)\n        self._name: Optional[str] = None\n        self._parent: Optional[Union[\"HwModule\", \"Interface\"]] = None\n        self._hdlNameOverride: Optional[str] = hdlNameOverride\n\n    def _on_append(self, self_obj: Self, item: T, index: int):\n        pass\n\n    def append(self, item: T):\n        if self._on_append is not HObjList._on_append:\n            self._on_append(self, item, len(self))\n        return list.append(self, item)\n\n    def clear(self, *args, **kwargs):\n        assert self._parent is None\n        return list.clear(self, *args, **kwargs)\n\n    def extend(self, iterable: Iterable[T]):\n        if self._on_append is not HObjList._on_append:\n            offset = len(self)\n            for i, item in enumerate(iterable):\n                self._on_append(self, item, offset + i)\n        return list.extend(self, iterable)\n\n    def insert(self, *args, **kwargs):\n        assert self._parent is None\n        return list.insert(self, *args, **kwargs)\n\n    def pop(self, *args, **kwargs) -> T:\n        assert self._parent is None\n        return list.pop(self, *args, **kwargs)\n\n    def remove(self, *args, **kwargs):\n        assert self._parent is None\n        return list.remove(self, *args, **kwargs)\n\n    def reverse(self, *args, **kwargs):\n        assert self._parent is None\n        return list.reverse(self, *args, **kwargs)\n\n    def sort(self, *args, **kwargs):\n        assert self._parent is None\n        return list.sort(self, *args, **kwargs)\n\n    def _getHdlName(self):\n        \"\"\"Get name in HDL \"\"\"\n\n        # list of name or tulple (name, separator)\n        name: List[Union[str, Tuple[str, str]]] = []\n        tmp = self\n        while isinstance(tmp, (HwIOBase, HObjList)):\n            n = tmp._name\n\n            if name:\n                name_sep = getattr(tmp, \"_NAME_SEPARATOR\", \"_\")\n                n = (n, name_sep)\n            else:\n                # no need to add separator at the end because this is a last part of the name\n                n = n\n\n            add_name_part_from_this = True\n            name_override = tmp._hdlNameOverride\n            if name_override is not None:\n                # recursively apply renames\n                if isinstance(name_override, str):\n                    if isinstance(n, tuple) and name_override:\n                        n = (name_override, n[1])\n                    else:\n                        n = name_override\n                elif isinstance(name_override, dict):\n                    last_name = name[-1]\n                    if isinstance(last_name, tuple):\n                        last_name = last_name[0]\n                    no = name_override.get(last_name, None)\n                    if no is not None:\n                        if isinstance(no, str):\n                            # everything what we resolved so far is overridden on this parent\n                            name = [no, ]\n                            add_name_part_from_this = False\n                        else:\n                            raise NotImplementedError()\n\n                else:\n                    raise TypeError(name_override)\n\n            if add_name_part_from_this:\n                name.append(n)\n            tmp = getattr(tmp, \"_parent\", None)\n\n        _name = []\n        for n in reversed(name):\n            if isinstance(n, str):\n                _name.append(n)\n            else:\n                _name.extend(n)\n\n        return \"\".join(_name)\n\n    def _getFullName(self) -> str:\n        \"\"\"get all name hierarchy separated by '.' \"\"\"\n        name = \"\"\n        tmp = self\n        while isinstance(tmp, (HwIOBase, HObjList)):\n            n = tmp._name\n            if name == '':\n                if n is not None:\n                    assert isinstance(n, str), (name, n)\n                    name = n\n            else:\n                if n is None:\n                    n = \"<unnamed>\"\n                name = f\"{n:s}.{name:s}\"\n\n            tmp = getattr(tmp, \"_parent\", None)\n\n        return name\n\n    def _make_association(self, *args, **kwargs):\n        \"\"\"\n        Delegate _make_association on items\n\n        :note: doc in :func:`~hwt.synthesizer.interfaceLevel.propDeclCollector._make_association`\n        \"\"\"\n        for o in self:\n            o._make_association(*args, **kwargs)\n        return self\n\n    def _updateHwParamsFrom(self, *args, **kwargs):\n        \"\"\"\n        :note: doc in :func:`~hwt.synthesizer.interfaceLevel.propDeclCollector._updateHwParamsFrom`\n        \"\"\"\n        for o in self:\n            if isinstance(o, (HwIOBase, HwModuleBase, HObjList)):\n                o._updateHwParamsFrom(*args, **kwargs)\n        return self\n\n    def _cleanRtlSignals(self, lockNonExternal=True):\n        for o in self:\n            if isinstance(o, (HwIOBase, HwModuleBase, HObjList)):\n                o._cleanRtlSignals(lockNonExternal=lockNonExternal)\n\n"
  },
  {
    "path": "hwt/hdl/__init__.py",
    "content": "\"\"\"\nThis package contains classes for representation of HDL\nlanguages (hdl types, RtlSignal, HdlAssignmentContainer, HdlStmCodeBlockContainer etc.).\n\nIt also contains classes for representation of complex HW structures\nlike dense transaction template (TransTmpl, FrameTmpl).\n\"\"\"\n# [TODO] derive from hdlConvertorAst.hdlAst"
  },
  {
    "path": "hwt/hdl/commonConstants.py",
    "content": "from hwt.hdl.types.defs import BIT\nb1 = BIT.from_py(1)\nb0 = BIT.from_py(0)\n"
  },
  {
    "path": "hwt/hdl/const.py",
    "content": "from typing import TypeVar, Generic, Self, Set\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.mainBases import RtlSignalBase\n\n\nT = TypeVar(\"T\", bound=\"HdlType\")\n\n\nclass HConst(Generic[T]):\n    \"\"\"\n    Wrap around hdl value with overloaded operators\n\n    operators are overloaded in every type separately\n    \"\"\"\n    __slots__ = [\"_dtype\", \"val\", \"vld_mask\"]\n\n    def __init__(self, dtype: \"HdlType\", val, vld_mask):\n        \"\"\"\n        :param val: pythonic value representing this value\n        :param dtype: data type object from which this value was derived from\n        :param vld_mask: validity mask for value\n        \"\"\"\n        self._dtype = dtype\n        self.val = val\n        self.vld_mask = vld_mask\n\n    def _is_full_valid(self):\n        return self.vld_mask == self._dtype.all_mask()\n\n    def _is_partially_valid(self) -> bool:\n        return self.vld_mask != 0\n\n    def _auto_cast(self, toType: \"HdlType\"):\n        \"\"\"\n        Cast value or signal of this type to another compatible type.\n\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        return self._dtype.auto_cast_HConst(self, toType)\n\n    def _reinterpret_cast(self, toType: \"HdlType\"):\n        \"\"\"\n        Cast value or signal of this type to another type of same size.\n\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        return self._dtype.reinterpret_cast_HConst(self, toType)\n\n    def staticEval(self) -> Self:\n        return self.__copy__()\n\n    def __copy__(self) -> Self:\n        return self.__class__(self._dtype, self.val, self.vld_mask)\n\n    @internal\n    def __hash__(self) -> int:\n        return hash((self._dtype, self.val, self.vld_mask))\n\n    def __repr__(self) -> str:\n        if self._is_full_valid():\n            vld_mask = \"\"\n        else:\n            vld_mask = \", mask {0:x}\".format(self.vld_mask)\n        return \"<{0:s} {1:s}{2:s}>\".format(\n            self.__class__.__name__, repr(self.val), vld_mask)\n\n    @classmethod\n    def _from_py(cls, typeObj, val, vld_mask) -> Self:\n        \"\"\"\n        from_py without value normalization and type checking\n        \"\"\"\n        return cls(typeObj, val, vld_mask)\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None) -> Self:\n        raise NotImplementedError(\n            f\"from_py fn is not implemented for\", cls)\n\n    def __eq__(self, other):\n        if isinstance(other, HConst):\n            return self._dtype == other._dtype and \\\n                self.vld_mask == other.vld_mask and\\\n                self.val == other.val\n        else:\n            return super().__eq__(other)\n\n    def _eq(self, other):\n        raise TypeError()\n\n    def __ne__(self, other):\n        eq = self._eq(other)\n        eq.val = not eq.val\n        return eq\n\n    def _walk_sensitivity(self, casualSensitivity: Set[RtlSignalBase], seen: Set[RtlSignalBase], ctx: SensitivityCtx):\n        \"\"\"\n        :see: :meth:`hwt.synthesizer.rtlLevel.rtlSignal.RtlSignal._walk_sensitivity`\n        \"\"\"\n        seen.add(self)\n\n\ndef areHConsts(*items):\n    \"\"\"\n    :return: True if all arguments are instances of HConst class else False\n    \"\"\"\n    for i in items:\n        if not isinstance(i, HConst):\n            return False\n    return True\n"
  },
  {
    "path": "hwt/hdl/constUtils.py",
    "content": "from typing import Union, List\n\nfrom hwt.hdl.const import HConst\n\n\ndef isSameHConst(a: HConst, b: HConst) -> bool:\n    \"\"\"\n    :return: True if two Value instances are same\n    :note: not just equal\n    \"\"\"\n    return a is b or (isinstance(a, HConst)\n                      and isinstance(b, HConst)\n                      and a.val == b.val\n                      and a.vld_mask == b.vld_mask)\n\n\ndef areSameHConsts(a: Union[None, List[HConst]],\n                 b: Union[None, List[HConst]]) -> bool:\n    \"\"\"\n    :return: True if two vectors of HConst/RtlSignal instances are same\n    :note: not just equal\n    \"\"\"\n    if a is b:\n        return True\n    if a is None or b is None:\n        return False\n    if len(a) == len(b):\n        for a_, b_ in zip(a, b):\n            if not isSameHConst(a_, b_):\n                return False\n        return True\n    else:\n        return False\n"
  },
  {
    "path": "hwt/hdl/frameTmpl.py",
    "content": "from itertools import zip_longest\nfrom math import ceil, floor, inf\nfrom typing import Union, Generator, List, Tuple\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.frameTmplUtils import TransTmplWordIterator, \\\n    ChoicesOfFrameParts\nfrom hwt.hdl.transPart import TransPart\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.pyUtils.arrayQuery import flatten\nfrom pyMathBitPrecise.bit_utils import mask, get_bit_range, set_bit_range\n\n\nclass FrameTmpl(object):\n    \"\"\"\n    Frame template is metainfomation about data structure, it's the template\n    of transaction for specific interface\n\n    Usuall flow of frame generatig consists of these steps:\n\n    1. Describe format of data by HDL type (HStruct, HUnion ...)\n\n    2. Convert it to TransTmpl to resolve addresses of each field in structure\n\n    3. Split parts of TransTmpl into words\n\n    4. Use parts in words to assembly frames\n\n    :ivar ~._fieldToTPart: dictionary {HStructField: TransPart} to resolve\n        this association, None by default, builded when packData\n        is called and is not builded\n    :note: others ivars described in __init__\n    \"\"\"\n\n    def __init__(self, origin: HdlType,\n                 wordWidth: int,\n                 startBitAddr: int,\n                 endBitAddr: int,\n                 transParts: List[TransPart]):\n        \"\"\"\n        :param origin: instance of HType (usually HStruct)\n            from which this FrameTmpl was generated from\n        :param wordWidth: width of word on interface\n            where this template should be used\n        :param startBitAddr: bit offset where this frame starts\n        :param endBitAddr: bit offset where this frame ends\n            (bit index of first bit behind this frame)\n        :param transParts: instances of TransPart which are parts of this frame\n        \"\"\"\n        self.origin = origin\n        self.wordWidth = wordWidth\n        assert startBitAddr <= endBitAddr\n        self.startBitAddr = startBitAddr\n        self.endBitAddr = endBitAddr\n        self.parts = transParts\n\n        self._fieldToTPart = None\n\n        for p in self.parts:\n            p.parent = self\n            assert p.startOfPart >= startBitAddr, (p, startBitAddr)\n            assert p.endOfPart <= endBitAddr, (p, endBitAddr)\n\n    @staticmethod\n    def framesFromTransTmpl(transaction: 'TransTmpl',\n                            wordWidth: int,\n                            maxFrameLen: Union[int, float]=inf,\n                            maxPaddingWords: Union[int, float]=inf,\n                            trimPaddingWordsOnStart: bool=False,\n                            trimPaddingWordsOnEnd: bool=False) -> Generator[\n                                'FrameTmpl', None, None]:\n        \"\"\"\n        Convert transaction template into FrameTmpls\n\n        :param transaction: transaction template used which are FrameTmpls\n            created from\n        :param wordWidth: width of data signal in target interface\n            where frames will be used\n        :param maxFrameLen: maximum length of frame in bits,\n            if exceeded another frame will be created\n        :param maxPaddingWords: maximum of continual padding words in frame,\n            if exceed frame is split and words are cut of\n        :attention: if maxPaddingWords<inf trimPaddingWordsOnEnd\n            or trimPaddingWordsOnStart has to be True\n            to decide where padding should be trimmed\n        :param trimPaddingWordsOnStart: trim padding from start of frame\n            at word granularity\n        :param trimPaddingWordsOnEnd: trim padding from end of frame\n            at word granularity\n        \"\"\"\n        isFirstInFrame = True\n        partsPending = False\n\n        startOfThisFrame = 0\n        assert maxFrameLen > 0\n        assert maxPaddingWords >= 0\n        if maxPaddingWords < inf:\n            assert trimPaddingWordsOnStart or trimPaddingWordsOnEnd, \\\n                \"Padding has to be cut off somewhere\"\n\n        it = TransTmplWordIterator(wordWidth)\n        lastWordI = 0\n        endOfThisFrame = maxFrameLen\n        parts = []\n        for wordI, word in it.groupByWordIndex(transaction, 0):\n            if wordI * wordWidth >= endOfThisFrame:\n                # now in first+ word behind the frame\n                # cut off padding at end of frame\n                paddingWords = wordI - lastWordI\n                if trimPaddingWordsOnEnd and paddingWords > maxPaddingWords:\n                    # cut off padding and align end of frame to word\n                    _endOfThisFrame = (lastWordI + 1) * wordWidth\n                else:\n                    _endOfThisFrame = wordI * wordWidth\n\n                yield FrameTmpl(transaction,\n                                wordWidth,\n                                startOfThisFrame,\n                                _endOfThisFrame,\n                                parts)\n\n                # prepare for start of new frame\n                parts = []\n                isFirstInFrame = True\n                partsPending = False\n                # start on new word\n                startOfThisFrame = _endOfThisFrame\n                endOfThisFrame = startOfThisFrame + maxFrameLen\n                lastWordI = wordI\n\n            # check if padding at potential end of frame can be cut off\n            if (not isFirstInFrame\n                    and trimPaddingWordsOnEnd\n                    and wordI - lastWordI > maxPaddingWords + 1):\n                # there is too much continual padding,\n                # cut it out and start new frame\n                _endOfThisFrame = (lastWordI + 1) * wordWidth\n                yield FrameTmpl(transaction,\n                                wordWidth,\n                                startOfThisFrame,\n                                _endOfThisFrame,\n                                parts)\n\n                # prepare for start of new frame\n                parts = []\n                isFirstInFrame = True\n                partsPending = False\n                # start on new word\n                lastWordI = wordI - 1\n                startOfThisFrame = lastWordI * wordWidth\n                endOfThisFrame = startOfThisFrame + maxFrameLen\n\n            if isFirstInFrame:\n                partsPending = True\n                isFirstInFrame = False\n                # cut off padding at start of frame\n                paddingWords = wordI - lastWordI\n                if trimPaddingWordsOnStart and paddingWords > maxPaddingWords:\n                    startOfThisFrame += paddingWords * wordWidth\n\n                endOfThisFrame = startOfThisFrame + maxFrameLen\n\n            # resolve end of this part\n            parts.extend(word)\n            lastWordI = wordI\n\n        # reminder in \"parts\" after last iteration\n        endOfThisFrame = transaction.bitAddrEnd\n        withPadding = not (trimPaddingWordsOnEnd or trimPaddingWordsOnStart)\n        if partsPending or (withPadding\n                            and endOfThisFrame != startOfThisFrame):\n            # cut off padding at end of frame\n            endOfLastWord = (lastWordI + 1) * wordWidth\n            if endOfThisFrame < endOfLastWord:\n                endOfThisFrame = endOfLastWord\n            else:\n                paddingWords = it.fullWordCnt(endOfLastWord, endOfThisFrame)\n                if trimPaddingWordsOnEnd and paddingWords > maxPaddingWords:\n                    endOfThisFrame -= paddingWords * wordWidth\n                    # align end of frame to word\n            endOfThisFrame = min(startOfThisFrame +\n                                 maxFrameLen, endOfThisFrame)\n\n            yield FrameTmpl(transaction,\n                            wordWidth,\n                            startOfThisFrame,\n                            endOfThisFrame,\n                            parts)\n            parts = []\n            startOfThisFrame = endOfThisFrame\n\n        # final padding on the end\n        while withPadding and startOfThisFrame < transaction.bitAddrEnd:\n            endOfThisFrame = min(startOfThisFrame +\n                                 maxFrameLen, transaction.bitAddrEnd)\n\n            yield FrameTmpl(transaction,\n                            wordWidth,\n                            startOfThisFrame,\n                            endOfThisFrame,\n                            [])\n\n            startOfThisFrame = endOfThisFrame\n\n    @internal\n    def _wordIndx(self, addr: int):\n        \"\"\"\n        convert bit address to index of word where this address is\n        \"\"\"\n        return floor(addr / self.wordWidth)\n\n    def getWordCnt(self):\n        \"\"\"\n        Get count of words in this frame\n        \"\"\"\n        return ceil((self.endBitAddr - self.startBitAddr) / self.wordWidth)\n\n    def walkWords(self, showPadding: bool=False)\\\n            -> Generator[Tuple[int, List[Union[TransPart, ChoicesOfFrameParts]]], None, None]:\n        \"\"\"\n        Walk enumerated words in this frame\n\n        :attention: not all indexes has to be present, only words\n            with items will be generated when not showPadding\n        :param showPadding: padding TransParts are also present\n        :return: generator of tuples (wordIndex, list of TransParts\n            in this word)\n        \"\"\"\n        wIndex = 0\n        lastEnd = self.startBitAddr\n        parts: List[TransPart] = []\n        for p in self.parts:\n            end = p.startOfPart\n            if showPadding and end != lastEnd:\n                # insert padding before data\n                while end != lastEnd:\n                    assert end >= lastEnd, (end, lastEnd)\n                    endOfWord = ceil(\n                        (lastEnd + 1) / self.wordWidth) * self.wordWidth\n                    endOfPadding = min(endOfWord, end)\n                    _p = TransPart(self, None, False, lastEnd, endOfPadding, 0)\n                    parts.append(_p)\n\n                    if endOfPadding >= endOfWord:\n                        yield (wIndex, parts)\n                        wIndex += 1\n                        parts = []\n\n                    lastEnd = endOfPadding\n\n            if self._wordIndx(lastEnd) != self._wordIndx(p.startOfPart):\n                # if input data continues to a next word, yield current word\n                # and start processing next one\n                yield (wIndex, parts)\n\n                wIndex += 1\n                parts = []\n                lastEnd = p.endOfPart\n\n            parts.append(p)\n            lastEnd = p.endOfPart\n            if lastEnd % self.wordWidth == 0:\n                # if we can not add anything to this word,\n                # yield it directly and continue on next word\n                yield (wIndex, parts)\n\n                wIndex += 1\n                parts = []\n\n        if showPadding and (parts\n                            or lastEnd != self.endBitAddr\n                            or lastEnd % self.wordWidth != 0):\n            # align end to end of last word\n            end = ceil(self.endBitAddr / self.wordWidth) * self.wordWidth\n            # padding is non removable if it is part of data\n            # and it is removable if it was generated by frame alignment\n            endOfNonRemovablePadding = self.origin.bitAddrEnd\n            while end != lastEnd:\n                assert end >= lastEnd, (end, lastEnd)\n                endOfWord = ((lastEnd // self.wordWidth) + 1) * self.wordWidth\n                endOfPadding = min(endOfWord, end)\n                if lastEnd < endOfNonRemovablePadding:\n                    endOfPadding = min(endOfPadding, endOfNonRemovablePadding)\n                    can_be_removed = False\n                else:\n                    can_be_removed = True\n                _p = TransPart(self, None, can_be_removed,\n                               lastEnd, endOfPadding, 0)\n                _p.parent = self\n                parts.append(_p)\n\n                if endOfPadding >= endOfWord:\n                    yield (wIndex, parts)\n                    wIndex += 1\n                    parts = []\n\n                lastEnd = endOfPadding\n\n        if parts:\n            # in the case end of frame is not aligned to end of word\n            yield (wIndex, parts)\n\n    @staticmethod\n    def fieldToDataDict(dtype, data, res):\n        return FrameTmpl._fieldToDataDict(dtype, (dtype,), data, res)\n\n    @staticmethod\n    def _fieldToDataDict(dtype, path, data, res):\n        \"\"\"\n        Construct dictionary {StructField:value} for faster lookup of values\n        for fields\n        \"\"\"\n        # assert data is None or isinstance(data, dict)\n        for f in dtype.fields:\n            try:\n                fVal = data[f.name]\n            except KeyError:\n                fVal = None\n\n            new_path = (*path, f)\n            if isinstance(f.dtype, HBits):\n                if fVal is not None:\n                    assert isinstance(fVal, int)\n                    res[new_path] = fVal\n            elif isinstance(f.dtype, HStruct):\n                if fVal:\n                    FrameTmpl._fieldToDataDict(f.dtype, new_path, fVal, res)\n            elif isinstance(f.dtype, HArray):\n                if fVal:\n                    # assert isinstance(fVal, class_or_tuple)\n                    res[new_path] = fVal\n\n        return res\n\n    def packData(self, data):\n        \"\"\"\n        Pack data into list of BitsVal of specified dataWidth\n\n        :param data: dict of values for struct fields {fieldName: value}\n\n        :return: list of BitsVal which are representing values of words\n        \"\"\"\n        typeOfWord = HBits(self.wordWidth, None)\n        fieldToVal = self._fieldToTPart\n        if fieldToVal is None:\n            fieldToVal = self._fieldToTPart = self.fieldToDataDict(\n                self.origin.dtype,\n                data,\n                {})\n\n        for _, transParts in self.walkWords(showPadding=True):\n            # build a single data word\n            actualVldMask = 0\n            actualVal = 0\n            for tPart in transParts:\n                high, low = tPart.getBusWordBitRange()\n                fhigh, flow = tPart.getFieldBitRange()\n                if not tPart.isPadding:\n                    val = fieldToVal.get(tPart.tmpl.origin, None)\n                else:\n                    val = None\n\n                if val is None:\n                    newBits = 0\n                    vld = 0\n                else:\n                    newBits = get_bit_range(val, flow, fhigh - flow)\n                    vld = mask(high - low)\n\n                actualVal = set_bit_range(actualVal, low, high - low, newBits)\n                actualVldMask = set_bit_range(actualVldMask, low, high - low, vld)\n\n            v = typeOfWord.getConstCls()(typeOfWord, actualVal,\n                                         actualVldMask)\n            yield v\n\n    @internal\n    def __repr__getName(self, transPart: TransPart, fieldWidth: int):\n        \"\"\"\n        Get name string for a field\n        \"\"\"\n        if transPart.isPadding:\n            return \"X\" * fieldWidth\n        else:\n            path = transPart.tmpl.getFieldPath()\n            names = []\n            for p in path:\n                if isinstance(p, int):\n                    names.append(f\"[{p:d}]\")\n                else:\n                    if names:\n                        names.append(f\".{p:s}\")\n                    else:\n                        names.append(p)\n\n            return \"\".join(names)\n\n    @internal\n    def __repr__word(self,\n                     index: int,\n                     width: int,\n                     padding: int,\n                     transParts: List[TransPart]):\n        buff = [f\"{index: <{padding}}|\", ]\n        DW = self.wordWidth\n        partsWithChoice = []\n\n        endAlignment = transParts[-1].endOfPart % DW\n        if endAlignment:\n            # -1 for ending |\n            percentOfWidth = (DW - endAlignment) / DW\n            # -1 for ending |\n            fieldWidth = max(0, int(percentOfWidth * width) - 1)\n            assert fieldWidth >= 0\n            s = '%s|' % (\"^\" * fieldWidth)\n            buff.append(s)\n\n        for tp in reversed(transParts):\n            percentOfWidth = tp.bit_length() / DW\n            # -1 for ending |\n            fieldWidth = max(0, int(percentOfWidth * width) - 1)\n            assert fieldWidth >= 0\n\n            # percentOffset = (tp.inFrameBitAddr % DW) / DW\n            # offset = int(percentOffset * width)\n            if isinstance(tp, ChoicesOfFrameParts):\n                name = \"<union>\"\n                partsWithChoice.append(tp)\n            else:\n                name = self.__repr__getName(tp, fieldWidth)\n            buff.append(f'{name: ^{fieldWidth}}|')\n        return (\"\".join(buff), partsWithChoice)\n\n    def __repr__(self, scale=1):\n        buff = []\n        s = f\"<{self.__class__.__name__:s} start:{self.startBitAddr:d}, end:{self.endBitAddr:d}\"\n        buff.append(s)\n\n        padding = 5\n        DW = self.wordWidth\n        width = int(DW * scale)\n\n        buff.append(\n            '{0: <{padding}}{1: <{halfLineWidth}}{2: >{halfLineWidth}}'.format(\n                \"\", DW - 1, 0, padding=padding, halfLineWidth=width // 2))\n        line = '{0: <{padding}}{1:-<{lineWidth}}'.format(\n            \"\", \"\", padding=padding, lineWidth=width + 1)\n        buff.append(line)\n\n        for w, transParts in self.walkWords(showPadding=True):\n            wStr, partsWithChoice = self.__repr__word(\n                w, width, padding, transParts)\n            buff.append(wStr)\n            while partsWithChoice:\n                for parts in zip_longest(*partsWithChoice):\n                    parts = list(flatten(parts, level=1))\n                    wStr, _partsWithChoice = self.__repr__word(\n                        w, width, padding, parts)\n                    buff.append(wStr)\n                partsWithChoice = _partsWithChoice\n\n        buff.append(line)\n        buff.append(\">\")\n        return \"\\n\".join(buff)\n"
  },
  {
    "path": "hwt/hdl/frameTmplUtils.py",
    "content": "from typing import Tuple\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.transPart import TransPart\nfrom hwt.hdl.transTmpl import OneOfTransaction\n\n\n@internal\ndef iterSort(iterators, cmpFn):\n    \"\"\"\n    Sort items from iterators(generators) by alwas selecting item\n    with lowest value (min first)\n\n    :return: generator of tuples (origin index, item) where origin index\n        is index of iterator in \"iterators\" from where item commes from\n    \"\"\"\n    actual = []\n    _iterators = []\n    for i, it in enumerate(iterators):\n        try:\n            a = next(it)\n            _iterators.append((i, it))\n            actual.append(a)\n        except StopIteration:\n            continue\n\n    while True:\n        if not _iterators:\n            return\n        elif len(_iterators) == 1:\n            originIndex, it = _iterators[0]\n            yield originIndex, actual[0]\n            for item in it:\n                yield originIndex, item\n            return\n\n        # select minimum and iterator from where it comes from\n        minimum = None\n        minimumIndex = None\n        secondMin = None\n        for i, val in enumerate(actual):\n            skipSecMinCheck = False\n            if minimum is None:\n                minimum = val\n                minimumIndex = i\n            elif cmpFn(val, minimum):\n                secondMin = minimum\n                minimum = val\n                minimumIndex = i\n                skipSecMinCheck = True\n            elif not skipSecMinCheck and (\n                    secondMin is None or cmpFn(val, secondMin)):\n                secondMin = val\n\n        actualI, actualIt = _iterators[minimumIndex]\n        while not cmpFn(secondMin, minimum):\n            yield (actualI, minimum)\n            try:\n                minimum = next(actualIt)\n            except StopIteration:\n                minimum = None\n                break\n\n        # consume from actual iterator while\n        if minimum is None:\n            del _iterators[minimumIndex]\n            del actual[minimumIndex]\n        else:\n            # minimum is not minimum anymore\n            actual[minimumIndex] = minimum\n\n\nclass TransPartGroup(list):\n    \"\"\"\n    Abstract parent class for groups of TransParts\n    \"\"\"\n    def setIsLast(self, val: bool) -> None:\n        self._isLast = val\n\n    def isLastPart(self) -> bool:\n        \"\"\"\n        :return: True if this part is last in parts derived from original field\n            else False\n        \"\"\"\n        return self._isLast\n\n    def getBusWordBitRange(self) -> Tuple[int, int]:\n        \"\"\"\n        :return: bit range which contains data of this part on bus data signal\n        \"\"\"\n        offset = self.startOfPart % self.parent.wordWidth\n        return (offset + self.bit_length(), offset)\n\n    def bit_length(self):\n        return self.endOfPart - self.startOfPart\n\n    def __repr__(self):\n        return \"<%s %s>\" % (self.__class__.__name__, list.__repr__(self))\n\n\nclass ChoicesOfFrameParts(TransPartGroup):\n    \"\"\"\n    List of ChoiceOfFrameParts\n    One of ChoiceOfFrameParts is used to represent the word, item depends\n    on context\n\n    :ivar ~.origin: OneOfTransaction instance\n    :ivar ~.startOfPart: bit addr of start of this group of frame parts\n    :ivar ~.endOfPart: bit addr of end of this group of frame parts\n    :ivar ~._isLast: flag which means this is the last part of original union\n    \"\"\"\n\n    def __init__(self, startOfPart: int, origin: OneOfTransaction):\n        self.origin = origin\n        self.startOfPart = startOfPart\n        self.endOfPart = None\n        self._isLast = False\n        super(ChoicesOfFrameParts, self).__init__()\n\n    def resolveEnd(self):\n        end = self.startOfPart\n        for items in self:\n            if items:\n                end = max(end, max(itm.endOfPart for itm in items))\n        self.endOfPart = end\n\n\nclass ChoiceOfFrameParts(list):\n    \"\"\"\n    :ivar ~.origin: ChoicesOfFrameParts instance\n    :ivar ~.tmpl: TransTmpl which was item generated from\n    \"\"\"\n\n    def __init__(self, origin, tmpl):\n        self.origin = origin\n        self.tmpl = tmpl\n\n    def __repr__(self):\n        return \"<%s %s>\" % (self.__class__.__name__, list.__repr__(self))\n\n\ndef groupIntoChoices(splitsOnWord, wordWidth: int, origin: OneOfTransaction):\n    \"\"\"\n    :param splitsOnWord: list of lists of parts (fields splited on word\n        boundaries)\n    :return: generators of ChoicesOfFrameParts for each word\n        which are not crossing word boundaries\n    \"\"\"\n    def cmpWordIndex(a, b):\n        return a.startOfPart // wordWidth < b.startOfPart // wordWidth\n\n    actual = None\n    itCnt = len(splitsOnWord)\n    for i, item in iterSort(splitsOnWord, cmpWordIndex):\n        _actualW = item.startOfPart // wordWidth\n        if actual is None:\n            # first pass\n            actual = ChoicesOfFrameParts(item.startOfPart, origin)\n            actual.extend(\n                ChoiceOfFrameParts(actual,\n                                   origin.possibleTransactions[_i])\n                for _i in range(itCnt))\n            actualW = _actualW\n        elif _actualW > actualW:\n            actual.resolveEnd()\n            yield actual\n            actual = ChoicesOfFrameParts(item.startOfPart, origin)\n            actual.extend(\n                ChoiceOfFrameParts(actual,\n                                   origin.possibleTransactions[_i])\n                for _i in range(itCnt))\n            actualW = _actualW\n        actual[i].append(item)\n\n    if actual is not None:\n        actual.setIsLast(True)\n        actual.resolveEnd()\n        yield actual\n\n\nclass TransTmplWordIterator():\n    \"\"\"\n    Iterator which reinterprets any structure\n    as generator of bits of specified width\n    \"\"\"\n    def __init__(self, wordWidth):\n        self.wordWidth = wordWidth\n\n    def fullWordCnt(self, start: int, end: int):\n        \"\"\"Count of complete words between two addresses\n        \"\"\"\n        assert end >= start, (start, end)\n        gap = max(0, (end - start) - (start % self.wordWidth))\n        return gap // self.wordWidth\n\n    def groupByWordIndex(self, transaction: 'TransTmpl', offset: int):\n        \"\"\"\n        Group transaction parts splited on words to words\n\n        :param transaction: TransTmpl instance which parts\n            should be grupped into words\n        :return: generator of tuples (wordIndex, list of transaction parts\n            in this word)\n        \"\"\"\n        actualW = None\n        partsInWord = []\n        wordWidth = self.wordWidth\n        for item in self.splitOnWords(transaction, offset):\n            _actualW = item.startOfPart // wordWidth\n            if actualW is None:\n                actualW = _actualW\n                partsInWord.append(item)\n            elif _actualW > actualW:\n                yield (actualW, partsInWord)\n                actualW = _actualW\n                partsInWord = [item, ]\n            else:\n                partsInWord.append(item)\n\n        if partsInWord:\n            yield (actualW, partsInWord)\n\n    @internal\n    def splitOnWords(self, transaction, addrOffset=0):\n        \"\"\"\n        :return: generator of TransPart instance\n        \"\"\"\n        wordWidth = self.wordWidth\n        end = addrOffset\n        for tmp in transaction.HwIO_walkFlatten(offset=addrOffset):\n            if isinstance(tmp, OneOfTransaction):\n                # unions\n                split = [self.splitOnWords(ch, end)\n                         for ch in tmp.possibleTransactions]\n                yield from groupIntoChoices(split, wordWidth, tmp)\n                end = addrOffset + tmp.possibleTransactions[0].bitAddrEnd\n            else:\n                # constant size types\n                (base, end), tmpl = tmp\n                startOfPart = base\n                while startOfPart != end:\n                    wordIndex = startOfPart // wordWidth\n                    endOfWord = (wordIndex + 1) * wordWidth\n                    endOfPart = min(endOfWord, end)\n                    inFieldOffset = startOfPart - base\n                    yield TransPart(self, tmpl, False, startOfPart, endOfPart,\n                                    inFieldOffset)\n                    startOfPart = endOfPart\n"
  },
  {
    "path": "hwt/hdl/hdlObject.py",
    "content": "from io import StringIO\n\nfrom hdlConvertorAst.translate.common.name_scope import NameScope\n\n\nclass HdlObject():\n    \"\"\"\n    Base Hdl object class for object which can be directly serialized\n    to target HDL language\n    \"\"\"\n\n    def __repr__(self):\n        from hwt.serializer.hwt import HwtDebugSerializer\n        name_scope = NameScope(None, \"debug\", False, debug=True)\n        to_hdl = HwtDebugSerializer.TO_HDL_AST(name_scope)\n        to_hdl.debug = True\n        hdl = to_hdl.as_hdl(self)\n        buff = StringIO()\n        # import sys\n        # buff = sys.stdout\n        ser = HwtDebugSerializer.TO_HDL(buff)\n        ser.visit_iHdlObj(hdl)\n        return buff.getvalue()\n"
  },
  {
    "path": "hwt/hdl/operator.py",
    "content": "from typing import Generator, Union, Tuple, Optional, Set, Sequence\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.hdlObject import HdlObject\nfrom hwt.hdl.operatorDefs import isEventDependentOp, HOperatorDef\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.arrayQuery import arr_all\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal, RtlSignalBase, \\\n    OperatorCaheKeyType\n\n\n@internal\ndef getCtxFromOps(operands: Sequence):\n    for o in operands:\n        if isinstance(o, RtlSignalBase):\n            return o._rtlCtx\n    return None # case for casts of constants\n\n\ndef isConst(item: Union[HConst, RtlSignalBase]):\n    \"\"\"\n    :return: True if expression is constant\n    \"\"\"\n    return isinstance(item, HConst) or item._const\n\n\nclass HOperatorNode(HdlObject):\n    \"\"\"\n    Class of operator in expression tree\n\n    :ivar ~.operands: list of operands\n    :ivar ~.evalFn: function to evaluate this operator\n    :ivar ~.operator: HOperatorDef instance\n    :ivar ~.result: result signal of this operator\n    \"\"\"\n\n    def __init__(self, operator: HOperatorDef,\n                 operands: Tuple[Union[RtlSignalBase, HConst]]):\n        self.operands = tuple(operands)\n        self.operator = operator\n        self.result: Optional[RtlSignal] = None\n\n    @internal\n    def staticEval(self):\n        \"\"\"\n        Recursively statistically evaluate result of this operator\n        \"\"\"\n        for o in self.operands:\n            o.staticEval()\n        self.result._val = self.operator.eval(self, simulator=None)\n\n    @internal\n    def _walk_sensitivity(self, casualSensitivity: Set[RtlSignal], seen: Set[RtlSignal], ctx: SensitivityCtx):\n        \"\"\"\n        :see: :meth:`hwt.synthesizer.rtlLevel.rtlSignal.RtlSignal._walk_sensitivity`\n        \"\"\"\n        seen.add(self)\n\n        if isEventDependentOp(self.operator):\n            if ctx.contains_ev_dependency:\n                assert self in ctx, \"has to have only a single clock signal\"\n            ctx.contains_ev_dependency = True\n            ctx.append(self)\n        else:\n            # walk source of signal\n            for operand in self.operands:\n                if operand not in seen:\n                    operand._walk_sensitivity(casualSensitivity, seen, ctx)\n\n    @internal\n    def _walk_public_drivers(self, seen: set) -> Generator[\"RtlSignal\", None, None]:\n        \"\"\"\n        Walk all non hidden signals in an expression\n        \"\"\"\n        for op in self.operands:\n            if not isinstance(op, HConst) and op not in seen:\n                seen.add(op)\n                yield from op._walk_public_drivers(seen)\n\n    @internal\n    @staticmethod\n    def withRes(opDef: HOperatorDef, operands: Sequence[Union[RtlSignalBase, HConst]], resT: HdlType):\n        \"\"\"\n        Create operator with result signal\n\n        :ivar ~.resT: data type of result signal\n        :ivar ~.outputs: iterable of signals which are outputs\n            from this operator\n        \"\"\"\n        # try return existing operator result\n        for i, o in enumerate(operands):\n            if isinstance(o, RtlSignalBase):\n                if i == 0:\n                    k = (opDef, i, *operands[1:])\n                else:\n                    k = (opDef, i, *operands[:i], *operands[i + 1:])\n                try:\n                    return o._usedOps[k]\n                except KeyError:\n                    pass\n                break\n\n        # instantiate new HOperatorNode\n        op = HOperatorNode(opDef, operands)\n        out: RtlSignal = resT.getRtlSignalCls()(getCtxFromOps(operands), None, resT)\n        out._const = arr_all(op.operands, isConst)\n        out._rtlDrivers.append(op)\n        out._rtlObjectOrigin = op\n        op.result = out\n\n        # Register potential signals to drivers/endpoints\n        first_signal = True\n        for i, o in enumerate(op.operands):\n            if isinstance(o, RtlSignalBase):\n                o._rtlEndpoints.append(op)\n                if first_signal:\n                    # register operator in _usedOps operator cache\n                    if i == 0:\n                        k = (opDef, i, *operands[1:])\n                    else:\n                        k = (opDef, i, *operands[:i], *operands[i + 1:])\n                    o._usedOps[k] = out\n                    o._usedOpsAlias[k] = {k, }\n                    first_signal = False\n            else:\n                assert isinstance(o, HConst), (\n                    \"HOperatorNode operands can be only signal or values got:\", o)\n\n        # pre-compute constant signal if all used types support it\n        if out._const:\n            precompute = resT._PRECOMPUTE_CONSTANT_SIGNALS\n            for o in operands:\n                precompute &= o._dtype._PRECOMPUTE_CONSTANT_SIGNALS\n                if not precompute:\n                    break\n\n            if precompute:\n                # if this signal is constant precompute its value\n                out.staticEval()\n\n        return out\n\n    @internal\n    def _replace_input(self, inp: RtlSignal, replacement: RtlSignal):\n        \"\"\"\n        Replace operand signal (non-recursively)\n        \n        :attention: costly operation because all records in operand cache for all inputs may be potentially updated\n        \"\"\"\n        assert self.result._rtlCtx is replacement._rtlCtx, self\n        newOperands = []\n        modified = False\n        for op in self.operands:\n            if op is inp:\n                modified = True\n                newOperands.append(replacement)\n            else:\n                newOperands.append(op)\n\n        assert modified, self\n        res = self.result\n        for op in self.operands:\n            if isinstance(op, RtlSignal):\n                op: RtlSignal\n                for k, v in tuple(op._usedOps.items()):\n                    k: OperatorCaheKeyType\n                    if v is res:\n                        if op is inp:\n                            # this operand is  originally replaced \"inp\" the cache key must be transfered\n                            # from original operand to a new replacement\n                            op._usedOps.pop(k)\n                            replacement._usedOps[k] = v\n                            aliases = op._usedOpsAlias.pop(k)\n                            aliases.remove(k)\n                            _aliases = None\n                            for a in aliases:\n                                _aliases = replacement._usedOpsAlias.get(a, None)\n                                if _aliases is not None:\n                                    break\n                            if _aliases is None:\n                                _aliases = {k, }\n                            else:\n                                _aliases.add(k)\n                            replacement._usedOpsAlias[k] = _aliases\n\n                        else:\n                            # some other operand is originally replaced \"inp\" the cache key must be updated\n                            op._usedOps.pop(k)\n                            kNew = (*k[0:2], *(replacement if _op is inp else _op for _op in k[2:]))\n                            op._usedOps[kNew] = v\n                            aliases = op._usedOpsAlias.pop(k)\n                            aliases.remove(k)\n                            aliases.add(kNew)\n                            op._usedOpsAlias[kNew] = aliases\n                break  # _usedOps/_usedOpsAlias is relevant only for the first operand\n\n        self.operands = tuple(newOperands)\n        inp._rtlEndpoints.discard(self)\n        replacement._rtlEndpoints.append(self)\n\n    @internal\n    def _destroy(self):\n        self.result._rtlDrivers.remove(self)\n        operands = self.operands\n        first_op_sig = True\n        for i, o in enumerate(operands):\n            if isinstance(o, RtlSignalBase):\n                # discard because same signal can be on multiple places in operand list\n                o._rtlEndpoints.discard(self)\n                if first_op_sig:\n                    # clean all references on this operator instance from RtlSignal._usedOps operator cache\n                    _k = (self.operator, i, *operands[:i], *operands[i + 1:])\n                    for k in o._usedOpsAlias[_k]:\n                        res = o._usedOps.pop(k)\n                        assert res is self.result, (self.result._rtlCtx.parent, \"HOperatorNode was not stored properly in operand cache\", res, self.result, o)\n                    first_op_sig = False\n        self.result._rtlObjectOrigin = None\n        self.result = None\n        self.operands = None\n        self.operator = None\n"
  },
  {
    "path": "hwt/hdl/operatorDefs.py",
    "content": "from operator import floordiv, add, sub, inv, mul, ne, and_, or_, \\\n    xor, gt, ge, lt, le, getitem, neg\nfrom typing import Optional\n\nfrom hdlConvertorAst.hdlAst._expr import HdlOpType\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.defs import INT, SLICE\n\n\ndef _getVal(v):\n    while not isinstance(v, HConst):\n        v = v._val\n\n    return v\n\n\nclass HOperatorDef():\n    \"\"\"\n    Operator definition\n\n    :ivar ~.id: name of operator\n    :ivar ~._evalFn: function which evaluates operands\n    :ivar ~.hdlConvertoAstOp: an operator which is used for export to hdlConvertoAst library\n    \"\"\"\n\n    def __init__(self, evalFn, allowsAssignTo=False, idStr:Optional[str]=None, hdlConvertoAstOp: Optional[HdlOpType]=None):\n        self.id = idStr  # assigned automatically in HwtOps\n        self._evalFn = evalFn\n        self.allowsAssignTo = allowsAssignTo\n        self.hdlConvertoAstOp = hdlConvertoAstOp\n\n    def __eq__(self, other):\n        return type(self) == type(other) and self.id == other.id\n\n    @internal\n    def __hash__(self):\n        return hash(self.id)\n\n    def eval(self, operator, simulator=None):\n        \"\"\"Load all operands and process them by self._evalFn\"\"\"\n        operands = [_getVal(o) for o in operator.operands]\n\n        return self._evalFn(*operands)\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} {self.id:s}>\"\n\n\ndef isEventDependentOp(operator):\n    return operator in (HwtOps.RISING_EDGE, HwtOps.FALLING_EDGE)\n\n\ndef onRisingEdgeFn(a):\n    return a._onRisingEdge()\n\n\ndef onFallingEdgeFn(a):\n    return a._onFallingEdge()\n\n\ndef dotOpFn(a, name):\n    return getattr(a, name)\n\n\n# [TODO] downto / to are relict of vhdl and should be replaced with slice\ndef downtoFn(a: int, b: int):\n    return SLICE.from_py(slice(a, b, -1))\n\n\ndef toFn(a: int, b: int):\n    return SLICE.from_py(slice(a, b, 1))\n\n\ndef concatFn(a: \"AnyHBitsValue\", b: \"AnyHBitsValue\") -> \"AnyHBitsValue\":\n    return a._concat(b)\n\n\ndef power(base, exp):\n    return base ** exp\n\n\ndef eqFn(a, b):\n    return a._eq(b)\n\n\ndef ternaryFn(cond: \"AnyHBitsValue\", vTrue, vFalse):\n    return cond._ternary(vTrue, vFalse)\n\n\ndef callFn(fn: \"HdlFunctionDef\", *operands, **kwargs):\n    return fn(*operands, **kwargs)\n\n\ndef bitsToIntFn(a: \"AnyHBitsValue\"):\n    return a._auto_cast(INT)\n\n\ndef intToBitsFn(a: \"AnyHBitsValue\", t: \"HdlType\"):\n    return a._auto_cast(t)\n\n\ndef bitsAsSignedFn(a: \"AnyHBitsValue\"):\n    return a._signed()\n\n\ndef bitsAsUnsignedFn(a: \"AnyHBitsValue\"):\n    return a._unsigned()\n\n\ndef bitsAsVec(a: \"AnyHBitsValue\"):\n    return a._vec()\n\n\ndef zextFn(a: \"AnyHBitsValue\", newWidth: int):\n    return a._zext(newWidth)\n\n\ndef sextFn(a: \"AnyHBitsValue\", newWidth: int):\n    return a._sext(newWidth)\n\n\ndef truncFn(a: \"AnyHBitsValue\", newWidth: int):\n    return a._trunc(newWidth)\n\n\nclass HwtOps():\n    \"\"\"\n    :attention: Remember that and operator \"and\" is & and \"or\" is \\\\|, \"and\"\n        and \"or\" can not be used because they can not be overloaded\n    :attention: These are operators of internal AST,\n        they are not equal to verilog or vhdl operators\n    \"\"\"\n    RISING_EDGE = HOperatorDef(onRisingEdgeFn)  # unnecessary\n    FALLING_EDGE = HOperatorDef(onFallingEdgeFn)  # unnecessary\n\n    MINUS_UNARY = HOperatorDef(neg)\n    DIV = HOperatorDef(floordiv)\n    UDIV = HOperatorDef(lambda a, b: a._unsigned() // b._unsigned())\n    SDIV = HOperatorDef(lambda a, b: a._signed() // b._signed())\n\n    ADD = HOperatorDef(add)\n    SUB = HOperatorDef(sub)\n    POW = HOperatorDef(power)\n    # see  https://stackoverflow.com/questions/25848879/difference-between-mod-and-rem-operators-in-vhdl\n    UREM = HOperatorDef(lambda a, b: a._unsigned() % b._unsigned())  # \"rem operator\"\n    SREM = HOperatorDef(lambda a, b: a._signed() % b._signed())  # \"modulo operator\"\n    # MUL bit_length and sign of src0, src1 and dst is the same\n    # sign/unsign variant with double result width is recognized from sext/zext of operands in final phases of serialization\n    MUL = HOperatorDef(mul)\n\n    NOT = HOperatorDef(inv, allowsAssignTo=True)\n    XOR = HOperatorDef(xor)\n    AND = HOperatorDef(and_)\n    OR = HOperatorDef(or_)\n\n    DOT = HOperatorDef(dotOpFn, allowsAssignTo=True)\n    DOWNTO = HOperatorDef(downtoFn)\n    TO = HOperatorDef(toFn)\n    CONCAT = HOperatorDef(concatFn, allowsAssignTo=True)\n    # :note: SEXT, ZEXT, TRUNC are redundant as it can be implemented using INDEX/CONCAT however they exist\n    #        from performance reasons as patern match for them would be very common during optimizations and\n    #        specific evaluation functions may be significantly faster\n    # :note: normalization rules:\n    #    * SEXT, ZEXT is prefered over concatenation\n    #    * sext(a:1b) should be used internally instead of concat(a, a)\n    #    * TRUNC is prefered over index with a single exception\n    #      * x[0] should be used internally instead of trunc(x, 1)\n    SEXT = HOperatorDef(sextFn)  # sign extension of bit vector to larger width\n    ZEXT = HOperatorDef(zextFn)  # zero extension  of bit vector to larger width\n    TRUNC = HOperatorDef(truncFn, allowsAssignTo=True)  # truncate width of bit vector\n\n    EQ = HOperatorDef(eqFn)\n    NE = HOperatorDef(ne)\n    # :note: for compare operands without U/S the info about sign is stored in type of operands\n    #     for U/S variant the signed flag in the type is ignored and signines is forced by operator definition\n    GT = HOperatorDef(gt)\n    GE = HOperatorDef(ge)\n    LT = HOperatorDef(lt)\n    LE = HOperatorDef(le)\n\n    ULE = HOperatorDef(lambda a, b: a._unsigned() <= b._unsigned())\n    ULT = HOperatorDef(lambda a, b: a._unsigned() < b._unsigned())\n    UGT = HOperatorDef(lambda a, b: a._unsigned() > b._unsigned())\n    UGE = HOperatorDef(lambda a, b: a._unsigned() >= b._unsigned())\n\n    SLE = HOperatorDef(lambda a, b: a._signed() <= b._signed())\n    SLT = HOperatorDef(lambda a, b: a._signed() < b._signed())\n    SGT = HOperatorDef(lambda a, b: a._signed() > b._signed())\n    SGE = HOperatorDef(lambda a, b: a._signed() >= b._signed())\n\n    # :note: INDEX is used for arrays and also for bit vectors\n    INDEX = HOperatorDef(getitem, allowsAssignTo=True)\n    TERNARY = HOperatorDef(ternaryFn)\n    CALL = HOperatorDef(callFn)\n\n    BitsAsSigned = HOperatorDef(bitsAsSignedFn, allowsAssignTo=True)\n    BitsAsUnsigned = HOperatorDef(bitsAsUnsignedFn, allowsAssignTo=True)\n    BitsAsVec = HOperatorDef(bitsAsVec, allowsAssignTo=True)\n\n\nfor a_name in dir(HwtOps):\n    o = getattr(HwtOps, a_name)\n    if isinstance(o, HOperatorDef):\n        o.id = a_name\n\nCAST_OPS = (HwtOps.BitsAsVec, HwtOps.BitsAsSigned, HwtOps.BitsAsUnsigned)\nBITWISE_OPS = (HwtOps.NOT, HwtOps.XOR, HwtOps.AND, HwtOps.OR)\nCOMPARE_OPS = (\n    HwtOps.EQ,\n    HwtOps.NE,\n    HwtOps.GT,\n    HwtOps.GE,\n    HwtOps.LT,\n    HwtOps.LE,\n    HwtOps.ULE,\n    HwtOps.ULT,\n    HwtOps.UGT,\n    HwtOps.UGE,\n    HwtOps.SLE,\n    HwtOps.SLT,\n    HwtOps.SGT,\n    HwtOps.SGE,\n)\n\n# change of compare operator on operand order swap\nCMP_OP_SWAP = {\n    HwtOps.EQ: HwtOps.EQ,  # (a == b) == (b == a)\n    HwtOps.NE: HwtOps.NE,  # (a != b) == (b != a)\n\n    HwtOps.GT: HwtOps.LT,  # (a > b)  == (b < a)\n    HwtOps.GE: HwtOps.LE,  # (a >= b) == (b <= a)\n    HwtOps.LT: HwtOps.GT,  # (a < b)  == (b > a)\n    HwtOps.LE: HwtOps.GE,  # (a <= b) == (b >= a)\n\n    HwtOps.UGT: HwtOps.ULT,\n    HwtOps.UGE: HwtOps.ULE,\n    HwtOps.ULT: HwtOps.UGT,\n    HwtOps.ULE: HwtOps.UGE,\n\n    HwtOps.SGT: HwtOps.SLT,\n    HwtOps.SGE: HwtOps.SLE,\n    HwtOps.SLT: HwtOps.SGT,\n    HwtOps.SLE: HwtOps.SGE,\n\n}\n\nCMP_OPS_NEG = {\n    HwtOps.EQ: HwtOps.NE,\n    HwtOps.NE: HwtOps.EQ,\n\n    HwtOps.GT: HwtOps.LE,\n    HwtOps.GE: HwtOps.LT,\n    HwtOps.LT: HwtOps.GE,\n    HwtOps.LE: HwtOps.GT,\n\n    HwtOps.UGT: HwtOps.ULE,\n    HwtOps.UGE: HwtOps.ULT,\n    HwtOps.ULT: HwtOps.UGE,\n    HwtOps.ULE: HwtOps.UGT,\n\n    HwtOps.SGT: HwtOps.SLE,\n    HwtOps.SGE: HwtOps.SLT,\n    HwtOps.SLT: HwtOps.SGE,\n    HwtOps.SLE: HwtOps.SGT,\n}\n\n# always commutative operators for which order of operands does not matter\nALWAYS_COMMUTATIVE_OPS = (HwtOps.EQ, HwtOps.NE, HwtOps.XOR, HwtOps.AND, HwtOps.OR, HwtOps.ADD, HwtOps.MUL)\n# always commutative associative operators for which order of operands in expression tree does not matter\nALWAYS_ASSOCIATIVE_COMMUTATIVE_OPS = (HwtOps.XOR, HwtOps.AND, HwtOps.OR, HwtOps.ADD, HwtOps.MUL)\nEVENT_OPS = (HwtOps.RISING_EDGE, HwtOps.FALLING_EDGE)\n"
  },
  {
    "path": "hwt/hdl/operatorUtils.py",
    "content": "from typing import Union, Tuple\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.statement import HdlStatement, SignalReplaceSpecType\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\n\n\n# from hwt.hdl.operator import Operator\n@internal\ndef _replace_input_in_expr(expr: Union[RtlSignalBase, HConst], toReplace: SignalReplaceSpecType) -> RtlSignalBase:\n    \"\"\"\n    :return: newly rewritten expression with the subexpression replaced, True if changed else False\n    \"\"\"\n    if isinstance(toReplace, dict):\n        replacement = toReplace.get(expr, None)\n    else:\n        _toReplace, replacement = toReplace\n        if expr is not _toReplace:\n            replacement = None\n            \n    if replacement is not None:\n        return replacement, True\n\n    elif isinstance(expr, RtlSignalBase) and expr._isUnnamedExpr:\n        op = expr._rtlObjectOrigin\n        if op is None:\n            try:\n                op = expr.singleDriver()\n            except SignalDriverErr:\n                return expr, False\n        if isinstance(op, (HdlPortItem, HdlStatement)):\n            return expr, False\n\n        # assert isinstance(op, Operator), op\n        operandChanged = False\n        ops = []\n        for o in op.operands:\n            _o, _change = _replace_input_in_expr(o, toReplace)\n            ops.append(_o)\n            operandChanged |= _change\n            \n        if operandChanged:\n            res = op.operator._evalFn(*ops)\n            return res, True\n        else:\n            return expr, False\n\n    else:\n        return expr, False\n\n\n@internal\ndef replace_input_in_expr(topStatement: \"HdlStatement\",\n                          parentStm: \"HdlStatement\",\n                          expr: Union[RtlSignalBase, HConst],\n                          toReplace: SignalReplaceSpecType,\n                          # maybeDisconnectedSignals: SetList[RtlSignalBase]\n                          ) -> Tuple[RtlSignalBase, bool]:\n    \"\"\"\n    :return: tuple (newExpression, True if expr is toReplace and should be replaced else False)\n    \"\"\"\n    res, didContainExpr = _replace_input_in_expr(expr, toReplace)\n    if didContainExpr:\n        # maybeDisconnectedSignals.append(expr)\n        if not isinstance(expr, HConst):\n            expr._rtlEndpoints.discard(topStatement)\n        if not isinstance(res, HConst):\n            res._rtlEndpoints.append(topStatement)\n\n        return res, True\n    else:\n        assert res is expr\n        return expr, False\n\n"
  },
  {
    "path": "hwt/hdl/portItem.py",
    "content": "from hwt.constants import DIRECTION\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.statement import HwtSyntaxError\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass HdlPortItem():\n    \"\"\"\n    HDL entity/module/component port item\n    Used to split signal paths on component boundary.\n\n    :note: src/dst are named based on input output signal direction\n        both dst and src can be parent/component signal, it depends on direction\n    \"\"\"\n\n    def __init__(self, name: str, direction: DIRECTION, dtype: HdlType, module: \"HwModule\"):\n        self.name = name\n        self.module = module\n        self._dtype = dtype\n        self.direction = direction\n        self.src = None\n        self.dst = None\n\n    @classmethod\n    def fromSignal(cls, s: HdlSignalItem, component, d: DIRECTION):\n        return cls(s._name, d, s._dtype, component)\n\n    @internal\n    def connectOuterSig(self, signal: RtlSignalBase):\n        \"\"\"\n        Connect to port item on submodule\n        \"\"\"\n        if self.direction == DIRECTION.IN:\n            if self.src is not None:\n                raise HwtSyntaxError(\n                    \"Port %s is already associated with %r\"\n                    % (self.name, self.src))\n            self.src = signal\n            signal._rtlEndpoints.append(self)\n\n        elif self.direction == DIRECTION.OUT:\n            if self.dst is not None:\n                raise HwtSyntaxError(\n                    \"Port %s is already associated with %r\"\n                    % (self.name, self.dst))\n            self.dst = signal\n            signal._rtlDrivers.append(self)\n\n        else:\n            raise NotImplementedError(self)\n\n        signal._hidden = False\n        signal._rtlCtx.subHwModules.add(self.module)\n\n    @internal\n    def connectInternSig(self, signal):\n        \"\"\"\n        Connect signal from internal side of of this component to this port.\n        \"\"\"\n        if self.direction == DIRECTION.OUT:\n            if self.src is not None:\n                raise HwtSyntaxError(\n                    \"Port %s is already associated with signal %s\"\n                    % (self.name, str(self.src)))\n            self.src = signal\n            self.src._rtlEndpoints.append(self)\n\n        elif self.direction == DIRECTION.IN:\n            if self.dst is not None:\n                raise HwtSyntaxError(\n                    \"Port %s is already associated with signal %s\"\n                    % (self.name, str(self.dst)))\n            self.dst = signal\n            self.dst._rtlDrivers.append(self)\n        else:\n            raise NotImplementedError(self.direction)\n\n    @internal\n    def getInternSig(self):\n        \"\"\"\n        return signal inside module which has this port\n        \"\"\"\n        d = self.direction\n        if d == DIRECTION.IN:\n            return self.dst\n        elif d == DIRECTION.OUT:\n            return self.src\n        else:\n            raise NotImplementedError(d)\n\n    @internal\n    def getOuterSig(self):\n        \"\"\"\n        return signal inside module which has this port\n        \"\"\"\n        d = self.direction\n        if d == DIRECTION.OUT:\n            return self.dst\n        elif d == DIRECTION.IN:\n            return self.src\n        else:\n            raise NotImplementedError(d)\n\n    @internal\n    def _walk_sensitivity(self, casualSensitivity: set, seen: set, ctx: SensitivityCtx):\n        \"\"\"\n        :see: :meth:`hwt.synthesizer.rtlLevel.rtlSignal.RtlSignal._walk_sensitivity`\n        \"\"\"\n        return\n        yield\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} src:{self.src}, dst:{self.dst}>\"\n"
  },
  {
    "path": "hwt/hdl/sensitivityCtx.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.pyUtils.setList import SetList\n\n\nclass SensitivityCtx(SetList):\n    \"\"\"\n    Sensitivity list used for resolution of sensitivity for statement instances\n\n    :ivar ~.contains_ev_dependency: True if this contains event dependent\n        sensitivity\n    \"\"\"\n\n    def __init__(self, initSeq=None):\n        SetList.__init__(self, initSeq=initSeq)\n        self.contains_ev_dependency = False\n\n    @internal\n    def extend(self, items):\n        SetList.extend(self, items)\n        if isinstance(items, SensitivityCtx):\n            self.contains_ev_dependency |= items.contains_ev_dependency\n\n    @internal\n    def clear(self):\n        SetList.clear(self)\n        self.contains_ev_dependency = False\n"
  },
  {
    "path": "hwt/hdl/statements/__init__.py",
    "content": ""
  },
  {
    "path": "hwt/hdl/statements/assignmentContainer.py",
    "content": "from typing import Tuple, List, Dict, Union, Optional, Generator\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.constUtils import isSameHConst, areSameHConsts\nfrom hwt.hdl.operatorUtils import replace_input_in_expr\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.statement import HdlStatement, SignalReplaceSpecType\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HdlAssignmentContainer(HdlStatement):\n    \"\"\"\n    Assignment container\n\n    :ivar ~.src: source\n    :ivar ~.dst: destination signal\n    :ivar ~.indexes: description of index selector on dst\n        (list of Index/Slice objects) (f.e. [0, 1] means  dst[0][1])\n\n    :cvar __instCntr: counter used for generating instance ids\n    :ivar ~._instId: internally used only for intuitive sorting of statements\n    \"\"\"\n\n    _DEEPCOPY_SKIP = (*HdlStatement._DEEPCOPY_SKIP, 'src', 'dst', 'indexes')\n    _DEEPCOPY_SHALLOW_ONLY = (*HdlStatement._DEEPCOPY_SHALLOW_ONLY, \"indexes\")\n\n    __instCntr = 0\n\n    def __init__(self, src: Union[RtlSignalBase, HConst], dst: RtlSignalBase,\n                 indexes: Optional[List[Union[RtlSignalBase, HConst]]]=None,\n                 virtual_only=False,\n                 parentStm: Optional[HdlStatement]=None,\n                 parentStmList: Optional[ListOfHdlStatement]=None,\n                 sensitivity: Optional[SetList]=None,\n                 event_dependent_from_branch:Optional[int]=None):\n        \"\"\"\n        :param dst: destination to assign to\n        :param src: source which is assigned from\n        :param indexes: description of index selector on dst\n            (list of Index/Slice objects) (f.e. [[0], [1]] means  dst[0][1])\n        :param virtual_only: flag indicates that this assignments\n            is only virtual and should not be added into\n            netlist, because it is only for internal notation\n        \"\"\"\n        super(HdlAssignmentContainer, self).__init__(\n            parentStm,\n            parentStmList,\n            sensitivity,\n            event_dependent_from_branch=event_dependent_from_branch)\n        self._instId = HdlAssignmentContainer._nextInstId()\n\n        self.src = src\n        self.dst = dst\n        assert isinstance(dst, RtlSignalBase), dst\n        self.indexes = indexes\n        self._collect_inputs()\n\n        if not virtual_only:\n            for i in self._inputs:\n                i._rtlEndpoints.append(self)\n                \n            dst._rtlDrivers.append(self)\n            dst._rtlCtx.statements.add(self)\n\n        self._outputs.append(dst)\n    \n    @override\n    def __deepcopy__(self, memo: dict):\n        result = super(HdlAssignmentContainer, self).__deepcopy__(memo)\n        result.src = self.src\n        result.dst = self.dst\n        result._instId = self._nextInstId()\n        return result\n\n    @internal\n    @override\n    def _collect_inputs(self) -> None:\n        src = self.src\n        if isinstance(src, RtlSignalBase):\n            self._inputs.append(src)\n\n        indexes = self.indexes\n        if indexes:\n            for i in indexes:\n                if isinstance(i, RtlSignalBase):\n                    self._inputs.append(i)\n        \n    @internal\n    @override\n    def _cut_off_drivers_of(self, sig: RtlSignalBase):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._cut_off_drivers_of`\n        \"\"\"\n        if self._try_cut_off_whole_stm(sig):\n            return self\n\n    @internal\n    @override\n    def _discover_enclosure(self) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_enclosure`\n        \"\"\"\n        assert self._enclosed_for is None\n        self._enclosed_for = set()\n        self._enclosed_for.update(self._outputs)\n\n    @internal\n    @override\n    def _discover_sensitivity(self, seen: set) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_sensitivity`\n        \"\"\"\n        assert self._sensitivity is None\n        ctx = self._sensitivity = SensitivityCtx()\n\n        casualSensitivity = set()\n        for inp in self._inputs:\n            if inp not in seen:\n                seen.add(inp)\n                inp._walk_sensitivity(casualSensitivity, seen, ctx)\n        ctx.extend(casualSensitivity)\n\n    @internal\n    @override\n    def _fill_enclosure(self, enclosure: Dict[RtlSignalBase, HdlStatement]):\n        \"\"\"\n        The assignment does not have any uncovered code branches\n\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._fill_enclosure`\n        \"\"\"\n        pass\n\n    @internal\n    @override\n    def _iter_stms(self) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms`\n        \"\"\"\n        return\n        yield\n\n    @internal\n    @override\n    def _iter_stms_for_output(self, output: RtlSignalBase) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms_for_output`\n        \"\"\"\n        return\n        yield\n\n    @internal\n    @override\n    def _on_parent_event_dependent(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._on_parent_event_dependent`\n        \"\"\"\n        self._event_dependent_from_branch = 0\n\n    @internal\n    @override\n    def _try_reduce(self) -> Tuple[ListOfHdlStatement, bool]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._try_reduce`\n        \"\"\"\n        return ListOfHdlStatement((self,)), False\n\n    @internal\n    @override\n    def _is_mergable(self, other: HdlStatement) -> bool:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._is_mergable`\n        \"\"\"\n        return isinstance(other, self.__class__)\n\n    @override\n    def isSame(self, other):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement.isSame`\n        \"\"\"\n        if isinstance(other, self.__class__):\n            if isSameHConst(self.dst, other.dst)\\\n                    and isSameHConst(self.src, other.src)\\\n                    and areSameHConsts(self.indexes, other.indexes):\n                return True\n        return False\n\n    @internal\n    @override\n    @classmethod\n    def _nextInstId(cls):\n        \"\"\"\n        Get next instance id\n        \"\"\"\n        i = cls.__instCntr\n        cls.__instCntr += 1\n        return i\n    \n    @internal\n    @override\n    def _replace_input_nested(self, topStm: HdlStatement, toReplace: SignalReplaceSpecType) -> None:\n       \n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_input`\n        \"\"\"\n        didUpdate = False\n        if self.indexes:\n            new_indexes = []\n            for ind in self.indexes:\n                new_i, _didUpdate = replace_input_in_expr(topStm, self, ind, toReplace)\n                new_indexes.append(new_i)\n                didUpdate |= _didUpdate\n                \n            self.indexes = new_indexes\n\n        self.src, _didUpdate = replace_input_in_expr(topStm, self, self.src, toReplace)\n        didUpdate |= _didUpdate\n        if didUpdate:\n            self._replace_input_update_sensitivity_and_inputs(toReplace)\n        return didUpdate\n"
  },
  {
    "path": "hwt/hdl/statements/codeBlockContainer.py",
    "content": "from itertools import compress\nfrom typing import List, Set, Tuple, Generator\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.hdl.statements.utils.reduction import HdlStatement_try_reduce_list\nfrom hwt.hdl.statements.utils.signalCut import HdlStatement_cut_off_drivers_of_list\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HdlStmCodeBlockContainer(HdlStatement):\n    \"\"\"\n    Hdl block statement used also to represent a HDL process\n\n    :ivar ~.name: name used as id in target HDL\n    :ivar ~.statements: list of statements in body of process\n\n    :note: HdlStmCodeBlockContainer do not have to be process in target HDL, for example\n        simple process which contains only unconditional assignment will\n        be rendered just as assignment. It depends on capabilities of the target HDL.\n    \"\"\"\n\n    def __init__(self):\n        super(HdlStmCodeBlockContainer, self).__init__()\n        self.name = None\n        self.statements = ListOfHdlStatement()\n        self.rank = 0\n\n    @internal\n    @classmethod\n    def from_known_io(cls, name: str, statements: ListOfHdlStatement,\n                 sensitivity: Set[\"RtlSignal\"],\n                 inputs: SetList, outputs: SetList) -> 'HdlStmCodeBlockContainer':\n        self = cls()\n        self.name = name\n        self.statements = statements\n        self._inputs = inputs\n        self._outputs = outputs\n        self._sensitivity = sensitivity\n        self.rank = sum(map(lambda s: s.rank, statements))\n        return self\n\n    @internal\n    @override\n    def _try_reduce(self) -> Tuple[List[\"HdlStatement\"], bool]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._try_reduce`\n        \"\"\"\n        new_statements, _, io_change = HdlStatement_try_reduce_list(self.statements)\n        return new_statements, io_change\n\n    @internal\n    @override\n    def _iter_stms(self) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms`\n        \"\"\"\n        yield from self.statements\n\n    @internal\n    @override\n    def _iter_stms_for_output(self, output: RtlSignalBase) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms_for_output`\n        \"\"\"\n        yield from self.statements.iterStatementsWithOutput(output)\n\n    @internal\n    @override\n    def _cut_off_drivers_of(self, sig: RtlSignalBase):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._cut_off_drivers_of`\n        \"\"\"\n        if self._try_cut_off_whole_stm(sig):\n            return self\n\n        # try to cut off all statements which are drivers of specified signal\n        # in all branches\n        child_keep_mask = []\n\n        newStatements = []\n        all_cut_off = True\n        all_cut_off &= HdlStatement_cut_off_drivers_of_list(\n            sig, self.statements, child_keep_mask, newStatements)\n        self.statements = list(compress(self.statements, child_keep_mask))\n\n        assert not all_cut_off, \"everything was cut of but this should be already known at the start\"\n\n        if newStatements:\n            # parts were cut off\n            # generate new statement for them\n            n = self.__class__(*newStatements)\n\n            if self.parentStm is None:\n                ctx = n._get_rtl_context()\n                ctx.statements.add(n)\n\n            self._cut_off_drivers_of_regenerate_io(sig, n)\n\n            return n\n\n    @internal\n    @override\n    def _replace_child_statement(self, stm:HdlStatement,\n            replacement:ListOfHdlStatement,\n            update_io:bool) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_child_statement`\n        \"\"\"\n\n        if update_io:\n            raise NotImplementedError()\n\n        statements: ListOfHdlStatement = self.statements\n        i = statements.index(stm)\n        statements.replace(self, stm, i, replacement)\n        # reset IO because it was shared with this statement\n        stm._destroy()\n"
  },
  {
    "path": "hwt/hdl/statements/ifContainter.py",
    "content": "\n\nfrom copy import deepcopy\nfrom functools import reduce\nfrom itertools import compress\nfrom operator import and_\nfrom typing import List, Tuple, Dict, Optional, Callable, Set, Generator\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.operatorUtils import replace_input_in_expr\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.statement import HdlStatement, SignalReplaceSpecType\nfrom hwt.hdl.statements.utils.comparison import  statementsAreSame, isSameStatementList\nfrom hwt.hdl.statements.utils.ioDiscovery import HdlStatement_discover_enclosure_for_statements\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.hdl.statements.utils.reduction import HdlStatement_merge_statement_lists, \\\n    HdlStatement_try_reduce_list, is_mergable_statement_list\nfrom hwt.hdl.statements.utils.signalCut import HdlStatement_cut_off_drivers_of_list\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.utils import RtlSignal_sort_key\nfrom hwt.synthesizer.rtlLevel.fill_stm_list_with_enclosure import fill_stm_list_with_enclosure\nfrom hwt.synthesizer.rtlLevel.rtlSignalWalkers import discover_sensitivity_of_sig\n\n\nclass IfContainer(HdlStatement):\n    \"\"\"\n    Structural container of if statement for hdl rendering\n\n    :ivar ~._ifTrue_enclosed_for: set of signals for which if ifTrue branch enclosed\n            (has not branch where signal is not assignment)\n    :ivar ~._elIfs_enclosed_for: list of sets of enclosed signals for each elif\n    :ivar ~._ifFalse_enclosed_for: set of enclosed signals for ifFalse branch\n    \"\"\"\n    _DEEPCOPY_SHALLOW_ONLY = (*HdlStatement._DEEPCOPY_SHALLOW_ONLY, '_ifTrue_enclosed_for', '_elIfs_enclosed_for', '_ifFalse_enclosed_for')\n    _DEEPCOPY_SKIP = (*HdlStatement._DEEPCOPY_SKIP, 'cond', 'elIfs')\n\n    def __init__(self, cond: RtlSignalBase, ifTrue=None, ifFalse=None, elIfs=None,\n                 parentStm=None, event_dependent_from_branch: Optional[int]=None):\n        \"\"\"\n        :param cond: RtlSignal as conditions for this if\n        :param ifTrue: list of statements which should be active if cond.\n            is met\n        :param elIfs: list of tuples (list of conditions, list of statements)\n        :param ifFalse: list of statements which should be active if cond.\n            and any other cond. in elIfs is met\n        \"\"\"\n        assert isinstance(cond, RtlSignalBase)\n        self.cond = cond\n        super(IfContainer, self).__init__(\n            parentStm,\n            event_dependent_from_branch=event_dependent_from_branch)\n\n        if ifTrue is None:\n            ifTrue = ListOfHdlStatement()\n        self.ifTrue: ListOfHdlStatement = ifTrue\n\n        if elIfs is None:\n            elIfs = []\n        self.elIfs: List[Tuple[RtlSignalBase, ListOfHdlStatement]] = elIfs\n\n        self.ifFalse: Optional[ListOfHdlStatement] = ifFalse\n        self._ifTrue_enclosed_for: Optional[Set[RtlSignalBase]] = None\n        self._elIfs_enclosed_for: Optional[Set[RtlSignalBase]] = None\n        self._ifFalse_enclosed_for: Optional[Set[RtlSignalBase]] = None\n\n    @override\n    def __deepcopy__(self, memo: dict):\n        result = super(IfContainer, self).__deepcopy__(memo)\n        result.cond = self.cond\n        result.elIfs = [(c, deepcopy(stms, memo)) for c, stms in self.elIfs]\n        return result\n\n    @internal\n    @override\n    def _collect_io(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._collect_io`\n        \"\"\"\n        if isinstance(self.cond, RtlSignalBase):\n            self._inputs.append(self.cond)\n        for c, _ in self.elIfs:\n            if isinstance(c, RtlSignalBase):\n                self._inputs.append(c)\n        super(IfContainer, self)._collect_io()\n\n    @internal\n    @override\n    def _collect_inputs(self) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._collect_inputs`\n        \"\"\"\n        if isinstance(self.cond, RtlSignalBase):\n            self._inputs.append(self.cond)\n        for c, _ in self.elIfs:\n            if isinstance(c, RtlSignalBase):\n                self._inputs.append(c)\n        super(IfContainer, self)._collect_inputs()\n\n    @internal\n    @override\n    def _clean_signal_meta(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._clean_signal_meta`\n        \"\"\"\n        self._sensitivity = None\n        self._ifTrue_enclosed_for = None\n        self._elIfs_enclosed_for = None\n        self._ifFalse_enclosed_for = None\n        HdlStatement._clean_signal_meta(self)\n\n    @internal\n    @override\n    def _cut_off_drivers_of(self, sig: RtlSignalBase):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._cut_off_drivers_of`\n        \"\"\"\n        if self._try_cut_off_whole_stm(sig):\n            return self\n\n        # try to cut off all statements which are drivers of specified signal\n        # in all branches\n        child_keep_mask = []\n\n        newIfTrue = []\n        all_cut_off = True\n        all_cut_off &= HdlStatement_cut_off_drivers_of_list(\n            sig, self.ifTrue, child_keep_mask, newIfTrue)\n        self.ifTrue = ListOfHdlStatement(compress(self.ifTrue, child_keep_mask))\n\n        newElifs = []\n        anyElifHit = False\n        for cond, stms in self.elIfs:\n            newCase = []\n            child_keep_mask.clear()\n            all_cut_off &= HdlStatement_cut_off_drivers_of_list(\n                sig, stms, child_keep_mask, newCase)\n\n            _stms = list(compress(stms, child_keep_mask))\n            stms.clear()\n            stms.extend(_stms)\n\n            if newCase:\n                anyElifHit = True\n            newElifs.append((cond, newCase))\n\n        newIfFalse = None\n        if self.ifFalse:\n            newIfFalse = []\n            child_keep_mask.clear()\n            all_cut_off &= HdlStatement_cut_off_drivers_of_list(\n                sig, self.ifFalse, child_keep_mask, newIfFalse)\n            self.ifFalse = ListOfHdlStatement(compress(self.ifFalse, child_keep_mask))\n\n        assert not all_cut_off, \"everything was cut of but this should be already known at the start\"\n\n        if newIfTrue or newIfFalse or anyElifHit or newIfFalse:\n            # parts were cut off\n            # generate new statement for them\n            cond_sig = self.cond\n            n = self.__class__(cond_sig, newIfTrue)\n            for c_sig, stms in newElifs:\n                n.Elif(c_sig, stms)\n            if newIfFalse is not None:\n                n.Else(newIfFalse)\n\n            if self.parentStm is None:\n                ctx = n._get_rtl_context()\n                ctx.statements.add(n)\n\n            self._cut_off_drivers_of_regenerate_io(sig, n)\n\n            return n\n\n    @internal\n    @override\n    def _discover_enclosure(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_enclosure`\n        \"\"\"\n        outputs = self._outputs\n        self._ifTrue_enclosed_for = HdlStatement_discover_enclosure_for_statements(\n            self.ifTrue, outputs)\n\n        elif_encls = self._elIfs_enclosed_for = []\n        for _, stms in self.elIfs:\n            e = HdlStatement_discover_enclosure_for_statements(\n                stms, outputs)\n            elif_encls.append(e)\n\n        self._ifFalse_enclosed_for = HdlStatement_discover_enclosure_for_statements(\n            self.ifFalse, outputs)\n\n        assert self._enclosed_for is None\n        encl = self._enclosed_for = set()\n\n        for s in self._ifTrue_enclosed_for:\n            enclosed = True\n\n            for elif_e in elif_encls:\n                if s not in elif_e:\n                    enclosed = False\n                    break\n\n            if enclosed and s in self._ifFalse_enclosed_for:\n                encl.add(s)\n\n    @internal\n    @override\n    def _discover_sensitivity(self, seen: set) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_sensitivity`\n        \"\"\"\n        assert self._sensitivity is None, self\n        ctx = self._sensitivity = SensitivityCtx()\n\n        discover_sensitivity_of_sig(self.cond, seen, ctx)\n        if ctx.contains_ev_dependency:\n            return\n\n        for stm in self.ifTrue:\n            stm._discover_sensitivity(seen)\n            ctx.extend(stm._sensitivity)\n\n        # elifs\n        for cond, stms in self.elIfs:\n            if ctx.contains_ev_dependency:\n                break\n\n            discover_sensitivity_of_sig(cond, seen, ctx)\n            if ctx.contains_ev_dependency:\n                break\n\n            for stm in stms:\n                if ctx.contains_ev_dependency:\n                    break\n\n                stm._discover_sensitivity(seen)\n                ctx.extend(stm._sensitivity)\n\n        if self.ifFalse:\n            assert not ctx.contains_ev_dependency, \"can not negate event\"\n            # else\n            for stm in self.ifFalse:\n                stm._discover_sensitivity(seen)\n                ctx.extend(stm._sensitivity)\n\n    @internal\n    @override\n    def _fill_enclosure(self, enclosure: Dict[RtlSignalBase, Callable[[], HdlStatement]]) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._fill_enclosure`\n        \"\"\"\n        enc = []\n        outputs = self._outputs\n        for e in sorted(enclosure.keys(), key=RtlSignal_sort_key):\n            if e in outputs and e not in self._enclosed_for:\n                enc.append(e)\n\n        if not enc:\n            return\n        fill_stm_list_with_enclosure(self, self._ifTrue_enclosed_for,\n                                     self.ifTrue, enc, enclosure)\n\n        for (_, stms), e in zip(self.elIfs, self._elIfs_enclosed_for):\n            fill_stm_list_with_enclosure(self, e, stms, enc, enclosure)\n\n        self.ifFalse = fill_stm_list_with_enclosure(self, self._ifFalse_enclosed_for,\n                                                    self.ifFalse, enc, enclosure)\n\n        self._enclosed_for.update(enc)\n\n    @internal\n    @override\n    def _iter_stms(self) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms`\n        \"\"\"\n        yield from self.ifTrue\n        for _, stms in self.elIfs:\n            yield from stms\n        if self.ifFalse is not None:\n            yield from self.ifFalse\n\n    @internal\n    @override\n    def _iter_stms_for_output(self, output: RtlSignalBase) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms_for_output`\n        \"\"\"\n        yield from self.ifTrue.iterStatementsWithOutput(output)\n        for _, stms in self.elIfs:\n            yield from stms.iterStatementsWithOutput(output)\n        if self.ifFalse is not None:\n            yield from self.ifFalse.iterStatementsWithOutput(output)\n\n    @internal\n    def _iter_all_elifs(self) -> Generator[Tuple[RtlSignalBase, ListOfHdlStatement], None, None]:\n        yield (self.cond, self.ifTrue)\n        yield from self.elIfs\n\n    @internal\n    @override\n    def _try_reduce(self) -> Tuple[bool, ListOfHdlStatement]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._try_reduce`\n        \"\"\"\n        # flag if IO of statement has changed\n        io_change = False\n\n        self.ifTrue, rank_decrease, _io_change = HdlStatement_try_reduce_list(\n            self.ifTrue)\n        self.rank -= rank_decrease\n        io_change |= _io_change\n\n        new_elifs = []\n        for cond, statements in self.elIfs:\n            _statements, rank_decrease, _io_change = HdlStatement_try_reduce_list(\n                statements)\n            self.rank -= rank_decrease\n            io_change |= _io_change\n            new_elifs.append((cond, _statements))\n        self.elIfs = new_elifs\n\n        if self.ifFalse is not None:\n            self.ifFalse, rank_decrease, _io_update_required = HdlStatement_try_reduce_list(\n                self.ifFalse)\n            self.rank -= rank_decrease\n            io_change |= _io_change\n\n        reduce_self = not self._condHasEffect(\n            self.ifTrue, self.ifFalse, self.elIfs)\n\n        if reduce_self:\n            res = self.ifTrue\n        else:\n            res = ListOfHdlStatement((self,))\n\n        self._on_reduce(reduce_self, io_change, res)\n\n        # try merge nested ifs as elifs\n        if self.ifFalse is not None and len(self.ifFalse) == 1:\n            child = self.ifFalse[0]\n            if isinstance(child, IfContainer):\n                self._merge_nested_if_from_else(child)\n\n        return res, io_change\n\n    @internal\n    def _merge_nested_if_from_else(self, ifStm: \"IfContainer\"):\n        \"\"\"\n        Merge nested IfContarner form else branch to this IfContainer\n        as elif and else branches\n        \"\"\"\n        self.elIfs.append((ifStm.cond, ifStm.ifTrue))\n        self.elIfs.extend(ifStm.elIfs)\n\n        self.ifFalse = ifStm.ifFalse\n\n    @internal\n    @override\n    def _is_mergable(self, other: HdlStatement) -> bool:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._is_mergable`\n        \"\"\"\n        if not isinstance(other, IfContainer):\n            return False\n\n        if (self.cond is not other.cond\n                or not is_mergable_statement_list(self.ifTrue, other.ifTrue)):\n            return False\n\n        if len(self.elIfs) != len(other.elIfs):\n            return False\n\n        for (a_c, a_stm), (b_c, b_stm) in zip(self.elIfs, other.elIfs):\n            if a_c is not b_c or not is_mergable_statement_list(a_stm, b_stm):\n                return False\n\n        return is_mergable_statement_list(self.ifFalse, other.ifFalse)\n\n    @internal\n    @override\n    def _merge_with_other_stm(self, other: \"IfContainer\") -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._merge_with_other_stm`\n        \"\"\"\n        merge = HdlStatement_merge_statement_lists\n        self.ifTrue = merge(self.ifTrue, other.ifTrue)\n\n        new_elifs = []\n        for ((c, elifA), (_, elifB)) in zip(self.elIfs, other.elIfs):\n            new_elifs.append((c, merge(elifA, elifB)))\n        self.elIfs = new_elifs\n\n        self.ifFalse = merge(self.ifFalse, other.ifFalse)\n\n        other.ifTrue = None\n        other.elIfs = None\n        other.ifFalse = None\n\n        self._on_merge(other)\n\n    @internal\n    @staticmethod\n    def _condHasEffect(ifTrue, ifFalse, elIfs):\n        stmCnt = len(ifTrue)\n        # [TODO] condition in empty if stm\n        if ifFalse is not None \\\n                and stmCnt == len(ifFalse) \\\n                and reduce(and_,\n                           [len(stm) == stmCnt\n                            for _, stm in elIfs],\n                           True):\n            for stms in zip(ifTrue, ifFalse, *map(lambda x: x[1], elIfs)):\n                if not statementsAreSame(stms):\n                    return True\n            return False\n        return True\n\n    @override\n    def isSame(self, other: HdlStatement) -> bool:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement.isSame`\n        \"\"\"\n        if self is other:\n            return True\n\n        if self.rank != other.rank:\n            return False\n\n        if isinstance(other, IfContainer):\n            if self.cond is other.cond:\n                if len(self.ifTrue) == len(other.ifTrue) \\\n                        and ((self.ifFalse is None and other.ifFalse is None) or\n                             len(self.ifFalse) == len(other.ifFalse)) \\\n                        and len(self.elIfs) == len(other.elIfs):\n                    if not isSameStatementList(self.ifTrue,\n                                               other.ifTrue) \\\n                            or not isSameStatementList(self.ifFalse,\n                                                       other.ifFalse):\n                        return False\n                    for (ac, astms), (bc, bstms) in zip(self.elIfs,\n                                                        other.elIfs):\n                        if not (ac == bc) or\\\n                                not isSameStatementList(astms, bstms):\n                            return False\n                    return True\n        return False\n    \n    @internal\n    @override\n    def _replace_input_nested(self, topStm: HdlStatement, toReplace: SignalReplaceSpecType) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_input`\n        \"\"\"\n        didUpdate = False\n        self.cond, _didUpdate = replace_input_in_expr(topStm, self, self.cond, toReplace)\n        didUpdate |= _didUpdate\n\n        for stm in self.ifTrue:\n            didUpdate |= stm._replace_input_nested(topStm, toReplace)\n\n        new_elifs = []\n        for (cond, stms) in self.elIfs:\n            new_cond, _didUpdate = replace_input_in_expr(topStm, self, cond, toReplace)\n            didUpdate |= _didUpdate\n            for stm in stms:\n                didUpdate |= stm._replace_input_nested(topStm, toReplace)\n            new_elifs.append((new_cond, stms))\n        self.elIfs = new_elifs\n\n        if self.ifFalse is not None:\n            for stm in self.ifFalse:\n                _didUpdate = stm._replace_input_nested(topStm, toReplace)\n                didUpdate |= _didUpdate\n\n        if didUpdate:\n            self._replace_input_update_sensitivity_and_inputs(toReplace)\n        return didUpdate\n\n    @internal\n    @override\n    def _replace_child_statement(self, stm:HdlStatement,\n            replacement:ListOfHdlStatement,\n            update_io:bool) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_child_statement`\n        \"\"\"\n\n        if update_io:\n            raise NotImplementedError()\n        for branch_list in (self.ifTrue, *(elif_stms for _, elif_stms in self.elIfs), self.ifFalse):\n            if branch_list is None:\n                continue\n            try:\n                i = branch_list.index(stm)\n            except ValueError:\n                # not in list\n                continue\n\n            branch_list.replace(self, stm, i, replacement)\n\n            # reset IO because it was shared with this statement\n            stm._destroy()\n            return\n\n        raise ValueError(\"Statement\", stm, \"not found in \", self)\n\n"
  },
  {
    "path": "hwt/hdl/statements/statement.py",
    "content": "from copy import deepcopy, copy\nfrom itertools import chain\nfrom typing import List, Tuple, Union, Optional, Dict, Callable, Generator\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.hdlObject import HdlObject\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.arrayQuery import flatten\nfrom hwt.pyUtils.setList import SetList\n\n\nclass HwtSyntaxError(Exception):\n    pass\n\nSignalReplaceSpecType = Union[Tuple[RtlSignalBase, RtlSignalBase], Dict[RtlSignalBase, RtlSignalBase]]\n\n\nclass HdlStatement(HdlObject):\n    \"\"\"\n    :ivar ~._event_dependent_from_branch: index of code branch if statement is event (clk) dependent else None\n    :ivar ~.parentStm: parent instance of HdlStatement or None\n    :ivar ~.parentStmList: list in parent statement where this statement is stored\n    :ivar ~._inputs: SetList of input signals for this statement\n        (All input signals which are directly used in any statement. Note that the expression is also the signal.)\n    :ivar ~._outputs: SetList of output signals for this statement\n    :ivar ~._sensitivity: SetList of input signals\n        or (rising/falling) operator\n    :ivar ~._enclosed_for: set of outputs for which this statement is enclosed\n        (for which there is not any unused branch)\n    :ivar ~.rank: number of used branches in statement, used as pre-filter\n        for statement comparing\n    \"\"\"\n    _DEEPCOPY_SKIP = ('parentStm', 'parentStmList')\n    _DEEPCOPY_SHALLOW_ONLY = (\"_inputs\", \"_outputs\", \"_enclosed_for\", \"_sensitivity\")\n\n    def __init__(self, parentStm:Optional[\"HdlStatement\"]=None,\n                 parentStmList: Optional[\"ListOfHdlStatement\"]=None,\n                 sensitivity:Optional[SetList]=None,\n                 event_dependent_from_branch:Optional[int]=None):\n        assert event_dependent_from_branch is None or isinstance(event_dependent_from_branch, int), event_dependent_from_branch\n        self._event_dependent_from_branch = event_dependent_from_branch\n        self.parentStm = parentStm\n        self.parentStmList = parentStmList\n        self._inputs = SetList()\n        self._outputs = SetList()\n        self._enclosed_for = None\n\n        self._sensitivity = sensitivity\n        self.rank = 0\n\n    def __deepcopy__(self, memo: dict):\n        cls = self.__class__\n        result = cls.__new__(cls)\n        memo[id(self)] = result\n        for k, v in self.__dict__.items():\n            if v is None:\n                new_v = None\n            elif k in self._DEEPCOPY_SKIP:\n                new_v = None\n            elif k in self._DEEPCOPY_SHALLOW_ONLY:\n                new_v = copy(v)\n            else:\n                new_v = deepcopy(v, memo)\n\n            setattr(result, k, new_v)\n\n        return result\n\n    @internal\n    def _clean_signal_meta(self):\n        \"\"\"\n        Clean informations about enclosure for outputs and sensitivity\n        of this statement\n        \"\"\"\n        self._enclosed_for = None\n        self._sensitivity = None\n        for stm in self._iter_stms():\n            stm._clean_signal_meta()\n\n    @internal\n    def _collect_io(self) -> None:\n        \"\"\"\n        Collect inputs/outputs from all child statements\n        to :py:attr:`~_input` / :py:attr:`_output` attribute on this object\n        \"\"\"\n        in_add = self._inputs.extend\n        out_add = self._outputs.extend\n\n        for stm in self._iter_stms():\n            in_add(stm._inputs)\n            out_add(stm._outputs)\n\n        if self.parentStmList is not None:\n            for o in self._outputs:\n                self.parentStmList._registerOutput(o, self)\n\n    @internal\n    def _collect_inputs(self) -> None:\n        \"\"\"\n        Collect inputs from all child statements\n        to :py:attr:`~_input` attribute on this object\n        \"\"\"\n        in_add = self._inputs.extend\n\n        for stm in self._iter_stms():\n            in_add(stm._inputs)\n\n    @internal\n    def _collect_outputs(self) -> None:\n        \"\"\"\n        Collect inputs from all child statements\n        to :py:attr:`_output` attribute on this object\n        \"\"\"\n\n        out_add = self._outputs.extend\n\n        for stm in self._iter_stms():\n            out_add(stm._outputs)\n\n        if self.parentStmList is not None:\n            for o in self._outputs:\n                self.parentStmList._registerOutput(o, self)\n\n    @internal\n    def _try_cut_off_whole_stm(self, sig: RtlSignalBase) -> bool:\n        \"\"\"\n        Try cut of output from statement and if this is only output of statement cut off whole statement.\n        Otherwise prepare for cutting of the signal from this statement.\n\n        :param sig: signal which drivers should be removed\n        :return: true if was removed or False if pruning of sig from this statement is required\n        \"\"\"\n        if self._sensitivity is not None or self._enclosed_for is not None:\n                raise NotImplementedError(\n                    \"Sensitivity and enclosure has to be cleaned first\")\n\n        if self.parentStmList is not None:\n            self.parentStmList._unregisterOutput(sig, self)\n\n        if len(self._outputs) == 1 and sig is self._outputs[0]:\n            # this statement has only this output, eject this statement from its parent\n            self.parentStm = None  # because new parent will be asigned immediately after cutting of\n            self.parentStmList = None\n            return True\n\n        sig._rtlDrivers.discard(self)\n        return False\n\n    @internal\n    def _cut_off_drivers_of(self, sig: RtlSignalBase) -> Union[None, \"HdlStatement\", List[\"HdlStatement\"]]:\n        \"\"\"\n        Cut all logic from statements which drives signal sig.\n\n        :param sig: signal which drivers should be removed\n        :return: A statement or statement list which was cut off from the original statement\n        \"\"\"\n        raise NotImplementedError(\"This is an abstract method and it should be implemented in child class\",\n                                  self.__class__)\n\n    @internal\n    def _cut_off_drivers_of_regenerate_io(self, cut_off_sig: RtlSignalBase, cut_of_smt: \"HdlStatement\"):\n        \"\"\"\n        Update _inputs/_outputs after some part of statement was cut of\n\n        :param cut_off_sig: a signal which driver is a cut_of_stm\n        :param cut_of_smt: the statement wich was cut off from original statement (selected by cut_off_sig)\n        \"\"\"\n        # update io of this\n        self._outputs.remove(cut_off_sig)\n        if cut_of_smt._inputs:\n            # update inputs on this\n            self._inputs.clear()\n            self._collect_inputs()\n            if self.parentStm is None:\n                for i in cut_of_smt._inputs:\n                    if i not in self._inputs:\n                        i._rtlEndpoints.remove(self)\n\n        if self.parentStm is None:\n            cut_off_sig._rtlDrivers.append(cut_of_smt)\n\n        if self.parentStmList is not None:\n            self.parentStmList._unregisterOutput(cut_off_sig, self)\n\n    @internal\n    def _discover_enclosure(self) -> None:\n        \"\"\"\n        Discover all outputs for which is this statement enclosed _enclosed_for property\n        (has driver in all code branches)\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__, self)\n\n    @internal\n    def _discover_sensitivity(self, seen: set) -> None:\n        \"\"\"\n        discover all sensitivity signals and store them to _sensitivity property\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__, self)\n\n    @internal\n    def _fill_enclosure(self, enclosure: Dict[RtlSignalBase, Callable[[], 'HdlStatement']]) -> None:\n        \"\"\"\n        Add assignments to a default values to a code branches which are not assigning to specified output signal.\n\n        :attention: enclosure has to be discoverd first use _discover_enclosure()  method\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__, self)\n\n    @internal\n    def _get_rtl_context(self) -> 'RtlNetlist':\n        \"\"\"\n        get RtlNetlist context from signals\n        \"\"\"\n        for sig in chain(self._inputs, self._outputs):\n            if sig._rtlCtx:\n                return sig._rtlCtx\n            else:\n                # Param instances does not have context\n                continue\n        raise HwtSyntaxError(\n            \"Statement does not have any signal in any context,\"\n            \" it should have at least some output or should be alreary optimized out\", self)\n\n    @internal\n    def _iter_stms(self):\n        \"\"\"\n        :return: iterator over all children statements\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__,\n                                  self)\n\n    @internal\n    def _iter_stms_for_output(self, output: RtlSignalBase) -> Generator[\"HdlStatement\", None, None]:\n        \"\"\"\n        :return: iterator of sub statements which have specified output as an output\n        \"\"\"\n        return\n        yield\n\n    @internal\n    def _merge_with_other_stm(self, other: \"HdlStatement\") -> None:\n        \"\"\"\n        :attention: statements has to be mergable (to check use _is_mergable method)\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__,\n                                  self)\n\n    @internal\n    def _on_reduce(self, self_reduced: bool, io_changed: bool,\n                   result_statements: List[\"HdlStatement\"]) -> None:\n        \"\"\"\n        Update signal IO after reduce attempt\n\n        :param self_reduced: if True this object was reduced\n        :param io_changed: if True IO of this object may changed\n            and has to be updated\n        :param result_statements: list of statements which are result\n            of reduce operation on this statement\n        \"\"\"\n\n        parentStm = self.parentStm\n        parentStmList = self.parentStmList\n        \n        if self_reduced:\n            was_top = parentStm is None\n            # update signal drivers/endpoints\n            if was_top:\n                # disconnect self from signals\n                ctx = self._get_rtl_context()\n                ctx.statements.remove(self)\n                ctx.statements.update(result_statements)\n\n                for i in self._inputs:\n                    i._rtlEndpoints.discard(self)\n                for o in self._outputs:\n                    o._rtlDrivers.remove(self)\n\n            for stm in result_statements:\n                stm.parentStm = parentStm\n                stm.parentStmList = parentStmList\n                if was_top:\n                    # connect signals to child statements\n                    for inp in stm._inputs:\n                        inp._rtlEndpoints.append(stm)\n                    for outp in stm._outputs:\n                        outp._rtlDrivers.append(stm)\n                else:\n                    for outp in stm._outputs:\n                        if parentStmList is not None:\n                            parentStmList._registerOutput(outp, stm)\n        else:\n            # parent has to update it's inputs/outputs\n            if io_changed:\n                if parentStmList is not None:\n                    for o in self._outputs:\n                        parentStmList._unregisterOutput(o, self)\n                self._inputs = SetList()\n                self._outputs = SetList()\n                self._collect_io()\n\n    @internal\n    def _on_merge(self, other: \"HdlStatement\"):\n        \"\"\"\n        After merging statements update IO, sensitivity and context\n\n        :attention: rank is not updated\n        \"\"\"\n        self._inputs.extend(other._inputs)\n        if self.parentStmList is not None:\n            for o in other._outputs:\n                if o not in self._outputs:\n                    self._outputs.append(o)\n                    self.parentStmList._registerOutput(o, self)\n        else:\n            self._outputs.extend(other._outputs)\n\n        if self._sensitivity is not None:\n            self._sensitivity.extend(other._sensitivity)\n        else:\n            assert other._sensitivity is None\n\n        if self._enclosed_for is not None:\n            self._enclosed_for.update(other._enclosed_for)\n        else:\n            assert other._enclosed_for is None\n\n        other_was_top = other.parentStm is None\n        if other_was_top:\n            other._get_rtl_context().statements.remove(other)\n            for s in other._inputs:\n                s._rtlEndpoints.discard(other)\n                s._rtlEndpoints.append(self)\n\n            for s in other._outputs:\n                s._rtlDrivers.discard(other)\n                s._rtlDrivers.append(self)\n\n    @internal\n    def _try_reduce(self) -> Tuple[List[\"HdlStatement\"], bool]:\n        raise NotImplementedError(\"This method should be implemented\"\n                                  \" on class of statement\", self.__class__,\n                                  self)\n\n    def _is_enclosed(self) -> bool:\n        \"\"\"\n        :return: True if every branch in statement assignas to all output signals else False\n        \"\"\"\n        return len(self._outputs) == len(self._enclosed_for)\n\n    @internal\n    def _is_mergable(self, other: \"HdlStatement\") -> bool:\n        if self is other:\n            raise ValueError(\"Can not merge statement with itself\")\n        else:\n            raise NotImplementedError(\"This method should be implemented\"\n                                      \" on class of statement\", self.__class__,\n                                      self)\n\n    @internal\n    def _on_parent_event_dependent(self):\n        \"\"\"\n        After parent statement become event dependent\n        propagate event dependency flag to child statements\n        \"\"\"\n        if self._event_dependent_from_branch != 0:\n            self._event_dependent_from_branch = 0\n            for stm in self._iter_stms():\n                stm._on_parent_event_dependent()\n\n    @internal\n    def _set_parent_stm(self, parentStm: \"HdlStatement\", parentStmList: \"ListOfHdlStatements\"):\n        \"\"\"\n        Assign parent statement and propagate dependency flags if necessary\n        \"\"\"\n        assert parentStm is not self.parentStm\n        was_top = self.parentStm is None\n        self.parentStm = parentStm\n        if self._event_dependent_from_branch is None\\\n                and parentStm._event_dependent_from_branch is not None:\n            self._on_parent_event_dependent()\n\n        topStatement = parentStm\n        parents = []\n        while True:\n            parents.append(topStatement)\n            if topStatement.parentStm is None:\n                break\n            topStatement = topStatement.parentStm\n\n        if was_top:\n            for inp in self._inputs:\n                inp._rtlEndpoints.discard(self)\n                inp._rtlEndpoints.append(topStatement)\n                for p in parents:\n                    p._inputs.append(inp)\n\n            for outp in self._outputs:\n                outp._rtlDrivers.discard(self)\n                outp._rtlDrivers.append(topStatement)\n                for p in parents:\n                    p._outputs.append(outp)\n\n            ctx = self._get_rtl_context()\n            ctx.statements.discard(self)\n\n        parentStm.rank += self.rank\n        self.parentStmList = parentStmList\n        for o in self._outputs:\n            parentStmList._registerOutput(o, self)\n\n    @internal\n    def _register_stements(self, statements: List[\"HdlStatement\"],\n                           target: \"ListOfHdlStatements\"):\n        \"\"\"\n        Append statements to this container\n        \"\"\"\n        for stm in flatten(statements):\n            assert stm.parentStm is None, (\n                \"HdlStatement instance has to have only a single parent\", stm)\n            stm._set_parent_stm(self, target)\n            target.append(stm)\n\n    def isSame(self, other: \"HdlStatement\") -> bool:\n        \"\"\"\n        :return: True if other has same meaning as self\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented in child class\", self.__class__, self)\n\n    @internal\n    def _destroy(self):\n        \"\"\"\n        Disconnect this statement from signals and delete it from RtlNetlist context\n\n        :attention: signal endpoints/drivers will be altered\n            that means they can not be used for iteration\n        \"\"\"\n        for i in self._inputs:\n            i._rtlEndpoints.discard(self)\n\n        if self.parentStm is None:\n            ctx = self._get_rtl_context()\n            for o in self._outputs:\n                o._rtlDrivers.remove(self)\n\n            ctx.statements.remove(self)\n            self.parentStm = None\n\n            if self.parentStmList is not None:\n                self.parentStmList = None\n                for o in self._outputs:\n                    self.parentStmList._unregisterOutput(o, self)\n\n    @internal\n    def _replace_input_nested(self, topStm: \"HdlStatement\", toReplace: SignalReplaceSpecType) -> None:\n        raise NotImplementedError(\"This method should be implemented in child class\", self.__class__, self)\n\n    @internal\n    def _replace_input(self, toReplace: SignalReplaceSpecType) -> bool:\n        \"\"\"\n        Replace input signal with another\n        :return: True if the expression was present in this statement (and was replaced)\n        :note: sensitivity/endpoints are actualized\n        :note: calling on children does not update parent's _inputs, _sensitivity or _enclosed_for\n        \"\"\"\n        assert self.parentStm is None, self\n        return self._replace_input_nested(self, toReplace)\n\n    @internal\n    def _replace_input_update_sensitivity_and_inputs(\n            self,\n            toReplace: SignalReplaceSpecType):\n        \"\"\"\n        This function updates _sensitivity and _inputs containers after the input was replaced in this statement.\n\n        :attention: it does not perform the replace of the input. It should be called after the replace.\n        \"\"\"\n        \n        # if we replace something some input expression may be altered thus full re-computation is required\n        self._inputs.clear()\n        self._collect_inputs()\n        if self._sensitivity is not None:\n            self._sensitivity = None\n            self._discover_sensitivity(set())\n\n    @internal\n    def _replace_child_statement(self, stm: \"HdlStatement\",\n                                 replacement: List[\"HdlStatement\"],\n                                 update_io: bool) -> None:\n        \"\"\"\n        Replace a child statement with a list of other statements\n\n        :attention: original statement is destroyed and entirely removed from circuit\n        :note: sensitivity/endoints are actualized\n        \"\"\"\n        raise NotImplementedError(\"This method should be implemented in child class\", self.__class__, self)\n\n"
  },
  {
    "path": "hwt/hdl/statements/switchContainer.py",
    "content": "from copy import deepcopy, copy\nfrom functools import reduce\nfrom itertools import compress\nfrom operator import and_\nfrom typing import List, Tuple, Dict, Optional, Callable, Set, Generator\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.constUtils import isSameHConst\nfrom hwt.hdl.operatorUtils import replace_input_in_expr\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.statement import HdlStatement, HwtSyntaxError, SignalReplaceSpecType\nfrom hwt.hdl.statements.utils.comparison import isSameStatementList, statementsAreSame\nfrom hwt.hdl.statements.utils.ioDiscovery import HdlStatement_discover_enclosure_for_statements\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.hdl.statements.utils.reduction import HdlStatement_merge_statement_lists, \\\n    HdlStatement_try_reduce_list, is_mergable_statement_list\nfrom hwt.hdl.statements.utils.signalCut import HdlStatement_cut_off_drivers_of_list\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.utils import RtlSignal_sort_key\nfrom hwt.synthesizer.rtlLevel.fill_stm_list_with_enclosure import fill_stm_list_with_enclosure\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass SwitchContainer(HdlStatement):\n    \"\"\"\n    Structural container for switch statement for hdl rendering\n\n    :ivar ~.switchOn: select signal of switch\n    :ivar ~.cases: list of tuples (value, statements)\n    :ivar ~.default: list of statements (for branch \"default\")\n    :ivar ~._case_value_index: dictionary {value:index} for every case in cases\n    :ivar ~._case_enclosed_for: list of sets of enclosed signal for each case branch\n    :ivar ~._default_enclosed_for: set of enclosed signals for branch default\n    \"\"\"\n    _DEEPCOPY_SKIP = (*HdlStatement._DEEPCOPY_SKIP, 'switchOn', 'cases')\n    _DEEPCOPY_SHALLOW_ONLY = (*HdlStatement._DEEPCOPY_SHALLOW_ONLY, '_case_value_index', '_case_enclosed_for', '_default_enclosed_for')\n\n    def __init__(self, switchOn: RtlSignal,\n                 cases: List[Tuple[HConst, ListOfHdlStatement]],\n                 default: Optional[ListOfHdlStatement]=None,\n                 parentStm: HdlStatement=None,\n                 event_dependent_from_branch: Optional[int]=None):\n\n        super(SwitchContainer, self).__init__(\n            parentStm=parentStm,\n            event_dependent_from_branch=event_dependent_from_branch)\n        self.switchOn = switchOn\n        self.cases = cases\n        self.default = default\n\n        self._case_value_index = {}\n        for i, (v, _) in enumerate(cases):\n            assert v not in self._case_value_index, v\n            self._case_value_index[v] = i\n\n        self._case_enclosed_for: Optional[List[Set[RtlSignal]]] = None\n        self._default_enclosed_for: Optional[Set[RtlSignal]] = None\n\n    @override\n    def __deepcopy__(self, memo: dict):\n        result = super(SwitchContainer, self).__deepcopy__(memo)\n        result.switchOn = self.switchOn\n        result.cases = [(c, deepcopy(stms, memo)) for c, stms in self.cases]\n        result._case_value_index = copy(self._case_value_index)\n        result._case_enclosed_for = copy(self._case_enclosed_for)\n        result._default_enclosed_for = copy(self._default_enclosed_for)\n        return result\n\n    @internal\n    @override\n    def _cut_off_drivers_of(self, sig: RtlSignalBase):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._cut_off_drivers_of`\n        \"\"\"\n        if self._try_cut_off_whole_stm(sig):\n            return self\n\n        # try to cut off all statements which are drivers of specified signal\n        # in all branches\n        child_keep_mask = []\n\n        all_cut_off = True\n        new_default = None\n        if self.default:\n            new_default = ListOfHdlStatement()\n            child_keep_mask.clear()\n            case_eliminated = HdlStatement_cut_off_drivers_of_list(\n                sig, self.default, child_keep_mask, new_default)\n            all_cut_off &= case_eliminated\n            if case_eliminated:\n                self.rank -= 1\n                self.default = None\n            else:\n                self.default = list(compress(self.default, child_keep_mask))\n\n        new_cases = []\n        case_keepmask = []\n        for val, stms in self.cases:\n            new_case = ListOfHdlStatement()\n            child_keep_mask.clear()\n            case_eliminated = HdlStatement_cut_off_drivers_of_list(\n                sig, stms, child_keep_mask, new_case)\n            if case_eliminated:\n                self.rank -= 1\n\n            all_cut_off &= case_eliminated\n            case_keepmask.append(not case_eliminated)\n\n            _stms = list(compress(stms, child_keep_mask))\n            stms.clear()\n            stms.extend(_stms)\n\n            if new_case or new_default:\n                # if there is a default we need to add case even in empty\n                # to prevent falling to default\n                new_cases.append((val, new_case))\n\n        self.cases = list(compress(self.cases, case_keepmask))\n\n        assert not all_cut_off, \"everything was cut of but this should be already known at start\"\n\n        if new_cases or new_default:\n            # parts were cut off\n            # generate new statement for them\n            sel_sig = self.switchOn\n            n = self.__class__(sel_sig)\n            n.add_cases(new_cases)\n            if new_default:\n                n.Default(*new_default)\n\n            if self.parentStm is None:\n                ctx = n._get_rtl_context()\n                ctx.statements.add(n)\n\n            self._cut_off_drivers_of_regenerate_io(sig, n)\n\n            return n\n\n    @internal\n    @override\n    def _clean_signal_meta(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._clean_signal_meta`\n        \"\"\"\n        self._case_enclosed_for = None\n        self._default_enclosed_for = None\n        HdlStatement._clean_signal_meta(self)\n\n    @internal\n    @override\n    def _collect_io(self):\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._collect_io`\n        \"\"\"\n        if isinstance(self.switchOn, RtlSignalBase):\n            self._inputs.append(self.switchOn)\n        for c, _ in self.cases:\n            if isinstance(c, RtlSignalBase):\n                self._inputs.append(c)\n        super(SwitchContainer, self)._collect_io()\n\n    @internal\n    @override\n    def _collect_inputs(self) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._collect_inputs`\n        \"\"\"\n        if isinstance(self.switchOn, RtlSignalBase):\n            self._inputs.append(self.switchOn)\n        for c, _ in self.cases:\n            if isinstance(c, RtlSignalBase):\n                self._inputs.append(c)\n        super(SwitchContainer, self)._collect_inputs()\n\n    @internal\n    @override\n    def _discover_enclosure(self) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_enclosure`\n        \"\"\"\n        assert self._enclosed_for is None\n        enclosure = self._enclosed_for = set()\n        case_enclosures = self._case_enclosed_for = []\n        outputs = self._outputs\n\n        for _, stms in self.cases:\n            c_e = HdlStatement_discover_enclosure_for_statements(stms, outputs)\n            case_enclosures.append(c_e)\n\n        self._default_enclosed_for = HdlStatement_discover_enclosure_for_statements(\n            self.default, outputs)\n\n        t = self.switchOn._dtype\n        if not self.default and len(self.cases) < t.domain_size():\n            # cases does not cover all branches\n            return\n\n        for s in outputs:\n            enclosed = True\n            for e in case_enclosures:\n                if s not in e:\n                    enclosed = False\n                    break\n\n            if enclosed and (not self.default or s in self._default_enclosed_for):\n                enclosure.add(s)\n\n    @internal\n    @override\n    def _discover_sensitivity(self, seen) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._discover_sensitivity`\n        \"\"\"\n        assert self._sensitivity is None, self\n        ctx = self._sensitivity = SensitivityCtx()\n\n        casual_sensitivity = set()\n        self.switchOn._walk_sensitivity(casual_sensitivity, seen, ctx)\n        if ctx.contains_ev_dependency:\n            raise HwtSyntaxError(\n                \"Can not switch on event operator result\", self.switchOn)\n        ctx.extend(casual_sensitivity)\n\n        for stm in self._iter_stms():\n            stm._discover_sensitivity(seen)\n            ctx.extend(stm._sensitivity)\n\n    @internal\n    @override\n    def _fill_enclosure(self, enclosure: Dict[RtlSignalBase, Callable[[], HdlStatement]]) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._fill_enclosure`\n        \"\"\"\n        select = []\n        outputs = self._outputs\n        for e in sorted(enclosure.keys(), key=RtlSignal_sort_key):\n            if e in outputs:\n                select.append(e)\n\n        for (_, stms), e in zip(self.cases, self._case_enclosed_for):\n            fill_stm_list_with_enclosure(self, e, stms, select, enclosure)\n            e.update(select)\n\n        t = self.switchOn._dtype\n        default_required = len(self.cases) < t.domain_size()\n\n        if self.default is not None or default_required:\n            self.default = fill_stm_list_with_enclosure(\n                self, self._default_enclosed_for, self.default, select, enclosure)\n            self._default_enclosed_for.update(select)\n\n        self._enclosed_for.update(select)\n\n    @internal\n    @override\n    def _iter_stms(self) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms`\n        \"\"\"\n        for _, stms in self.cases:\n            yield from stms\n\n        if self.default is not None:\n            yield from self.default\n\n    @internal\n    @override\n    def _iter_stms_for_output(self, output: RtlSignalBase) -> Generator[HdlStatement, None, None]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._iter_stms_for_output`\n        \"\"\"\n        for _, stms in self.cases:\n            yield from stms.iterStatementsWithOutput(output)\n\n        if self.default is not None:\n            yield from self.default.iterStatementsWithOutput(output)\n\n    @internal\n    @override\n    def _is_mergable(self, other) -> bool:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._is_mergable`\n        \"\"\"\n        if not isinstance(other, SwitchContainer):\n            return False\n\n        if not (self.switchOn is other.switchOn and\n                len(self.cases) == len(other.cases) and\n                is_mergable_statement_list(self.default, other.default)):\n            return False\n\n        for (vA, caseA), (vB, caseB) in zip(self.cases, other.cases):\n            if vA != vB or not is_mergable_statement_list(caseA, caseB):\n                return False\n\n        return True\n\n    @internal\n    @override\n    def _merge_with_other_stm(self, other: \"SwitchContainer\") -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._merge_with_other_stm`\n        \"\"\"\n        merge = HdlStatement_merge_statement_lists\n        newCases = []\n        for (c, caseA), (_, caseB) in zip(self.cases, other.cases):\n            newCases.append((c, merge(caseA, caseB)))\n\n        self.cases = newCases\n        other.cases = None\n        self.default = merge(self.default, other.default)\n        other.default = None\n\n        self._on_merge(other)\n\n    @internal\n    @override\n    def _try_reduce(self) -> Tuple[List[\"HdlStatement\"], bool]:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._try_reduce`\n        \"\"\"\n        io_change = False\n\n        # try reduce the content of the case branches\n        new_cases = []\n        for val, statements in self.cases:\n            _statements, rank_decrease, _io_change = HdlStatement_try_reduce_list(\n                statements)\n            io_change |= _io_change\n            self.rank -= rank_decrease\n            new_cases.append((val, _statements))\n        self.cases = new_cases\n\n        # try reduce content of the defult branch\n        if self.default is not None:\n            self.default, rank_decrease, _io_change = HdlStatement_try_reduce_list(\n                self.default)\n            self.rank -= rank_decrease\n            io_change |= _io_change\n\n        # try reduce self\n        reduce_self = not self._condHasEffect()\n        if reduce_self:\n            if self.cases:\n                res = self.cases[0][1]\n            elif self.default is not None:\n                res = self.default\n            else:\n                res = []\n        else:\n            res = [self, ]\n\n        self._on_reduce(reduce_self, io_change, res)\n\n        if not self.default:\n            t = self.switchOn._dtype\n            if isinstance(t, HEnum):\n                dom_size = t.domain_size()\n                val_cnt = len(t._allValues)\n                if len(self.cases) == val_cnt and val_cnt < dom_size:\n                    # bit representation is not fully matching enum description\n                    # need to set last case as default to prevent latches\n                    _, stms = self.cases.pop()\n                    self.default = stms\n\n        return res, io_change\n\n    @internal\n    def _condHasEffect(self) -> bool:\n        \"\"\"\n        :return: True if statements in branches has different effect\n        \"\"\"\n        if not self.cases:\n            return False\n\n        # [TODO]\n        type_domain_covered = bool(self.default) or len(\n            self.cases) == self.switchOn._dtype.domain_size()\n\n        stmCnt = len(self.cases[0][1])\n        if type_domain_covered and reduce(\n                and_,\n                [len(stm) == stmCnt\n                 for _, stm in self.cases],\n                True) and (self.default is None\n                           or len(self.default) == stmCnt):\n            stms = list(self._iter_stms())\n            if statementsAreSame(stms):\n                return False\n            else:\n                return True\n        return True\n\n    @internal\n    @override\n    def _replace_input_nested(self, topStm: \"HdlStatement\", toReplace: SignalReplaceSpecType) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_input`\n        \"\"\"\n        didUpdate = False\n        self.switchOn, _didUpdate = replace_input_in_expr(topStm, self, self.switchOn, toReplace)\n        didUpdate |= _didUpdate\n\n        for (_, stms) in self.cases:\n            for stm in stms:\n                stm: HdlStatement\n                didUpdate |= stm._replace_input_nested(topStm, toReplace)\n\n        if self.default is not None:\n            for stm in self.default:\n                didUpdate |= stm._replace_input_nested(topStm, toReplace)\n\n        if didUpdate:\n            self._replace_input_update_sensitivity_and_inputs(toReplace)\n        return didUpdate\n\n    @internal\n    @override\n    def _replace_child_statement(self, stm: HdlStatement,\n            replacement:ListOfHdlStatement,\n            update_io:bool) -> None:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement._replace_child_statement`\n        \"\"\"\n\n        if update_io:\n            raise NotImplementedError()\n        for branch_list in (*(case_stms for _, case_stms in self.cases), self.default):\n            if branch_list is None:\n                continue\n            try:\n                i = branch_list.index(stm)\n            except ValueError:\n                # not in list\n                continue\n\n            branch_list.replace(self, stm, i, replacement)\n\n            # reset IO because it was shared with this statement\n            stm._destroy()\n            return\n\n        raise ValueError(\"Statement\", stm, \"not found in \", self)\n\n    @override\n    def isSame(self, other: HdlStatement) -> bool:\n        \"\"\"\n        :see: :meth:`hwt.hdl.statements.statement.HdlStatement.isSame`\n        \"\"\"\n        if self is other:\n            return True\n\n        if self.rank != other.rank:\n            return False\n\n        if isinstance(other, SwitchContainer) \\\n                and isSameHConst(self.switchOn, other.switchOn)\\\n                and len(self.cases) == len(other.cases)\\\n                and isSameStatementList(self.default, other.default):\n            for (ac, astm), (bc, bstm) in zip(self.cases, other.cases):\n                if not isSameHConst(ac, bc)\\\n                        or not isSameStatementList(astm, bstm):\n                    return False\n            return True\n        return False\n"
  },
  {
    "path": "hwt/hdl/statements/utils/__init__.py",
    "content": ""
  },
  {
    "path": "hwt/hdl/statements/utils/comparison.py",
    "content": "from hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\n\n\ndef isSameStatementList(stmListA: ListOfHdlStatement,\n                        stmListB: ListOfHdlStatement) -> bool:\n    \"\"\"\n    :return: True if two lists of HdlStatement instances are same\n    \"\"\"\n    if stmListA is stmListB:\n        return True\n    if stmListA is None or stmListB is None:\n        return False\n\n    for a, b in zip(stmListA, stmListB):\n        if not a.isSame(b):\n            return False\n\n    return True\n\n\ndef statementsAreSame(statements: ListOfHdlStatement) -> bool:\n    \"\"\"\n    :return: True if all statements are same\n    \"\"\"\n    iterator = iter(statements)\n    try:\n        first = next(iterator)\n    except StopIteration:\n        return True\n\n    return all(first.isSame(rest) for rest in iterator)\n"
  },
  {
    "path": "hwt/hdl/statements/utils/ioDiscovery.py",
    "content": "from typing import List, Set\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.mainBases import RtlSignalBase\n\n\n@internal\ndef HdlStatement_discover_enclosure_for_statements(\n        statements: ListOfHdlStatement,\n        outputs: List[RtlSignalBase]) -> Set[RtlSignalBase]:\n    \"\"\"\n    Discover enclosure for list of statements\n\n    :param statements: list of statements in one code branch\n    :param outputs: list of outputs which should be driven from this statement list\n    :return: set of signals for which this statement list have always some driver\n        (is enclosed)\n    \"\"\"\n    result = set()\n    if not statements:\n        return result\n\n    for stm in statements:\n        stm._discover_enclosure()\n\n    for o in outputs:\n        has_driver = False\n\n        for stm in statements.iterStatementsWithOutput(o):\n            assert not has_driver\n            has_driver = False\n            result.update(stm._enclosed_for)\n\n    return result\n\n"
  },
  {
    "path": "hwt/hdl/statements/utils/listOfHdlStatements.py",
    "content": "from copy import deepcopy\nfrom itertools import islice\nfrom typing import Sequence, Dict, List, Union\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass ListOfHdlStatement(list):\n    \"\"\"\n    A list of hdl statements used in statements to keep track of children\n    \"\"\"\n\n    def __init__(self, *args):\n        list.__init__(self)\n        self.firstStmWithBranchesI = None\n        self._outputToStatementList: Dict[RtlSignalBase, List[HdlStatement]] = {}\n        if args:\n            assert  len(args) == 1, (\"expected at most 1 argument\", args)\n            self.extend(args[0])\n\n    def append(self, v: HdlStatement):\n        if self.firstStmWithBranchesI is None and v.rank > 0:\n            self.firstStmWithBranchesI = len(self)\n\n        for o in v._outputs:\n            self._registerOutput(o, v)\n\n        return list.append(self, v)\n\n    def extend(self, stms: Sequence[HdlStatement]):\n        for v in stms:\n            self.append(v)\n\n    def insert(self, i: int, v: HdlStatement):\n        assert isinstance(i, int), i\n        res = list.insert(self, i, v)\n        self.firstStmWithBranchesI = NOT_SPECIFIED\n        for o in v._outputs:\n            self._registerOutput(o, v)\n\n        return res\n\n    def pop(self):\n        raise NotImplementedError()\n\n    def remove(self, item):\n        raise NotImplementedError()\n\n    def discard(self, item):\n        raise NotImplementedError()\n\n    def iterStatementsWithOutput(self, out: RtlSignalBase):\n        yield from self._outputToStatementList.get(out, ())\n\n    def _unregisterOutput(self, o: RtlSignalBase, stm: HdlStatement):\n        self._outputToStatementList[o].remove(stm)\n\n    def _registerOutput(self, o: RtlSignalBase, stm: HdlStatement):\n        self._outputToStatementList.setdefault(o, []).append(stm)\n\n    def __setitem__(self, index:Union[int, slice], value:Union[\"ListOfHdlStatement\", HdlStatement]):\n        cur = self[index]\n        if isinstance(index, int):\n            for o in cur._outputs:\n                self._outputToStatementList[o].remove(cur)\n        else:\n            for _cur in cur:\n                for o in _cur._outputs:\n                    self._outputToStatementList[o].remove(_cur)\n\n        res = list.__setitem__(self, index, value)\n        self.firstStmWithBranchesI = NOT_SPECIFIED\n        if isinstance(index, int):\n            for o in value._outputs:\n                self._registerOutput(o, value)\n        else:\n            for v in value:\n                for o in v._outputs:\n                    self._registerOutput(o, v)\n\n        return res\n\n    @internal\n    def _iter_stms_with_branches(self):\n        \"\"\"\n        :return: iterate statement with rank > 0\n        \"\"\"\n        startI = self.firstStmWithBranchesI\n        if startI is None:\n            return\n        elif startI is NOT_SPECIFIED:\n            # recompute firstStmWithBranchesI\n            startI = None\n            for i, stm in enumerate(self):\n                if stm.rank == 0:\n                    continue\n\n                if startI is None:\n                    startI = i\n\n            self.firstStmWithBranchesI = startI\n\n        else:\n            # use known firstStmWithBranchesI to skip not interesting\n            for stm in islice(self, startI, None):\n                if stm.rank == 0:\n                    continue\n                yield stm\n\n    def sort(self, *args, **kwargs):\n        res = list.sort(self, *args, **kwargs)\n        self.firstStmWithBranchesI = None\n        return res\n\n    def replace(self, parentStm: HdlStatement, toReplaceStm: HdlStatement, index: int, replacement: List[HdlStatement]):\n        \"\"\"\n        Replace a single statement in this list with the list of statements while updating all cached values.\n        \"\"\"\n        parentStm.rank -= toReplaceStm.rank\n        self[index:index + 1] = replacement\n        for o in toReplaceStm._outputs:\n            self._unregisterOutput(o, toReplaceStm)\n\n        for rstm in replacement:\n            for o in rstm._outputs:\n                self._registerOutput(o, rstm)\n            rstm._set_parent_stm(parentStm, self)\n\n    def __deepcopy__(self, memo: dict):\n        cls = self.__class__\n        result = cls(deepcopy(i, memo) for i in self)\n        memo[id(self)] = result\n        return result\n\n"
  },
  {
    "path": "hwt/hdl/statements/utils/reduction.py",
    "content": "from itertools import islice, zip_longest\nfrom typing import Tuple\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.pyUtils.arrayQuery import groupedby\nfrom hwt.constants import NOT_SPECIFIED\n\n\n@internal\ndef HdlStatement_merge_statement_lists(stmsA: ListOfHdlStatement, stmsB: ListOfHdlStatement)\\\n        ->ListOfHdlStatement:\n    \"\"\"\n    Merge two lists of statements into one\n\n    :return: list of merged statements\n    \"\"\"\n    if stmsA is None and stmsB is None:\n        return None\n    elif stmsA is None:\n        return stmsB\n    elif stmsB is None:\n        return stmsA\n\n    tmp = ListOfHdlStatement()\n\n    # copy all with already known not to merge\n    if stmsA.firstStmWithBranchesI is NOT_SPECIFIED:\n        # we need to check items ourselfs\n        a_it = iter(stmsA)\n    elif stmsA.firstStmWithBranchesI is not None:\n        # we know the first item which requires extra care, we can copy all predecessors\n        tmp.extend(islice(stmsA, 0, stmsA.firstStmWithBranchesI))\n        a_it = islice(stmsA, stmsA.firstStmWithBranchesI, None)\n    else:\n        # items do no require any care, we can copy them all, but instead we use original list\n        # to avoid copy\n        tmp = stmsA\n        a_it = iter(tuple())\n\n    if stmsB.firstStmWithBranchesI is not None:\n        tmp.extend(islice(stmsB, 0, stmsB.firstStmWithBranchesI))\n        b_it = islice(stmsB, stmsB.firstStmWithBranchesI, None)\n    else:\n        b_it = iter(stmsB)\n\n    a = None\n    b = None\n    a_empty = False\n    b_empty = False\n\n    while not a_empty and not b_empty:\n        while not a_empty:\n            a = next(a_it, None)\n            if a is None:\n                a_empty = True\n                break\n            elif a.rank == 0:\n                # simple statement does not require merging\n                tmp.append(a)\n                a = None\n            else:\n                break\n\n        while not b_empty:\n            b = next(b_it, None)\n            if b is None:\n                b_empty = True\n                break\n            elif b.rank == 0:\n                # simple statement does not require merging\n                tmp.append(b)\n                b = None\n            else:\n                break\n\n        if a is not None or b is not None:\n            if a is None:\n                a = b\n                b = None\n\n            if a is not None and b is not None:\n                a._merge_with_other_stm(b)\n\n            tmp.append(a)\n            a = None\n            b = None\n\n    return tmp\n\n\n@internal\ndef HdlStatement_try_reduce_list(statements: ListOfHdlStatement)\\\n        ->Tuple[ListOfHdlStatement, int, bool]:\n    \"\"\"\n    Simplify statements in the list\n    \"\"\"\n    io_change = False\n    new_statements = ListOfHdlStatement()\n\n    for stm in statements:\n        reduced, _io_change = stm._try_reduce()\n        new_statements.extend(reduced)\n        io_change |= _io_change\n\n    new_statements, rank_decrease = HdlStatement_merge_statements(\n        new_statements)\n\n    new_statements, io_change, _rank_decrease = HdlStatement_reduce_overridden_assignments(new_statements)\n    rank_decrease += _rank_decrease\n    return new_statements, rank_decrease, io_change\n\n\n@internal\ndef HdlStatement_reduce_overridden_assignments(statements: ListOfHdlStatement)\\\n        ->Tuple[ListOfHdlStatement, bool, int]:\n    io_change = False\n    new_statements = []\n    rank_decrease = 0\n\n    fully_driven_outputs = set()\n    for stm in reversed(statements):\n        if fully_driven_outputs.issuperset(stm._outputs):\n            rank_decrease += stm.rank\n            io_change = True\n            continue\n\n        if isinstance(stm, HdlAssignmentContainer):\n            fully_driven_outputs.update(stm._outputs)\n\n        new_statements.append(stm)\n\n    return ListOfHdlStatement(reversed(new_statements)), io_change, rank_decrease\n\n\n@internal\ndef HdlStatement_merge_statements(statements: ListOfHdlStatement)\\\n        ->Tuple[ListOfHdlStatement, int]:\n    \"\"\"\n    Merge statements in list to remove duplicated if-then-else trees\n\n    :return: tuple (list of merged statements, rank decrease due merging)\n    :note: rank decrease is sum of ranks of reduced statements\n    :attention: statement list has to me mergable\n    \"\"\"\n    order = {}\n    for i, stm in enumerate(statements):\n        order[stm] = i\n\n    new_statements = ListOfHdlStatement()\n    rank_decrease = 0\n\n    for rank, stms in groupedby(statements, lambda s: s.rank):\n        if rank == 0:\n            new_statements.extend(stms)\n        else:\n            if len(stms) == 1:\n                new_statements.extend(stms)\n                continue\n\n            # try to merge statements if they are same condition tree\n            for iA, stmA in enumerate(stms):\n                if stmA is None:\n                    continue\n\n                for iB, stmB in enumerate(islice(stms, iA + 1, None)):\n                    if stmB is None:\n                        continue\n\n                    if stmA._is_mergable(stmB):\n                        rank_decrease += stmB.rank\n                        stmA._merge_with_other_stm(stmB)\n                        stms[iA + 1 + iB] = None\n\n                new_statements.append(stmA)\n\n    new_statements.sort(key=lambda stm: order[stm])\n    return new_statements, rank_decrease\n\n\n@internal\ndef is_mergable_statement_list(stmsA: ListOfHdlStatement, stmsB: ListOfHdlStatement):\n    \"\"\"\n    Walk statements and compare if they can be merged into one statement list\n    \"\"\"\n    if stmsA is None and stmsB is None:\n        return True\n\n    elif stmsA is None or stmsB is None:\n        return False\n\n    # [todo] there is a performance error when the list has no statements with rank != 0\n    # all items needs to be checked everytime, for \"rtl register if (clk)\" statements\n    # this is a problem as this list can grow large (100K+ items) and needs to be compared with every\n    # not yet merged statement\n    for (a, b) in zip_longest(stmsA._iter_stms_with_branches(),\n                              stmsB._iter_stms_with_branches()):\n        if a is None or b is None or not a._is_mergable(b):\n            return False\n\n    # lists are empty\n    return True\n\n"
  },
  {
    "path": "hwt/hdl/statements/utils/signalCut.py",
    "content": "from typing import List\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.mainBases import RtlSignalBase\n\n\n@internal\ndef HdlStatement_cut_off_drivers_of_list(sig: RtlSignalBase,\n                             statements: ListOfHdlStatement,\n                             keep_mask: List[bool],\n                             new_statements: ListOfHdlStatement) -> bool:\n    \"\"\"\n    Cut all logic from statements which drives signal sig.\n\n    :param sig: signal which drivers should be removed\n    :param statements: list of statements to filter\n    :param keep_mask: list of flags if True statements was driver only of sig\n    :param new_statements: output list of filtered statements\n\n    :return: True if all input statements were reduced\n    \"\"\"\n    all_cut_off = True\n    for stm in statements:\n        if sig in stm._outputs:\n            newStm = stm._cut_off_drivers_of(sig)\n            keep = True\n            if newStm is None:\n                # statement is des not have drivers of sig\n                all_cut_off = False\n            elif newStm is stm:\n                # statement drives only sig\n                keep = False\n                new_statements.append(newStm)\n            else:\n                # statement was splited on multiple statements\n                all_cut_off = False\n                new_statements.append(newStm)\n        else:\n            all_cut_off = False\n            keep = True\n\n        keep_mask.append(keep)\n\n    return all_cut_off\n"
  },
  {
    "path": "hwt/hdl/transPart.py",
    "content": "from typing import Tuple, Optional\n\nfrom hwt.hdl.transTmpl import TransTmpl\n\n\nclass TransPart(object):\n    \"\"\"\n    Container for informations about parts of TransTmpl split on databus words\n\n    :ivar ~.parent: instance of FrameTmpl\n    :ivar ~.tmpl: origin template which is this representation of\n        (StructField/HdlType instance)\n    :ivar ~.canBeRemoved: True if it is padding to assert data alignment and is not\n        actually part of data and can be removed\n    :ivar ~.isPadding: True if this TransaPart is just a padding\n        and contains non valid data\n    :ivar ~.startOfPart: bit addr of start of this part\n    :ivar ~.endOfPart: bit addr of end of this part\n    :ivar ~.inFieldOffset: bit offset of this part in parent field\n    \"\"\"\n\n    def __init__(self, parent: 'FrameTmpl',\n                 tmpl: Optional[TransTmpl],\n                 canBeRemoved: bool,\n                 startOfPart: int,\n                 endOfPart: int,\n                 inFieldOffset: int):\n        self.parent = parent\n        self.tmpl = tmpl\n        # assert tmpl is None or isinstance(tmpl, TransTmpl), tmpl\n        self.isPadding = tmpl is None\n        self.canBeRemoved = canBeRemoved\n        self.startOfPart = startOfPart\n        self.endOfPart = endOfPart\n        self.inFieldOffset = inFieldOffset\n\n    def bit_length(self) -> int:\n        \"\"\"\n        :return: bit length of this part\n        \"\"\"\n        return self.endOfPart - self.startOfPart\n\n    def getBusWordBitRange(self) -> Tuple[int, int]:\n        \"\"\"\n        :return: bit range which contains data of this part on bus data signal\n        \"\"\"\n        offset = self.startOfPart % self.parent.wordWidth\n        return (offset + self.bit_length(), offset)\n\n    def getFieldBitRange(self) -> Tuple[int, int]:\n        \"\"\"\n        :return: bit range which contains data of this part on interface\n            of field\n        \"\"\"\n        offset = self.inFieldOffset\n        return (self.bit_length() + offset, offset)\n\n    def isLastPart(self) -> bool:\n        \"\"\"\n        :return: True if this part is last in parts derived from original field\n            else False\n        \"\"\"\n        return self.tmpl.bitAddrEnd == self.endOfPart\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} {self.tmpl}, startOfPart:{self.startOfPart:d}, endOfPart:{self.endOfPart:d}>\"\n"
  },
  {
    "path": "hwt/hdl/transTmpl.py",
    "content": "from builtins import isinstance\nfrom copy import deepcopy\nfrom typing import Callable, Tuple, Generator, Union, Optional\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.stream import HStream\nfrom hwt.hdl.types.struct import HStruct, HStructField\nfrom hwt.hdl.types.union import HUnion\nfrom hwt.pyUtils.arrayQuery import iter_with_last\nfrom hwt.synthesizer.typePath import TypePath\n\n\ndef _default_shouldEnterFn(transTmpl: 'TransTmpl') -> Tuple[bool, bool]:\n    return (bool(transTmpl.children), not bool(transTmpl.children))\n\n\nclass TransTmpl(object):\n    \"\"\"\n    Transaction template for types of constant size\n\n    Container of informations about frames generated from any HType\n    (HStruct etc.)\n    * contains precalculated address range for all members of type\n\n    :note: Array/Stream items are are stored as a single instance\n        so the memory consumption of this object is entirely independent\n        on size of arrays which it describes.\n\n    :ivar ~.dtype: type of this item\n    :ivar ~.bitAddr: offset of start of this item in bits\n    :ivar ~.bitAddrEnd: end of this item in bits\n    :ivar ~.parent: object which generated this item, optional TransTmpl\n    :ivar ~.origin: object which was template for generating of this item\n    :ivar ~.itemCnt: if this transaction template is for array or stream this is\n        item count for such an array or stream\n    :ivar ~.childrenAreChoice: flag which tells if children are sequence\n        or only one of them can be used in same time\n    :ivar rel_field_path: path in original data type relative to parent\n    \"\"\"\n\n    def __init__(self, dtype: HdlType, bitAddr: int=0,\n                 parent: Optional['TransTmpl']=None,\n                 origin: Optional[HStructField]=None,\n                 rel_field_path: TypePath=TypePath()):\n        self.parent = parent\n        assert isinstance(dtype, HdlType), dtype\n        assert isinstance(rel_field_path, TypePath), rel_field_path\n        assert parent is None or isinstance(parent, TransTmpl), parent\n        if origin is None:\n            origin = (dtype,)\n        else:\n            assert isinstance(origin, tuple), origin\n        self.origin = origin\n        self.dtype = dtype\n        self.children = []\n        self.itemCnt = None\n        self.rel_field_path = rel_field_path\n        self._loadFromHType(dtype, bitAddr)\n\n    @internal\n    def _loadFromBits(self, dtype: HdlType, bitAddr: int):\n        \"\"\"\n        Parse HBits type to this transaction template instance\n\n        :return: address of it's end\n        \"\"\"\n        return bitAddr + dtype.bit_length()\n\n    @internal\n    def _loadFromHStruct(self, dtype: HdlType, bitAddr: int):\n        \"\"\"\n        Parse HStruct type to this transaction template instance\n\n        :return: address of it's end\n        \"\"\"\n\n        for f in dtype.fields:\n            t = f.dtype\n\n            isPadding = f.name is None\n\n            if isPadding:\n                width = t.bit_length()\n                bitAddr += width\n            else:\n                origin = (*self.origin, f)\n                fi = TransTmpl(t, bitAddr,\n                               parent=self,\n                               origin=origin,\n                               rel_field_path=TypePath(f.name,),\n                )\n                self.children.append(fi)\n                bitAddr = fi.bitAddrEnd\n\n        return bitAddr\n\n    @internal\n    def _loadFromUnion(self, dtype: HdlType, bitAddr: int) -> int:\n        \"\"\"\n        Parse HUnion type to this transaction template instance\n\n        :return: address of it's end\n        \"\"\"\n        for f in dtype.fields.values():\n            ch = TransTmpl(f.dtype, 0, parent=self,\n                           origin=(*self.origin, f),\n                           rel_field_path=TypePath(f.name,),\n                           )\n            self.children.append(ch)\n        return bitAddr + dtype.bit_length()\n\n    @internal\n    def _loadFromArray(self, dtype: HdlType, bitAddr: int) -> int:\n        \"\"\"\n        Parse HArray type to this transaction template instance\n\n        :return: address of it's end\n        \"\"\"\n        self.itemCnt = int(dtype.size)\n        self.children = TransTmpl(\n            dtype.element_t, 0, parent=self,\n            origin=(*self.origin, 0),\n            rel_field_path=TypePath(0,)\n        )\n        return bitAddr + self.itemCnt * self.children.bitAddrEnd\n\n    @internal\n    def _loadFromHStream(self, dtype: HStream, bitAddr: int) -> int:\n        \"\"\"\n        Parse HStream type to this transaction template instance\n\n        :return: address of it's end\n        \"\"\"\n        self.children = TransTmpl(\n            dtype.element_t, 0, parent=self, origin=self.origin,\n            rel_field_path=TypePath(0,))\n\n        if not isinstance(dtype.len_min, int) or dtype.len_min != dtype.len_max:\n            raise ValueError(\"This template is ment only\"\n                             \" for types of constant and finite size\")\n\n        self.itemCnt = dtype.len_min\n        return bitAddr + dtype.element_t.bit_length() * self.itemCnt\n\n    def _loadFromHType(self, dtype: HdlType, bitAddr: int) -> None:\n        \"\"\"\n        Parse any HDL type to this transaction template instance\n        \"\"\"\n        self.bitAddr = bitAddr\n        childrenAreChoice = False\n        if isinstance(dtype, HBits):\n            ld = self._loadFromBits\n        elif isinstance(dtype, HStruct):\n            ld = self._loadFromHStruct\n        elif isinstance(dtype, HArray):\n            ld = self._loadFromArray\n        elif isinstance(dtype, HStream):\n            ld = self._loadFromHStream\n        elif isinstance(dtype, HUnion):\n            ld = self._loadFromUnion\n            childrenAreChoice = True\n        else:\n            raise TypeError(\"expected instance of HdlType\", dtype)\n\n        self.bitAddrEnd = ld(dtype, bitAddr)\n        self.childrenAreChoice = childrenAreChoice\n\n    def bit_length(self) -> int:\n        \"\"\"\n        :return: number of bits in this transaction\n        \"\"\"\n        return self.bitAddrEnd - self.bitAddr\n\n    def HwIO_walkFlatten(self, offset: int=0,\n                    shouldEnterFn=_default_shouldEnterFn\n                    ) -> Generator[\n            Union[Tuple[Tuple[int, int], 'TransTmpl'], 'OneOfTransaction'],\n            None, None]:\n        \"\"\"\n        Walk fields in instance of TransTmpl\n\n        :param offset: optional offset for all children in this TransTmpl\n        :param shouldEnterFn: function (transTmpl) which returns True\n            when field should be split on it's children\n        :param shouldEnterFn: function(transTmpl) which should return\n            (shouldEnter, shouldUse) where shouldEnter is flag that means\n            iterator should look inside of this actual object\n            and shouldUse flag means that this field should be used\n            (=generator should yield it)\n        :return: generator of tuples ((startBitAddress, endBitAddress),\n            TransTmpl instance)\n        \"\"\"\n\n        t = self.dtype\n        base = self.bitAddr + offset\n        end = self.bitAddrEnd + offset\n\n        shouldEnter, shouldYield = shouldEnterFn(self)\n        if shouldYield:\n            yield ((base, end), self)\n\n        if shouldEnter:\n            if isinstance(t, HBits):\n                pass\n            elif isinstance(t, HStruct):\n                for c in self.children:\n                    yield from c.HwIO_walkFlatten(\n                        offset,\n                        shouldEnterFn)\n            elif isinstance(t, (HArray, HStream)):\n                itemSize = (self.bitAddrEnd - self.bitAddr) // self.itemCnt\n                for i in range(self.itemCnt):\n                    if i == 0:\n                        c = self.children\n                    else:\n                        # spot a new array item\n                        c = deepcopy(self.children)\n                        assert c.rel_field_path == (0,), c.rel_field_path\n                        # replace the index\n                        c.rel_field_path = TypePath(i, )\n\n                    yield from c.HwIO_walkFlatten(\n                        base + i * itemSize,\n                        shouldEnterFn)\n\n            elif isinstance(t, HUnion):\n                yield OneOfTransaction(self, offset, shouldEnterFn,\n                                       self.children)\n            else:\n                raise TypeError(t)\n\n    def getFieldPath(self):\n        \"\"\"\n        Get field path which specifies the location in original HdlType data type\n        \"\"\"\n        path = []\n        tmpl = self\n        while tmpl is not None:\n            path.extend(reversed(tmpl.rel_field_path))\n            tmpl = tmpl.parent\n        return TypePath(*reversed(path))\n\n    def __deepcopy__(self, memo):\n        cls = self.__class__\n        result = cls.__new__(cls)\n        memo[id(self)] = result\n        for k, v in self.__dict__.items():\n            setattr(result, k, deepcopy(v, memo))\n        c = self.children\n        if isinstance(c, TransTmpl):\n            c.parent = self\n        else:\n            for _c in c:\n                _c.parent = self\n\n        return result\n\n    def __repr__(self, offset: int=0):\n        offsetStr = \"\".join([\"    \" for _ in range(offset)])\n\n        try:\n            name = self.origin[-1].name\n        except (AttributeError, IndexError):\n            name = None\n\n        if name:\n            name = f\" name:{name:s},\"\n        else:\n            name = \"\"\n\n        s = f\"{offsetStr:s}<TransTmpl{name} start:{self.bitAddr:d}, end:{self.bitAddrEnd:d}\"\n        if isinstance(self.dtype, (HArray, HStream)):\n            s_buff = [\n                s, f\", itemCnt:{self.itemCnt:d}\\n\",\n                self.children.__repr__(offset=offset + 1), \"\\n\",\n                offsetStr, \">\"\n            ]\n            return \"\".join(s_buff)\n        elif not self.children:\n            return s + \">\"\n\n        buff = [s, ]\n        for isLast, child in iter_with_last(self.children):\n            buff.append(child.__repr__(offset=offset + 1))\n            if self.childrenAreChoice and not isLast:\n                buff.append(offsetStr + \"    <OR>\")\n\n        buff.append(offsetStr + \">\")\n        return \"\\n\".join(buff)\n\n\nclass OneOfTransaction(object):\n    \"\"\"\n    Container of possible transactions for transactions deriverd\n    from HUnion type\n\n    :ivar ~.parent: parent TransTmpl instance\n    :ivar ~.offset: bit addr offset in parent type structure\n    :ivar ~.shouldEnterFn: function(transTmpl) which should\n        return (shouldEnter, shouldUse)\n        where shouldEnter is flag that means iterator should look\n        inside of this actual object and shouldUse flag means that this field\n        should be used (=generator should yield it)\n    :ivar ~.possibleTransactions: tuple of TransTmpl instances\n        from which only one can be used in same time\n    \"\"\"\n\n    def __init__(self, parent: TransTmpl,\n                 offset: int,\n                 shouldEnterFn: Callable[[TransTmpl], Tuple[bool, bool]],\n                 possibleTransactions: Tuple[TransTmpl]):\n        self.parent = parent\n        self.offset = offset\n        self.shouldEnterFn = shouldEnterFn\n        self.possibleTransactions = possibleTransactions\n\n    def walkFlattenChilds(self) -> Generator[\n            Union[Tuple[Tuple[int, int], TransTmpl], 'OneOfTransaction'],\n            None, None]:\n        \"\"\"\n        :return: generator of generators of tuples\n            ((startBitAddress, endBitAddress), TransTmpl instance)\n            for each possiblility in this transaction\n        \"\"\"\n        for p in self.possibleTransactions:\n            yield p.HwIO_walkFlatten(offset=self.offset,\n                                shouldEnterFn=self.shouldEnterFn)\n"
  },
  {
    "path": "hwt/hdl/types/__init__.py",
    "content": "\"\"\"\nThis package contains HDL types (e.g. Bits), value classes\nand conversion functions for them.\n\"\"\"\n"
  },
  {
    "path": "hwt/hdl/types/array.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HArray(HdlType):\n    \"\"\"\n    HDL array type\n\n    :ivar ~.element_t: type of elements\n    :ivar ~.size: number of items\n    \"\"\"\n\n    def __init__(self, element_t, size, const=False):\n        super(HArray, self).__init__(const=const)\n        self.element_t = element_t\n        self.size = size\n\n    def __eq__(self, other):\n        return self is other or (\n            type(self) is type(other) and\n            self.size == other.size and\n            self.element_t == other.element_t\n        )\n\n    @internal\n    def __hash__(self):\n        return hash((self.const, self.element_t, self.size))\n\n    def bit_length(self):\n        \"\"\"\n        :return: bit width for this type\n        \"\"\"\n        try:\n            itemSize = self.element_t.bit_length\n        except AttributeError:\n            itemSize = None\n        if itemSize is None:\n            raise TypeError(\n                \"Can not determine size of array because item has\"\n                \" not determinable size\")\n\n        s = self.size\n        if isinstance(s, RtlSignalBase):\n            s = int(s.staticEval())\n        return s * itemSize()\n\n    @internal\n    @override\n    @classmethod\n    def get_reinterpret_cast_HConst_fn(cls):\n        from hwt.hdl.types.arrayCast import reinterpret_cast_HArray\n        return reinterpret_cast_HArray\n\n    @internal\n    @override\n    @classmethod\n    def get_reinterpret_cast_RtlSignal_fn(cls):\n        from hwt.hdl.types.arrayCast import reinterpret_cast_HArray\n        return reinterpret_cast_HArray\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.arrayConst import HArrayConst\n            cls._constCls = HArrayConst\n            return cls._constCls\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        try:\n            return cls._rtlSignalCls\n        except AttributeError:\n            from hwt.hdl.types.arrayConst import HArrayRtlSignal\n            cls._rtlSignalCls = HArrayRtlSignal\n            return cls._rtlSignalCls\n\n    @override\n    def isScalar(self):\n        return False\n\n    def __repr__(self, indent=0, withAddr=None, expandStructs=False):\n        \"\"\"\n        :param indent: number of indentation\n        :param withAddr: if is not None is used as a additional\n            information about on which address this type is stored\n            (used only by HStruct)\n        :param expandStructs: expand HStructTypes (used by HStruct and Array)\n        \"\"\"\n        return \"%s[%r]\" % (self.element_t.__repr__(indent=indent,\n                                                 withAddr=withAddr,\n                                                 expandStructs=expandStructs),\n                           self.size)\n"
  },
  {
    "path": "hwt/hdl/types/arrayCast.py",
    "content": "from typing import Union, Optional\n\nfrom hwt.code import Concat\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import default_reinterpret_cast_fn, HdlType\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.synthesizer.exceptions import TypeConversionErr\nfrom pyMathBitPrecise.bit_utils import get_bit_range, mask\n\n\nHArrayAnyValue = Union[\"HArrayConst\", \"HArrayRtlSignal\"]\n\n\n@internal\ndef getBits_from_array(array: HArrayAnyValue, wordWidth: int, start: int, end: int,\n                       reinterpretElmToType: Optional[HdlType]=None):\n    \"\"\"\n    Gets value of bits between selected range from memory\n\n    :param start: bit address of start of bit of bits\n    :param end: bit address of first bit behind bits\n    :return: instance of BitsVal (derived from SimBits type) which contains\n        copy of selected bits\n    \"\"\"\n    inPartOffset = 0\n    value = HBits(end - start, None).from_py(None)\n\n    while start != end:\n        assert start < end, (start, end)\n\n        dataWordIndex = start // wordWidth\n\n        v = array[dataWordIndex]\n        if reinterpretElmToType is not None:\n            v = v._reinterpret_cast(reinterpretElmToType)\n\n        endOfWord = (dataWordIndex + 1) * wordWidth\n        width = min(end, endOfWord) - start\n        offset = start % wordWidth\n\n        val = get_bit_range(v.val, offset, width)\n        vld_mask = get_bit_range(v.vld_mask, offset, width)\n\n        m = mask(width)\n        value.val |= (val & m) << inPartOffset\n        value.vld_mask |= (vld_mask & m) << inPartOffset\n\n        inPartOffset += width\n        start += width\n\n    return value\n\n\n@internal\ndef reinterptet_HArray_to_HBits(typeFrom: HArray, sigOrConst: HArrayAnyValue, bitsT: HBits):\n    \"\"\"\n    Cast HArray signal or value to signal or value of type HBits\n    \"\"\"\n    size = int(typeFrom.size)\n    widthOfElm = typeFrom.element_t.bit_length()\n    w = bitsT.bit_length()\n    if size * widthOfElm != w:\n        raise TypeConversionErr(\n            \"Size of types is different\", size * widthOfElm, w)\n\n    partT = HBits(widthOfElm)\n    parts = [p._reinterpret_cast(partT) for p in sigOrConst]\n\n    return Concat(*reversed(parts))._reinterpret_cast(bitsT)\n\n\n@internal\ndef reinterpret_HArray_to_HArray(typeFrom: HArray, sigOrConst: HArrayAnyValue, arrayT: HArray):\n    mySize = int(typeFrom.size)\n    myWidthOfElm = typeFrom.element_t.bit_length()\n    size = int(arrayT.size)\n    widthOfElm = arrayT.element_t.bit_length()\n\n    if size * widthOfElm != mySize * myWidthOfElm:\n        raise TypeConversionErr(\"Size of types is different\",\n                                size * widthOfElm, mySize * myWidthOfElm)\n\n    if isinstance(typeFrom.element_t, HBits):\n        reinterpretElmToType = None\n    else:\n        reinterpretElmToType = HBits(myWidthOfElm)\n\n    res = arrayT.from_py(None)\n    res.vld_mask = sigOrConst.vld_mask\n    for i in range(size):\n        start = i * widthOfElm\n        end = (i + 1) * widthOfElm\n        item = getBits_from_array(\n            sigOrConst, myWidthOfElm, start, end, reinterpretElmToType)\n        res[i] = item._reinterpret_cast(arrayT.element_t)\n\n    return res\n\n\n@internal\ndef reinterpret_HArray_to_HStruct(typeFrom: HArray, sigOrConst: HArrayAnyValue, structT):\n    as_bits = sigOrConst._reinterpret_cast(HBits(typeFrom.bit_length()))\n    return as_bits._reinterpret_cast(structT)\n\n\n@internal\ndef reinterpret_cast_HArray(typeFrom: HArray, sigOrConst: HArrayAnyValue, toType):\n    if isinstance(toType, HBits):\n        return reinterptet_HArray_to_HBits(typeFrom, sigOrConst, toType)\n    elif isinstance(toType, HArray):\n        return reinterpret_HArray_to_HArray(typeFrom, sigOrConst, toType)\n    elif isinstance(toType, HStruct):\n        return reinterpret_HArray_to_HStruct(typeFrom, sigOrConst, toType)\n    else:\n        return default_reinterpret_cast_fn(typeFrom, sigOrConst, toType)\n"
  },
  {
    "path": "hwt/hdl/types/arrayConst.py",
    "content": "from copy import copy\nfrom typing import Union, Self\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.types.bitConstFunctions import HBitsAnyIndexCompatibleValue\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, INT\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom pyMathBitPrecise.bit_utils import ValidityError\n\n\ndef _HArrayGetitem(self: Union[\"HArrayRtlSignal\", \"HArrayConst\"], iamVal: bool, key):\n    key = toHVal(key)\n    isSLICE = isinstance(key, HSlice.getConstCls())\n\n    if isSLICE:\n        raise NotImplementedError()\n    elif isinstance(key, (HConst, RtlSignalBase)):\n        pass\n    else:\n        raise NotImplementedError(\n            f\"Index operation not implemented for index {key}\")\n\n    if iamVal and isinstance(key, HConst):\n        return self._getitem__const(key)\n\n    return HOperatorNode.withRes(HwtOps.INDEX, [self, key], self._dtype.element_t)\n\n\nclass HArrayRtlSignal(RtlSignal):\n\n    def __getitem__(self, key):\n        try:\n            return _HArrayGetitem(self, False, key)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __iter__(self):\n        mySize = len(self)\n\n        for i in range(mySize):\n            yield self[i]\n\n    def __call__(self, source,\n        dst_resolve_fn=lambda x:x._getDestinationSignalForAssignmentToThis(),\n        exclude=None,\n        fit=False) -> list[HdlAssignmentContainer]:\n        assert len(self) == len(source), (\"source and destination array must be of the same size\", len(self) == len(source))\n        res = []\n        for src, dst in zip(source, self):\n            a = dst.__call__(src, dst_resolve_fn=dst_resolve_fn, exclude=exclude, fit=fit)\n            if isinstance(a, (list, tuple)):\n                res.extend(a)\n            else:\n                res.append(a)\n\n        return res\n\n    def __len__(self):\n        return int(self._dtype.size)\n\n\nclass HArrayConst(HConst):\n    \"\"\"\n    Class for values of array HDL type\n    \"\"\"\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param val: None or dictionary {index:HConst} or iterrable of values\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        size = typeObj.size\n        if isinstance(size, HConst):\n            size = int(size)\n\n        elements = {}\n        if vld_mask == 0:\n            val = None\n\n        if val is None:\n            vld_mask = 0\n\n        elif isinstance(val, dict):\n            if vld_mask is None:\n                vld_mask = 1\n\n            for k, v in val.items():\n                if not isinstance(k, int):\n                    k = int(k)  # expecting {index: value} dict\n\n                if k >= size:\n                    raise ValueError(\"Initialization value dictionary contains index which is larger than size of initialized array\", typeObj, k)\n\n                e = elements[k] = typeObj.element_t.from_py(v)\n                vld_mask &= e._is_full_valid()\n        else:\n            if vld_mask is None:\n                vld_mask = 1\n\n            for k, v in enumerate(val):\n                if k >= size:\n                    raise ValueError(\"Initialization value sequence is larger than size of initialized array\", typeObj, val)\n\n                if isinstance(v, RtlSignalBase):  # is signal\n                    assert v._dtype == typeObj.element_t\n                    e = v\n                else:\n                    e = typeObj.element_t.from_py(v)\n                elements[k] = e\n                vld_mask &= e._is_full_valid()\n\n        if len(elements) != size:\n            vld_mask = 0\n\n        return cls(typeObj, elements, vld_mask)\n\n    def to_py(self):\n        v = self.val\n        invalid_elm = self._dtype.element_t.from_py(None)\n        return [v.get(i, invalid_elm).to_py()\n                for i in range(self._dtype.size)]\n\n    @internal\n    def __hash__(self):\n        return hash(self._dtype)\n        # return hash((self._dtype, self.val, self.vld_mask))\n\n    def _is_full_valid(self):\n        return self.vld_mask == 1\n\n    def _is_partially_valid(self) -> bool:\n        return self._is_full_valid() or any(v._is_partially_valid() for v in self.val.values())\n\n    @internal\n    def _getitem__const(self, key):\n        \"\"\"\n        :attention: this will clone item from array, iterate over .val\n            if you need to modify items\n        \"\"\"\n        try:\n            kv = key.val\n            if not key._is_full_valid():\n                raise KeyError()\n            else:\n                if kv >= self._dtype.size:\n                    raise KeyError()\n\n            return self.val[kv].__copy__()\n        except KeyError:\n            return self._dtype.element_t.from_py(None)\n\n    def __getitem__(self, key):\n        try:\n            return _HArrayGetitem(self, True, key)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __setitem__(self, index: HBitsAnyIndexCompatibleValue, value) -> Self:\n        \"\"\"\n        Only syntax sugar for user, not used inside HWT\n\n        * Not used in HW design (__getitem__ and overloaded call operator is used instead for item assigning)\n        \"\"\"\n        try:\n            if isinstance(index, int):\n                index = INT.from_py(index)\n            else:\n                assert isinstance(index._dtype, HBits), index._dtype\n\n            if isinstance(value, HConst):\n                assert value._dtype == self._dtype.element_t, (\n                    value._dtype, self._dtype.element_t)\n            else:\n                value = self._dtype.element_t.from_py(value)\n\n            if index._is_full_valid():\n                self.val[index.val] = value.__copy__()\n            else:\n                self.val = {}\n\n            self.vld_mask = int(\n                len(self.val) == self._dtype.size and\n                all(e._is_full_valid() for e in self.val.values())\n            )\n            return self\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __iter__(self):\n        mySize = len(self)\n\n        for i in range(mySize):\n            yield self[i]\n\n    def __len__(self):\n        return int(self._dtype.size)\n\n    def _eq(self, other):\n        assert self._dtype.element_t == other._dtype.element_t\n        assert self._dtype.size == other._dtype.size\n        try:\n            eq = True\n            vld = 1\n            keysA = set(self.val)\n            keysB = set(other.val)\n            sharedKeys = keysA.union(keysB)\n\n            lsh = len(sharedKeys)\n            if (lsh == int(self._dtype.size)\n                    and len(keysA) == lsh\n                    and len(keysB) == lsh):\n                for k in sharedKeys:\n                    a = self.val[k]\n                    b = other.val[k]\n\n                    eq = eq and bool(a) == bool(b)\n                    if not eq:\n                        break\n                    vld = vld & a.vld_mask & b.vld_mask\n            else:\n                eq = False\n                vld = 0\n\n            return BOOL.getConstCls()(BOOL, int(eq), vld)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n"
  },
  {
    "path": "hwt/hdl/types/bitConstFunctions.py",
    "content": "from operator import ne, eq\nfrom typing import Callable, Union, Optional\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps, HOperatorDef, CMP_OP_SWAP\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.math import isPow2, log2ceil\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\nfrom pyMathBitPrecise.bit_utils import mask\nfrom pyMathBitPrecise.bits3t import bitsCmp__val, bitsBitOp__val, \\\n    bitsArithOp__val, Bits3val, bitsCmp__val_NE, bitsCmp__val_EQ\n\n\nHBitsAnyCompatibleValue = Union[\"HBitsRtlSignal\", \"HBitsConst\", int, None]\nHBitsAnyIndexCompatibleValue = Union[int, slice, RtlSignalBase[HSlice], RtlSignalBase[HBits], None]\nAnyHBitsValue = Union[\"HBitsRtlSignal\", \"HBitsConst\"]\n\n\n@internal\ndef bitsCmp_detect_useless_cmp(op0: \"HBitsRtlSignal\", op1: \"HBitsConst\", op: HOperatorDef) -> Optional[HOperatorDef]:\n    v = int(op1)\n    width = op1._dtype.bit_length()\n    if op0._dtype.signed:\n        min_val = -1 if width == 1 else -mask(width - 1) - 1\n        max_val = 0 if width == 1 else mask(width - 1)\n    else:\n        min_val = 0\n        max_val = mask(width)\n\n    if v == min_val:\n        # value can not be lower than min_val\n        if op == HwtOps.GE:\n            # -> always True\n            return BOOL.from_py(1, 1)\n        elif op == HwtOps.LT:\n            # -> always False\n            return BOOL.from_py(0, 1)\n        elif op == HwtOps.LE:\n            # convert <= to == to highlight the real function\n            return HwtOps.EQ\n    elif v == max_val:\n        # value can not be greater than max_val\n        if op == HwtOps.GT:\n            # always False\n            return BOOL.from_py(0, 1)\n        elif op == HwtOps.LE:\n            # always True\n            return BOOL.from_py(1, 1)\n        elif op == HwtOps.GE:\n            # because value can not be greater than max\n            return HwtOps.EQ\n\n\n@internal\ndef bitsCmp(self: AnyHBitsValue, selfIsHConst: bool, other: HBitsAnyCompatibleValue,\n            op: HOperatorDef,\n            selfReduceVal: HConst,\n            evalFn:Callable[[AnyHBitsValue, AnyHBitsValue], AnyHBitsValue]=None) -> AnyHBitsValue:\n    \"\"\"\n    Apply a generic comparison binary operator\n\n    :attention: If other is bool signal convert this to bool (not ideal,\n        due VHDL event operator)\n    :ivar self: operand 0\n    :ivar other: operand 1\n    :ivar op: operator used\n    :ivar selfReduceVal: the value which is a result if operands are all same signal (e.g. a==a = 1, b<b=0)\n    :ivar evalFn: override of a python operator function (by default one from \"op\" is used)\n    \"\"\"\n    t = self._dtype\n    other = toHVal(other, t)\n    ot = other._dtype\n    if not isinstance(ot, t.__class__):\n        raise TypeError(ot)\n\n    if evalFn is None:\n        evalFn = op._evalFn\n\n    otherIsConst = isinstance(other, HConst)\n    type_compatible = False\n    if ot == BOOL:\n        self = self._auto_cast(BOOL)\n        type_compatible = True\n    elif t == ot:\n        type_compatible = True\n    # lock type width/signed to other type with\n    elif not ot.strict_width or not ot.strict_sign:\n        type_compatible = True\n        other = other._auto_cast(t)\n    elif not t.strict_width or not t.strict_sign:\n        type_compatible = True\n        other = other._auto_cast(ot)\n\n    elif t.bit_length() == 1 and ot.bit_length() == 1\\\n            and t.signed is ot.signed \\\n            and t.force_vector != ot.force_vector:\n        # automatically cast to vector with a single item to a single bit\n        if t.force_vector:\n            self = self[0]\n            t = self._dtype\n        else:\n            other = other[0]\n            ot = other._dtype\n\n        type_compatible = True\n\n    if selfIsHConst and otherIsConst:\n        if type_compatible:\n            if evalFn == ne:\n                return bitsCmp__val_NE(self, other)\n            elif evalFn == eq:\n                return bitsCmp__val_EQ(self, other)\n            else:\n                return bitsCmp__val(self, other, evalFn)\n    else:\n        if type_compatible:\n            # try to reduce useless cmp\n            res = None\n            if otherIsConst and other._is_full_valid():\n                res = bitsCmp_detect_useless_cmp(self, other, op)\n            elif selfIsHConst and self._is_full_valid():\n                res = bitsCmp_detect_useless_cmp(other, self, CMP_OP_SWAP[op])\n\n            if res is None:\n                pass\n            elif isinstance(res, HConst):\n                return res\n            else:\n                assert res == HwtOps.EQ, res\n                op = res\n\n            if self is other:\n                return selfReduceVal\n            else:\n                return HOperatorNode.withRes(op, [self, other], BOOL)\n\n        elif t.strict_width and ot.strict_width and t.bit_length() != ot.bit_length():\n            pass\n        elif t.signed != ot.signed:\n            # handle sign casts\n            if t.signed is None:\n                self = self._cast_sign(ot.signed)\n                return bitsCmp(self, selfIsHConst, other, op, evalFn)\n            elif ot.signed is None:\n                other = other._cast_sign(t.signed)\n                return bitsCmp(self, selfIsHConst, other, op, evalFn)\n        elif t.force_vector != ot.force_vector:\n            # handle vector to bit casts\n            if t.force_vector:\n                self = self[0]\n            else:\n                other = other[0]\n            return bitsCmp(self, selfIsHConst, other, op, evalFn)\n\n    raise TypeError(f\"Values of types (\", self._dtype, other._dtype, \") are not comparable\")\n\n\n@internal\ndef extractNegation(sig: RtlSignalBase) -> tuple[AnyHBitsValue, bool]:\n    \"\"\"\n    :return: tuple(the signal without negation, True if signal was negated)\n    \"\"\"\n    try:\n        d = sig.singleDriver()\n    except SignalDriverErr:\n        return (sig, False)\n\n    if isinstance(d, HOperatorNode) and d.operator == HwtOps.NOT:\n        return d.operands[0], True\n    return sig, False\n\n\n@internal\ndef bitsBitOp(self: Union[RtlSignalBase, HConst],\n              selfIsHConst: bool, other: HBitsAnyCompatibleValue,\n              op: HOperatorDef,\n              getVldFn: Callable[[HConst, HConst], int],\n              reduceValCheckFn: Callable[[RtlSignalBase, HConst], bool],\n              reduceSigCheckFn: Callable[[RtlSignalBase,  # op0Original\n                                          bool,  # op0Negated\n                                          bool  # op1Negated\n                                          ], Union[RtlSignalBase, HConst]]) -> AnyHBitsValue:\n    \"\"\"\n    Apply a generic bitwise binary operator\n\n    :attention: If other is Bool signal, convert this to bool\n        (not ideal, due VHDL event operator)\n    :ivar self: operand 0\n    :ivar other: operand 1\n    :ivar op: operator used\n    :ivar getVldFn: function to resolve invalid (X) states\n    :ivar reduceValCheckFn: function to reduce useless operators (partially evaluate the expression if possible)\n    :ivar reduceSigCheckFn: function to reduce useless operators for signals and its negation flags\n        (e.g. a&a = a, a&~a=0, b^b=0)\n        function parameters are in format (op0Original:RtlSignalBase, op0Negated: bool, op1Negated:bool) -> Union[RtlSignalBase, HConst]:\n        returns result signal if reduction is possible else None\n    \"\"\"\n    other = toHVal(other, self._dtype)\n    otherIsHConst = isinstance(other, HConst)\n\n    if selfIsHConst and otherIsHConst:\n        other = other._auto_cast(self._dtype)\n        return bitsBitOp__val(self, other, op._evalFn, getVldFn)\n    else:\n        s_t = self._dtype\n        o_t = other._dtype\n        if not isinstance(o_t, s_t.__class__):\n            raise TypeError(o_t)\n\n        if s_t == o_t:\n            pass\n        elif o_t == BOOL and s_t != BOOL:\n            self = self._auto_cast(BOOL)\n            return op._evalFn(self, other)\n        elif o_t != BOOL and s_t == BOOL:\n            other = other._auto_cast(BOOL)\n            return op._evalFn(self, other)\n        else:\n            if s_t.signed is not o_t.signed and bool(s_t.signed) == bool(o_t.signed):\n                # automatically cast unsigned to vector\n                if s_t.signed == False and o_t.signed is None:\n                    self = self._vec()\n                    s_t = self._dtype\n                elif s_t.signed is None and o_t.signed == False:\n                    other = other._vec()\n                    o_t = other._dtype\n                else:\n                    raise ValueError(\"Invalid value for signed flag of type\", s_t.signed, o_t.signed, s_t, o_t)\n\n            if s_t == o_t:\n                # due to previsous cast the type may become the same\n                pass\n            elif s_t.bit_length() == 1 and o_t.bit_length() == 1\\\n                    and s_t.signed is o_t.signed \\\n                    and s_t.force_vector != o_t.force_vector:\n                # automatically cast to vector with a single item to a single bit\n                if s_t.force_vector:\n                    self = self[0]\n                else:\n                    other = other[0]\n\n            else:\n                raise TypeError(\"Can not apply operator %r (%r, %r)\" %\n                                (op, self._dtype, other._dtype))\n\n        if otherIsHConst:\n            r = reduceValCheckFn(self, other)\n            if r is not None:\n                return r\n\n        elif selfIsHConst:\n            r = reduceValCheckFn(other, self)\n            if r is not None:\n                return r\n\n        else:\n            _self, _self_n = extractNegation(self)\n            _other, _other_n = extractNegation(other)\n            if _self is _other:\n                return reduceSigCheckFn(self, _self_n, _other_n)\n\n        return HOperatorNode.withRes(op, [self, other], self._dtype)\n\n\n@internal\ndef bitsArithOp(self: AnyHBitsValue, selfIsHConst: bool, other: HBitsAnyCompatibleValue, op: HOperatorDef) -> AnyHBitsValue:\n    other = toHVal(other, self._dtype)\n    if not isinstance(other._dtype, HBits):\n        raise TypeError(other._dtype)\n\n    otherIsHConst = isinstance(other, HConst)\n\n    if selfIsHConst and otherIsHConst:\n        return bitsArithOp__val(self, other, op._evalFn)\n    else:\n        if self._dtype.signed is None:\n            self = self._unsigned()\n\n        if op in (HwtOps.ADD, HwtOps.SUB) and otherIsHConst and other._is_full_valid() and int(other) == 0:\n            return self\n\n        resT = self._dtype\n        if op == HwtOps.ADD and selfIsHConst and self._is_full_valid() and int(self) == 0:\n            return other._auto_cast(resT)\n\n        if isinstance(other._dtype, HBits):\n            t0 = self._dtype\n            t1 = other._dtype\n            if t0.bit_length() != t1.bit_length():\n                if not t1.strict_width:\n                    # resize to type of this\n                    other = other._auto_cast(t1)\n                    t1 = other._dtype\n                    pass\n                elif not t0.strict_width:\n                    # resize self to type of result\n                    self = self._auto_cast(t0)\n                    t0 = self._dtype\n                    pass\n                else:\n                    raise TypeError(\"%r %r %r\" % (self, op, other))\n\n            if t1.signed != resT.signed:\n                other = other._cast_sign(t0.signed)\n        else:\n            raise TypeError(\"%r %r %r\" % (self, op, other))\n\n        o = HOperatorNode.withRes(op, [self, other], self._dtype)\n        return o._auto_cast(resT)\n\n\n@internal\ndef bitsFloordiv(self: AnyHBitsValue, selfIsHConst: bool, other: HBitsAnyCompatibleValue) -> AnyHBitsValue:\n    other = toHVal(other, suggestedType=self._dtype)\n    if selfIsHConst and isinstance(other, HConst):\n        return Bits3val.__floordiv__(self, other)\n    else:\n        if not isinstance(other._dtype, self._dtype.__class__):\n            raise TypeError()\n\n        return HOperatorNode.withRes(HwtOps.SDIV if self._dtype.signed else HwtOps.UDIV,\n                                [self, other],\n                                self._dtype)\n\n\n@internal\ndef _bitsMulModGetResultType(myT: \"HBits\", otherT: \"HBits\"):\n    if otherT.strict_sign:\n        res_sign = otherT.signed\n        if myT.strict_sign:\n            assert bool(res_sign) == bool(myT.signed), (myT, otherT)\n    elif myT.strict_sign:\n        res_sign = myT.signed\n    else:\n        res_sign = self._dtype.signed or otherT.signed\n\n    if otherT.strict_width:\n        res_w = otherT.bit_length()\n        if myT.strict_width:\n            assert res_w == myT.bit_length(), (myT, otherT)\n        subResT = resT = otherT\n    elif myT.strict_width:\n        res_w = myT.bit_length()\n        subResT = resT = myT\n    else:\n        res_w = max(myT.bit_length(), otherT.bit_length())\n        subResT = HBits(res_w, signed=res_sign)\n        resT = HBits(res_w, signed=myT.signed)\n    return subResT, resT\n\n\n@internal\ndef bitsMul(self: AnyHBitsValue, selfIsHConst: bool, other: HBitsAnyCompatibleValue) -> AnyHBitsValue:\n    HBits = self._dtype.__class__\n    other = toHVal(other, suggestedType=self._dtype)\n    if not isinstance(other._dtype, HBits):\n        raise TypeError(other)\n\n    otherIsHConst = isinstance(other, HConst)\n\n    if selfIsHConst and otherIsHConst:\n        return Bits3val.__mul__(self, other)\n    else:\n        # reduce *1 and *0\n        if selfIsHConst and self._is_full_valid():\n            _s = int(self)\n            if _s == 0:\n                return self._dtype.from_py(0)\n            elif _s == 1:\n                return other._auto_cast(self._dtype)\n\n        if otherIsHConst and other._is_full_valid():\n            _o = int(other)\n            if _o == 0:\n                return self._dtype.from_py(0)\n            elif _o == 1:\n                return self\n\n        myT = self._dtype\n        if self._dtype.signed is None:\n            self = self._unsigned()\n\n        if isinstance(other._dtype, HBits):\n            s = other._dtype.signed\n            if s is None:\n                other = other._unsigned()\n        else:\n            raise TypeError(self, HwtOps.MUL, other)\n\n        subResT, resT = _bitsMulModGetResultType(myT, other._dtype)\n        o = HOperatorNode.withRes(HwtOps.MUL, [self, other], subResT)\n        return o._auto_cast(resT)\n\n\n@internal\ndef bitsRem(self: AnyHBitsValue, selfIsHConst: bool, other: HBitsAnyCompatibleValue) -> AnyHBitsValue:\n    HBits = self._dtype.__class__\n    other = toHVal(other, suggestedType=self._dtype)\n    if not isinstance(other._dtype, HBits):\n        raise TypeError(other)\n\n    otherIsHConst = isinstance(other, HConst)\n\n    if selfIsHConst and otherIsHConst:\n        return Bits3val.__mod__(self, other)\n    else:\n        if selfIsHConst and self._is_full_valid():\n            _s = int(self)\n            if _s == 0:\n                # 0 % x == 0\n                return self\n\n        if otherIsHConst and other._is_full_valid():\n            _o = int(other)\n            if _o == 0:\n                # x % 0 = x\n                return self\n            elif isPow2(_s):\n                # x % 2**cutOffBits\n                cutOffBits = log2ceil(_s)\n                return HBits(cutOffBits).from_py(0)._concat(self[:cutOffBits])\n\n        myT = self._dtype\n        if self._dtype.signed is None:\n            self = self._unsigned()\n\n        if self._dtype.signed:\n            op = HwtOps.SREM\n        else:\n            op = HwtOps.UREM\n\n        if isinstance(other._dtype, HBits):\n            s = other._dtype.signed\n            if s is None:\n                other = other._unsigned()\n        else:\n            raise TypeError(self, op, other)\n\n        subResT, resT = _bitsMulModGetResultType(myT, other._dtype)\n        o = HOperatorNode.withRes(op, [self, other], subResT)\n        return o._auto_cast(resT)\n\n\n@internal\ndef bitsLshift(self: AnyHBitsValue, shiftAmount: HBitsAnyCompatibleValue) -> AnyHBitsValue:\n    \"\"\"\n    shift left by a constant amount with 0 padding\n    \"\"\"\n    if isinstance(shiftAmount, HConst) and not shiftAmount._is_full_valid():\n        return self._dtype.from_py(None)\n\n    shiftAmount = int(shiftAmount)\n    if shiftAmount == 0:\n        return self\n\n    assert shiftAmount > 0, (\"shift amount must be positive value\", shiftAmount)\n    width = self._dtype.bit_length()\n    suffix = HBits(min(width, shiftAmount)).from_py(0)\n    if shiftAmount >= width:\n        return suffix\n    else:\n        return self[(width - shiftAmount):]._concat(suffix)\n\n\n@internal\ndef bitsRshift(self: AnyHBitsValue, shiftAmount: HBitsAnyCompatibleValue) -> AnyHBitsValue:\n    \"\"\"\n    shift right by a constant amount\n\n    :note: arithmetic shift if type is signed else logical shift with 0 padding\n    \"\"\"\n    if isinstance(shiftAmount, HConst) and not shiftAmount._is_full_valid():\n        return self._dtype.from_py(None)\n\n    shiftAmount = int(shiftAmount)\n    if shiftAmount == 0:\n        return self\n    assert shiftAmount > 0, (\"shift amount must be positive value\", shiftAmount)\n    width = self._dtype.bit_length()\n\n    if shiftAmount < width:\n        return self[:shiftAmount]._ext(width, bool(self._dtype.signed))\n    elif shiftAmount > width:\n        if self._dtype.signed:\n            msb = self[width - 1]\n            return msb._sext(width)\n        else:\n            return self._dtype.from_py(0)\n    else:\n        assert shiftAmount == 0, shiftAmount\n        return self\n"
  },
  {
    "path": "hwt/hdl/types/bitConstFunctionsGetitem.py",
    "content": "from typing import Union, Optional, Literal\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps, HOperatorDef\nfrom hwt.hdl.types.bitConstFunctions import AnyHBitsValue, \\\n    HBitsAnyIndexCompatibleValue\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import INT, SLICE, BIT, BIT_N\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.sliceUtils import slice_to_HSlice\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import RtlSignalBase\nfrom pyMathBitPrecise.bits3t import Bits3val\n\n\n@internal\ndef _match_msb_get(v: \"HBitsRtlSignal\"):\n    \"\"\"\n    :returns: x if v == x[x.width - 1] else None\n    \"\"\"\n    if v._dtype.bit_length() != 1:\n        return None\n\n    opVIsResultOf = _get_operator_i_am_the_result_of(v)\n    if opVIsResultOf == HwtOps.INDEX:\n        iOp = v.singleDriver()\n        iOpSrc, iOpI = iOp.operands\n        if isinstance(iOpI, HConst) and iOpI._is_full_valid() and isinstance(iOpI._dtype, HBits) and int(iOpI) == iOpSrc._dtype.bit_length() - 1:\n            return iOpSrc\n\n    return None\n\n\n@internal\ndef _fold_concat_of_msb_using_sext(v: \"HBitsRtlSignal\", vReplicatinCount:int, other: \"HBitsRtlSignal\", other_w: int):\n    msbSrc = _match_msb_get(v)\n    if msbSrc is other or other._dtype.bit_length() == 1 and v is other:\n        # fold concat(x.msb, x) -> sext(x)\n        return other._sext(other_w + vReplicatinCount)\n\n    else:\n        opOtherIsResultOf = _get_operator_i_am_the_result_of(other)\n        if opOtherIsResultOf == HwtOps.SEXT and msbSrc == other.singleDriver().operands[0]:\n            # fold concat(x.msb, sext(x)) -> sext(x)\n            return msbSrc._sext(other_w + vReplicatinCount)\n        elif opOtherIsResultOf == HwtOps.CONCAT:\n            otherD: HOperatorNode = other.singleDriver()\n            highBits, lowBits = otherD.operands\n            if highBits is v:\n                # fold concat(x1b, concat(x1b, y))) -> concat(sext(x1b), y)\n                assert highBits._dtype.bit_length() == 1, highBits\n                return highBits._sext(1 + vReplicatinCount)._concat(lowBits)\n            elif highBits is msbSrc:\n                # fold concat(x.msb, concat(x, y)) -> concat(sext(x), y)\n                return highBits._sext(highBits._dtype.bit_length() + vReplicatinCount)._concat(lowBits)\n            else:\n                opHighBitsIsResultOf = _get_operator_i_am_the_result_of(highBits)\n                if opHighBitsIsResultOf == HwtOps.SEXT:\n                    hiBitsSrc = highBits.singleDriver().operands[0]\n                    if hiBitsSrc is msbSrc:\n                        # fold concat(x.msb, concat(sext(x), y)) -> concat(sext(x), y)\n                        return msbSrc._sext(highBits._dtype.bit_length() + vReplicatinCount)._concat(lowBits)\n    return None\n\n\n@internal\ndef _get_operator_i_am_the_result_of(const_or_sig: Union[RtlSignalBase, HConst]) -> Optional[HOperatorDef]:\n    if len(const_or_sig._rtlDrivers) == 1 and isinstance(const_or_sig._rtlObjectOrigin, HOperatorNode):\n        return const_or_sig._rtlObjectOrigin.operator\n    else:\n        return None\n\n\n@internal\ndef bitsGetitem_foldSliceOnCONCAT(v: AnyHBitsValue, start:int, stop: int, key: HBitsAnyIndexCompatibleValue) -> AnyHBitsValue:\n    op_h, op_l = v._rtlObjectOrigin.operands\n    op_l_w = op_l._dtype.bit_length()\n    assert start > stop, (start, stop, \"Should be in MSB:LSB format\")\n    if start <= op_l_w:\n        # entirely in first operand of concat\n        if op_l_w == 1:\n            if isinstance(key._dtype, HSlice):\n                assert int(key.val.start) == 1 and int(key.val.stop) == 0 and int(key.val.step) == -1, key\n                return op_l\n            else:\n                assert int(key) == 0, key\n                return op_l\n        else:\n            return op_l[key]\n    elif stop >= op_l_w:\n        # intirely in second operand of concat\n        start -= op_l_w\n        stop -= op_l_w\n        if op_h._dtype.bit_length() == 1:\n            assert start - stop == 1\n            return op_h\n        else:\n            return op_h[SLICE.from_py(slice(start, stop, -1))]\n    else:\n        # partially in op_h and op_l, allpy slice on concat operands and return concatenation of it\n        if stop != 0 or op_l._dtype.bit_length() > 1:\n            op_l = op_l[:stop]\n\n        if op_h._dtype.bit_length() == 1:\n            assert start - op_l_w == 1, (\"Out of range slice (but this error should be catched sooner)\", v, key)\n        else:\n            op_h = op_h[start - op_l_w:0]\n\n        return op_h._concat(op_l)\n\n\n@internal\ndef bitsGetitem_foldSliceOnEXT(v: AnyHBitsValue,\n                               start:int, stop: int,\n                               key: HBitsAnyIndexCompatibleValue,\n                               iAmResultOfOp: Literal[HwtOps.ZEXT, HwtOps.SEXT]) -> AnyHBitsValue:\n    assert iAmResultOfOp in (HwtOps.ZEXT, HwtOps.SEXT), iAmResultOfOp\n        # :note: start points at MSB and stop on LSB (start:stop, eg 8:0)\n    extSrc = v.singleDriver().operands[0]\n    extSrcWidth = extSrc._dtype.bit_length()\n    resultWidth = start - stop\n    if start < extSrcWidth:\n        # selecting only bits from extSrc\n        if stop == 0:\n            return extSrc._trunc(start)\n        else:\n            return extSrc[key]\n\n    elif stop >= extSrcWidth:\n        # only msb bits are selected from ext and\n        if iAmResultOfOp == HwtOps.ZEXT:\n            return v._dtype._createMutated(resultWidth).from_py(0)\n        else:\n            return extSrc.getMsb()._sext(resultWidth)\n    else:\n        # selected value overlaps between extSrc and extension bits\n        if stop != 0:\n            extSrc = extSrc[:stop]\n        return extSrc._ext(resultWidth, iAmResultOfOp == HwtOps.SEXT)\n\n\n@internal\ndef bitsGetitem_foldBitGetOnEXT(v: AnyHBitsValue,\n                                i:int,\n                                key: HBitsAnyIndexCompatibleValue,\n                                iAmResultOfOp: Literal[HwtOps.ZEXT, HwtOps.SEXT]) -> AnyHBitsValue:\n    # fold zext(x)[i] -> x[i] if x.width < i else 0\n    # fold sext(x)[i] -> x[i] if x.width < i else x.msb\n    extSrc = v.singleDriver().operands[0]\n    extSrcWidth = extSrc._dtype.bit_length()\n    if i < extSrcWidth:\n        # selecting only bits from extSrc\n        return extSrc[key]\n    else:\n        # only msb bits are selected from ext and\n        if iAmResultOfOp == HwtOps.ZEXT:\n            return v._dtype._createMutated(1).from_py(0)\n        else:\n            return extSrc.getMsb()\n\n\n@internal\ndef bitsGetitem_foldBitGetOnConcat(v: AnyHBitsValue, key: HBitsAnyIndexCompatibleValue, _index:int, iAmResultOfOp: Optional[HOperatorDef]):\n    # index directly in the member of concatenation\n    update_key = False\n    while iAmResultOfOp == HwtOps.CONCAT:\n        op_h, op_l = v._rtlObjectOrigin.operands\n        op_l_w = op_l._dtype.bit_length()\n        if _index < op_l_w:\n            v = op_l\n        else:\n            v = op_h\n            _index -= op_l_w\n            update_key = True\n        iamConst = isinstance(v, HConst)\n        iAmResultOfOp = None if iamConst else _get_operator_i_am_the_result_of(v)\n        # [todo] check if swap of negated flag can cause anything wrong\n\n    if update_key:\n        key = key._dtype.from_py(_index)\n\n    return v, key\n\n\n@internal\ndef bitsGetitem(v: AnyHBitsValue, iamConst:bool, key: HBitsAnyIndexCompatibleValue) -> AnyHBitsValue:\n    \"\"\"\n    [] operator\n\n    :attention: Table below is for little endian bit order (MSB:LSB)\n        which is default.\n        This is **reversed** as it is in pure python\n        where it is [0, len(v)].\n\n    :attention: Slice on slice signal is automatically reduced\n        to single slice. This function also looks trough concatenations.\n\n    +-----------------------------+----------------------------------------------------------------------------------+\n    | a[up:low]                   | items low through up; a[16:8] selects upper byte from 16b vector a               |\n    +-----------------------------+----------------------------------------------------------------------------------+\n    | a[up:]                      | low is automatically substituted with 0; a[8:] will select lower 8 bits          |\n    +-----------------------------+----------------------------------------------------------------------------------+\n    | a[:end]                     | up is automatically substituted; a[:8] will select upper byte from 16b vector a  |\n    +-----------------------------+----------------------------------------------------------------------------------+\n    | a[:], a[-1], a[-2:], a[:-2] | raises NotImplementedError   (not implemented due to complicated support in hdl) |\n    +-----------+----------------------------------------------------------------------------------------------------+\n\n    :note: signed is preserved as in VHDL, and not like in Verilog where result of slice is always unsigned\n    \"\"\"\n    st = v._dtype\n    vWidth = st.bit_length()\n\n    if isinstance(key, slice):\n        key = slice_to_HSlice(key, vWidth)\n        isSLICE = True\n    else:\n        isSLICE = isinstance(key, HSlice.getConstCls())\n\n    is1bScalar = vWidth == 1 and not st.force_vector\n    if not isSLICE:\n        if is1bScalar and \\\n                ((isinstance(key, int) and key == 0) or\\\n                 (isinstance(key, HConst) and key._is_full_valid() and int(key) == 0)):\n            return v\n        key = toHVal(key, INT)\n    else:\n        if is1bScalar and key.val.start == 1 and key.val.stop == 0 and key.val.step == -1:\n            return v\n\n    if is1bScalar:\n        # assert not indexing on single bit\n        raise IndexError(\"indexing on single bit\")\n\n    iAmResultOfOp = None if iamConst else _get_operator_i_am_the_result_of(v)\n    if iAmResultOfOp == HwtOps.TRUNC:\n        # fold trunc(x)[i] to x[i]\n        return v.singleDriver().operands[0][key]\n    elif iAmResultOfOp == HwtOps.BitsAsSigned or iAmResultOfOp == HwtOps.BitsAsUnsigned:\n        # fold x._signed()[i] to x[i]._signed()\n        return iAmResultOfOp._evalFn(v.singleDriver().operands[0][key])\n\n    HBits = v._dtype.__class__\n    if isSLICE:\n        # :note: downto notation\n        start = key.val.start\n        stop = key.val.stop\n        if key.val.step != -1:\n            raise NotImplementedError()\n\n        startIsConst = isinstance(start, HConst)\n        stopIsConst = isinstance(stop, HConst)\n        indexesAreHConst = startIsConst and stopIsConst\n        if indexesAreHConst and start.val == vWidth and stop.val == 0:\n            # selecting all bits no conversion needed\n            # fold x[h:l] -> x\n            return v\n\n        # check start boundaries\n        if startIsConst:\n            _start = int(start)\n            if _start < 0 or _start > vWidth:\n                raise IndexError(\"start index is out of range start:\", _start, \" width:\", vWidth, \"\")\n\n        # check end boundaries\n        if stopIsConst:\n            _stop = int(stop)\n            if _stop < 0 or _stop >= vWidth:\n                raise IndexError(\"stop index is out of range stop:\", _stop, \" width:\", vWidth)\n\n        # check width of selected range\n        if startIsConst and stopIsConst and _start - _stop <= 0:\n            raise IndexError(\"start (represents MSB bit index +1) must be > stop (represents LSB bit index)\", _start, _stop)\n\n        if iAmResultOfOp == HwtOps.INDEX:\n            # try reduce v and parent slice to one\n            # fold x[a:b][start:stop] -> x[b+start:b+stop]\n            original, parentIndex = v._rtlObjectOrigin.operands\n            if isinstance(parentIndex._dtype, HSlice):\n                parentLower = parentIndex.val.stop\n                start = parentLower + start\n                stop = parentLower + stop\n                return original[start:stop]\n\n        elif startIsConst and stopIsConst:\n            # index directly in the member of concatenation\n            # :note: start points at MSB and stop on LSB (start:stop, eg 8:0)\n            stop = int(stop)\n            start = int(start)\n            if iAmResultOfOp == HwtOps.CONCAT:\n                return bitsGetitem_foldSliceOnCONCAT(v, start, stop, key)\n            elif iAmResultOfOp == HwtOps.ZEXT or iAmResultOfOp == HwtOps.SEXT:\n                return bitsGetitem_foldSliceOnEXT(v, start, stop, key, iAmResultOfOp)\n            elif stop == 0:\n                return v._trunc(start)\n\n        if iamConst:\n            if isinstance(key, SLICE.getConstCls()):\n                key = key.val\n            res = Bits3val.__getitem__(v, key)\n            if res._dtype.bit_length() == 1 and not res._dtype.force_vector:\n                assert res._dtype is not v._dtype\n                res._dtype.force_vector = True\n            return res\n        else:\n            key = SLICE.from_py(slice(start, stop, -1))\n            _resWidth = start - stop\n            resT = HBits(bit_length=_resWidth, force_vector=_resWidth == 1,\n                        signed=st.signed, negated=st.negated)\n\n    elif isinstance(key, HBits.getConstCls()):\n        # int like value addressing a single bit\n        if st.negated:\n            resT = BIT_N\n        else:\n            resT = BIT\n        if not key._is_full_valid():\n            return resT.from_py(None)\n\n        # check index range\n        _index = int(key)\n        # if _index == 0 and not st.force_vector:\n        #     # fold x[0] -> x._trunc(1)\n        #     return v._trunc(1)\n\n        if _index < 0 or _index > vWidth - 1:\n            raise IndexError(_index)\n        if iAmResultOfOp == HwtOps.INDEX:\n            # index directly in parent signal\n            # fold x[a:b][i] -> x[b+i]\n            original, parentIndex = v._rtlObjectOrigin.operands\n            if isinstance(parentIndex._dtype, HSlice):\n                parentLower = parentIndex.val.stop\n                return original[parentLower + _index]\n\n        elif iAmResultOfOp == HwtOps.TRUNC:\n            # fold x._trunc(n)[i] to x[i]\n            original = v._rtlObjectOrigin.operands[0]\n            return original[_index]\n\n        elif iAmResultOfOp == HwtOps.ZEXT or iAmResultOfOp == HwtOps.SEXT:\n            return bitsGetitem_foldBitGetOnEXT(v, _index, key, iAmResultOfOp)\n\n        else:\n            # index directly in the member of concatenation\n            # fold concat(a, x)[i] -> x[i]\n            _v, _key = bitsGetitem_foldBitGetOnConcat(v, key, _index, iAmResultOfOp)\n            changed = v is not _v or _key is not key\n            v = _v\n            key = _key\n            iamConst = isinstance(v, HConst)\n            st = v._dtype\n            if isinstance(key, HBits.getConstCls()) and int(key) == 0 and (\n                    v._dtype.bit_length() == 1 and not v._dtype.force_vector\n                ):\n                return v\n            elif changed:\n                return v[key]\n\n        if iamConst:\n            # at the end because multiple non-constant indexes may be applied on constant and we want to merge them\n            return Bits3val.__getitem__(v, key)\n        elif key._is_full_valid() and int(key) == 0 and (v._dtype == BIT or v._dtype == BIT_N):\n            return v\n\n    elif isinstance(key, RtlSignalBase):\n        t = key._dtype\n        if isinstance(t, HSlice):\n            bit_length = key.staticEval()._size()\n            resT = HBits(bit_length,\n                        force_vector=bit_length == 1,\n                        signed=st.signed,\n                        negated=st.negated)\n        elif isinstance(t, HBits):\n            resT = BIT\n        else:\n            raise TypeError(\n                \"Index operation not implemented\"\n                \" for index of type \", t)\n\n    else:\n        raise TypeError(\n            \"Index operation not implemented for index \", key)\n\n    if st.negated and resT is BIT:\n        resT = BIT_N\n\n    return HOperatorNode.withRes(HwtOps.INDEX, [v, key], resT)\n\n"
  },
  {
    "path": "hwt/hdl/types/bitConst_opReduce.py",
    "content": "from typing import Union\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.mainBases import RtlSignalBase\nfrom pyMathBitPrecise.bit_utils import mask\n\n\n@internal\ndef tryReduceAnd(sig:RtlSignalBase, val: HConst):\n    \"\"\"\n    Return sig and val reduced by & operator or None\n    if it is not possible to statically reduce expression\n    \"\"\"\n    m = sig._dtype.all_mask()\n    if val._is_full_valid():\n        v = val.val\n        if v == m:\n            return sig\n        elif v == 0:\n            return val\n\n\n@internal\ndef tryReduceOr(sig:RtlSignalBase, val: HConst):\n    \"\"\"\n    Return sig and val reduced by | operator or None\n    if it is not possible to statically reduce expression\n    \"\"\"\n    m = sig._dtype.all_mask()\n    if not val.vld_mask:\n        return val\n\n    if val._is_full_valid():\n        v = val.val\n        if v == m:\n            return val\n        elif v == 0:\n            return sig\n\n\n@internal\ndef tryReduceXor(sig:RtlSignalBase, val: HConst):\n    \"\"\"\n    Return sig and val reduced by ^ operator or None\n    if it is not possible to statically reduce expression\n    \"\"\"\n    m = sig._dtype.all_mask()\n    if not val.vld_mask:\n        return val\n\n    if val._is_full_valid():\n        v = val.val\n        if v == m:\n            return ~sig\n        elif v == 0:\n            return sig\n\n\ndef reduceSigCheckFnAnd(op0Original:RtlSignalBase, op0Negated: bool, op1Negated:bool) -> Union[RtlSignalBase, HConst]:\n    if op0Negated == op1Negated:\n        # a & a -> a\n        # ~a & ~a -> ~a\n        return op0Original\n    else:\n        # a | ~a -> 0\n        # ~a | a -> 0\n        return op0Original._dtype.from_py(0)\n\n\ndef reduceSigCheckFnOr(op0Original:RtlSignalBase, op0Negated: bool, op1Negated:bool) -> Union[RtlSignalBase, HConst]:\n    if op0Negated == op1Negated:\n        # a | a -> a\n        # ~a | ~a -> ~a\n        return op0Original\n    else:\n        # a | ~a -> 1\n        # ~a | a -> 1\n        t = op0Original._dtype\n        return t.from_py(mask(t.bit_length()))\n\n\ndef reduceSigCheckFnXor(op0Original:RtlSignalBase, op0Negated: bool, op1Negated:bool) -> Union[RtlSignalBase, HConst]:\n    t = op0Original._dtype\n    if op0Negated == op1Negated:\n        # a ^ a -> 0\n        # ~a ^ ~a -> 0\n        return t.from_py(0)\n    else:\n        # a ^ ~a -> 1\n        # ~a ^ a -> 1\n        return t.from_py(mask(t.bit_length()))\n\n"
  },
  {
    "path": "hwt/hdl/types/bits.py",
    "content": "from typing import Union, Literal, Optional, Self\n\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.generic.indent import getIndent\nfrom pyMathBitPrecise.bits3t import Bits3t\n\nBITS_DEFAUTL_SIGNED = None\nBITS_DEFAUTL_FORCEVECTOR = False\nBITS_DEFAUTL_NEGATED = False\n\n\nclass HBits(HdlType, Bits3t):\n    \"\"\"\n    Elemental HDL type representing bits (vector or single bit)\n    \"\"\"\n\n    def __init__(self, bit_length: Union[int, \"AnyHBitsValue\"],\n                 signed:Literal[None, True, False]=BITS_DEFAUTL_SIGNED,\n                 force_vector:bool=BITS_DEFAUTL_FORCEVECTOR,\n                 negated:bool=BITS_DEFAUTL_NEGATED,\n                 name:Optional[str]=None,\n                 const:bool=False,\n                 strict_sign:bool=True, strict_width:bool=True):\n        \"\"\"\n        :param negated: if true the value is in negated form\n        \"\"\"\n        self.negated = negated\n        HdlType.__init__(self, const=const)\n        bit_length = int(bit_length)\n        assert bit_length > 0, bit_length\n        Bits3t.__init__(self, bit_length, signed, name=name,\n                        force_vector=force_vector or bit_length == 1 and signed is not None,\n                        strict_sign=strict_sign, strict_width=strict_width)\n\n    def _createMutated(self,\n                 bit_length: Union[int, \"AnyHBitsValue\"]=NOT_SPECIFIED,\n                 signed:Literal[None, True, False]=NOT_SPECIFIED,\n                 force_vector:bool=NOT_SPECIFIED,\n                 negated:bool=NOT_SPECIFIED,\n                 name:Optional[str]=NOT_SPECIFIED,\n                 const:bool=NOT_SPECIFIED,\n                 strict_sign:bool=NOT_SPECIFIED,\n                 strict_width:bool=NOT_SPECIFIED\n                 ) -> Self:\n        if bit_length is NOT_SPECIFIED:\n            bit_length = self.bit_length()\n        else:\n            if force_vector is NOT_SPECIFIED and self.force_vector and bit_length > 1 and self.bit_length() == 1:\n                force_vector = False\n        if signed is NOT_SPECIFIED:\n            signed = self.signed\n        if force_vector is NOT_SPECIFIED:\n            force_vector = self.force_vector\n        if negated is NOT_SPECIFIED:\n            negated = self.negated\n        if name is NOT_SPECIFIED:\n            name = None\n        if const is NOT_SPECIFIED:\n            const = self.const\n        if strict_sign is NOT_SPECIFIED:\n            strict_sign = self.strict_sign\n        if strict_width is NOT_SPECIFIED:\n            strict_width = self.strict_width\n\n        return self.__class__(\n            bit_length,\n            signed=signed,\n            force_vector=force_vector,\n            negated=negated,\n            name=name,\n            const=const,\n            strict_sign=strict_sign,\n            strict_width=strict_width\n        )\n\n    @internal\n    def domain_size(self):\n        \"\"\"\n        :return: how many values can have specified type\n        \"\"\"\n        return int(2 ** self.bit_length())\n\n    @internal\n    @classmethod\n    def get_auto_cast_HConst_fn(cls):\n        from hwt.hdl.types.bitsCast import convertBits__HConst\n        return convertBits__HConst\n\n    @internal\n    @override\n    @classmethod\n    def get_reinterpret_cast_HConst_fn(cls):\n        from hwt.hdl.types.bitsCast import reinterpretBits__HConst\n        return reinterpretBits__HConst\n\n    @internal\n    @classmethod\n    def get_auto_cast_RtlSignal_fn(cls):\n        from hwt.hdl.types.bitsCast import convertBits__RtlSignal\n        return convertBits__RtlSignal\n\n    @internal\n    @override\n    @classmethod\n    def get_reinterpret_cast_RtlSignal_fn(cls):\n        from hwt.hdl.types.bitsCast import reinterpretBits__RtlSignal\n        return reinterpretBits__RtlSignal\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.bitsConst import HBitsConst\n            cls._constCls = HBitsConst\n            return cls._constCls\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        try:\n            return cls._rtlSignalCls\n        except AttributeError:\n            from hwt.hdl.types.bitsRtlSignal import HBitsRtlSignal\n            cls._rtlSignalCls = HBitsRtlSignal\n            return cls._rtlSignalCls\n\n    def getAllOnesValue(self):\n        return self.from_py(self._all_mask)\n\n    def __hash__(self):\n        return hash((Bits3t.__hash__(self), self.const))\n\n    def __eq__(self, other):\n        return Bits3t.__eq__(self, other) and \\\n             isinstance(other, self.__class__) and \\\n             self.const == other.const\n\n    def __repr__(self, indent=0, withAddr=None, expandStructs=False):\n        \"\"\"\n        :param indent: number of indentation\n        :param withAddr: if is not None is used as a additional\n            information about on which address this type is stored\n            (used only by HStruct)\n        :param expandStructs: expand HStructTypes (used by HStruct and HArray)\n        \"\"\"\n        constr = []\n        if self.name is not None:\n            constr.append('\"%s\"' % self.name)\n        c = self.bit_length()\n        if c == 1:\n            constr.append(\"1bit\")\n            if self.force_vector:\n                constr.append(\"force_vector\")\n        else:\n            constr.append(f\"{c:d}bits\")\n\n        if self.const:\n            constr.append(\"const\")\n\n        if self.signed:\n            constr.append(\"signed\")\n        elif self.signed is False:\n            constr.append(\"unsigned\")\n\n        if not self.strict_sign:\n            constr.append(\"strict_sign=False\")\n\n        if not self.strict_width:\n            constr.append(\"strict_width=False\")\n\n        return \"%s<%s, %s>\" % (getIndent(indent),\n                               self.__class__.__name__,\n                               \", \".join(constr))\n"
  },
  {
    "path": "hwt/hdl/types/bitsCast.py",
    "content": "from typing import Union\n\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsCastUtils import fitTo_t, BitWidthErr\nfrom hwt.hdl.types.defs import INT, BOOL\nfrom hwt.hdl.types.hdlType import HdlType, default_auto_cast_fn\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.hdl.types.union import HUnion\nfrom hwt.hwIOs.hwIOArray import HwIOArray\nfrom hwt.hwIOs.hwIOStruct import HdlType_to_HwIO\nfrom hwt.mainBases import HwIOBase\nfrom hwt.synthesizer.exceptions import TypeConversionErr\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwt.synthesizer.vectorUtils import iterBits\nfrom pyMathBitPrecise.bit_utils import set_bit_range, mask\n\n\n@internal\ndef convertBits__HConst(curType: HBits, val: \"HBitsConst\", toType: HdlType):\n    \"\"\"\n    :param curType: current type\n    :param val: constant object to cast into toType\n    :param toType: type to cast val to\n    \"\"\"\n    if toType == BOOL:\n        return val != curType.getConstCls().from_py(curType, 0)\n    elif isinstance(toType, HBits):\n        if curType.signed != toType.signed:\n            if curType.strict_sign and bool(curType.signed) != bool(toType.signed):\n                raise TypeConversionErr(curType, toType)\n            val = val._cast_sign(toType.signed)\n\n        w_from, w_to = curType.bit_length(), toType.bit_length()\n        if w_from != w_to:\n            if curType.strict_width:\n                raise TypeConversionErr(curType, toType)\n            if w_from > w_to:\n                # cut off some bits from value\n                new_m = val.vld_mask & toType.all_mask()\n            else:\n                # w_from < w_to, extend the value to some bit length\n                extra_mask_bits = mask(w_to - w_from)\n                new_m = set_bit_range(val.vld_mask, w_from, w_to - w_from, extra_mask_bits)\n            val = toType.from_py(val.val, new_m)\n\n        if val._dtype != toType:\n            # sign and width checked, only name, strict_* flags can be different\n            val = toType.from_py(val.val, val.vld_mask)\n        return val\n    elif toType == INT:\n        return INT.getConstCls()(INT, val.val,\n                                 int(val._is_full_valid()))\n\n    return default_auto_cast_fn(curType, val, toType)\n\n\n@internal\ndef convertBits__RtlSignal(curType: HBits, sig: RtlSignal, toType: HdlType):\n    \"\"\"\n    Cast Bit subtypes, (integers, bool, ...)\n    \"\"\"\n    if toType == BOOL:\n        if curType.bit_length() == 1:\n            v = 0 if sig._dtype.negated else 1\n            if isinstance(sig, RtlSignal):\n                sig: RtlSignal\n                try:\n                    d = sig.singleDriver()\n                except SignalDriverErr:\n                    d = None\n\n                if d is not None and isinstance(d, HOperatorNode) and d.operator == HwtOps.NOT:\n                    # signal itself is negated, ~a = 1 to a = 0\n                    v = int(not bool(v))\n                    sig = d.operands[0]\n\n            return sig._eq(curType.getConstCls().from_py(curType, v))\n    elif isinstance(toType, HBits):\n        if curType.bit_length() == toType.bit_length():\n            # if curType.force_vector != toType.force_vector:\n            #    raise NotImplementedError(curType, toType)\n\n            if curType.const == toType.const:\n                return sig._cast_sign(toType.signed)\n\n    return default_auto_cast_fn(curType, sig, toType)\n\n\n@internal\ndef reinterpret_bits_to_hstruct__HConst(val: HConst, hStructT: HStruct):\n    \"\"\"\n    Reinterpret signal of type HBits to signal of type HStruct\n    \"\"\"\n    container = hStructT.from_py(None)\n    hStructT.vld_mask = int(val._is_full_valid())\n    offset = 0\n    for f in hStructT.fields:\n        t = f.dtype\n        width = t.bit_length()\n        if f.name is not None:\n            v = val[(width + offset):offset]\n            v = v._reinterpret_cast(t)\n            setattr(container, f.name, v)\n\n        offset += width\n    if offset != val._dtype.bit_length():\n        raise BitWidthErr(\"Src type contains more bits than dst\", val._dtype.bit_length(), hStructT.bit_length(), val._dtype, hStructT)\n\n    return container\n\n\n@internal\ndef transfer_signals(src: Union[HwIOBase, HObjList], dst: Union[HwIOBase, HObjList]):\n    if isinstance(src, HObjList):\n        assert len(src) == len(dst)\n        for si, di in zip(src, dst):\n            transfer_signals(si, di)\n\n    elif isinstance(src, (RtlSignal, HConst)):\n        assert not dst._hwIOs, (src, dst)\n        dst._sig = src\n\n    elif src._hwIOs:\n        # HwIOBase\n        assert len(src._hwIOs) == len(dst._hwIOs), (src, dst)\n        for si, di in zip(src._hwIOs, dst._hwIOs):\n            transfer_signals(si, di)\n    else:\n        dst._sig = src._sig\n        dst._sigInside = src._sigInside\n\n\n@internal\ndef reinterpret_bits_to_hstruct__RtlSignal(val: RtlSignal, hStructT: HStruct):\n    \"\"\"\n    Reinterpret signal of type :class:`HBits` to signal of type :class:`HStruct`\n    \"\"\"\n    container = HdlType_to_HwIO().apply(hStructT)\n    container._loadHwDeclarations()\n    offset = 0\n    for f in hStructT.fields:\n        t = f.dtype\n        width = t.bit_length()\n        if f.name is not None:\n            if offset == 0 and val._dtype.bit_length() == width:\n                v = val\n            else:\n                v = val[(width + offset):offset]\n            v = v._reinterpret_cast(t)\n            current = getattr(container, f.name)\n            transfer_signals(v, current)\n\n        offset += width\n    if offset != val._dtype.bit_length():\n        raise BitWidthErr(\"Src type contains more bits than dst\", val._dtype.bit_length(), hStructT.bit_length(), val._dtype, hStructT)\n\n    return container\n\n\n@internal\ndef reinterpret_bits_to_harray(sigOrConst: Union[RtlSignal, HConst], hArrayT: HArray):\n    elmT = hArrayT.element_t\n    elmWidth = elmT.bit_length()\n    if isinstance(sigOrConst, HConst):\n        a = hArrayT.from_py(None)\n        a.vld_mask = int(sigOrConst._is_full_valid())\n    else:\n        a = HwIOArray(None for _ in range(hArrayT.size))\n\n    for i, item in enumerate(iterBits(sigOrConst,\n                                      bitsInOne=elmWidth,\n                                      skipPadding=False)):\n        item = item._reinterpret_cast(elmT)\n        a[i] = item\n\n    return a\n\n\n@internal\ndef reinterpretBits__HConst(curType: HBits, val: HConst, toType: HdlType):\n    if isinstance(toType, HBits):\n        if curType.signed != toType.signed:\n            val = val._cast_sign(toType.signed)\n        val = fitTo_t(val, toType)  # , extend=False, shrink=False\n        if val._dtype == toType:\n            return val\n        else:\n            return convertBits__HConst(val._dtype, val, toType)\n    elif isinstance(toType, HStruct):\n        return reinterpret_bits_to_hstruct__HConst(val, toType)\n    elif isinstance(toType, HUnion):\n        raise NotImplementedError()\n    elif isinstance(toType, HArray):\n        return reinterpret_bits_to_harray(val, toType)\n\n    return default_auto_cast_fn(curType, val, toType)\n\n\n@internal\ndef reinterpretBits__RtlSignal(curType: HBits, sig: RtlSignal, toType: HdlType):\n    \"\"\"\n    Cast object of same bit size between to other type\n    (f.e. bits to struct, union or array)\n    \"\"\"\n    if isinstance(toType, HBits):\n        if curType.signed != toType.signed:\n            sig = sig._cast_sign(toType.signed)\n        sig = fitTo_t(sig, toType)\n        if sig._dtype == toType:\n            return sig\n        else:\n            return convertBits__RtlSignal(sig._dtype, sig, toType)\n    elif sig._dtype.bit_length() == toType.bit_length():\n        if isinstance(toType, HStruct):\n            return reinterpret_bits_to_hstruct__RtlSignal(sig, toType)\n        elif isinstance(toType, HUnion):\n            raise NotImplementedError()\n        elif isinstance(toType, HArray):\n            return reinterpret_bits_to_harray(sig, toType)\n\n    return default_auto_cast_fn(curType, sig, toType)\n"
  },
  {
    "path": "hwt/hdl/types/bitsCastUtils.py",
    "content": "from typing import Union\n\nfrom hwt.hdl.types.bits import HBits\n\n\nclass BitWidthErr(Exception):\n    \"\"\"\n    Wrong bit width of signal/value\n    \"\"\"\n\n\ndef fitTo_t(what: Union[\"HBitsRtlSignal\", \"HBitsConst\"], where_t: HBits,\n            extend: bool=True, shrink: bool=True) -> Union[\"HBitsRtlSignal\", \"HBitsConst\"]:\n    \"\"\"\n    Slice signal \"what\" to fit in \"where\"\n    or\n    arithmetically (for signed by MSB / unsigned, vector with 0) extend\n    \"what\" to same width as \"where\"\n\n    little-endian impl.\n\n    :param extend: allow increasing of the signal width\n    :param shrink: allow shrinking of the signal width\n    \"\"\"\n\n    whatWidth = what._dtype.bit_length()\n    toWidth = where_t.bit_length()\n    if toWidth == whatWidth:\n        return what\n    elif toWidth < whatWidth:\n        # slice\n        if not shrink:\n            raise BitWidthErr()\n\n        return what[toWidth:]\n    else:\n        if not extend:\n            raise BitWidthErr()\n\n        res = what._ext(toWidth)\n        if where_t.signed is not None:\n            return res._reinterpret_cast(where_t)\n        return res\n\n\ndef fitTo(what: Union[\"HBitsRtlSignal\", \"HBitsConst\"], where: Union[\"HBitsRtlSignal\", \"HBitsConst\"],\n          extend: bool=True, shrink: bool=True) -> Union[\"HBitsRtlSignal\", \"HBitsConst\"]:\n    return fitTo_t(what, where._dtype, extend, shrink)\n\n"
  },
  {
    "path": "hwt/hdl/types/bitsConst.py",
    "content": "from copy import copy\nfrom operator import eq\nfrom typing import Union, Self\n\nfrom hdlConvertorAst.to.hdlUtils import bit_string\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.bitConstFunctions import bitsCmp, \\\n    bitsBitOp, bitsArithOp, bitsFloordiv, bitsMul, bitsLshift, \\\n    bitsRshift, HBitsAnyIndexCompatibleValue, HBitsAnyCompatibleValue, bitsRem\nfrom hwt.hdl.types.bitConstFunctionsGetitem import bitsGetitem\nfrom hwt.hdl.types.bitConst_opReduce import tryReduceOr, tryReduceAnd, \\\n    tryReduceXor, reduceSigCheckFnAnd, reduceSigCheckFnOr, reduceSigCheckFnXor\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsRtlSignal import HBitsRtlSignal\nfrom hwt.hdl.types.defs import BOOL, INT, BIT, SLICE\nfrom hwt.hdl.types.sliceUtils import slice_to_HSlice\nfrom hwt.hdl.types.typeCast import toHVal\nfrom pyMathBitPrecise.bits3t import Bits3val\nfrom pyMathBitPrecise.bits3t_vld_masks import vld_mask_for_xor, vld_mask_for_and, \\\n    vld_mask_for_or\n\n\nclass HBitsConst(HConst, Bits3val):\n    \"\"\"\n    :attention: operator on signals are using value operator functions as well\n    \"\"\"\n    _BOOL = HBits(1, name=\"bool\")\n    _SIGNED_FOR_SLICE_RESULT = NOT_SPECIFIED\n    _SIGNED_FOR_CONCAT_RESULT = None\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None) -> Self:\n        val, vld_mask = typeObj._normalize_val_and_mask(val, vld_mask)\n        return cls(typeObj, val, vld_mask=vld_mask)\n\n    @internal\n    def _cast_sign(self, signed:Union[bool, None]) -> Self:\n        try:\n            t = self._dtype\n            v = Bits3val._cast_sign(self, signed,\n                                    name=None,\n                                    force_vector=t.bit_length() == 1 if signed else t.force_vector)\n            if self._dtype == v._dtype:\n                # no change of type, use this instance\n                return self\n            else:\n                return v\n\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _signed(self) -> Self:\n        return self._cast_sign(True)\n\n    def _unsigned(self) -> Self:\n        return self._cast_sign(False)\n\n    def _vec(self) -> Self:\n        return self._cast_sign(None)\n\n    @internal\n    def _concat(self, other: Union[Self, \"HBitsRtlSignal\"]) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            if isinstance(other, HConst):\n                return Bits3val._concat(self._vec(), other._vec())\n            else:\n                if self._is_full_valid():\n                    if int(self) == 0:\n                        # fold concat(0, x) -> zext(x)\n                        return other._zext(self._dtype.bit_length() + other._dtype.bit_length())\n\n                return HBitsRtlSignal._concat(self, other)\n\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __getitem__(self, key: HBitsAnyIndexCompatibleValue) -> Self:\n        try:\n            return bitsGetitem(self, True, key)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __setitem__(self, index: HBitsAnyIndexCompatibleValue, value: Union[Self, \"HBitsRtlSignal\"]) -> Self:\n        \"\"\"\n        this []= operator can not be called in design description, it can be only used to update HConsts\n        \"\"\"\n        try:\n            # convert index to HSlice or hInt\n            if isinstance(index, HConst):\n                pass\n            elif isinstance(index, slice):\n                length = self._dtype.bit_length()\n                index = slice_to_HSlice(index, length)\n                if not index._is_full_valid():\n                    raise ValueError(\"invalid index\", index)\n            else:\n                index = INT.from_py(index)\n\n            # convert value to bits of length specified by index\n            if index._dtype == SLICE:\n                HBits = self._dtype.__class__\n                itemT = HBits(index._size())\n            else:\n                itemT = BIT\n\n            if isinstance(value, HConst):\n                value = value._auto_cast(itemT)\n            else:\n                value = itemT.from_py(value)\n\n            return Bits3val.__setitem__(self, index, value)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __invert__(self) -> Self:\n        try:\n            return Bits3val.__invert__(self)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __hash__(self):\n        return Bits3val.__hash__(self)\n\n    # comparisons\n    def _isOn(self):\n        return self._auto_cast(BOOL)\n\n    def _eq(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.EQ, _b1, eq)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __ne__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.NE, _b0)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __lt__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.SLT if self._dtype.signed else HwtOps.ULT, _b0, evalFn=HwtOps.LT._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __gt__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.SGT if self._dtype.signed else HwtOps.UGT, _b0, evalFn=HwtOps.GT._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __ge__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.SGE if self._dtype.signed else HwtOps.UGE, _b1, evalFn=HwtOps.GE._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __le__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsCmp(self, True, other, HwtOps.SLE if self._dtype.signed else HwtOps.ULE, _b1, evalFn=HwtOps.LE._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    # bitwise\n    def __xor__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsBitOp(self, True, other, HwtOps.XOR,\n                             vld_mask_for_xor, tryReduceXor, reduceSigCheckFnXor)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __and__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsBitOp(self, True, other, HwtOps.AND,\n                             vld_mask_for_and, tryReduceAnd, reduceSigCheckFnAnd)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __or__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsBitOp(self, True, other, HwtOps.OR,\n                             vld_mask_for_or, tryReduceOr, reduceSigCheckFnOr)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __lshift__(self, other: Union[int, Self]) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsLshift(self, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __rshift__(self, other: Union[int, Self]) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsRshift(self, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __neg__(self) -> Self:\n        try:\n            return Bits3val.__neg__(self)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    # arithmetic\n    def __sub__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsArithOp(self, True, other, HwtOps.SUB)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __add__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsArithOp(self, True, other, HwtOps.ADD)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __floordiv__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsFloordiv(self, True, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __mul__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsMul(self, True, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __mod__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            return bitsRem(self, True, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _ternary(self, vTrue: Union[Self, \"HBitsRtlSignal\"], vFalse: Union[Self, \"HBitsRtlSignal\"]) -> Union[Self, \"HBitsRtlSignal\"]:\n        try:\n            vTrue = toHVal(vTrue)\n            vFalse = toHVal(vFalse, suggestedType=vTrue._dtype)\n\n            if not self._is_full_valid():\n                return vTrue._dtype.from_py(None)\n            elif self:\n                return vTrue\n            else:\n                return vFalse\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __abs__(self):\n        if not self._dtype.signed:\n            return self\n        return (self < 0)._ternary(-self, self)\n\n    def getMsb(self) -> Self:\n        return self[self._dtype.bit_length() - 1]\n\n    def __len__(self) -> int:\n        return self._dtype.bit_length()\n\n    def __eq__(self, other):\n        if isinstance(other, HConst):\n            t = self._dtype\n            o_t = other._dtype\n            typeCompatible = (\n                t == o_t\n                    or (\n                        t.bit_length() == 1 and\n                        o_t.bit_length() == 1 and \\\n                        t.signed is o_t.signed and \\\n                        t.force_vector != o_t.force_vector\n                        )\n            )\n            return typeCompatible and \\\n                self.vld_mask == other.vld_mask and\\\n                self.val == other.val\n        else:\n            return False\n\n    def prettyRepr(self) -> str:\n        t = self._dtype\n        bs = bit_string(self.val, t.bit_length(), self.vld_mask)\n        signChar = ('i' if t.signed else 'b' if t.signed is None else 'u')\n        b = bs.base\n        if t.bit_length() == 1 and t.force_vector:\n            vecSpec = \"vec\"\n        else:\n            vecSpec = \"\"\n\n        if b == 2:\n            if bs.bits == 1:\n                base_char = \"\"\n            else:\n                base_char = 'b'\n        elif b == 8:\n            base_char = 'O'\n        elif b == 10:\n            base_char = 'd'\n        elif b == 16:\n            base_char = 'h'\n        else:\n            raise NotImplementedError(b)\n        return f\"{signChar:s}{t.bit_length()}{vecSpec:s}'{base_char}{bs.val}\"\n\n    def __repr__(self) -> str:\n        return Bits3val.__repr__(self)\n\n\n_b1 = BIT.from_py(1)\n_b0 = BIT.from_py(0)\n"
  },
  {
    "path": "hwt/hdl/types/bitsRtlSignal.py",
    "content": "from copy import copy\nfrom operator import eq\nfrom typing import Union, Optional, Self, Literal\n\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.bitConstFunctions import bitsCmp, \\\n    bitsBitOp, bitsArithOp, bitsFloordiv, bitsMul, bitsLshift, \\\n    bitsRshift, HBitsAnyIndexCompatibleValue, HBitsAnyCompatibleValue, bitsRem\nfrom hwt.hdl.types.bitConstFunctionsGetitem import _get_operator_i_am_the_result_of, \\\n    bitsGetitem, _fold_concat_of_msb_using_sext\nfrom hwt.hdl.types.bitConst_opReduce import tryReduceOr, tryReduceAnd, \\\n    tryReduceXor, reduceSigCheckFnAnd, reduceSigCheckFnOr, reduceSigCheckFnXor\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, BIT\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import HwIOBase\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom pyMathBitPrecise.bit_utils import ValidityError\nfrom pyMathBitPrecise.bits3t import _NOT_SPECIFIED, Bits3val\nfrom pyMathBitPrecise.bits3t_vld_masks import vld_mask_for_xor, vld_mask_for_and, \\\n    vld_mask_for_or\n\n\nclass HBitsRtlSignal(RtlSignal):\n\n    @internal\n    def _cast_sign(self, signed: Optional[bool]) -> Self:\n        \"\"\"\n        Convert signum, no bit manipulation just data are represented\n        differently\n\n        :param signed: if True value will be signed,\n            if False value will be unsigned,\n            if None value will be vector without any sign specification\n        \"\"\"\n        if self._dtype.signed == signed:\n            return self\n        t = copy(self._dtype)\n        t.signed = signed\n        if t.signed is not None and t.bit_length() == 1:\n            t.force_vector = True\n\n        if signed is None:\n            cnv = HwtOps.BitsAsVec\n        elif signed:\n            cnv = HwtOps.BitsAsSigned\n        else:\n            cnv = HwtOps.BitsAsUnsigned\n\n        return HOperatorNode.withRes(cnv, [self], t)\n\n    def _signed(self) -> Self:\n        return self._cast_sign(True)\n\n    def _unsigned(self) -> Self:\n        return self._cast_sign(False)\n\n    def _vec(self) -> Self:\n        return self._cast_sign(None)\n\n    def _concat(self, other: Union[\"HBitsConst\", Self]) -> Self:\n        \"\"\"\n        Concatenate this with other to one wider value/signal\n        \"\"\"\n        try:\n            other._dtype.bit_length\n        except AttributeError:\n            raise TypeError(\"Can not concat HBits with an object of unknown size or endianity\", other)\n\n        try:\n            w = self._dtype.bit_length()\n            other_w = other._dtype.bit_length()\n            if isinstance(self, HwIOBase):\n                self = self._sig\n\n            if isinstance(other, HwIOBase):\n                other = other._sig\n\n            if isinstance(self, HBitsRtlSignal) and isinstance(other, HBitsRtlSignal):\n                if w == 1:\n                    sext = _fold_concat_of_msb_using_sext(self, 1, other, other_w)\n                    if sext is not None:\n                        return sext\n                else:\n                    # it may be sext of msb bit\n                    operator0 = _get_operator_i_am_the_result_of(self)\n                    if operator0 == HwtOps.SEXT:\n                        op0 = self.singleDriver()\n                        op0Src = op0.operands[0]\n                        if op0Src._dtype.bit_length() == 1:\n                            sext = _fold_concat_of_msb_using_sext(op0Src, int(op0.operands[1]), other, other_w)\n                            if sext is not None:\n                                # fold concat(x.msb.sext(), x) -> x.sext()\n                                return sext\n\n            self = self._vec()\n            resWidth = w + other_w\n            HBits = self._dtype.__class__\n            resT = HBits(resWidth, signed=self._dtype.signed, force_vector=resWidth == 1)\n            # is instance of signal\n\n            if other._dtype == BOOL:\n                other = other._auto_cast(BIT)\n            elif isinstance(other._dtype, HBits):\n                if other._dtype.signed is not None:\n                    other = other._vec()\n            else:\n                raise TypeError(other._dtype)\n\n            if self._dtype.signed is not None:\n                self = self._vec()\n\n            return HOperatorNode.withRes(HwtOps.CONCAT, [self, other], resT)\\\n                           ._auto_cast(HBits(resWidth,\n                                            signed=self._dtype.signed))\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _ext(self, newWidth: Union[int, \"HBitsConst\"], signed: Union[bool, Literal[NOT_SPECIFIED]]=NOT_SPECIFIED) -> Self:\n        \"\"\"\n        construct zext/sext operator\n        :note: preserves sign of type\n        \"\"\"\n        assert newWidth > 0, newWidth\n        if signed is NOT_SPECIFIED:\n            signed = bool(self._dtype.signed)\n        else:\n            assert isinstance(signed, bool), signed\n        try:\n            w = self._dtype.bit_length()\n            extBitCnt = int(newWidth) - w\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n        if extBitCnt < 0:\n            raise AssertionError(\"newWidth >= current width\", newWidth, w, self,)\n        elif extBitCnt == 0:\n            return self\n\n        extOp = HwtOps.SEXT if signed else HwtOps.ZEXT\n        try:\n            resTy = self._dtype._createMutated(bit_length=w + extBitCnt)\n            while True:\n                # fold ext((ext(x))) -> ext(x)\n                selfOp = _get_operator_i_am_the_result_of(self)\n                if selfOp == extOp:\n                    self = self.singleDriver().operands[0]\n                    continue\n                elif selfOp == HwtOps.CONCAT:\n                    d: HOperatorNode = self.singleDriver()\n                    assert len(d.operands) == 2\n                    hiBits, loBits = d.operands\n                    newHiBitsExtWidth = newWidth - w + hiBits._dtype.bit_length()\n                    if isinstance(hiBits, HConst):\n                        hiBits = hiBits._ext(newHiBitsExtWidth, signed)\n                        # fold ext(concat(c, x)) to concat(cExtended, x)\n                        return hiBits._concat(loBits)\n                    else:\n                        selfHiBitsOp = _get_operator_i_am_the_result_of(hiBits)\n                        if selfHiBitsOp == extOp:\n                            # fold ext(concat(ext(x), y)) to concat(ext(x), y)\n                            return hiBits.singleDriver().operands[0]._ext(newHiBitsExtWidth, signed)._concat(loBits)\n\n                break\n\n            return HOperatorNode.withRes(extOp, [self, toHVal(newWidth)], resTy)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _sext(self, newWidth: Union[int, \"HBitsConst\"]) -> Self:\n        \"\"\"\n        signed extension, pad with MSB bit on MSB side to newWidth result width\n        :see: :meth:`HBitsRtlSignal._ext`\n        \"\"\"\n        return self._ext(newWidth, True)\n\n    def _zext(self, newWidth: Union[int, \"HBitsConst\"]) -> Self:\n        \"\"\"\n        zero extension, pad with 0 on msb side to newWidth result width\n        :see: :meth:`HBitsRtlSignal._ext`\n        \"\"\"\n        return self._ext(newWidth, False)\n\n    def _trunc(self, newWidth: Union[int, \"HBitsConst\"]):\n        assert newWidth > 0, newWidth\n        try:\n            w = self._dtype.bit_length()\n            cutBitCnt = w - int(newWidth)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n        if cutBitCnt < 0:\n            raise AssertionError(\"newWidth <= current width\", newWidth, w, self,)\n        elif cutBitCnt == 0:\n            return self\n\n        try:\n            if newWidth == 1 and self._dtype.signed is None:\n                # fold x._trunc(1) to x[0]\n                return self[0]\n\n            resTy = self._dtype._createMutated(bit_length=w - cutBitCnt)\n            while True:\n                # fold trunc((trunc(x))) -> trunc(x)\n                # fold trunc(concat(a, x)) -> trunc(x) if trunc select only lower first (lsb) member of concat\n                selfOp = _get_operator_i_am_the_result_of(self)\n                if selfOp == HwtOps.TRUNC:\n                    self = self.singleDriver().operands[0]\n                    continue\n                elif selfOp == HwtOps.BitsAsSigned or selfOp == HwtOps.BitsAsUnsigned:\n                    # fold x._signed()._trunc() to x._trunc()._signed()\n                    return selfOp._evalFn(self.singleDriver().operands[0]._trunc(newWidth))\n                elif selfOp == HwtOps.CONCAT:\n                    concLowBits = self.singleDriver().operands[0]\n                    concLowBitsWidth = concLowBits._dtype.bit_length()\n                    if concLowBitsWidth == resTy.bit_length():\n                        return concLowBits\n                    elif concLowBitsWidth > resTy.bit_length():\n                        self = concLowBits\n                        continue\n                break\n\n            return HOperatorNode.withRes(HwtOps.TRUNC, [self, toHVal(newWidth)], resTy)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _extOrTrunc(self, newWidth: int, signed: Union[bool, None, Literal[_NOT_SPECIFIED]]=_NOT_SPECIFIED) -> Self:\n        return Bits3val._extOrTrunc(self, newWidth, signed)\n\n    def __getitem__(self, key: HBitsAnyIndexCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        \"\"\"\n        :see: :func:`bitsGetitem`\n        \"\"\"\n        try:\n            return bitsGetitem(self, False, key)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __setitem__(self, index, value):\n        raise TypeError(\"To assign a member of hdl array/vector/list/... use a[index](c) instead of a[index] = c\")\n\n    def __invert__(self) -> Self:\n        try:\n            # try reduce double negation\n            d = self.singleDriver()\n            if isinstance(d, HOperatorNode) and d.operator == HwtOps.NOT:\n                return d.operands[0]\n        except SignalDriverErr:\n            pass\n        return HOperatorNode.withRes(HwtOps.NOT, [self], self._dtype)\n\n    def __hash__(self) -> int:\n        return hash(id(self))\n\n    # comparisons\n    def _isOn(self) -> Self:\n        return self._auto_cast(BOOL)\n\n    def _eq(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.EQ, BIT.from_py(1), eq)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __ne__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.NE, BIT.from_py(0))\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __lt__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.SLT if self._dtype.signed else HwtOps.ULT, BIT.from_py(0), evalFn=HwtOps.LT._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __gt__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.SGT if self._dtype.signed else HwtOps.UGT, BIT.from_py(0), evalFn=HwtOps.GT._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __ge__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.SGE if self._dtype.signed else HwtOps.UGE, BIT.from_py(1), evalFn=HwtOps.GE._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __le__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsCmp(self, False, other, HwtOps.SLE if self._dtype.signed else HwtOps.ULE, BIT.from_py(1), evalFn=HwtOps.LE._evalFn)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    # bitwise\n    def __xor__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsBitOp(self, False, other, HwtOps.XOR,\n                             vld_mask_for_xor, tryReduceXor, reduceSigCheckFnXor)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __and__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsBitOp(self, False, other, HwtOps.AND,\n                             vld_mask_for_and, tryReduceAnd, reduceSigCheckFnAnd)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __or__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsBitOp(self, False, other, HwtOps.OR,\n                         vld_mask_for_or, tryReduceOr, reduceSigCheckFnOr)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __lshift__(self, other: Union[int, \"HBitsConst\"]) -> Union[Self, \"HBitsConst\"]:\n        try:\n            return bitsLshift(self, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __rshift__(self, other: Union[int, \"HBitsConst\"]) -> Union[Self, \"HBitsConst\"]:\n        try:\n            return bitsRshift(self, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __neg__(self) -> Self:\n        if not self._dtype.signed:\n            self = self._signed()\n\n        resT = self._dtype\n\n        o = HOperatorNode.withRes(HwtOps.MINUS_UNARY, [self], self._dtype)\n        return o._auto_cast(resT)\n\n    # arithmetic\n    def __sub__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsArithOp(self, False, other, HwtOps.SUB)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __add__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsArithOp(self, False, other, HwtOps.ADD)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __floordiv__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsFloordiv(self, False, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __mul__(self, other: HBitsAnyCompatibleValue) -> Union[\"HBitsConst\", Self]:\n        try:\n            return bitsMul(self, False, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __mod__(self, other: HBitsAnyCompatibleValue) -> Union[Self, \"HBitsConst\"]:\n        try:\n            return bitsRem(self, True, other)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _ternary(self, vTrue: Union[\"HBitsConst\", Self], vFalse: Union[\"HBitsConst\", Self]) -> Union[\"HBitsConst\", Self]:\n        try:\n            vTrue = toHVal(vTrue)\n            vFalse = toHVal(vFalse, suggestedType=vTrue._dtype)\n            try:\n                if vTrue == vFalse:\n                    return vTrue\n            except (ValidityError, NotImplementedError):\n                pass\n\n            if not (vTrue._dtype == vFalse._dtype):\n                # all case values of ternary has to have same type\n                vFalse = vFalse._auto_cast(vTrue._dtype)\n\n            if vTrue._dtype.isScalar():\n                return HOperatorNode.withRes(\n                    HwtOps.TERNARY,\n                    [self, vTrue, vFalse],\n                    vTrue._dtype)\n            else:\n                # elementwise\n                res = copy(vTrue)\n                if isinstance(res, RtlSignal):\n                    raise NotImplementedError(vTrue)\n                elif isinstance(res, HwIOBase):\n                    res._hwIOs = []\n                    for iTrue in vTrue._hwIOs:\n                        iFalse = iTrue._onParentPropertyPath.getOnObject(vFalse)\n                        newI = self._ternary(iTrue, iFalse)\n                        iTrue._onParentPropertyPath.setOnObject(res, newI)\n                        res._hwIOs.append(newI)\n                    _fieldsToHwIOs = getattr(res, \"_fieldsToHwIOs\", None)\n                else:\n                    for i, (t, f) in enumerate(zip(vTrue, vFalse)):\n                        res[i] = self._ternary(t, f)\n                if _fieldsToHwIOs is not None:\n                    res._fieldsToHwIOs = {p: p.getOnObject(res) for p in _fieldsToHwIOs.keys()}\n                return res\n\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def __abs__(self):\n        if not self._dtype.signed:\n            return self\n        return (self < 0)._ternary(-self, self)\n\n    def getMsb(self) -> Self:\n        return self[self._dtype.bit_length() - 1]\n\n    def _onFallingEdge(self) -> Self:\n        return HOperatorNode.withRes(HwtOps.FALLING_EDGE, [self], BOOL)\n\n    def _onRisingEdge(self) -> Self:\n        return HOperatorNode.withRes(HwtOps.RISING_EDGE, [self], BOOL)\n\n    def __len__(self) -> int:\n        return self._dtype.bit_length()\n\n"
  },
  {
    "path": "hwt/hdl/types/defs.py",
    "content": "\"\"\"\nDefinitions of most common types\n\"\"\"\n\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.string import HString\n\n\nBOOL = HBits(bit_length=1, name=\"bool\")\nINT = HBits(bit_length=32, signed=True, name=\"int\",\n           strict_sign=False, strict_width=False)\nBIT = HBits(bit_length=1)\nBIT_N = HBits(bit_length=1, negated=True)\nSTR = HString()\nSLICE = HSlice()\nFLOAT64 = HFloat(11, 52, name=\"float64\")"
  },
  {
    "path": "hwt/hdl/types/enum.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\n\n\n# [TODO] use python enum and only emulate HDL enum for HDL\nclass HEnum(HdlType):\n    \"\"\"\n    Hdl enum type\n\n    :ivar ~.name: name of this type\n    :ivar ~._allValues: tuple of all values for this enum\n    :note: for each value there is a property on this type object\n    \"\"\"\n\n    def __init__(self, name, valueNames, const=False):\n        \"\"\"\n        :param name: name for this type\n        :param valueNames: sequence of string which will be used as names\n            for enum members\n        \"\"\"\n        super(HEnum, self).__init__(const=const)\n        self.name = name\n        self._allValues = tuple(valueNames)\n        for name in valueNames:\n            v = self.from_py(name)\n            assert not hasattr(self, name)\n            setattr(self, name, v)\n\n    def all_mask(self):\n        return 1\n\n    def bit_length(self):\n        return len(self._allValues).bit_length()\n\n    @internal\n    def domain_size(self):\n        \"\"\"\n        :return: how many values can have specified type\n        \"\"\"\n        return int(2 ** self.bit_length())\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        try:\n            return cls._rtlSignalCls\n        except AttributeError:\n            from hwt.hdl.types.enumConst import HEnumRtlSignal\n            cls._rtlSignalCls = HEnumRtlSignal\n            return cls._rtlSignalCls\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.enumConst import HEnumConst\n            cls._constCls = HEnumConst\n            return cls._constCls\n"
  },
  {
    "path": "hwt/hdl/types/enumConst.py",
    "content": "from typing import Union, Self\n\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.defs import BOOL\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\n_HBoolConst = BOOL.getConstCls()\n\n\nclass HEnumRtlSignal(RtlSignal):\n\n    def _eq(self, other: Union[Self, \"HEnumConst\"]) -> \"HBitsConst\":\n        assert self._dtype is other._dtype, (self._dtype, other._dtype)\n        return HOperatorNode.withRes(HwtOps.EQ, [self, other], BOOL)\n\n    def __ne__(self, other: Union[Self, \"HEnumConst\"]) -> \"HBitsConst\":\n        assert self._dtype is other._dtype, (self._dtype, other._dtype)\n        return HOperatorNode.withRes(HwtOps.NE, [self, other], BOOL)\n\n\nclass HEnumConst(HConst):\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param val: value of python type bool or None\n        :param typeObj: instance of HEnum\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        if val is None:\n            assert vld_mask is None or vld_mask == 0\n            valid = False\n            val = typeObj._allValues[0]\n        else:\n            if vld_mask is None or vld_mask == 1:\n                assert isinstance(val, str)\n                valid = True\n            else:\n                valid = False\n                val = None\n\n        return cls(typeObj, val, valid)\n\n    def _eq(self, other: Union[HEnumRtlSignal, Self]) -> \"HBitsConst\":\n        if isinstance(other, RtlSignal):\n            return HEnumRtlSignal._eq(other)\n\n        assert self._dtype is other._dtype, (self._dtype, other._dtype)\n        eq = self.val == other.val \\\n            and self.vld_mask == other.vld_mask == 1\n\n        vld_mask = int(self.vld_mask == other.vld_mask == 1)\n        return _HBoolConst(BOOL, int(eq), vld_mask)\n\n    def __ne__(self, other: Union[HEnumRtlSignal, Self]) -> \"HBitsConst\":\n        if isinstance(other, RtlSignal):\n            return HEnumRtlSignal.__ne__(other)\n\n        assert self._dtype is other._dtype, (self._dtype, other._dtype)\n        neq = self.val != other.val \\\n            and self.vld_mask == other.vld_mask == 1\n\n        vld_mask = int(self.vld_mask == other.vld_mask == 1)\n        return _HBoolConst(BOOL, int(neq), vld_mask)\n\n"
  },
  {
    "path": "hwt/hdl/types/float.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\nfrom pyMathBitPrecise.floatt import Floatt\n\n\nclass HFloat(HdlType, Floatt):\n    \"\"\"\n    Basic HDL type representing IEEE 754 like float type.\n\n    :note: This type is meant for HwModule parameters, operations with this type are not synthetisable.\n    \"\"\"\n\n    def __init__(self, exponent_w, mantisa_w,\n                 name=None,\n                 const=False):\n        \"\"\"\n        :param negated: if true the value is in negated form\n        \"\"\"\n        HdlType.__init__(self, const=const)\n        assert exponent_w > 0, exponent_w\n        assert mantisa_w > 0, mantisa_w\n        Floatt.__init__(self, exponent_w, mantisa_w, name=name)\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        from hwt.hdl.types.floatConst import HFloatConst\n        return HFloatConst\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        from hwt.hdl.types.floatConst import HFloatRtlSignal\n        return HFloatRtlSignal\n\n"
  },
  {
    "path": "hwt/hdl/types/floatConst.py",
    "content": "from copy import copy\nfrom decimal import DecimalTuple\nimport math\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.defs import BOOL\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom pyMathBitPrecise.floatt import FloattVal\n\n\n_HBoolConst = BOOL.getConstCls()\n\n\ndef _HFloatEq(self, self_is_val: bool, other):\n    other = toHVal(other, self._dtype)\n    other_is_val = isinstance(self, HConst)\n\n    if self_is_val and other_is_val:\n        return _HBoolConst(BOOL, int(self.val == other.val), self.vld_mask & other.vld_mask)\n    else:\n        assert self._dtype == other._dtype, (self, self._dtype, other, other._dtype)\n        return HOperatorNode.withRes(HwtOps.EQ, [self, other], BOOL)\n\n\nclass HFloatRtlSignal(RtlSignal):\n\n    def _eq(self, other):\n        return _HFloatEq(self, False, other)\n\n\nclass HFloatConst(HConst, FloattVal):\n    \"\"\"\n    HConst class for HFloat type.\n    \"\"\"\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        assert vld_mask is None, vld_mask\n        if isinstance(val, int):\n            val = float(val)\n            if float(val) != val:\n                raise NotImplementedError(\"Need to implement better conversion method\")\n\n        if val is None:\n            sign = 0\n            exp = 0\n            man = 0\n            assert vld_mask is None or vld_mask == 0\n            vld_mask = 0\n        elif isinstance(val, float):\n            man, exp = math.frexp(val)\n            man = abs(man)\n            man = int(man * (2 ** typeObj.mantisa_w))\n            sign = int(val < 0)\n            if vld_mask is None:\n                vld_mask = 1\n        elif isinstance(val, tuple):\n            sign, man, exp = val\n            if vld_mask is None:\n                vld_mask = 1\n        else:\n            raise TypeError(val)\n\n        return cls(typeObj, DecimalTuple(sign, man, exp), vld_mask)\n\n    def _is_full_valid(self):\n        return self.vld_mask == 1\n\n    def to_py(self):\n        \"\"\"\n        Convert to python slice object\n        \"\"\"\n        return float(self)\n\n    def _eq(self, other):\n        return _HFloatEq(self, True, other)\n\n    def __copy__(self):\n        v = HConst.__copy__(self)\n        v.val = copy(v.val)\n        return v\n\n    @internal\n    def __hash__(self):\n        v = self.val\n        return hash((self._dtype, v))\n"
  },
  {
    "path": "hwt/hdl/types/function.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HFunction(HdlType):\n    \"\"\"\n    A type which represent reference to HDL function.\n    \n    :note: For compatibility with HDL only. It is not meant to be used\n        as a function pointer to call a function in synthetisable code.\n    \"\"\"\n\n    def all_mask(self):\n        return 1\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        return HFunctionConst\n\n\nclass HFunctionConst(HConst):\n    pass\n"
  },
  {
    "path": "hwt/hdl/types/hdlType.py",
    "content": "from enum import Enum\nfrom typing import Union, Type, Self, Optional\n\nfrom hwt.doc_markers import internal\nfrom hwt.synthesizer.exceptions import TypeConversionErr\n\n\nclass MethodNotOverloaded(NotImplementedError):\n    \"\"\"\n    Method is missing overload of abstract parent method.\n    \"\"\"\n    pass\n\n\nclass HdlType():\n    \"\"\"\n    Base class for all hardware related types.\n\n    :ivar const: if True the type has const specifier which means that the value\n        should not be modified after initialization and is read only\n    :note: Cast functions are linked trough HldType class because Python lacks forward declarations.\n    :cvar ~._PRECOMPUTE_CONSTANT_SIGNALS: if true a constant expressions\n        made from this type have value pre-computed.\n    \n    :note: Each implementation of HdlType also defines is HConst and RtlSignal class.\n        These classes then implement operators and methods for constants/expressions.\n    \"\"\"\n    _PRECOMPUTE_CONSTANT_SIGNALS = True\n\n    def __init__(self, const=False):\n        self.const = const\n\n    def _from_py(self, v, vld_mask) -> \"HConst\":\n        \"\"\"\n        same as from_py just without type checks\n        \"\"\"\n        return self.getConstCls()._from_py(self, v, vld_mask)\n\n    def from_py(self, v, vld_mask=None) -> \"HConst\":\n        \"\"\"\n        Construct value of this type.\n        Delegated on value class for this type\n        \"\"\"\n        if isinstance(v, Enum):\n            v = v.value\n        return self.getConstCls().from_py(self, v, vld_mask=vld_mask)\n\n    def auto_cast_HConst(self, v: \"HConst\", toType: Self) -> \"HConst\":\n        \"\"\"\n        Cast constant of this type to another compatible type.\n        :note: auto cast may change bitwidth if type\n            implements it in auto cast\n\n        :param v: constant to cast\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        if v._dtype == toType:\n            return v\n\n        try:\n            castFn = self._auto_cast_HConst_fn\n        except AttributeError:\n            castFn = self.get_auto_cast_HConst_fn()\n            self._auto_cast_HConst_fn = castFn\n\n        try:\n            return castFn(self, v, toType)\n        except TypeConversionErr:\n            pass\n        return toType._reverse_auto_cast_HConst(v, self)\n\n    def auto_cast_RtlSignal(self, v: \"RtlSignal\", toType: Self) -> \"RtlSignal\":\n        \"\"\"\n        Equivalent of :meth:`~.auto_cast_HConst` for :class:`RtlSignal` instances\n        \"\"\"\n        if v._dtype == toType:\n            return v\n\n        try:\n            castFn = self._auto_cast_RtlSignal_fn\n        except AttributeError:\n            castFn = self.get_auto_cast_RtlSignal_fn()\n            self._auto_cast_RtlSignal_fn = castFn\n\n        try:\n            return castFn(self, v, toType)\n        except TypeConversionErr:\n            pass\n        return toType._reverse_auto_cast_RtlSignal(v, self)\n\n    def reinterpret_cast_HConst(self, v: \"HConst\", toType: Self) -> \"HConst\":\n        \"\"\"\n        Cast constant of this type to another type of same size.\n\n        :param v: constant to cast\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        if v._dtype == toType:\n            return v\n\n        try:\n            castFn = self._reinterpret_cast_HConst_fn\n        except AttributeError:\n            castFn = self.get_reinterpret_cast_HConst_fn()\n            self._reinterpret_cast_HConst_fn = castFn\n\n        try:\n            return castFn(self, v, toType)\n        except TypeConversionErr:\n            pass\n        return toType._reverse_reinterpret_cast_HConst(v, self)\n\n    def reinterpret_cast_RtlSignal(self, v: \"RtlSignal\", toType: Self) -> \"RtlSignal\":\n        \"\"\"\n        Cast value or signal of this type to another type of same size.\n\n        :param v: signal to cast\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        if v._dtype == toType:\n            return v\n\n        try:\n            castFn = self._reinterpret_cast_RtlSignal_fn\n        except AttributeError:\n            castFn = self.get_reinterpret_cast_RtlSignal_fn()\n            self._reinterpret_cast_RtlSignal_fn = castFn\n\n        try:\n            # call _reinterpret_cast_RtlSignal_fn to cast this type to toType\n            return castFn(self, v, toType)\n        except TypeConversionErr:\n            pass\n\n        return toType._reverse_reinterpret_cast_RtlSignal(v, self)\n\n    # reverse casts which are doing the same thing but cast methods are implemented on dst type\n    # :note: this is there to allow casting old types(self) to a new types(toType)\n    #   when old type does not know anything about new type\n    def _reverse_auto_cast_HConst(self, v: \"HConst\", fromType: Self) -> \"HConst\":\n        try:\n            castFn = self._reverse_auto_cast_HConst_fn\n        except AttributeError:\n            castFn = self.get_reverse_auto_cast_HConst_fn()\n            self._reverse_auto_cast_HConst_fn = castFn\n\n        return castFn(self, v, fromType)\n\n    def _reverse_auto_cast_RtlSignal(self, v: \"RtlSignal\", fromType: Self) -> \"RtlSignal\":\n        try:\n            castFn = self._reverse_auto_cast_RtlSignal_fn\n        except AttributeError:\n            castFn = self.get_reverse_auto_cast_RtlSignal_fn()\n            self._reverse_auto_cast_RtlSignal_fn = castFn\n\n        return castFn(self, v, fromType)\n\n    def _reverse_reinterpret_cast_HConst(self, v: \"HConst\", fromType: Self) -> \"HConst\":\n        try:\n            castFn = self._reverse_reinterpret_cast_HConst_fn\n        except AttributeError:\n            castFn = self.get_reverse_reinterpret_cast_HConst_fn()\n            self._reverse_reinterpret_cast_HConst_fn = castFn\n\n        return castFn(self, v, fromType)\n\n    def _reverse_reinterpret_cast_RtlSignal(self, v: \"RtlSignal\", fromType: Self) -> \"RtlSignal\":\n        try:\n            castFn = self._reverse_reinterpret_cast_RtlSignal_fn\n        except AttributeError:\n            castFn = self.get_reverse_reinterpret_cast_RtlSignal_fn()\n            self._reverse_reinterpret_cast_RtlSignal_fn = castFn\n\n        return castFn(self, v, fromType)\n\n    # methods for getting cast function which cast value of one type to another\n    # for more details :see: methods for casting of this class\n    @internal\n    @classmethod\n    def get_auto_cast_HConst_fn(cls):\n        return default_auto_cast_fn\n\n    @internal\n    @classmethod\n    def get_auto_cast_RtlSignal_fn(cls):\n        return default_auto_cast_fn\n\n    @internal\n    @classmethod\n    def get_reverse_auto_cast_RtlSignal_fn(cls):\n        return default_reverse_auto_cast_fn\n\n    @internal\n    @classmethod\n    def get_reverse_auto_cast_HConst_fn(cls):\n        return default_reverse_auto_cast_fn\n\n    @internal\n    @classmethod\n    def get_reinterpret_cast_HConst_fn(cls):\n        return default_reinterpret_cast_fn\n\n    @internal\n    @classmethod\n    def get_reverse_reinterpret_cast_HConst_fn(cls):\n        return default_reverse_reinterpret_cast_fn\n\n    @internal\n    @classmethod\n    def get_reinterpret_cast_RtlSignal_fn(cls):\n        return default_reinterpret_cast_fn\n\n    @internal\n    @classmethod\n    def get_reverse_reinterpret_cast_RtlSignal_fn(cls):\n        return default_reverse_reinterpret_cast_fn\n\n    @internal\n    @classmethod\n    def getConstCls(cls) -> Type[\"HConst\"]:\n        \"\"\"\n        :attention: Overrode in implementation of concrete HdlType.\n\n        :return: class for value derived from this type\n        \"\"\"\n        raise NotImplementedError(cls)\n\n    @internal\n    @classmethod\n    def getRtlSignalCls(cls) -> Type[\"RtlSignal\"]:\n        \"\"\"\n        :attention: Overrode in implementation of concrete HdlType.\n\n        :return: class for value derived from this type\n        \"\"\"\n        raise NotImplementedError(cls)\n\n    def _as_hdl(self, to_Hdl: \"ToHdlAst\", declaration:bool):\n        raise MethodNotOverloaded()\n\n    def _as_hdl_requires_def(self, to_Hdl: \"ToHdlAst\", other_types: list):\n        raise MethodNotOverloaded()\n\n    def isScalar(self):\n        return True\n\n    def __getitem__(self, key):\n        \"\"\"\n        [] operator to create an array of this type.\n        \"\"\"\n        assert int(key) > 0, key  # array has to have some items\n        from hwt.hdl.types.array import HArray\n        return HArray(self, key)\n\n    def __repr__(self, indent:int=0, withAddr:Optional[int]=None, expandStructs=False):\n        \"\"\"\n        :param indent: number of indentation\n        :param withAddr: if is not None, it is used as a additional\n            information about on which address this type is stored\n            (used only by HStruct)\n        :param expandStructs: expand HStructTypes (used by HStruct and Array)\n        \"\"\"\n        name = getattr(self, \"name\", \"\")\n        if name is None:\n            name = \"\"\n        return f\"<{self.__class__.__name__:s} {name:s}>\"\n\n\n@internal\ndef default_auto_cast_fn(typeFrom: HdlType, sigOrConst: Union[\"RtlSignal\", \"HConst\"], toType: HdlType):\n    raise TypeConversionErr(\"auto_cast\", typeFrom, \"->\", toType, \"is not implemented\")\n\n\n@internal\ndef default_reverse_auto_cast_fn(toType: HdlType, sigOrConst: Union[\"RtlSignal\", \"HConst\"], fromType: HdlType):\n    raise TypeConversionErr(\"auto_cast\", fromType, \"->\", toType, \"is not implemented\")\n\n\n@internal\ndef default_reinterpret_cast_fn(fromType: HdlType, sigOrConst: Union[\"RtlSignal\", \"HConst\"], toType: HdlType):\n    raise TypeConversionErr(\"reinterpret_cast\", fromType, \"->\", toType, \"is not implemented\")\n\n\n@internal\ndef default_reverse_reinterpret_cast_fn(toType: HdlType, sigOrConst: Union[\"RtlSignal\", \"HConst\"], fromType: HdlType):\n    raise TypeConversionErr(\"reinterpret_cast\", fromType, \"->\", toType, \"is not implemented\")\n"
  },
  {
    "path": "hwt/hdl/types/slice.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HSlice(HdlType):\n    \"\"\"\n    Slice type, used for selecting items from arrays or vectors\n    \"\"\"\n\n    @internal\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.sliceConst import HSliceConst\n            cls._constCls = HSliceConst\n            return cls._constCls\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        try:\n            return cls._rtlSignalCls\n        except AttributeError:\n            from hwt.hdl.types.sliceConst import HSliceRtlSignal\n            cls._rtlSignalCls = HSliceRtlSignal\n            return cls._rtlSignalCls\n"
  },
  {
    "path": "hwt/hdl/types/sliceConst.py",
    "content": "from copy import copy\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import INT\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\ndef slice_member_to_HConst(v):\n    if isinstance(v, RtlSignalBase):  # is signal\n        assert isinstance(v._dtype, HBits)\n        return v\n    elif isinstance(v, HConst):\n        if isinstance(v, HBitsConst):\n            return v\n        else:\n            return v._auto_cast(INT)\n    else:\n        return INT.from_py(v)\n\n\nclass HSliceRtlSignal(RtlSignal):\n    pass\n\n\nclass HSliceConst(HConst):\n    \"\"\"\n    HConst class for HSlice type\n    \"\"\"\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        assert vld_mask is None, vld_mask\n        if val is None:\n            val = slice(None, None, None)\n        else:\n            assert isinstance(val, slice), val\n            start = slice_member_to_HConst(val.start)\n            stop = slice_member_to_HConst(val.stop)\n            step = slice_member_to_HConst(val.step)\n            val = slice(start, stop, step)\n\n        return cls(typeObj, val, vld_mask=1)\n\n    def _is_full_valid(self) -> bool:\n        v = self.val\n        return v.start._is_full_valid() and v.stop._is_full_valid()\n\n    def _is_partially_valid(self) -> bool:\n        v = self.val\n        return v.start._is_partially_valid() and v.stop._is_partially_valid()\n\n    def to_py(self):\n        \"\"\"\n        Convert to python slice object\n        \"\"\"\n        v = self.val\n        return slice(int(v.start), int(v.stop), int(v.step))\n\n    def _size(self):\n        \"\"\"\n        :return: how many bits is this slice selecting\n        \"\"\"\n        v = self.val\n        if v.step == -1:\n            return int(v.start) - int(v.stop)\n        elif v.step == 1:\n            return int(v.stop) - int(v.start)\n        else:\n            raise NotImplementedError(self)\n\n    def _eq(self, other):\n        return self.val == other.val\n\n    def __lt__(self, other):\n        if self.val.step != other.val.step:\n            raise ValueError()\n        if isinstance(other, INT.getConstCls()):\n            return self.val.start < other\n        else:\n            return (self.val.start, self.val.stop) < (other.val.start, other.val.stop)\n\n    def __copy__(self):\n        v = HConst.__copy__(self)\n        v.val = copy(v.val)\n        return v\n\n    def staticEval(self):\n        v = self.val\n        new_v = slice(\n            v.start.staticEval(),\n            v.stop.staticEval(),\n            v.step.staticEval(),\n        )\n        return self.__class__.from_py(self._dtype, new_v)\n\n    @internal\n    def __hash__(self):\n        v = self.val\n        return hash((self._dtype, v.start, v.stop, v.step))\n\n    def __repr__(self):\n        v = self.val\n        if self._is_full_valid():\n            return f\"<{self.__class__.__name__:s} {int(v.start):d}:{int(v.stop):d}:{int(v.step):d}>\"\n        else:\n            vld_mask = \", mask {0:x}\".format(self.vld_mask)\n            return f\"<{self.__class__.__name__:s} {v}{vld_mask:s}>\"\n\n"
  },
  {
    "path": "hwt/hdl/types/sliceUtils.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.defs import INT, SLICE\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.typeCast import toHVal\n\n\n@internal\ndef slice_to_HSlice(sliceVals: slice, widthOfSlicedVec: int):\n    \"\"\"convert python slice to value of SLICE hdl type\"\"\"\n    if sliceVals.step is None:\n        step = -1\n    else:\n        step = sliceVals.step\n\n    start = sliceVals.start\n    if start is None:\n        start = INT.from_py(widthOfSlicedVec)\n    else:\n        start = toHVal(start)\n\n    stop = sliceVals.stop\n    if stop is None:\n        stop = INT.from_py(0)\n    else:\n        stop = toHVal(stop)\n\n    v = slice(start, stop, step)\n    return HSlice.getConstCls()(SLICE, v, 1)\n"
  },
  {
    "path": "hwt/hdl/types/stream.py",
    "content": "from math import inf, isinf\nfrom typing import List, Optional\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.generic.indent import getIndent\n\n\nclass HStream(HdlType):\n    \"\"\"\n    Stream is an abstract type. It is an array with unspecified size.\n\n    :ivar ~.element_t: type of the smallest chunk of data\n        which can be send over this stream\n    :ivar ~.len_min: minimum repetitions of element_t (inclusive interval)\n    :ivar ~.len_max: maximum repetitions of element_t (inclusive interval)\n    :ivar ~.start_offsets: list of numbers which represents the number of invalid bytes\n        before valid data on stream (invalid bytes means the bytes\n        which does not have bit validity set, e.g. Axi4Stream keep=0b10 -> offset=1\n        )\n    \"\"\"\n\n    def __init__(self, element_t,\n                 frame_len=inf,\n                 start_offsets: Optional[List[int]]=None,\n                 const=False):\n        super(HStream, self).__init__(const=const)\n        self.element_t = element_t\n        if isinstance(frame_len, float) and isinf(frame_len):\n            frame_len = (1, inf)\n        elif isinstance(frame_len, int):\n            frame_len = (frame_len, frame_len)\n        self.len_min, self.len_max = frame_len\n        if start_offsets is None:\n            start_offsets = (0, )\n        self.start_offsets = tuple(start_offsets)\n\n    def bit_length(self):\n        if self.len_min != self.len_max or isinf(self.len_max):\n            raise TypeError(\"This HStream does not have constant size\", self)\n        else:\n            # len_min == len_max\n            return self.len_min * self.element_t.bit_length()\n\n    def __eq__(self, other: HdlType):\n        if self is other:\n            return True\n        if (type(self) is type(other)):\n            if self.start_offsets == other.start_offsets \\\n                    and self.len_min == other.len_min \\\n                    and self.len_max == other.len_max:\n                return self.element_t == other.element_t\n        return False\n\n    def __hash__(self):\n        return hash((self.start_offsets, self.len_min, self.len_max, self.element_t))\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.streamConst import HStreamConst\n            cls._constCls = HStreamConst\n            return cls._constCls\n\n    def __repr__(self, indent=0, withAddr=None, expandStructs=False):\n        return \"%s<%s len:%s, align:%r\\n%s>\" % (\n            getIndent(indent),\n            self.__class__.__name__,\n            (self.len_min, self.len_max),\n            self.start_offsets,\n            self.element_t.__repr__(indent=indent+1,\n                                    withAddr=withAddr,\n                                    expandStructs=expandStructs),\n        )\n"
  },
  {
    "path": "hwt/hdl/types/streamConst.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, INT\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass HStreamConst(HConst):\n    \"\"\"\n    Class for values of HStream HDL type\n    \"\"\"\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param typeObj: HStream instance\n        :param val: None or iterrable of values\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        min_len = typeObj.len_min\n\n        if vld_mask == 0:\n            val = None\n        element_t = typeObj.element_t\n        if val is None:\n            elements = [element_t.from_py(None) for _ in range(min_len)]\n        else:\n            elements = []\n            for v in val:\n                if isinstance(v, RtlSignalBase):  # is signal\n                    assert v._dtype == typeObj.element_t\n                    e = v\n                else:\n                    e = typeObj.element_t.from_py(v)\n                elements.append(e)\n            cur_len = len(elements)\n            assert cur_len >= min_len and cur_len <= typeObj.len_max\n        _mask = int(bool(val))\n        if vld_mask is None:\n            vld_mask = _mask\n        else:\n            assert (vld_mask == _mask)\n\n        return cls(typeObj, elements, vld_mask)\n\n    def to_py(self):\n        if not self._is_full_valid():\n            raise ValueError(f\"Value of {self} is not fully defined\")\n        return [v.to_py() for v in self.val]\n\n    @internal\n    def __hash__(self):\n        return hash((self._dtype, self.val, self.vld_mask))\n\n    def _is_full_valid(self):\n        return self.vld_mask == 1\n\n    @internal\n    def _getitem__const(self, key):\n        \"\"\"\n        :attention: this will clone item from array, iterate over .val\n            if you need to modify items\n        \"\"\"\n        kv = key.val\n        if not key._is_full_valid():\n            raise KeyError()\n\n        return self.val[kv].__copy__()\n\n    def __getitem__(self, key):\n        key = toHVal(key)\n        isSLICE = isinstance(key, HSlice.getConstCls())\n\n        if isSLICE:\n            raise NotImplementedError()\n        elif isinstance(key, (HConst, RtlSignalBase)):\n            pass\n        else:\n            raise NotImplementedError(\n                f\"Index operation not implemented for index {key}\")\n\n        kv = key.val\n        if not key._is_full_valid():\n            raise KeyError()\n\n        return self.val[kv].__copy__()\n\n    def __setitem__(self, index, value):\n        \"\"\"\n        Only syntax sugar for user, not used inside HWT\n\n        * In HW design is not used (__getitem__ returns \"reference\"\n            and it is used)\n        \"\"\"\n        if isinstance(index, int):\n            index = INT.from_py(index)\n        else:\n            assert isinstance(index._dtype, HBits), index._dtype\n\n        if not isinstance(value, HConst):\n            value = self._dtype.element_t.from_py(value)\n        else:\n            assert value._dtype == self._dtype.element_t, (\n                value._dtype, self._dtype.element_t)\n\n        if index._is_full_valid():\n            self.val[index.val] = value.__copy__()\n        else:\n            self.val = {}\n        return self\n\n    def __iter__(self):\n        return iter(self.val)\n\n    def __len__(self):\n        return len(self.val)\n\n    def _eq(self, other):\n        assert isinstance(other, HStreamConst)\n        assert self._dtype.element_t == other._dtype.element_t\n\n        eq = True\n        vld = 1\n\n        if (len(self.val) == len(other.val)):\n            for a, b in zip(self.val, other.val):\n                eq = eq and bool(a) == bool(b)\n                if not eq:\n                    break\n                vld = vld & a.vld_mask & b.vld_mask\n        else:\n            eq = False\n            vld = 0\n\n        return BOOL.getConstCls()(BOOL, int(eq), vld)\n"
  },
  {
    "path": "hwt/hdl/types/string.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HString(HdlType):\n    \"\"\"\n    :note: This type is meant for HwModule parameters, operations with this type are not synthetisable.\n    \"\"\"\n\n    def all_mask(self):\n        return 1\n\n    @internal\n    @override\n    @classmethod\n    def getConstCls(cls):\n        try:\n            return cls._constCls\n        except AttributeError:\n            from hwt.hdl.types.stringConst import HStringConst\n            cls._constCls = HStringConst\n            return cls._constCls\n\n    @internal\n    @override\n    @classmethod\n    def getRtlSignalCls(cls):\n        try:\n            return cls._rtlSignalCls\n        except AttributeError:\n            from hwt.hdl.types.stringConst import HStringRtlSignal\n            cls._rtlSignalCls = HStringRtlSignal\n            return cls._rtlSignalCls\n"
  },
  {
    "path": "hwt/hdl/types/stringConst.py",
    "content": "from hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.defs import BOOL\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass HStringRtlSignal(RtlSignal):\n\n    def _eq(self, other):\n        other = toHVal(other, self._dtype)\n        assert self._dtype == other._dtype, (self, self._dtype, other, other._dtype)\n        return HOperatorNode.withRes(HwtOps.EQ, [self, other], BOOL)\n\n\nclass HStringConst(HConst):\n    \"\"\"\n    Value class for hdl HString type\n    \"\"\"\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param val: python string or None\n        :param typeObj: instance of HString HdlType\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        assert isinstance(val, str) or val is None\n        vld = 0 if val is None else 1\n        if not vld:\n            assert vld_mask is None or vld_mask == 0\n            val = \"\"\n        else:\n            if vld_mask == 0:\n                val = \"\"\n                vld = 0\n\n        return cls(typeObj, val, vld)\n\n    def to_py(self):\n        if not self._is_full_valid():\n            raise ValueError(f\"Value of {self} is not fully defined\")\n        return self.val\n\n    def _eq(self, other):\n        other = toHVal(other, self._dtype)\n\n        if isinstance(self, HConst):\n            eq = self.val == other.val\n            vld = int(self.vld_mask and other.vld_mask)\n            return BOOL.getConstCls()(BOOL, int(eq), vld)\n\n        else:\n            return HStringRtlSignal._eq(other)\n"
  },
  {
    "path": "hwt/hdl/types/struct.py",
    "content": "from typing import Self\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.structValBase import HStructConstBase, HStructRtlSignalBase\nfrom hwt.hwIO import HwIO\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.generic.indent import getIndent\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass HStructFieldMeta():\n    \"\"\"\n    Metadata for a field in :class:`HStruct` type\n\n    :ivar ~.split: flag which specifies if structured data type of this field\n        should be synchronized as a one interface\n        or each it's part should be synchronized separately\n    \"\"\"\n\n    def __init__(self, split=False):\n        self.split = split\n\n    def __eq__(self, other):\n        if other is None:\n            return False\n        return self.split == other.split\n\n    @internal\n    def __hash__(self):\n        return hash(self.split)\n\n\nclass HStructField(object):\n    \"\"\"\n    Object holding info about a single member in :class:`HStruct` type\n    \"\"\"\n\n    def __init__(self, typ: HdlType, name: str, meta=None):\n        assert isinstance(name, str) or name is None, name\n        assert isinstance(typ, HdlType), typ\n        self.name = name\n        self.dtype = typ\n        self.meta = meta\n\n    def __eq__(self, other):\n        return self.name == other.name and\\\n               self.dtype == other.dtype and\\\n               self.meta == other.meta\n\n    def __hash__(self):\n        return hash((self.name, self.dtype, self.meta))\n\n    def __repr__(self):\n        name = self.name\n        if name is None:\n            name = \"<padding>\"\n\n        return f\"<HStructField {self.dtype}, {name:s}>\"\n\n\n_protectedNames = {\n    # RtlSignal props\n    \"_dtype\",\n    * dir(RtlSignal),\n    # HConst\n    * dir(HConst),\n    # HwIO props\n    \"_setAttrListener\",\n    \"_associatedClk\",\n    \"_associatedRst\",\n    \"_parent\",\n    \"_name\",\n    \"_masterDir\",\n    \"_direction\",\n    \"_ctx\",\n    \"_isExtern\",\n    \"_ag\",\n    \"_hdlPort\",\n    \"_hdlNameOverride\",\n    *dir(HwIO),\n    # HwIOSignal props\n    # \"_sig\", \"_sigInside\", \"_isAccessible\",\n    # *dir(HwIOSignal),\n}\n\n\nclass HStruct(HdlType):\n    \"\"\"\n    HDL structure type\n\n    :ivar ~.fields: tuple of :class:`~.HStructField` instances in this struct\n    :ivar ~.name: name of this HStruct type\n    :ivar ~.field_by_name: dictionary which maps the name of the field to :class:`~.HStructField` instance\n    :ivar ~._constCls: Class of value for this type as usual\n        in HdlType implementations\n    \n    .. code-block::python\n        # type definition\n        t = HStruct(\n            (BIT, \"a\"),\n            (BIT, \"b\"),\n        )\n        # constant instantiation \n        v = t.from_py({\"a\": 1, \"b\":0})\n    \n    :attention: v._reinterpet_cast(HBits(2)) packs the first member (\"a\") to a bit 0 (first member at the lowest address as in C)\n        Note that this is exactly opposite as in SystemVerilog struct packed {bit a; bit b;}\n        where bit \"b\" would be bit 0    \n    \n    :ivar _HStructConstBase: base class for HStructConst to allow for instance method re-definion\n        for constants of child types\n    :ivar _HStructRtlSignalBase: base class for HStructRtlSignal to allow for instance method re-definion\n        for constants of child types\n        \n    .. code-block::python\n        # example of use of _HStructConstBase/_HStructRtlSignalBase\n        t = HStruct(\n            (BIT, \"a\"),\n            (BIT, \"b\"),\n        )\n        class MyHStructConstBase(HStructConstBase)\n            def any(self):\n                return self.a | self.b\n        t._HStructConstBase = MyHStructConstBase\n\n        v = t.from_py({\"a\": 1, \"b\":0})\n        t.any()\n    \n    \"\"\"\n    _HStructConstBase = HStructConstBase\n    _HStructRtlSignalBase = HStructRtlSignalBase\n\n    def __init__(self, *template, name=None, const=False):\n        \"\"\"\n        :param template: list of tuples (type, name) or :class:`~.HStructField` objects\n            name can be None (= padding)\n        :param name: optional name used for debugging purposes\n        \"\"\"\n        super(HStruct, self).__init__(const=const)\n\n        fields = []\n        field_by_name = {}\n        self.name = name\n        bit_length = 0\n        for f in template:\n            try:\n                field = HStructField(*f)\n            except TypeError:\n                field = f\n            if not isinstance(field, HStructField):\n                raise TypeError(f\"Template for struct field {f} is\"\n                                \" not in valid format\")\n\n            fields.append(field)\n            if field.name is not None:\n                assert field.name not in field_by_name, field.name\n                field_by_name[field.name] = field\n\n            t = field.dtype\n            if bit_length is not None:\n                try:\n                    _bit_length = t.bit_length()\n                    bit_length += _bit_length\n                except TypeError:\n                    bit_length = None\n\n        self.fields = tuple(fields)\n        self.field_by_name = field_by_name\n        self.__hash = hash((self.name, self.const, self.fields))\n        self.__bit_length_val = bit_length\n\n        usedNames = set(field_by_name.keys())\n        assert not _protectedNames.intersection(usedNames), \\\n            _protectedNames.intersection(usedNames)\n\n        class HStructConst(self._HStructConstBase):\n            __slots__ = list(usedNames)\n\n        class HStructRtlSignal(self._HStructRtlSignalBase):\n            __slots__ = list(usedNames)\n\n        if name is not None:\n            HStructConst.__name__ = name + \"Const\"\n            HStructRtlSignal.__name__ = name + \"RtlSignal\"\n\n        self._constCls = HStructConst\n        self._rtlSignalCls = HStructRtlSignal\n\n    def bit_length(self) -> int:\n        bl = self.__bit_length_val\n        if bl is None:\n            raise TypeError(\"Can not request bit_lenght on type\"\n                            \" which has not fixed size\")\n        else:\n            return self.__bit_length_val\n\n    @internal\n    @override\n    def getConstCls(self):\n        return self._constCls\n\n    @internal\n    @override\n    def getRtlSignalCls(self):\n        \"\"\"\n        :attention: RtlSignal of this class is actually never instantiated and :class:`HwIOStruct` is used instead.\n            However the methods of RtlSignal class are called from HwIOStruct.\n            This is to have RtlSignal with single HDL id only and to keep RTL level data structures as simple as possible. \n        \"\"\"\n        return self._rtlSignalCls\n\n    @internal\n    @classmethod\n    def get_reinterpret_cast_HConst_fn(cls):\n        from hwt.hdl.types.structCast import hstruct_reinterpret\n        return hstruct_reinterpret\n\n    @internal\n    @classmethod\n    def get_reinterpret_cast_RtlSignal_fn(cls):\n        from hwt.hdl.types.structCast import hstruct_reinterpret\n        return hstruct_reinterpret\n\n    @internal\n    def __fields__eq__(self, other: Self) -> bool:\n        if len(self.fields) != len(other.fields):\n            return False\n        for sf, of in zip(self.fields, other.fields):\n            if (sf.name != of.name or\n                    sf.dtype != of.dtype or\n                    sf.meta != of.meta):\n                return False\n        return True\n\n    def __eq__(self, other: HdlType) -> bool:\n        if self is other:\n            return True\n        if (type(self) is type(other)):\n            if self.name != other.name or self.const != other.const:\n                return False\n            try:\n                self_l = self.bit_length()\n            except TypeError:\n                self_l = -1\n            try:\n                other_l = other.bit_length()\n            except TypeError:\n                other_l = -1\n\n            return self_l == other_l and self.__fields__eq__(other)\n        return False\n\n    @internal\n    def __hash__(self):\n        return self.__hash\n\n    def __add__(self, other):\n        \"\"\"\n        override of addition, merge struct into one\n        \"\"\"\n        assert isinstance(other, HStruct)\n        return HStruct(*self.fields, *other.fields)\n\n    @override\n    def isScalar(self):\n        return False\n\n    def __repr__(self, indent=0, withAddr=None, expandStructs=False):\n        \"\"\"\n        :param indent: number of indentation\n        :param withAddr: if is not None is used as a additional\n            information about on which address this type is stored\n            (used only by HStruct)\n        :param expandStructs: expand HStructTypes (used by HStruct and HArray)\n        \"\"\"\n        if self.name:\n            name = self.name + \" \"\n        else:\n            name = \"\"\n\n        myIndent = getIndent(indent)\n        childIndent = getIndent(indent + 1)\n        header = f\"{myIndent:s}struct {name:s}{{\"\n\n        buff = [header, ]\n        for f in self.fields:\n            if withAddr is not None:\n                withAddr_B = withAddr // 8\n                addrTag = f\" // start:0x{withAddr:x}(bit) 0x{withAddr_B:x}(byte)\"\n            else:\n                addrTag = \"\"\n\n            if f.name is None:\n                buff.append(f\"{childIndent:s}//{f.dtype} empty space{addrTag:s}\")\n            else:\n                buff.append(\"%s %s%s\" % (\n                               f.dtype.__repr__(indent=indent + 1,\n                                                withAddr=withAddr,\n                                                expandStructs=expandStructs),\n                            f.name, addrTag))\n            if withAddr is not None:\n                withAddr += f.dtype.bit_length()\n\n        buff.append(f\"{myIndent:s}}}\")\n        return \"\\n\".join(buff)\n\n\ndef offsetof(structTy: HStruct, field: HStructField):\n    \"\"\"\n    Get bit offset field in HStruct\n    \"\"\"\n    off = 0\n    for f in structTy.fields:\n        f: HStructField\n        if f is field:\n            return off\n        else:\n            off += f.dtype.bit_length()\n\n    raise AssertionError(\"field was not found in struct type fields\", structTy, field)\n\n"
  },
  {
    "path": "hwt/hdl/types/structCast.py",
    "content": "from typing import Union\n\nfrom hwt.code import Concat\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType, default_reinterpret_cast_fn\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.hwIOs.std import HwIOSignal\nfrom hwt.mainBases import HwIOBase\nfrom hwt.mainBases import RtlSignalBase\n\n\n@internal\ndef hstruct_reinterpret_to_bits(self: HStruct, sigOrConst: Union[RtlSignalBase, HConst], toType: HdlType):\n    assert toType.bit_length() == self.bit_length()\n    parts = []\n    for f in self.fields:\n        if f.name is None:\n            width = f.dtype.bit_length()\n            part = HBits(width).from_py(None)\n        else:\n            part = getattr(sigOrConst, f.name)\n            if isinstance(part, HwIOSignal):\n                part = part._sig\n\n            if isinstance(part, HObjList):\n                elmTyFlat = HBits(f.dtype.element_t.bit_length())\n                for partPart in part:\n                    pp = partPart._reinterpret_cast(elmTyFlat)\n                    parts.append(pp)\n                continue\n            elif not isinstance(part, (HConst, RtlSignalBase, HwIOBase)):\n                part = f.dtype.from_py(part)\n            elif not isinstance(part._dtype, toType.__class__):\n                part = part._reinterpret_cast(toType.__class__(part._dtype.bit_length()))\n            # else add part as is\n            assert isinstance(part._dtype, HBits), part\n\n        parts.append(part)\n\n    return Concat(*reversed(parts))\n\n\n@internal\ndef hstruct_reinterpret_using_bits(self: HStruct, sigOrConst: Union[RtlSignalBase, HConst], toType: HdlType):\n    as_bits = sigOrConst._reinterpret_cast(HBits(self.bit_length()))\n    return as_bits._reinterpret_cast(toType)\n\n\n@internal\ndef hstruct_reinterpret(self: HStruct, sigOrConst: Union[RtlSignalBase, HConst], toType: HdlType):\n    if isinstance(toType, HBits):\n        return hstruct_reinterpret_to_bits(self, sigOrConst, toType)\n    elif isinstance(toType, (HStruct, HArray)):\n        return hstruct_reinterpret_using_bits(self, sigOrConst, toType)\n    else:\n        return default_reinterpret_cast_fn(self, sigOrConst, toType)\n"
  },
  {
    "path": "hwt/hdl/types/structUtils.py",
    "content": "from copy import copy\nfrom typing import Union, Dict\n\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.stream import HStream\nfrom hwt.hdl.types.struct import HStructField, HStruct\nfrom hwt.synthesizer.typePath import TypePath\n\nfiled_filter_t = Dict[Union[int, str], \"filed_filter_t\"]\n\n\ndef HdlType_select(t: HStruct, fieldsToUse: filed_filter_t):\n    \"\"\"\n    Select fields from type structure (rest will become padding)\n\n    :param t: HdlType type instance\n    :param fieldsToUse: dict {name:{...}} or set of names to select,\n        dictionary is used to select nested fields\n        in HStruct/HUnion fields/array items\n        (f.e. {\"struct1\": {\"field1\", \"field2\"}, \"field3\":{}}\n        will select field1 and 2 from struct1 and field3 from root)\n    \"\"\"\n\n    template = []\n    fieldsToUse = fieldsToUse\n    foundNames = set()\n    if isinstance(t, (HArray, HStream)):\n        assert len(fieldsToUse) <= 1, (\"select only on item 0, because it has to be same for all array items\", fieldsToUse)\n        k, v = list(fieldsToUse.items())[0]\n        assert k == 0\n        new_t = copy(t)\n        new_t.elment = HdlType_select(t.element_t, v)\n        return new_t\n    elif isinstance(t, (HBits, HEnum)):\n        # scalar\n        return t\n    else:\n        # struct/Union\n        for f in t.fields:\n            name = None\n            subfields = []\n\n            if f.name is not None:\n                try:\n                    if isinstance(fieldsToUse, dict):\n                        subfields = fieldsToUse[f.name]\n                        name = f.name\n                    else:\n                        if f.name in fieldsToUse:\n                            name = f.name\n                except KeyError:\n                    name = None\n\n            if name is not None and subfields:\n                new_t = HdlType_select(f.dtype, subfields)\n                template.append(HStructField(new_t, name))\n            else:\n                template.append(HStructField(f.dtype, name))\n\n            if f.name is not None:\n                foundNames.add(f.name)\n\n        if isinstance(fieldsToUse, dict):\n            fieldsToUse = set(fieldsToUse.keys())\n        assert fieldsToUse.issubset(foundNames)\n\n        return t.__class__(*template)\n\n\ndef field_path_get_type(root: HdlType, field_path: TypePath):\n    \"\"\"\n    Get a data type of element using field path\n    \"\"\"\n    t = root\n    for p in field_path:\n        if isinstance(p, int):\n            t = t.element_t\n        else:\n            assert isinstance(p, str), p\n            t = t.field_by_name[p].dtype\n    return t\n\n\ndef HStruct_tuple_to_dict(v: tuple, t: HdlType, call_to_py_on_scalars=True) -> dict:\n    \"\"\"\n    Convert a tuple of items for HStruct field to a dictionary field name to field value,\n    recursively.\n    \"\"\"\n    if isinstance(t, HStruct):\n        assert len(v) == len(t.fields), (len(v), t)\n        return {f.name: HStruct_tuple_to_dict(vItem, f.dtype, call_to_py_on_scalars=call_to_py_on_scalars) for f, vItem in zip(t.fields, v)}\n    elif isinstance(t, HArray):\n        assert len(v) == t.size, (len(v), t)\n        return [HStruct_tuple_to_dict(vItem, t.element_t, call_to_py_on_scalars=call_to_py_on_scalars) for vItem in v]\n    else:\n        assert t.isScalar(), t\n        if call_to_py_on_scalars:\n            return v.to_py()\n        else:\n            return v\n"
  },
  {
    "path": "hwt/hdl/types/structValBase.py",
    "content": "from typing import Optional, Union\n\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.types.defs import STR\nfrom hwt.hwIO import HwIO\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.generic.indent import getIndent\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass HStructRtlSignalBase(RtlSignal):\n    __slots__ = []\n\n    def __len__(self):\n        return len(self.__slots__)\n\n    def __iter__(self):\n        for f in self._dtype.fields:\n            if f.name is None:\n                yield f._dtype.from_py(None)\n            else:\n                yield getattr(self, f.name)\n\n    def __getattr__(self, name:str) -> RtlSignal:\n        structField = self._dtype.field_by_name.get(name, None)\n        if structField is None:\n            raise AttributeError(self.__class__, ' object has no attribute ', name)\n\n        structField: \"HStructField\"\n        return HOperatorNode.withRes(HwtOps.DOT, (self, STR.from_py(name)), structField.dtype)\n\n    def __call__(self, source,\n        dst_resolve_fn=lambda x:x._getDestinationSignalForAssignmentToThis(),\n        exclude=None,\n        fit=False) -> list[HdlAssignmentContainer]:\n        res = []\n        if isinstance(source, dict):\n            source = [source[field.name] for field in self._dtype.fields]\n        else:\n            assert len(self) == len(source), (\"source and destination array must be of the same size\", len(self) == len(source))\n\n        for src, dst in zip(source, self):\n            a = dst.__call__(src, dst_resolve_fn=dst_resolve_fn, exclude=exclude, fit=fit)\n            if isinstance(a, (list, tuple)):\n                res.extend(a)\n            else:\n                res.append(a)\n\n        return res\n\n    def __repr__(self, indent=0):\n        return HStructConstBase.__repr__(self, indent=indent)\n\n\nclass HStructConstBase(HConst):\n    \"\"\"\n    Base class for values for structure types.\n    Every structure type has it's own value class derived from this.\n    \"\"\"\n    __slots__ = []\n\n    def __init__(self, typeObj: \"HStruct\", val: Optional[Union[dict, tuple]], skipCheck=False):\n        \"\"\"\n        :param val: None or dict {field name: field value}\n        :param typeObj: instance of HString HdlType\n        :param skipCheck: flag to skip field name consistency in val\n        \"\"\"\n        self._dtype = typeObj\n        if not skipCheck and val is not None:\n            if isinstance(val, dict):\n                assert set(self.__slots__).issuperset(set(val.keys())), \\\n                    (\"struct value specifies undefined members\",\n                     set(val.keys()).difference(set(self.__slots__)))\n            else:\n                assert len(val) == len(self.__slots__), (\"struct value has different number of values than initialization value\", len(val), len(self.__slots__))\n\n        if isinstance(val, dict):\n            for f in self._dtype.fields:\n                if f.name is None:\n                    continue\n                if val is None:\n                    v = None\n                else:\n                    v = val.get(f.name, None)\n\n                if not isinstance(v, (HConst, HwIO, RtlSignalBase)):\n                    v = f.dtype.from_py(v)\n\n                setattr(self, f.name, v)\n\n        else:\n            if val is None:\n                val = (None for _ in range(len(self.__slots__)))\n\n            valIt = iter(val)\n            for f in self._dtype.fields:\n                if f.name is None:\n                    continue\n                if val is None:\n                    v = None\n                else:\n                    v = next(valIt)\n\n                if not isinstance(v, (HConst, RtlSignalBase)):\n                    v = f.dtype.from_py(v)\n\n                setattr(self, f.name, v)\n\n    def __len__(self):\n        return len(self.__slots__)\n\n    def __iter__(self):\n        for f in self._dtype.fields:\n            if f.name is None:\n                yield f._dtype.from_py(None)\n            else:\n                yield getattr(self, f.name)\n\n    def __copy__(self):\n        d = {}\n        for f in self._dtype.fields:\n            if f.name is None:\n                continue\n\n            v = getattr(self, f.name)\n            if not isinstance(v, RtlSignalBase):\n                v = v.__copy__()\n            d[f.name] = v\n\n        return self.__class__(self._dtype, d, skipCheck=True)\n\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param val: None or dict {field name: field value}\n        :param typeObj: instance of HString HdlType\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        if vld_mask == 0:\n            val = None\n        return cls(typeObj, val)\n\n    def _is_full_valid(self):\n        for f in self._dtype.fields:\n            if f.name is not None:\n                val = getattr(self, f.name, None)\n                if val is None or not val._is_full_valid():\n                    return False\n        return True\n\n    def _is_partially_valid(self) -> bool:\n        for f in self._dtype.fields:\n            if f.name is not None:\n                val = getattr(self, f.name, None)\n                if val is None and val._is_partially_valid():\n                    return True\n        return False\n\n    def to_py(self):\n        d = {}\n        for f in self._dtype.fields:\n            if f.name is not None:\n                val = getattr(self, f.name).to_py()\n                d[f.name] = val\n        return d\n\n    def __ne__(self, other):\n        if isinstance(other, HConst):\n            if self._dtype == other._dtype:\n                for f in self._dtype.fields:\n                    isPadding = f.name is None\n                    if not isPadding:\n                        sf = getattr(self, f.name)\n                        of = getattr(other, f.name)\n                        if (sf != of):\n                            return True\n                return False\n            else:\n                return True\n        else:\n            return super(HConst, self).__ne__(other)\n\n    def _eq(self, other):\n        return self.__eq__(other)\n\n    def __eq__(self, other):\n        if isinstance(other, HConst):\n            if self._dtype == other._dtype:\n                for f in self._dtype.fields:\n                    isPadding = f.name is None\n                    if not isPadding:\n                        sf = getattr(self, f.name)\n                        of = getattr(other, f.name)\n                        if not (sf == of):\n                            return False\n                return True\n            else:\n                return False\n        else:\n            return super(HConst, self).__eq__(other)\n\n    def __repr__(self, indent=0):\n        buff = [\"{\"]\n        indentOfFields = getIndent(indent + 1)\n\n        for f in self._dtype.fields:\n            if f.name is not None:\n                val = getattr(self, f.name)\n                try:\n                    v = val.__repr__(indent=indent + 1)\n                except TypeError:\n                    v = repr(val)\n\n                buff.append(f\"{indentOfFields:s}{f.name:s}: {v:s}\")\n\n        buff.append(getIndent(indent) + \"}\")\n        return (\"\\n\").join(buff)\n\n"
  },
  {
    "path": "hwt/hdl/types/typeCast.py",
    "content": "\nfrom typing import Optional, Any, Union\n\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.defs import INT, STR, BOOL, SLICE, FLOAT64\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.mainBases import HwIOBase, RtlSignalBase\n\ndefaultPyConversions = {\n    int: INT,\n    str: STR,\n    bool: BOOL,\n    slice: SLICE,\n    float: FLOAT64\n}\n\n\ndef toHVal(op: Any, suggestedType: Optional[HdlType]=None) -> Union[HConst, RtlSignalBase, HwIOBase]:\n    \"\"\"Convert python or hdl HConst/RtlSignal object to hdl HConst/RtlSignal object\"\"\"\n    if isinstance(op, (HConst, HdlSignalItem)):\n        return op\n    elif isinstance(op, HwIOBase):\n        sig = getattr(op, \"_sig\", None)\n        if sig is not None:\n            return sig\n        else:\n            return op\n    else:\n        if suggestedType is not None:\n            return suggestedType.from_py(op)\n\n        if isinstance(op, int):\n            if op >= 1 << 31:\n                raise TypeError(\n                    f\"Number {op:d} is too big to fit in 32 bit integer of HDL\"\n                    \" use Bits type instead\")\n            elif op < -(1 << 31):\n                raise TypeError(\n                    f\"Number {op:d} is too small to fit in 32 bit integer\"\n                    \" of HDL use Bits type instead\")\n\n        try:\n            hType = defaultPyConversions[type(op)]\n        except KeyError:\n            hType = None\n\n        if hType is None:\n            raise TypeError(f\"Unknown hardware type for instance of {op.__class__}\")\n\n        return hType.from_py(op)\n\n"
  },
  {
    "path": "hwt/hdl/types/union.py",
    "content": "from collections import OrderedDict\nfrom typing import Optional, Tuple, Any\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.struct import HStructField\nfrom hwt.serializer.generic.indent import getIndent\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n_protectedNames = {\"clone\", \"staticEval\",\n                  \"from_py\", \"_dtype\", \"_usedField\", \"_val\"}\n\n\nclass HUnionConstBase(HConst):\n    \"\"\"\n    Base class for values for union types.\n    Every union type has it's own value class derived from this.\n\n    :ivar ~._dtype: union type of this value\n    :ivar ~.__usedField: member which is actually used to represent value\n    :ivar ~.__val: value for __usedField\n    \"\"\"\n    __slots__ = [\"_dtype\", \"_val\", \"_usedField\"]\n\n    def __init__(self, typeObj: \"HUnion\", val: Optional[Tuple[str, Any]]):\n        \"\"\"\n        :param val: None or tuple (member name, member value)\n        :param typeObj: instance of HUnion HdlType for this value\n        \"\"\"\n        self._dtype = typeObj\n        if val is not None:\n            memberName, v = val\n        else:\n            memberName = next(iter((typeObj.fields.keys())))\n            v = None\n\n        f = self._dtype.fields[memberName]\n        if not isinstance(v, HConst):\n            v = f.dtype.from_py(v)\n        else:\n            v._auto_cast(f.dtype)\n        self._val = v\n        self._usedField = f\n\n    @override\n    @classmethod\n    def from_py(cls, typeObj, val, vld_mask=None):\n        \"\"\"\n        :param val: None or tuple (member name, member value)\n        :param typeObj: instance of HUnion HdlType for this value\n        :param vld_mask: if is None validity is resolved from val\n            if is 0 value is invalidated\n            if is 1 value has to be valid\n        \"\"\"\n        if vld_mask == 0:\n            val = None\n        return cls(typeObj, val)\n\n    def __repr__(self, indent=0):\n        # [TODO] refactor too similar to StructValBase.__repr__\n        buff = [\"{\"]\n        indentOfFields = getIndent(indent + 1)\n\n        for f in self._dtype.fields.values():\n            if f.name is not None:\n                val = getattr(self, f.name)\n                try:\n                    v = val.__repr__(indent=indent + 1)\n                except TypeError:\n                    v = repr(val)\n\n                buff.append(f\"{indentOfFields:s}{f.name:s}: {v:s}\")\n        buff.append(getIndent(indent) + \"}\")\n        return (\"\\n\").join(buff)\n\n\nclass HUnionRtlSignalBase(RtlSignal):\n\n    __slots__ = [\"_dtype\", \"_val\", \"_usedField\"]\n\n    def __repr__(self, indent=0):\n        return HUnionConstBase.__repr__(indent=indent)\n\n\n@internal\nclass HUnionMemberHandler(object):\n    \"\"\"\n    Object which manages the acces to HUnion field\n    \"\"\"\n\n    def __init__(self, field):\n        self.field = field\n\n    def set(self, parent, v):\n        f = parent._dtype.fields[self.field.name]\n        if not isinstance(v, HConst):\n            v = f.dtype.from_py(v)\n        else:\n            v._auto_cast(f.dtype)\n\n        parent._val = v\n        parent._usedField = f\n\n    def get(self, parent):\n        name = self.field.name\n        v = parent._val\n        if parent._usedField.name == name:\n            return v\n        else:\n            f = parent._dtype.fields[name]\n            v = v._reinterpret_cast(f.dtype)\n            parent._val = v\n            parent._usedField = f\n            return v\n\n\nclass HUnion(HdlType):\n    \"\"\"\n    HDL union type (same data multiple representations)\n\n    :ivar ~.fields: read only OrderedDict {key:StructField} for each\n        member in this union\n    :ivar ~.name: name of this type\n    :ivar ~.__bit_length_val: precalculated bit_length of this type\n    \"\"\"\n\n    def __init__(self, *template, name=None, const=False):\n        \"\"\"\n        :param template: list of tuples (type, name) or HStructField objects\n            name can be None (= padding)\n        :param name: optional name used for debugging purposes\n        \"\"\"\n        super(HUnion, self).__init__(const=const)\n        self.fields = OrderedDict()\n        self.field_by_name = self.fields\n        self.name = name\n        bit_length = None\n\n        class HUnionConst(HUnionConstBase):\n            pass\n\n        class HUnionRtlSignal(HUnionRtlSignalBase):\n            pass\n\n        for f in template:\n            try:\n                field = HStructField(*f)\n            except TypeError:\n                field = f\n            if not isinstance(field, HStructField):\n                raise TypeError(\n                    \"Template for struct field %s is not\"\n                    \" in valid format\" % repr(f))\n\n            assert field.name is not None\n            self.fields[field.name] = field\n\n            t = field.dtype\n            if bit_length is None:\n                bit_length = t.bit_length()\n            else:\n                _bit_length = t.bit_length()\n                if _bit_length != bit_length:\n                    raise TypeError(\n                        field.name, \" has different size than others\")\n\n            memberHandler = HUnionMemberHandler(field)\n            p = property(fget=memberHandler.get, fset=memberHandler.set)\n            setattr(HUnionConst, field.name, p)\n            setattr(HUnionRtlSignal, field.name, p)\n\n        self.__bit_length_val = bit_length\n        self.__hash = hash((self.name, tuple(self.fields.items())))\n\n        usedNames = set(self.fields.keys())\n        assert not _protectedNames.intersection(\n            usedNames), _protectedNames.intersection(usedNames)\n\n        if name is not None:\n            HUnionConst.__name__ = name + \"Const\"\n            HUnionRtlSignal.__name__ = name + \"RtlSignal\"\n\n        self._constCls = HUnionConst\n        self._rtlSignalCls = HUnionRtlSignal\n\n    def bit_length(self):\n        bl = self.__bit_length_val\n        if bl is None:\n            raise TypeError(\"Can not request bit_lenght on type\"\n                            \" which has not fixed size\")\n        else:\n            return self.__bit_length_val\n\n    @internal\n    @override\n    def getConstCls(self):\n        return self._constCls\n\n    @internal\n    def __fields__eq__(self, other):\n        if len(self.fields) != len(other.fields):\n            return False\n\n        for k, sf in self.fields.items():\n            try:\n                of = other.fields[k]\n            except KeyError:\n                return False\n\n            if (sf.dtype != of.dtype or\n                    sf.meta != of.meta):\n                return False\n\n        return True\n\n    def __eq__(self, other):\n        return self is other or (\n            type(self) is type(other) and\n            self.bit_length() == other.bit_length() and\n            self.__fields__eq__(other))\n\n    @internal\n    def __hash__(self):\n        return self.__hash\n\n    @override\n    def isScalar(self):\n        return False\n\n    def __repr__(self, indent=0, withAddr=None, expandStructs=False):\n        \"\"\"\n        :param indent: number of indentation\n        :param withAddr: if is not None is used as a additional\n            information about on which address this type is stored\n            (used only by HStruct)\n        :param expandStructs: expand HStructTypes (used by HStruct and HArray)\n        \"\"\"\n        if self.name:\n            name = self.name + \" \"\n        else:\n            name = \"\"\n\n        myIndent = getIndent(indent)\n        childIndent = getIndent(indent + 1)\n        header = f\"{myIndent:s}union {name:s}{{\"\n\n        buff = [header, ]\n        for f in self.fields.values():\n            if f.name is None:\n                buff.append(f\"{childIndent:s}//{f.dtype} empty space\")\n            else:\n                buff.append(\"%s %s\" % (\n                                f.dtype.__repr__(indent=indent + 1,\n                                                 withAddr=withAddr,\n                                                 expandStructs=expandStructs),\n                            f.name))\n\n        buff.append(f\"{myIndent:s}}}\")\n        return \"\\n\".join(buff)\n"
  },
  {
    "path": "hwt/hdl/types/utils.py",
    "content": "from typing import Union, List\n\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.stream import HStream\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.hdl.types.union import HUnion\nfrom hwt.mainBases import RtlSignalBase\n\n\ndef walkFlattenFields(sigOrConst: Union[RtlSignalBase, HConst], skipPadding=True):\n    \"\"\"\n    Walk all simple values in HStruct or HArray\n    \"\"\"\n    t = sigOrConst._dtype\n    if isinstance(t, HBits):\n        yield sigOrConst\n    elif isinstance(t, HUnion):\n        yield from walkFlattenFields(sigOrConst._val, skipPadding=skipPadding)\n    elif isinstance(t, HStruct):\n        for f in t.fields:\n            isPadding = f.name is None\n            if not isPadding or not skipPadding:\n                if isPadding:\n                    v = f.dtype.from_py(None)\n                else:\n                    v = getattr(sigOrConst, f.name)\n\n                yield from walkFlattenFields(v)\n\n    elif isinstance(t, HArray):\n        for item in sigOrConst:\n            yield from walkFlattenFields(item)\n    elif isinstance(t, HStream):\n        assert isinstance(sigOrConst, HConst), sigOrConst\n        for v in sigOrConst:\n            yield from walkFlattenFields(v)\n    else:\n        raise NotImplementedError(t)\n\n\ndef HConst_from_words(t: HdlType,\n                      data: List[Union[HConst, RtlSignalBase, int]],\n                      getDataFn=None, dataWidth=None) -> HConst:\n    \"\"\"\n    Parse raw HBits array to a value of specified HdlType\n    \"\"\"\n    if getDataFn is None:\n        assert dataWidth is not None\n\n        def _getDataFn(x):\n            return toHVal(x)._auto_cast(HBits(dataWidth))\n\n        getDataFn = _getDataFn\n\n    val = t.from_py(None)\n\n    fData = iter(data)\n\n    # actual is storage variable for items from frameData\n    actualOffset = 0\n    actual = None\n\n    for v in walkFlattenFields(val, skipPadding=False):\n        # walk flatten fields and take values from fData and parse them to\n        # field\n        required = v._dtype.bit_length()\n\n        if actual is None:\n            actualOffset = 0\n            try:\n                actual = getDataFn(next(fData))\n            except StopIteration:\n                raise ValueError(\"Insufficcient amount of data to build value for specified type\", t, v, required)\n\n            if dataWidth is None:\n                dataWidth = actual._dtype.bit_length()\n            actuallyHave = dataWidth\n        else:\n            actuallyHave = actual._dtype.bit_length() - actualOffset\n\n        while actuallyHave < required:\n            # collect data for this field\n            try:\n                d = getDataFn(next(fData))\n            except StopIteration:\n                raise ValueError(\"Insufficcient amount of data to build value for specified type\", t, v, required, actuallyHave)\n\n            actual = d._concat(actual)\n            actuallyHave += dataWidth\n\n        if actuallyHave >= required:\n            # parse value of actual to field\n            # skip padding\n            _v = actual[(required + actualOffset):actualOffset]\n            _v = _v._auto_cast(v._dtype)\n            v.val = _v.val\n            v.vld_mask = _v.vld_mask\n\n            # update slice out what was taken\n            actuallyHave -= required\n            actualOffset += required\n\n        if actuallyHave == 0:\n            actual = None\n\n    if actual is not None:\n        assert actual._dtype.bit_length(\n        ) - actualOffset < dataWidth, (\n            \"It should be just a padding at the end of frame, but there is some additional data\"\n        )\n    return val\n\n\ndef is_only_padding(t: HdlType) -> bool:\n    if isinstance(t, HStruct):\n        for f in t.fields:\n            if f.name is not None and not is_only_padding(f.dtype):\n                return False\n        return True\n    elif isinstance(t, (HArray, HStream)):\n        return is_only_padding(t.element_t)\n    return False\n"
  },
  {
    "path": "hwt/hdl/variables.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.hdlObject import HdlObject\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass HdlSignalItem(HdlObject):\n    \"\"\"\n    Basic hdl signal used to design circuits\n    \"\"\"\n    __slots__ = [\n        \"_name\",\n        \"_dtype\",\n        \"virtual_only\",\n        \"def_val\",\n    ]\n    \n    def __init__(self, name: str, dtype: \"HdlType\", def_val=None, virtual_only=False):\n        \"\"\"\n        :param _name: name for better orientation in netlists\n            (used only in serialization)\n        :param dtype: data type of this signal\n        :param def_val: value for initialization\n        :param virtual_only: flag indicates that this assignments is only\n            virtual and should not be added into\n            netlist, because it is only for internal notation\n        \"\"\"\n        assert isinstance(name, str), name\n        self._name = name\n        self._dtype = dtype\n        self.virtual_only = virtual_only\n        if def_val is None:\n            def_val = dtype.from_py(None)\n        self.def_val = def_val\n        self._set_def_val()\n\n    @internal\n    def _set_def_val(self):\n        v = self.def_val\n        if isinstance(v, RtlSignalBase):\n            v = v.staticEval()\n\n        self._val = v.__copy__()\n"
  },
  {
    "path": "hwt/hwIO.py",
    "content": "from copy import copy\nfrom typing import Optional, Union, Generator, Callable, Self, Collection\n\nfrom hdlConvertorAst.translate.common.name_scope import NameScope\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bitsCastUtils import fitTo\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.mainBases import HwIOBase\nfrom hwt.synthesizer.exceptions import IntfLvlConfErr, InterfaceStructureErr\nfrom hwt.synthesizer.interfaceLevel.directionFns import \\\n    HwIODirectionFns\nfrom hwt.synthesizer.rtlLevel.netlist import RtlNetlist\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwt.synthesizer.typePath import TypePath\nfrom hwtSimApi.agents.base import AgentBase\nfrom ipCorePackager.constants import DIRECTION, INTF_DIRECTION\n\n\nfrom hwt.synthesizer.interfaceLevel.implDependent import\\\n    HwIOImplDependentFns\nfrom hwt.synthesizer.interfaceLevel.propDeclrCollector import\\\n    PropDeclrCollector\n\n\ndef _default_param_updater(self, myP, parentPval):\n    myP.set_value(parentPval)\n\n\nclass HwIO(HwIOBase, HwIOImplDependentFns,\n           PropDeclrCollector, HwIODirectionFns):\n    \"\"\"\n    Base class for all interfaces in interface synthesizer\n\n    :cvar _NAME_SEPARATOR: separator for nested interface names\n    :ivar ~._hwParams: [] of parameter\n    :ivar ~._hwIOs: [] sub interfaces\n    :ivar ~._name: name assigned during synthesis\n    :ivar ~._onParentPropertyPath: path composed of property name and indexes in on parent to identify\n        object location in parent properties\n    :ivar ~._parent: parent object (HwModule or HwIO instance)\n    :ivar ~._isExtern: If true synthesizer sets it as external port of unit\n    :ivar ~._associatedClk: clock Signal (interface) associated with\n        this interface if is none simulation agent try to search it on parent\n    :ivar ~._associatedRst: rst(_n) Signal (interface) associated\n        with this interface if is none simulation agent try to search\n        it on parent\n\n    :note: only interfaces without _hwIOs have\n\n    :ivar ~._boundedSigLvlHwModule: RTL unit for which was this interface created\n\n\n    Agenda of directions and HDL\n\n    :ivar ~._masterDir: specifies which direction has this interface at master\n    :ivar ~._direction: means actual direction of this interface resolved\n        by its drivers\n    :ivar ~._rtlCtx: RTL netlist context of all signals and params\n        on this interface after interface is registered on parent _ctx\n        is merged\n    :ivar ~._hdlPort: a HdlPortItem instance available once the unit is synthesized\n\n    Agenda of simulations\n\n    :ivar ~._ag: agent object connected to this interface\n        (initialized only before simulation)\n    \"\"\"\n\n    _NAME_SEPARATOR = \"_\"\n\n    def __init__(self, masterDir=DIRECTION.OUT,\n                 hdlName:Optional[Union[str, dict[str, str]]]=None,\n                 loadConfig=True):\n        \"\"\"\n        This constructor is called when constructing new interface,\n        it is usually done manually while creating :class:`hwt.hwModule.HwModule` or\n        automatically while extracting interfaces from HwModuleWithSoure\n\n        :param masterDir: direction which this interface should have for master\n        :param loadConfig: do load config in __init__\n        \"\"\"\n        self._setAttrListener: Optional[Callable[[str, object], None]] = None\n        self._associatedClk: Optional[HwIO] = None\n        self._associatedRst: Optional[HwIO] = None\n        self._parent: Optional[\"HwModule\"] = None\n        self._onParentPropertyPath: Optional[TypePath] = None\n        self._name: Optional[str] = None\n\n        # super().__init__()\n        self._masterDir: DIRECTION = masterDir\n        # HwIO is instantiated inside of :class:`hwt.hwModule.HwModule` first,\n        # master direction actually means slave from outside view\n        self._direction: INTF_DIRECTION = INTF_DIRECTION.UNKNOWN\n        self._rtlCtx: Optional[RtlNetlist] = None\n\n        if loadConfig:\n            self._loadConfig()\n\n        # flags for better design error detection\n        self._isExtern = False\n        self._ag: Optional[AgentBase] = None\n        self._hdlPort: Optional[HdlPortItem] = None\n        self._hdlNameOverride = hdlName\n\n    def _m(self) -> Self:\n        \"\"\"\n        Note that this interface will be master\n\n        :return: self\n        \"\"\"\n        assert not hasattr(self, \"_hwIOs\") or not self._hwIOs, \\\n            \"Too late to change direction of interface\"\n        self._direction = DIRECTION.asIntfDirection(DIRECTION.opposite(self._masterDir))\n\n        return self\n\n    def __call__(self, other: Union[Self, HConst, object], exclude:Optional[Collection[Union[Self, HConst]]]=None,\n                 fit:bool=False) -> list[HdlAssignmentContainer]:\n        \"\"\"\n        :attention: it is not call of function it is operator of assignment\n        \"\"\"\n        assert self._direction != INTF_DIRECTION.MASTER\n        return self._connectTo(other, exclude, fit)\n        try:\n            return self._connectTo(other, exclude, fit)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    @internal\n    def _loadHwDeclarations(self):\n        \"\"\"\n        load declarations from _declr method\n        This function is called first for parent and then for children\n        \"\"\"\n        if not hasattr(self, \"_hwIOs\"):\n            self._hwIOs = []\n        self._setAttrListener = self._declrCollector\n        self.hwDeclr()\n        self._setAttrListener = None\n\n        for sHwIO in self._hwIOs:\n            sHwIO._loadHwDeclarations()\n            sHwIO._setAsExtern(self._isExtern)\n\n        if self._isExtern:\n            # direction from inside of unit (reverset compared to outside direction)\n            if self._direction == INTF_DIRECTION.UNKNOWN:\n                self._direction = INTF_DIRECTION.MASTER\n            self._setDirectionsLikeIn(self._direction)\n\n    @internal\n    def _cleanRtlSignals(self, lockNonExternal=True):\n        \"\"\"\n        Remove all signals from this interface (used after unit is synthesized\n        and its parent is connecting its interface to this unit)\n        \"\"\"\n\n        if self._hwIOs:\n            for sHwIO in self._hwIOs:\n                sHwIO._cleanRtlSignals(lockNonExternal=lockNonExternal)\n\n    def _connectTo(self, master: Union[Self, HConst, object], exclude:Optional[Collection[Union[Self, HConst]]]=None,\n                   fit:bool=False) -> list[HdlAssignmentContainer]:\n        \"\"\"\n        connect to another interface interface (on RTL level)\n        works like self <= master in VHDL\n        \"\"\"\n        return list(self._connectToIter(master, exclude, fit))\n\n    @internal\n    def _connectToIter(self, master: Union[Self, HConst, object], exclude:Optional[Collection[Union[Self, HConst]]],\n                       fit: bool) -> Generator[HdlAssignmentContainer, None, None]:\n        if exclude and (self in exclude or master in exclude):\n            return\n\n        if self._hwIOs or isinstance(self, HObjList):\n            masterIsHwIO = isinstance(master, HwIO)\n            if masterIsHwIO:\n                seenMasterHwIOs = set()\n            else:\n                seenMasterPropCnt = 0\n\n            for hio in self._hwIOs:\n                if exclude and hio in exclude:\n                    mHwIO = getattr(master, hio._name, None)\n                    if mHwIO is not None:\n                        seenMasterHwIOs.add(mHwIO)\n                    continue\n                if master is None:\n                    mHwIO = hio._dtype.from_py(None)\n                else:\n                    try:\n                        mHwIO = getattr(master, hio._name)\n                    except AttributeError:\n                        if not hio._onParentPropertyPath:\n                            raise IntfLvlConfErr(\"Invalid interface structure\", hio, \"<=\", master, \"src missing\", hio._name)\n                        try:\n                            mHwIO = hio._onParentPropertyPath.getOnObject(master)\n                        except (AttributeError, KeyError, IndexError):\n                            raise IntfLvlConfErr(\"Invalid interface structure\", hio, \"<=\", master, \"src missing\", hio._name,\n                                                 \"and _onParentPropertyPath is invalid\", hio._onParentPropertyPath)\n\n                if masterIsHwIO:\n                    seenMasterHwIOs.add(mHwIO)\n                else:\n                    seenMasterPropCnt += 1\n                if exclude and mHwIO in exclude:\n                    continue\n\n                if isinstance(mHwIO, (HConst, RtlSignal)):\n                    # HStruct values\n                    if (hio._masterDir in (DIRECTION.OUT, DIRECTION.INOUT) and hio._direction == INTF_DIRECTION.MASTER) or\\\n                        (hio._masterDir == DIRECTION.IN and hio._direction == INTF_DIRECTION.SLAVE):\n                        raise IntfLvlConfErr(\n                            \"Invalid connection\", hio, \"<=\", mHwIO)\n                    yield from hio._connectToIter(mHwIO,\n                                                  exclude,\n                                                  fit)\n                elif mHwIO._masterDir == DIRECTION.OUT:\n                    if hio._masterDir != mHwIO._masterDir:\n                        raise IntfLvlConfErr(\n                            \"Invalid connection\", hio, \"<=\", mHwIO)\n\n                    yield from hio._connectToIter(mHwIO,\n                                                  exclude,\n                                                  fit)\n                else:\n                    if hio._masterDir != mHwIO._masterDir:\n                        raise IntfLvlConfErr(\n                            \"Invalid connection\", mHwIO, \"<=\", hio)\n\n                    yield from mHwIO._connectToIter(hio,\n                                                   exclude,\n                                                   fit)\n            if master is None:\n                pass  # no check for prop cnt\n            else:\n                if masterIsHwIO:\n                    masterHwIOCnt = len(master._hwIOs)\n                else:\n                    if isinstance(master._dtype, HArray):\n                        masterHwIOCnt = len(master)\n                    else:\n                        # assert isinstance(master._dtype, HStruct)\n                        masterHwIOCnt = len(master._dtype.fields)\n\n                if (masterIsHwIO and len(seenMasterHwIOs) != masterHwIOCnt) or (not masterIsHwIO and seenMasterPropCnt != masterHwIOCnt):\n                    if exclude:\n                        # there is a possibility that the master interface was excluded,\n                        # but we did not see it as the interface of the same name was not present on self\n                        for hio in self._hwIOs:\n                            if hio in exclude or hio not in seenMasterHwIOs:\n                                continue\n                            else:\n                                # hio is an interface which is extra on master and is missing an equivalent on slave\n                                raise InterfaceStructureErr(self, master, exclude)\n                    else:\n                        raise InterfaceStructureErr(self, master, exclude)\n\n        else:\n            if not isinstance(master, (HConst, RtlSignal)) and master._hwIOs:\n                raise InterfaceStructureErr(self, master, exclude)\n\n            dstSig = toHVal(self)\n            srcSig = toHVal(master)\n\n            if fit:\n                srcSig = fitTo(srcSig, dstSig)\n\n            yield dstSig(srcSig)\n\n    @internal\n    def _signalsForHwIO(self,\n                        ctx: RtlNetlist,\n                        res: Optional[dict[RtlSignal, DIRECTION]],\n                        name_scope: Optional[NameScope],\n                        prefix='', typeTransform=None,\n                        reverse_dir=False):\n        \"\"\"\n        Generate RtlSignal _sig and HdlPortInstance _hdlPort\n        for each interface which has no subinterface\n\n        :note: if already has _sig return use it instead\n\n        :param ctx: instance of RtlNetlist where signals should be created\n        :param res: output dictionary where result should be stored\n        :param prefix: name prefix for created signals\n        :param name_scope: name scope used to check collisions on port names\n            if this a current top (every component is checked\n            when it is seen first time)\n        :param typeTransform: optional function (type) returns modified type\n            for signal\n        \"\"\"\n        if self._hwIOs or isinstance(self, HObjList):\n            for hwIO in self._hwIOs:\n                hwIO._signalsForHwIO(ctx, res, name_scope,\n                                          prefix=prefix,\n                                          typeTransform=typeTransform,\n                                          reverse_dir=reverse_dir)\n        else:\n            assert self._sig is None, self\n            t = self._dtype\n            if typeTransform is not None:\n                t = typeTransform(t)\n\n            hdlName = prefix + self._getHdlName()\n\n            s = ctx.sig(hdlName, t)\n            s._hwIO = self\n            self._sig = s\n\n            if self._isExtern:\n                d = INTF_DIRECTION.asDirection(self._direction)\n                m = ctx.parent\n                if reverse_dir:\n                    d = DIRECTION.opposite(d)\n                    assert self._hdlPort is None, (\n                        \"Now creating a hdl interface for top\"\n                        \" it but seems that it was already created\")\n\n                if res is not None:\n                    res[s] = d\n\n                if reverse_dir:\n                    pi = HdlPortItem.fromSignal(s, m, d)\n                    # port of current top component\n                    s._name = name_scope.checked_name(s._name, s)\n                    pi.connectInternSig(s)\n                    ctx.hwModDec.ports.append(pi)\n                else:\n                    pi = self._hdlPort\n                    # port of some subcomponent which names were already checked\n                    pi.connectOuterSig(s)\n\n                self._hdlPort = pi\n\n    def _getHdlName(self) -> str:\n        \"\"\"Get name in HDL \"\"\"\n        return HObjList._getHdlName(self)\n\n    def _getFullName(self) -> str:\n        \"\"\"get all name hierarchy separated by '.' \"\"\"\n        return HObjList._getFullName(self)\n\n    def _updateHwParamsFrom(self, otherObj, updater=_default_param_updater,\n                          exclude:Optional[tuple[set[str], set[str]]]=None, prefix=\"\"):\n        \"\"\"\n        :note: doc in :func:`~hwt.synthesizer.interfaceLevel.propDeclCollector._updateHwParamsFrom`\n        \"\"\"\n        PropDeclrCollector._updateHwParamsFrom(\n            self, otherObj, updater, exclude, prefix)\n        return self\n\n    def _bit_length(self) -> int:\n        \"\"\"Sum of all width of hwIOs in this interface\"\"\"\n        try:\n            hwIOs = self._hwIOs\n        except AttributeError:\n            hwIOs = None\n\n        if hwIOs is None:\n            # not loaded interface\n            _hwIO = self.__copy__()\n            _hwIO._loadHwDeclarations()\n            hwIOs = _hwIO._hwIOs\n\n        if hwIOs:\n            w = 0\n            for hwIO in hwIOs:\n                w += hwIO._bit_length()\n            return w\n        else:\n            return self._dtype.bit_length()\n\n    def __repr__(self) -> str:\n        if hasattr(self, \"_dtype\"):\n            t = f\" {self._dtype}\"\n        else:\n            t = \"\"\n\n        if hasattr(self, '_width'):\n            w = \" _width=%s\" % str(self._width)\n        else:\n            w = \"\"\n\n        name = self._getFullName()\n        return f\"<{self.__class__.__name__} {name:s}{w:s}{t:s}>\"\n"
  },
  {
    "path": "hwt/hwIOs/__init__.py",
    "content": "\"\"\"\nThis package contains primitive hardware interfaces.\n\"\"\"\n"
  },
  {
    "path": "hwt/hwIOs/agents/__init__.py",
    "content": "\"\"\"\nThis package contains a UVM like simulation agents to handle IO between circuit running in simulator and the code which drives the simulation.\n\"\"\""
  },
  {
    "path": "hwt/hwIOs/agents/bramPort.py",
    "content": "from collections import deque\nfrom typing import Literal, Union\n\nfrom hwt.constants import READ, WRITE, NOP\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.agents.clk import ClockAgent\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.triggers import WaitCombRead, WaitWriteOnly, WaitCombStable, Timer\nfrom pyMathBitPrecise.bit_utils import apply_set_and_clear, mask, \\\n    byte_mask_to_bit_mask_int, bit_mask_to_byte_mask_int\n\n\n@staticmethod\ndef storeToRamMaskedByIndex(ram:dict[int, Union[tuple[int, int], HBitsConst]],\n                            index: int,\n                            data: Union[int, HBitsConst],\n                            bitmask: Union[int, HBitsConst],\n                            isInHBits=False):\n    if not bitmask:\n        # nothing will be set, no point in further update\n        return\n    # clear all bytes unsed by mask\n    data &= bitmask\n\n    if isInHBits:\n        # explicitely invalidate bytes of data\n        data = data._dtype.from_py(data.val, data.vld_mask & bitmask.val)\n\n    cur = ram.get(index)\n    if cur is not None:\n        # merge previous and new data\n        if isInHBits:\n            data = apply_set_and_clear(cur, data & bitmask, bitmask)\n        else:\n            data = apply_set_and_clear(cur[0], data & bitmask, bitmask)\n            bitmask |= cur[1]\n\n    # print(f\"storing   {index:02x}: ({data if isinstance(data, int) else data.val:04x}, {int(bitmask):04x}) {bit_mask_to_byte_mask_int(int(bitmask), 32):01x}\")\n    if isInHBits:\n        ram[index] = data\n    else:\n        ram[index] = (data, bitmask)\n\n\n@staticmethod\ndef storeToRamMaskedByAddress(ram: dict[int, Union[tuple[int, int], HBitsConst]],\n                              address: int,\n                              wordAlignAddrBitCnt: int,\n                              data: Union[int, HBitsConst],\n                              bitmask: Union[int, HBitsConst],\n                              isInHBits=False):\n    # print(f\"storing a:{address:08x}: ({data:064x}, {bitmask:064x}) {bit_mask_to_byte_mask_int(bitmask, 256):08x}\")\n    alignShift = address & mask(wordAlignAddrBitCnt)\n    index0 = address >> wordAlignAddrBitCnt\n    if alignShift:\n        # the address is not aligned to a word boundary must split to 2 transactions\n        # if first store actually sotres some data\n        if isInHBits:\n            DATA_WIDTH = data._dtype.bit_length()\n            MASK_WIDTH = bitmask._dtype.bit_length()\n            data = data._zext(DATA_WIDTH * 2)\n            bitmask = bitmask._zext(MASK_WIDTH * 2)\n        data <<= alignShift * 8\n        bitmask <<= alignShift * 8\n        if isInHBits:\n            bitmask0 = bitmask[MASK_WIDTH:]\n            bitmask1 = bitmask[:MASK_WIDTH]\n        else:\n            wordBitCnt = (2 ** wordAlignAddrBitCnt) * 8\n            wordBitMask = mask(wordBitCnt)\n            bitmask0 = bitmask & wordBitMask\n            bitmask1 = bitmask >> wordBitCnt\n\n        if bitmask0:\n            if isInHBits:\n                data0 = data[DATA_WIDTH:]\n            else:\n                data0 = data & wordBitMask\n\n            storeToRamMaskedByIndex(ram, index0, data0, bitmask0, isInHBits=isInHBits)\n\n        # if second store actually stores some data\n        if bitmask1:\n            if isInHBits:\n                data1 = data[:DATA_WIDTH]\n            else:\n                data1 = data >> wordBitCnt\n            storeToRamMaskedByIndex(ram, index0 + 1, data1, bitmask1, isInHBits=isInHBits)\n    else:\n        storeToRamMaskedByIndex(ram, index0, data, bitmask)\n\n\nHwIOBramPort_noClkAgent_requestTy = Union[\n                            tuple[READ, HBitsConst],\n                            tuple[WRITE, HBitsConst, HBitsConst],  # addr, data\n                            tuple[WRITE, HBitsConst, HBitsConst, HBitsConst],  # addr, data, mask\n                            ]\n\n\nclass HwIOBramPort_noClkAgent(SyncAgentBase):\n    \"\"\"\n    A simulation agent for BramPort_withoutClk interface\n    In slave mode acts as a memory, in master mode dispatches\n    requests stored in \"requests\" dequeue\n\n    :ivar ~.requests: list of tuples (request type, address, [write data])\n        - used for driver\n    :ivar ~.data: list of data in memory, used for monitor\n    :ivar ~.mem: if agent is in monitor mode (= is slave) all reads and writes\n        are performed on mem object\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIOBramPort_noClk\"):\n        super().__init__(sim, hwIO, allowNoReset=True)\n        self.HAS_WE = hasattr(hwIO, \"we\")\n        self.HAS_BE = hwIO.HAS_BE and hwIO.DATA_WIDTH > 8\n        if self.HAS_BE:\n            assert hwIO.DATA_WIDTH % 8 == 0, (\"Expects only complete bytes\", hwIO, hwIO.DATA_WIDTH)\n        self.requests: deque[HwIOBramPort_noClkAgent_requestTy] = deque()\n        self.readPending = False\n        self.r_data = deque()\n\n        self.mem: dict[int, HBitsConst] = {}\n        self.requireInit = True\n        self.clk_ag = None\n\n    def doReq(self, req: HwIOBramPort_noClkAgent_requestTy):\n        rw = req[0]\n        addr = req[1]\n        hwIO = self.hwIO\n\n        if rw == READ:\n            assert hwIO.HAS_R, hwIO\n            we = 0\n            wdata = None\n            self.readPending = True\n            if self._debugOutput is not None:\n                self._debugOutput.write(\"%s, after %r read_req: %d\\n\" % (\n                                        self.hwIO._getFullName(),\n                                        self.sim.now, addr))\n        elif rw == WRITE:\n            assert hwIO.HAS_W, hwIO\n            wdata = req[2]\n            if len(req) == 3:\n                if self.HAS_WE:\n                    we = mask(hwIO.we._dtype.bit_length())\n            else:\n                assert self.HAS_WE\n                we = req[3]\n\n            if self._debugOutput is not None:\n                self._debugOutput.write(f\"{self.hwIO._getFullName():s}, after {self.sim.now:d}\"\n                                        f\" write: 0x{int(addr):x}:{wdata} {int(we)}\\n\")\n\n        else:\n            raise NotImplementedError(rw)\n\n        hwIO.addr.write(addr)\n        if self.HAS_WE:\n            hwIO.we.write(we)\n        if hwIO.HAS_W:\n            hwIO.din.write(wdata)\n\n    def onReadReq(self, addr: HBitsConst):\n        \"\"\"\n        on readReqRecieved in monitor mode\n        \"\"\"\n        self.requests.append((READ, addr))\n\n    def onWriteReq(self, addr: HBitsConst, data: HBitsConst, mask: Union[HBitsConst, Literal[0, 1, None]]):\n        \"\"\"\n        on writeReqRecieved in monitor mode\n        \"\"\"\n        self.requests.append((WRITE, addr, data, mask))\n\n    def monitor(self):\n        \"\"\"\n        Handle read/write request on this interfaces\n\n        This method is executed on clock edge.\n        This means that the read data should be put on dout after clock edge.\n        \"\"\"\n        hwIO = self.hwIO\n\n        yield WaitCombStable()\n        if self.notReset():\n            en = hwIO.en.read()\n            en = int(en)\n            if en:\n                if self.HAS_WE:\n                    we = hwIO.we.read()\n                    we = int(we)\n                elif hwIO.HAS_W:\n                    we = 1\n                else:\n                    we = 0\n\n                addr = hwIO.addr.read()\n                if we:\n                    data = hwIO.din.read()\n                    self.onWriteReq(addr, data, we)\n                elif hwIO.HAS_R:\n                    self.onReadReq(addr)\n\n        if self.requests:\n            req = self.requests.popleft()\n            t = req[0]\n            addr = req[1]\n            if t == READ:\n                v = self.mem.get(addr.val, None)\n                yield Timer(1)\n                yield WaitWriteOnly()\n                hwIO.dout.write(v)\n                if self._debugOutput is not None:\n                    self._debugOutput.write(f\"{self.hwIO._getFullName(),}, after {self.sim.now}, read 0x{int(addr):x} {v}\\n\")\n            else:\n                assert t == WRITE\n                # yield WaitWriteOnly()\n                # hwIO.dout.write(None)\n                yield Timer(1)\n                # after clock edge\n                yield WaitWriteOnly()\n                wData = req[2]\n                wMask = req[3]\n                if addr._is_full_valid():\n                    if self.HAS_BE:\n                        maskWidth = hwIO.we._dtype.bit_length()\n                        wMaskExt = byte_mask_to_bit_mask_int(wMask, maskWidth)\n                        if self._debugOutput is not None:\n                            self._debugOutput.write(f\"{self.hwIO._getFullName(),}, after {self.sim.now}, write 0x{int(addr):x} {wData}, 0x{wMask:x}\\n\")\n                        storeToRamMaskedByIndex(self.mem, int(addr), wData, HBits(maskWidth * 8).from_py(wMaskExt), isInHBits=True)\n                    else:\n                        if self._debugOutput is not None:\n                            self._debugOutput.write(f\"{self.hwIO._getFullName(),}, after {self.sim.now}, write 0x{int(addr):x} {wData}\\n\")\n\n                        self.mem[addr.val] = wData\n                else:\n                    if self._debugOutput is not None:\n                        self._debugOutput.write(f\"{self.hwIO._getFullName(),}, after {self.sim.now}, write with invalid addr\\n\")\n                    self.mem.clear()\n\n    def driver(self):\n        hwIO = self.hwIO\n        if self.requireInit:\n            yield WaitWriteOnly()\n            hwIO.en.write(0)\n\n            if self.HAS_WE:\n                hwIO.we.write(0)\n            self.requireInit = False\n\n        readPending = self.readPending\n        yield WaitCombRead()\n        if self.requests and self.notReset():\n            yield WaitWriteOnly()\n            req = self.requests.popleft()\n            if req is NOP:\n                hwIO.en.write(0)\n                if self.HAS_WE:\n                    hwIO.we.write(0)\n                self.readPending = False\n            else:\n                self.doReq(req)\n                hwIO.en.write(1)\n        else:\n            yield WaitWriteOnly()\n            hwIO.en.write(0)\n            if self.HAS_WE:\n                hwIO.we.write(0)\n            self.readPending = False\n\n        if readPending:\n            # in previous clock the read request was dispatched, now we are collecting the data\n            yield WaitCombStable()\n            # now we are after clk edge\n            d = hwIO.dout.read()\n            self.r_data.append(d)\n            if self._debugOutput is not None:\n                self._debugOutput.write(\"%s, on %r read_data: %d\\n\" % (\n                                        self.hwIO._getFullName(),\n                                        self.sim.now, d.val))\n\n\nclass HwIOBramPortAgent(HwIOBramPort_noClkAgent):\n\n    def getDrivers(self):\n        yield from super(HwIOBramPortAgent, self).getDrivers()\n        self.clk_ag = ClockAgent(self.sim, self.hwIO.clk)\n        yield from self.clk_ag.getDrivers()\n"
  },
  {
    "path": "hwt/hwIOs/agents/fifo.py",
    "content": "from collections import deque\n\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.constants import CLK_PERIOD\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.process_utils import OnRisingCallbackLoop\nfrom hwtSimApi.triggers import Timer, WaitWriteOnly, WaitCombRead, WaitCombStable, \\\n    WaitTimeslotEnd\n\n\nclass HwIOFifoReaderAgent(SyncAgentBase):\n    \"\"\"\n    Simulation agent for FifoReader interface\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIOFifoReader\", allowNoReset=False):\n        super(HwIOFifoReaderAgent, self).__init__(sim, hwIO, allowNoReset)\n        self.data = deque()\n        self.readPending = False\n        self.lastData = None\n\n        # flags to keep data coherent when enable state changes\n        self.lastData_invalidate = False\n        self.readPending_invalidate = False\n        if hwIO.DATA_WIDTH == 0:\n            raise NotImplementedError()\n\n    def setEnable_asDriver(self, en: bool):\n        lastEn = self._enabled\n        super(HwIOFifoReaderAgent, self).setEnable_asDriver(en)\n        self.hwIO.wait.write(not en)\n        self.lastData_invalidate = not en\n        if not lastEn:\n            self.dataWriter.setEnable(en)\n\n    def setEnable_asMonitor(self, en: bool):\n        lastEn = self._enabled\n        super(HwIOFifoReaderAgent, self).setEnable_asMonitor(en)\n        self.hwIO.en.write(en)\n        self.readPending_invalidate = not en\n        if not lastEn:\n            self.dataReader.setEnable(en)\n        # else dataReader will disable itself\n\n    def driver_init(self):\n        yield WaitWriteOnly()\n        self.hwIO.wait.write(not self._enabled)\n\n    def monitor_init(self):\n        yield WaitWriteOnly()\n        self.hwIO.en.write(self._enabled)\n\n    def get_data(self):\n        return self.hwIO.data.read()\n\n    def dataReader(self):\n        yield Timer(1)\n        if self.readPending:\n            yield WaitCombRead()\n            d = self.get_data()\n            self.data.append(d)\n\n            if self.readPending_invalidate:\n                self.readPending = False\n        if not self.readPending and not self._enabled:\n            self.dataWriter.setEnable(False)\n\n    def getMonitors(self):\n        self.dataReader = OnRisingCallbackLoop(self.sim, self.clk,\n                                               self.dataReader,\n                                               self.getEnable)\n        yield self.monitor_init()\n        yield from super(HwIOFifoReaderAgent, self).getMonitors()\n        yield self.dataReader()\n\n    def monitor(self):\n        \"\"\"\n        Initialize data reading if wait is 0\n        \"\"\"\n        hwIO = self.hwIO\n        yield WaitCombRead()\n        if self.notReset():\n            # wait until wait signal is stable\n            wait_last = None\n            while True:\n                yield WaitCombRead()\n                wait = hwIO.wait.read()\n                try:\n                    wait = int(wait)\n                except ValueError:\n                    raise AssertionError(self.sim.now, hwIO, \"wait signal in invalid state\")\n\n                if wait is wait_last:\n                    break\n                else:\n                    wait_last = wait\n                    yield WaitWriteOnly()\n\n            rd = not wait\n        else:\n            rd = False\n\n        yield WaitWriteOnly()\n        hwIO.en.write(rd)\n\n        self.readPending = rd\n\n    def getDrivers(self):\n        self.dataWriter = OnRisingCallbackLoop(self.sim, self.clk,\n                                               self.dataWriter,\n                                               self.getEnable)\n        yield self.driver_init()\n        yield from super(HwIOFifoReaderAgent, self).getDrivers()\n        yield self.dataWriter()\n\n    def set_data(self, d):\n        self.hwIO.data.write(d)\n\n    def dataWriter(self):\n        # delay data litle bit to have nicer wave\n        # otherwise write happens before next clk period\n        # and it means in 0 time and we will not be able to see it in wave\n        yield Timer(1)\n        yield WaitWriteOnly()\n        self.set_data(self.lastData)\n        if self.lastData_invalidate:\n            self.lastData = None\n\n        if not self._enabled:\n            self.dataWriter.setEnable(False)\n\n    def driver(self):\n        # now we are before clock event\n        # * set wait signal\n        # * set last data (done in separate process)\n        # * if en == 1, pop next data for next clk\n        hwIO = self.hwIO\n        yield WaitCombRead()\n        rst_n = self.notReset()\n        # speculative write\n        if rst_n and self.data:\n            wait = 0\n        else:\n            wait = 1\n\n        yield WaitWriteOnly()\n        hwIO.wait.write(wait)\n\n        if rst_n:\n            # wait for potential update of en\n            # check if write can be performed and if it possible do real write\n            yield WaitTimeslotEnd()\n            en = hwIO.en.read()\n            try:\n                en = int(en)\n            except ValueError:\n                raise AssertionError(self.sim.now, hwIO,\n                                     \"en signal in invalid state\")\n\n            if en:\n                assert self.data, (self.sim.now, hwIO, \"underflow\")\n                self.lastData = self.data.popleft()\n\n\nclass HwIOFifoWriterAgent(SyncAgentBase):\n    \"\"\"\n    Simulation agent for FifoWriter interface\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIOFifoWriter\", allowNoReset=False):\n        super(HwIOFifoWriterAgent, self).__init__(\n            sim, hwIO, allowNoReset=allowNoReset)\n        self.data = deque()\n        if hwIO.DATA_WIDTH == 0:\n            raise NotImplementedError()\n\n    def driver_init(self):\n        yield WaitWriteOnly()\n        self.hwIO.en.write(self._enabled)\n\n    def monitor_init(self):\n        yield WaitWriteOnly()\n        self.hwIO.wait.write(not self._enabled)\n\n    def setEnable_asDriver(self, en: bool):\n        SyncAgentBase.setEnable_asDriver(self, en)\n        self.hwIO.en.write(en)\n\n    def setEnable_asMonitor(self, en: bool):\n        SyncAgentBase.setEnable_asMonitor(self, en)\n        self.hwIO.wait.write(not en)\n\n    def get_data(self):\n        return self.hwIO.data.read()\n\n    def set_data(self, d):\n        self.hwIO.data.write(d)\n\n    def monitor(self):\n        # set wait signal\n        # if en == 1 take data\n        hwIO = self.hwIO\n        yield WaitWriteOnly()\n        hwIO.wait.write(0)\n\n        yield WaitCombStable()\n        # wait for potential update of en\n\n        en = hwIO.en.read()\n        try:\n            en = int(en)\n        except ValueError:\n            raise AssertionError(self.sim.now, hwIO,\n                                 \"en signal in invalid state\")\n\n        if en:\n            yield Timer(CLK_PERIOD // 10)\n            yield WaitCombRead()\n            self.data.append(self.get_data())\n\n    def driver(self):\n        # if wait == 0 set en=1 and set data\n        hwIO = self.hwIO\n\n        d = None\n        v = 0\n        yield WaitCombRead()\n        if self.notReset() and self.data:\n            yield WaitCombRead()\n\n            wait = hwIO.wait.read()\n            try:\n                wait = int(wait)\n            except ValueError:\n                raise AssertionError(self.sim.now, hwIO,\n                                     \"wait signal in invalid state\")\n            if not wait:\n                d = self.data.popleft()\n                v = 1\n\n        yield WaitWriteOnly()\n        self.set_data(d)\n        hwIO.en.write(v)\n\n    def getDrivers(self):\n        yield from SyncAgentBase.getDrivers(self)\n        yield self.driver_init()\n\n    def getMonitors(self):\n        yield from SyncAgentBase.getMonitors(self)\n        yield self.monitor_init()\n"
  },
  {
    "path": "hwt/hwIOs/agents/rdSync.py",
    "content": "from collections import deque\n\nfrom hwt.constants import NOP\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.triggers import WaitCombRead, WaitWriteOnly\n\n\nclass HwIODataRdAgent(SyncAgentBase):\n    \"\"\"\n    Simulation/verification agent for RdSynced interface\n    \"\"\"\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIODataRd\", allowNoReset=True):\n        super().__init__(sim, hwIO, allowNoReset=allowNoReset)\n        self.actualData = NOP\n        self.data = deque()\n        self._rd = self.get_ready_signal(hwIO)\n\n    @classmethod\n    def get_ready_signal(cls, hwIO: \"HwIODataRd\"):\n        return hwIO.rd\n\n    def get_ready(self):\n        return self._rd.read()\n\n    def set_ready(self, val):\n        self._rd.write(val)\n\n    def setEnable_asMonitor(self, en: bool):\n        super(HwIODataRdAgent, self).setEnable_asMonitor(en)\n        if not en:\n            self.set_ready(0)\n\n    def monitor(self):\n        \"\"\"Collect data from interface\"\"\"\n        yield WaitCombRead()\n        if self.notReset() and self._enabled:\n            yield WaitWriteOnly()\n            self.set_ready(1)\n\n            yield WaitCombRead()\n            d = self.get_data()\n            self.data.append(d)\n        else:\n            yield WaitWriteOnly()\n            self.set_ready(0)\n\n    def get_data(self):\n        \"\"\"extract data from interface\"\"\"\n        return self.hwIO.data.read()\n\n    def set_data(self, data):\n        \"\"\"write data to interface\"\"\"\n        self.hwIO.data.write(data)\n\n    def driver(self):\n        \"\"\"Push data to interface\"\"\"\n        yield WaitWriteOnly()\n        if self.actualData is NOP and self.data:\n            self.actualData = self.data.popleft()\n\n        do = self.actualData is not NOP\n\n        if do:\n            self.set_data(self.actualData)\n        else:\n            self.set_data(None)\n\n        yield WaitCombRead()\n        en = self.notReset() and self._enabled\n        if not (en and do):\n            return\n\n        if en:\n            rd = self.get_ready()\n            try:\n                rd = int(rd)\n            except ValueError:\n                raise AssertionError(\n                    (\"%r: ready signal for interface %r is in invalid state,\"\n                     \" this would cause desynchronization\") %\n                    (self.sim.now, self.hwIO))\n            if rd:\n                if self._debugOutput is not None:\n                    self._debugOutput.write(\"%s, wrote, %d: %r\\n\" % (\n                                               self.hwIO._getFullName(),\n                                               self.sim.now, self.actualData))\n                if self.data:\n                    self.actualData = self.data.popleft()\n                else:\n                    self.actualData = NOP\n"
  },
  {
    "path": "hwt/hwIOs/agents/rdVldSync.py",
    "content": "from hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.agents.rdVldSync import DataRdVldAgent\nfrom hwtSimApi.hdlSimulator import HdlSimulator\n\n\nclass HwIODataRdVldAgent(SyncAgentBase, DataRdVldAgent):\n    \"\"\"\n    Simulation/verification agent for :class:`hwt.hwIOs.std.Handshaked`\n    interface there is onMonitorReady(simulator)\n    and onDriverWriteAck(simulator) unimplemented method\n    which can be used for interfaces with bi-directional data streams\n\n    :note: 2-phase (xor) handshake\n\n    :attention: requires clk and rst/rstn signal (\n        If you do not have any create simulation wrapper with it.\n        Without it you can very easily end up with a combinational loop.)\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIODataRdVld\", allowNoReset=False):\n        rst = self._discoverReset(hwIO, allowNoReset)\n        clk = hwIO._getAssociatedClk()\n        DataRdVldAgent.__init__(self, sim, hwIO, clk, rst)\n        self._vld = self.get_valid_signal(hwIO)\n        self._rd = self.get_ready_signal(hwIO)\n\n    @classmethod\n    def get_ready_signal(cls, hwIO: \"HwIODataRdVld\"):\n        return hwIO.rd._sigInside\n\n    def get_ready(self):\n        return self._rd.read()\n\n    def set_ready(self, val):\n        self._rd.write(val)\n\n    @classmethod\n    def get_valid_signal(cls, hwIO: \"HwIODataRdVld\"):\n        return hwIO.vld._sigInside\n\n    def get_valid(self):\n        \"\"\"get \"valid\" signal\"\"\"\n        return self._vld.read()\n\n    def set_valid(self, val):\n        return self._vld.write(val)\n\n    def get_data(self):\n        \"\"\"extract data from interface\"\"\"\n        return self.hwIO.data.read()\n\n    def set_data(self, data):\n        \"\"\"write data to interface\"\"\"\n        self.hwIO.data.write(data)\n\n\nclass UniversalRdVldSyncAgent(HwIODataRdVldAgent):\n    \"\"\"\n    Same thing like :class:`hwt.hwIOs.agents.rdVldSync.HwIODataRdVldAgent`\n    just the get_data/set_data method is predefined to use a tuple constructed\n    from signals available on this interface.\n\n    :ivar ~._signals: tuple of data signals of this interface (excluding ready and valid signal)\n    :ivar ~._sigCnt: len(_signals)\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIODataRdVld\", allowNoReset=False):\n        HwIODataRdVldAgent.__init__(self, sim, hwIO, allowNoReset=allowNoReset)\n\n        signals = []\n        rd = self.get_ready_signal(hwIO)\n        vld = self.get_valid_signal(hwIO)\n        for hwIO in hwIO._hwIOs:\n            if hwIO._hwIOs or (hwIO._sigInside is not rd and hwIO._sigInside is not vld):\n                signals.append(hwIO)\n        self._signals = tuple(signals)\n        self._sigCnt = len(signals)\n\n    def get_data(self):\n        if self._sigCnt == 1:\n            return self._signals[0].read()\n        else:\n            return tuple(sig.read() for sig in self._signals)\n\n    def set_data(self, data):\n        if data is None:\n            for sig in self._signals:\n                sig.write(None)\n        else:\n            if self._sigCnt == 1:\n                self._signals[0].write(data)\n            else:\n                assert len(data) == self._sigCnt, (\n                    \"invalid number of data for an interface\",\n                    len(data),\n                    self._signals,\n                    self.hwIO._getFullName())\n                for sig, val in zip(self._signals, data):\n                    try:\n                        sig.write(val)\n                    except:\n                        raise ValueError(\"Error while writing \", val, \"to \", sig)\n\n\nclass HwIORdVldSyncAgent(HwIODataRdVldAgent):\n    \"\"\"\n    Simulation/verification agent for HwIOVldRd interface\n\n    :attention: there is no data channel on this interface\n        it is synchronization only and it actually does not have\n        any meaningful data collected data in monitor\n        mode are just values of simulation time when item was collected\n    \"\"\"\n\n    def set_data(self, data):\n        pass\n\n    def get_data(self):\n        return self.sim.now\n\n\nclass RdVldSyncReadListener():\n\n    def __init__(self, hsAgent: HwIODataRdVldAgent):\n        self.original_afterRead = hsAgent._afterRead\n        hsAgent._afterRead = self._afterReadWrap\n        self.agent = hsAgent\n        self.callbacks = {}\n\n    def _afterReadWrap(self):\n        if self.original_afterRead is not None:\n            self.original_afterRead()\n        try:\n            cb = self.callbacks.pop(len(self.agent.data))\n        except KeyError:\n            return\n        cb()\n\n    def register(self, transCnt, callback):\n        self.callbacks[transCnt] = callback\n"
  },
  {
    "path": "hwt/hwIOs/agents/regCntrl.py",
    "content": "from hwt.hwIOs.agents.signal import HwIOSignalAgent\nfrom hwt.hwIOs.agents.vldSync import HwIODataVldAgent\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.agents.base import AgentBase\n\n\nclass HwIORegCntrlAgent(SyncAgentBase):\n    \"\"\"\n    Simulation/verification agent for RegCntrl interface\n    \"\"\"\n\n    def __init__(self, sim, hwIO: \"HwIORegCntrl\"):\n        super().__init__(sim, hwIO)\n\n        self._din = HwIOSignalAgent(sim, hwIO.din)\n        self._dout = HwIODataVldAgent(sim, hwIO.dout, allowNoReset=True)\n\n    def setEnable_asDriver(self, en: bool):\n        AgentBase.setEnable(self, en)\n        self._din.setEnable(en)\n        self._dout.setEnable(en)\n\n    def setEnable_asMonitor(self, en: bool):\n        AgentBase.setEnable(self, en)\n        self._din.setEnable(en)\n        self._dout.setEnable(en)\n\n    def din_getter(self):\n        return self._din.data\n\n    def din_setter(self, newVal):\n        self._din.data = newVal\n\n    din = property(din_getter, din_setter)\n\n    def dout_getter(self):\n        return self._dout.data\n\n    def dout_setter(self, newVal):\n        self._dout.data = newVal\n\n    dout = property(dout_getter, dout_setter)\n\n    def getDrivers(self):\n        yield from self._din.getMonitors()\n        yield from self._dout.getDrivers()\n\n    def getMonitors(self):\n        yield from self._din.getDrivers()\n        yield from self._dout.getMonitors()\n"
  },
  {
    "path": "hwt/hwIOs/agents/signal.py",
    "content": "from collections import deque\n\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwtSimApi.agents.base import AgentBase\nfrom hwtSimApi.constants import CLK_PERIOD\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.triggers import Timer, WaitWriteOnly, WaitCombRead, WaitCombStable\n\n\nclass HwIOSignalAgent(SyncAgentBase):\n    \"\"\"\n    Agent for signal interface, it can use clock and reset interface\n    for synchronization or can be synchronized by delay\n\n    :attention: clock synchronization has higher priority\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIOSignal\", delay=None):\n        AgentBase.__init__(self, sim, hwIO)\n        self.delay = delay\n        self.initDelay = 0\n\n        # resolve clk and rstn\n        try:\n            self.clk = self.hwIO._getAssociatedClk()\n        except IntfLvlConfErr:\n            self.clk = None\n        self.rst, self.rstOffIn = self._discoverReset(hwIO, True)\n        self.data = deque()\n\n        self.initPending = True\n    \n        if self.clk is None:\n            if self.delay is None:\n                self.delay = CLK_PERIOD\n            self.monitor = self.monitorWithTimer\n            self.driver = self.driverWithTimer\n        else:\n            if self.initDelay:\n                raise NotImplementedError(\"initDelay only without clock\")\n            if self.delay:\n                raise ValueError(\"clock and delay synchronization at once\")\n            c = self.SELECTED_EDGE_CALLBACK\n            self.monitor = c(self.sim, self.clk, self.monitorWithClk, self.getEnable)\n            self.driver = c(self.sim, self.clk, self.driverWithClk, self.getEnable)\n\n    def getDrivers(self):\n        yield self.driverInit()\n        if self.clk is None:\n            if self.delay is None:\n                self.delay = CLK_PERIOD\n            yield self.driverWithTimer()\n        else:\n            if self.initDelay:\n                raise NotImplementedError(\"initDelay only without clock\")\n            if self.delay:\n                raise ValueError(\"clock and delay synchronization at once\")\n            c = self.SELECTED_EDGE_CALLBACK\n            if not isinstance(self.driver, c):\n                self.driver = c(self.sim, self.clk, self.driverWithClk, self.getEnable)\n            yield self.driver()\n            \n    def getMonitors(self):\n        if self.clk is None:\n            if self.delay is None:\n                self.delay = CLK_PERIOD\n            yield self.monitorWithTimer()\n        else:\n            if self.initDelay:\n                raise NotImplementedError(\"initDelay only without clock\")\n            if self.delay:\n                raise ValueError(\"clock and delay synchronization at once\")\n            c = self.SELECTED_EDGE_CALLBACK\n            if not isinstance(self.monitor, c):\n                self.monitor = c(self.sim, self.clk, self.monitorWithClk, self.getEnable)\n            yield self.monitor()\n\n    def driverInit(self):\n        yield WaitWriteOnly()\n        if not self._enabled:\n            return\n        try:\n            d = self.data[0]\n        except IndexError:\n            d = None\n\n        self.set_data(d)\n\n    def get_data(self):\n        return self.hwIO.read()\n\n    def set_data(self, data):\n        self.hwIO.write(data)\n\n    def driverWithClk(self):\n        # if clock is specified this function is periodically called every\n        # clk tick, if agent is enabled\n        yield WaitCombRead()\n        if not self._enabled:\n            return\n        if self.data and self.notReset():\n            yield WaitWriteOnly()\n            if not self._enabled:\n                return\n            d = self.data.popleft()\n            self.set_data(d)\n\n    def driverWithTimer(self):\n        if self.initPending:\n            if self.initDelay:\n                yield Timer(self.initDelay)\n            self.initPending = False\n        # if clock is specified this function is periodically called every\n        # clk tick\n        while True:\n            yield WaitWriteOnly()\n            if self._enabled and self.data and self.notReset():\n                yield WaitWriteOnly()\n                if self._enabled:\n                    d = self.data.popleft()\n                    self.set_data(d)\n\n            yield Timer(self.delay)\n\n    def monitorWithTimer(self):\n        if self.initPending and self.initDelay:\n            yield Timer(self.initDelay)\n            self.initPending = False\n        # if there is no clk, we have to manage periodic call by our self\n        while True:\n            yield WaitCombRead()\n            if self._enabled and self.notReset():\n                d = self.get_data()\n                self.data.append(d)\n\n            yield Timer(self.delay)\n\n    def monitorWithClk(self):\n        # if clock is specified this function is periodically called every\n        # clk tick, when agent is enabled\n        yield WaitCombStable()\n        if self._enabled and self.notReset():\n            d = self.get_data()\n            self.data.append(d)\n"
  },
  {
    "path": "hwt/hwIOs/agents/struct.py",
    "content": "from typing import Union\n\nfrom hwt.hdl.types.structValBase import HStructConstBase\nfrom hwtSimApi.agents.base import AgentBase\nfrom hwtSimApi.hdlSimulator import HdlSimulator\n\n\nclass HwIOStructAgent(AgentBase):\n    \"\"\"\n    Agent for HwIOStruct\n\n    :summary: only purpose is to instantiate agents for child interfaces\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIOStruct\"):\n        AgentBase.__init__(self, sim, hwIO)\n        for subHwIO in hwIO._hwIOs:\n            subHwIO._initSimAgent(sim)\n\n    def set_data(self, d: Union[HStructConstBase, list]):\n        hwIO = self.hwIO\n        if d is None:\n            for hio in hwIO._hwIOs:\n                hio._ag.set_data(None)\n        elif getattr(d, \"_dtype\", None) is hwIO._dtype:\n            for hio in hwIO._hwIOs:\n                v = getattr(d, hio._name)\n                hio._ag.set_data(v)           \n        else:\n            assert len(d) == len(hwIO._hwIOs), (d, hwIO._hwIOs)\n            for v, hio in zip(d, hwIO._hwIOs):\n                hio._ag.set_data(v)\n    \n    def get_data(self):\n        hwIO = self.hwIO\n        return tuple(hio._ag.get_data() for hio in hwIO._hwIOs)\n\n    def getMonitors(self):\n        for hio in self.hwIO._hwIOs:\n            yield from hio._ag.getMonitors()\n\n    def getDrivers(self):\n        for hio in self.hwIO._hwIOs:\n            yield from hio._ag.getDrivers()\n"
  },
  {
    "path": "hwt/hwIOs/agents/tuleWithCallback.py",
    "content": "\nclass TupleWithCallback(tuple):\n\n    def __new__(cls, *args, onDone=None):\n        t = tuple.__new__(cls, args)\n        if onDone is not None:\n            t.onDone = onDone\n        return t\n\n"
  },
  {
    "path": "hwt/hwIOs/agents/union.py",
    "content": "from hwt.hwIOs.agents.struct import HwIOStructAgent\n\n\nclass HwIOUnionSourceAgent(HwIOStructAgent):\n\n    def getMonitors(self):\n        sel = self.hwIO._select\n        for hio in self.hwIO._hwIOs:\n            if hio is sel:\n                yield from hio._ag.getDrivers()\n            else:\n                yield from hio._ag.getMonitors()\n\n    def getDrivers(self):\n        sel = self.hwIO._select\n        for hio in self.hwIO._hwIOs:\n            if hio is sel:\n                yield from hio._ag.getMonitors()\n            else:\n                yield from hio._ag.getDrivers()\n"
  },
  {
    "path": "hwt/hwIOs/agents/universalComposite.py",
    "content": "from hwt.hwIO import HwIO\nfrom hwtSimApi.agents.base import AgentBase\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.constants import INTF_DIRECTION\n\n\nclass UniversalCompositeAgent(AgentBase):\n    \"\"\"\n    Composite agent which just instantiates agents for every subinterface\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: HwIO):\n        self.__enable = True\n        super(UniversalCompositeAgent, self).__init__(sim, hwIO)\n        for hwIO in hwIO._hwIOs:\n            hwIO._initSimAgent(sim)\n\n    def getEnable(self):\n        return self.__enable\n\n    def setEnable(self, v: bool):\n        \"\"\"\n        Distribute change of enable on child agents\n        \"\"\"\n        self.__enable = v\n        for sHwIO in self.hwIO._hwIOs:\n            sHwIO._ag.setEnable(v)\n\n    def getDrivers(self):\n        for sHwIO in self.hwIO._hwIOs:\n            if sHwIO._direction == INTF_DIRECTION.MASTER:\n                yield from sHwIO._ag.getMonitors()\n            else:\n                yield from sHwIO._ag.getDrivers()\n\n    def getMonitors(self):\n        for sHwIO in self.hwIO._hwIOs:\n            if sHwIO._direction == INTF_DIRECTION.MASTER:\n                yield from sHwIO._ag.getMonitors()\n            else:\n                yield from sHwIO._ag.getDrivers()\n"
  },
  {
    "path": "hwt/hwIOs/agents/vldSync.py",
    "content": "from collections import deque\n\nfrom hwt.constants import NOP\nfrom hwt.simulator.agentBase import SyncAgentBase\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.triggers import WaitCombRead, WaitWriteOnly, WaitCombStable\nfrom pyMathBitPrecise.bit_utils import ValidityError\n\n\nclass HwIODataVldAgent(SyncAgentBase):\n\n    def __init__(self, sim: HdlSimulator, hwIO: \"HwIODataVld\", allowNoReset=False):\n        super(HwIODataVldAgent, self).__init__(\n            sim,\n            hwIO,\n            allowNoReset=allowNoReset)\n        self.data = deque()\n        self._vld = self.get_valid_signal(hwIO)\n\n    def get_data(self):\n        return self.hwIO.data.read()\n\n    def set_data(self, data):\n        self.hwIO.data.write(data)\n\n    @classmethod\n    def get_valid_signal(cls, hwIO):\n        return hwIO.vld\n\n    def get_valid(self):\n        return self._vld.read()\n\n    def set_valid(self, val):\n        self._lastVld = val\n        return self._vld.write(val)\n\n    def setEnable_asDriver(self, en):\n        super(HwIODataVldAgent, self).setEnable_asDriver(en)\n        if not en:\n            self.set_valid(0)\n\n    def monitor(self):\n        yield WaitCombStable()\n        if self.notReset():\n            hwIO = self.hwIO\n            vld = self.get_valid()\n            try:\n                vld = int(vld)\n            except ValidityError:\n                raise ValidityError(self.sim.now, hwIO._getFullName(),\n                                    \"vld signal in invalid state (would cause desynchronisation)\")\n            if vld:\n                d = self.get_data()\n                if self._debugOutput is not None:\n                    self._debugOutput.write(\"%s, read, %d: %r\\n\" % (\n                        hwIO._getFullName(),\n                        self.sim.now, d))\n                self.data.append(d)\n\n    def driver(self):\n        yield WaitCombRead()\n        if self.data and self.notReset():\n            d = self.data.popleft()\n        else:\n            d = NOP\n\n        yield WaitWriteOnly()\n        if d is NOP:\n            self.set_data(None)\n            self.set_valid(0)\n        else:\n            self.set_data(d)\n            self.set_valid(1)\n            if self._debugOutput is not None:\n                self._debugOutput.write(\"%s, wrote, %d: %r\\n\" % (\n                    self.hwIO._getFullName(),\n                    self.sim.now, self.actualData))\n"
  },
  {
    "path": "hwt/hwIOs/hwIOArray.py",
    "content": "from copy import copy\nfrom itertools import zip_longest\nfrom typing import Sequence, Optional, Union, Self\n\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.types.structValBase import HStructConstBase\nfrom hwt.hwIO import HwIO\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.synthesizer.typePath import TypePath\nfrom hwtSimApi.agents.base import AgentBase\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass HwIOArray(HObjList[Optional[HwIO]], HwIO):\n    \"\"\"\n    HwIO for array like interfaces, this object is mutable but\n    for conviniece it is better to populate this in constructor\n    or atleast before registration on parent object.\n    \"\"\"\n\n    def __init__(self, items: Sequence[HwIO]=(), masterDir=DIRECTION.OUT,\n                 hdlName:Optional[Union[str, dict[str, str]]]=None,\n                 loadConfig=True):\n        HObjList.__init__(self, items)\n        HwIO.__init__(self, masterDir=masterDir, hdlName=hdlName, loadConfig=loadConfig)\n        self._on_append = self._registerArray_append\n\n    @override\n    def hwDeclr(self):\n        for i, item in enumerate(self):\n            self._registerArray_append(self, item, i)\n        assert len(self) - sum(1 if item is None else 0 for item in self) == len(self._hwIOs), (self, len(self), len(self._hwIOs))\n\n    @override\n    def __hash__(self):\n        # :note: __hash__, __eq__ are overriden because HObjList by default is non hashable\n        return id(self)\n\n    @override\n    def __eq__(self, other:object) -> bool:\n        \"\"\"\n        HwIO is an unique object representig IO of the component that is only the same object should equal to self\n        \"\"\"\n        return other is self\n\n    @override\n    def __copy__(self):\n        c = self.__class__(copy(i) for i in self)\n        if self:\n            c._updateHwParamsFrom(self[0])\n        return c\n\n    @internal\n    def _registerSubmodule(self, mName:str, submodule:\"HwModule\", onParentPropertyPath: TypePath):\n        raise AssertionError(self, \"should not have submodules\", mName, submodule, onParentPropertyPath)\n\n    @override\n    def __call__(self, other: Self, exclude=None, fit=False):\n        \"\"\"\n        () operator behaving as assignment operator\n        \"\"\"\n        if not isinstance(other, (list, tuple)):\n            raise TypeError(other)\n        if len(self) != len(other):\n            raise ValueError(\"Different number of interfaces in list\",\n                             len(self), len(other))\n\n        statements = []\n        for a, b in zip(self, other):\n            stms = a(b, exclude=exclude, fit=fit)\n            if isinstance(stms, HdlStatement):\n                statements.append(stms)\n            else:\n                statements += stms\n\n        return statements\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        # rst = self._getAssociatedRst()\n        self._ag = HwIOArrayAgent(sim, self)  # , (rst, rst._dtype.negated)\n\n    def __repr__(self, *args, **kwargs) -> str:\n        return HwIO.__repr__(self, *args, **kwargs)\n\n\nclass HwIOArrayAgent(AgentBase):\n    \"\"\"\n    Agent for HwIOArray\n\n    :summary: only purpose is to instantiate agents for child interfaces\n    \"\"\"\n\n    def __init__(self, sim: HdlSimulator, hwIO: HwIOArray):\n        AgentBase.__init__(self, sim, hwIO)\n        for subHwIO in hwIO._hwIOs:\n            subHwIO._initSimAgent(sim)\n\n    def extendDataFromTuples(self, dataTuples: Sequence[tuple]):\n        hwIOAgData = [hwio._ag.data for hwio in self.hwIO._hwIOs]\n        hwIOsCnt = len(hwIOAgData)\n        for dTuple in dataTuples:\n            assert len(dTuple) == hwIOsCnt, (dTuple, hwIOsCnt)\n            for v, hioData in zip(dTuple, hwIOAgData):\n                hioData.append(v)\n\n    def getDataAsTuples(self):\n        yield from zip_longest(*(hio._ag.data for hio in self.hwIO._hwIOs))\n\n    def set_data(self, d: Union[HStructConstBase, list]):\n        hwIO = self.hwIO\n        if d is None:\n            for hio in hwIO._hwIOs:\n                hio._ag.set_data(None)\n        else:\n            assert len(d) == len(hwIO._hwIOs), (d, hwIO._hwIOs)\n            for v, hio in zip(d, hwIO._hwIOs):\n                hio._ag.set_data(v)\n\n    def get_data(self):\n        hwIO = self.hwIO\n        return tuple(hio._ag.get_data() for hio in hwIO._hwIOs)\n\n    def getMonitors(self):\n        for hio in self.hwIO._hwIOs:\n            yield from hio._ag.getMonitors()\n\n    def getDrivers(self):\n        for hio in self.hwIO._hwIOs:\n            yield from hio._ag.getDrivers()\n"
  },
  {
    "path": "hwt/hwIOs/hwIODifferential.py",
    "content": "from hwt.hdl.types.bits import HBits\nfrom hwt.hwIO import HwIO\nfrom hwt.hwIOs.std import HwIOSignal\nfrom hwt.pyUtils.typingFuture import override\n\n\nclass HwIODifferentialSig(HwIO):\n    \"\"\"\n    HwIO of differential pair\n    \"\"\"\n\n    @override\n    def hwDeclr(self):\n        self.n = HwIOSignal(dtype=HBits(1, negated=True))\n        self.p = HwIOSignal()\n"
  },
  {
    "path": "hwt/hwIOs/hwIOStruct.py",
    "content": "from copy import copy\nfrom typing import Optional, Union, Set\n\nfrom hwt.code import And, Or\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.hdl.types.structCast import hstruct_reinterpret\nfrom hwt.hdl.types.structValBase import HStructConstBase\nfrom hwt.hwIO import HwIO\nfrom hwt.hwIOs.agents.rdSync import HwIODataRdAgent\nfrom hwt.hwIOs.agents.rdVldSync import HwIODataRdVldAgent\nfrom hwt.hwIOs.agents.struct import HwIOStructAgent\nfrom hwt.hwIOs.agents.vldSync import HwIODataVldAgent\nfrom hwt.hwIOs.hwIOArray import HwIOArray\nfrom hwt.hwIOs.std import HwIODataVld, HwIODataRd, HwIOSignal, HwIORdVldSync\nfrom hwt.hwParam import HwParam\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwt.synthesizer.typePath import TypePath\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass BoundedMethodProxy():\n\n    def __init__(self, newInstance, method):\n        self.newInstance = newInstance\n        self.method = method\n\n    def __call__(self, *args, **kwargs):\n        return self.method(self.newInstance, *args, **kwargs)\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} {self.newInstance} {self.method}>\"\n\n\nclass HwIOStruct(HwIO):\n    \"\"\"\n    Create dynamic interface based on HStruct or HUnion description\n\n    :ivar ~._fieldsToHwIOs: dictionary {field_path: sub interface for it}\n        field path is a tuple of HStructFields which leads to this interface\n    :ivar ~._dtype: HStruct instance used as template for this interface\n    :ivar ~._instantiateFieldFn: function(FieldTemplateItem instance)\n        return HwIO instance\n    :attention: _instantiateFieldFn should also share _fieldsToHwIOs\n        with all other instances of HwIOStruct on this interface\n    \"\"\"\n\n    def __init__(self, structT: HStruct,\n                 field_path: Optional[TypePath],\n                 instantiateFieldFn,\n                 masterDir=DIRECTION.OUT,\n                 loadConfig=True):\n        HwIO.__init__(self,\n                      masterDir=masterDir,\n                      loadConfig=loadConfig)\n        if field_path:\n            assert isinstance(field_path, TypePath), field_path\n        else:\n            field_path = TypePath()\n        self._isAccessible = True\n        self._field_path = field_path\n        self._dtype = structT\n        assert self._dtype.fields, \"Needs to have at least some members (otherwise this interface is useless)\"\n        self._instantiateFieldFn = instantiateFieldFn\n        self._fieldsToHwIOs: dict[TypePath, HwIO] = {}\n\n    @override\n    def hwDeclr(self):\n        _t = self._dtype\n        assert _t is not None\n        if isinstance(_t, HStruct):\n            fields = _t.fields\n        else:\n            fields = _t.fields.values()\n\n        self._fieldsToHwIOs[self._field_path] = self\n\n        for field in fields:\n            # skip padding\n            if field.name is not None:\n                # generate interface based on struct field\n                hwIO = self._instantiateFieldFn(self, field)\n                p = self._field_path / field.name\n                assert p not in self._fieldsToHwIOs, p\n                self._fieldsToHwIOs[p] = hwIO\n\n                setattr(self, field.name, hwIO)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOStructAgent(sim, self)\n\n    def _raiseBinOperatorError(self, opStr, other):\n        raise TypeError(\"unsupported operand type(s) for \", opStr, \": \",\n                        self.__class__.__name__, self._dtype,\n                        \" and \",\n                        other.__class__.__name__, other._dtype if isinstance(other, (HwIO, RtlSignal, HConst)) else None)\n\n    @override\n    def _eq(self, other: Union[\"HwIOStruct\", HStructConstBase]):\n        if isinstance(other, self.__class__):\n            assert self._dtype == other._dtype\n            return And(*(sHwIO._eq(oi) for sHwIO, oi in zip(self._hwIOs, other._hwIOs)))\n        else:\n            return And(*(sHwIO._eq(getattr(other, sHwIO._name)) for sHwIO in self._hwIOs))\n\n    @override\n    def __add__(self, other):\n        try:\n            sigOpFn = self._dtype.getRtlSignalCls().__add__\n        except:\n            self._raiseBinOperatorError(\"+\", other)\n\n        return sigOpFn(self, other)\n\n    @override\n    def __sub__(self, other):\n        try:\n            sigOpFn = self._dtype.getRtlSignalCls().__sub__\n        except:\n            self._raiseBinOperatorError(\"-\", other)\n\n        return sigOpFn(self, other)\n\n    @override\n    def __mul__(self, other):\n        try:\n            sigOpFn = self._dtype.getRtlSignalCls().__mul__\n        except:\n            self._raiseBinOperatorError(\"*\", other)\n\n        return sigOpFn(self, other)\n\n    @override\n    def __truediv__(self, other):\n        try:\n            sigOpFn = self._dtype.getRtlSignalCls().__truediv__\n        except:\n            self._raiseBinOperatorError(\"/\", other)\n\n        return sigOpFn(self, other)\n\n    @override\n    def __floordiv__(self, other):\n        try:\n            sigOpFn = self._dtype.getRtlSignalCls().__floordiv__\n        except:\n            self._raiseBinOperatorError(\"//\", other)\n\n        return sigOpFn(self, other)\n\n    @override\n    def __ne__(self, other: Union[\"HwIOStruct\", HStructConstBase]):\n        if isinstance(other, self.__class__):\n            assert self._dtype == other._dtype\n            return Or(*(sHwIO != oi for sHwIO, oi in zip(self._hwIOs, other._hwIOs)))\n        else:\n            return Or(*(sHwIO != getattr(other, sHwIO._name) for sHwIO in self._hwIOs))\n\n    @override\n    def _reinterpret_cast(self, toT: HdlType):\n        return hstruct_reinterpret(self._dtype, self, toT)\n\n    def __iter__(self):\n        return iter(self._hwIOs)\n\n    def __len__(self):\n        return len(self._hwIOs)\n\n    def __getattr__(self, name:str):\n        if name == \"_dtype\" or name == \"_setAttrListener\" or self._setAttrListener is not None:\n            raise AttributeError(name)\n\n        try:\n            rtlSignalCls = self._dtype.getRtlSignalCls()\n        except NotImplementedError:\n            raise AttributeError(name)\n\n        sigMethod = getattr(rtlSignalCls, name)\n        return BoundedMethodProxy(self, sigMethod)  # bound method to this instance\n\n    def __copy__(self):\n        \"\"\"\n        Create new instance of interface of same type and configuration\n        \"\"\"\n        hwIO = self.__class__(self._dtype,\n                 self._field_path,\n                 self._instantiateFieldFn,\n                 masterDir=self._masterDir,\n                 loadConfig=hasattr(self, '_hwParams'))\n        hwIO._updateHwParamsFrom(self)\n        return hwIO\n\n\nclass HdlType_to_HwIO():\n    \"\"\"\n    Convert instance of HdlType to an interface which represents same data.\n\n    :note: HwIO is only instantiated, that means it does not have sub-interfaces\n        loaded yet, it can be done manually or by assigning to a property of parent HwIO/HwModule\n        instance.\n    \"\"\"\n\n    def apply(self, dtype: HdlType, field_path: Optional[TypePath]=None, masterDir=DIRECTION.OUT) -> HwIO:\n        \"\"\"\n        Run the conversion\n        \"\"\"\n        if isinstance(dtype, HStruct):\n            return HwIOStruct(dtype, field_path,\n                              instantiateFieldFn=self.instantiateFieldFn,\n                              masterDir=masterDir)\n        elif dtype.isScalar():\n            return HwIOSignal(dtype=dtype, masterDir=masterDir)\n        elif isinstance(dtype, HArray):\n            return HwIOArray(self.apply(dtype.element_t, masterDir=masterDir)\n                             for _ in range(dtype.size))\n        else:\n            raise NotImplementedError(dtype)\n\n    @internal\n    def instantiateFieldFn(self, hwIO, fieldInfo) -> HwIO:\n        if isinstance(hwIO, HwIOStruct):\n            c = self.apply(\n                fieldInfo.dtype,\n                field_path=hwIO._field_path / fieldInfo.name)\n            c._fieldsToHwIOs = hwIO._fieldsToHwIOs\n            return c\n        else:\n            raise NotImplementedError(hwIO)\n\n\nclass HwIO_to_HdlType():\n    \"\"\"\n    Convert instance of HdlType to an interface which represents same data.\n\n    :note: HwIO instance has to have definitions loaded.\n    \"\"\"\n\n    def apply(self, hwIO: Union[HwIO, RtlSignal], const=False, exclude: Optional[Set[HwIO]]=None):\n        \"\"\"\n        Run the conversion\n        \"\"\"\n        assert exclude is None or hwIO not in exclude\n        if isinstance(hwIO, HwIO) and hwIO._hwIOs:\n            if isinstance(hwIO, HwIOArray):\n                assert hwIO, \"HwIOArray must have atleast some items to resolve type\"\n                return self.apply(hwIO[0], const=const, exclude=exclude)[len(hwIO)]\n            else:\n                return HStruct(\n                    *((self.apply(sHwIO, const=const, exclude=exclude), sHwIO._name)\n                      for sHwIO in hwIO._hwIOs if exclude is None or sHwIO not in exclude)\n                )\n        else:\n            t = hwIO._dtype\n            if t.const != const:\n                t = copy(t)\n                t.const = const\n            return t\n\n\nclass HwIOStructRd(HwIODataRd):\n    \"\"\"\n    A HwIODataRd interface which has a data signal of type specified in configuration of this interface\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.T: HdlType = HwParam(None)\n\n    @override\n    def hwDeclr(self):\n        assert isinstance(self.T, HdlType), (self.T, self._name)\n        self._dtype = self.T\n        self.data = HdlType_to_HwIO().apply(self.T)\n        self.rd = HwIOSignal(masterDir=DIRECTION.IN)\n\n    @override\n    def _initSimAgent(self, sim:HdlSimulator):\n        self._ag = HwIOStructRdAgent(sim, self)\n\n\nclass HwIOStructRdAgent(HwIODataRdAgent):\n\n    def __init__(self, sim:HdlSimulator, hwIO:HwIOStructRd, allowNoReset=False):\n        HwIODataRdAgent.__init__(self, sim, hwIO, allowNoReset=allowNoReset)\n        hwIO.data._initSimAgent(sim)\n        self._data_ag = hwIO.data._ag\n\n    @override\n    def set_data(self, data):\n        return self._data_ag.set_data(data)\n\n    @override\n    def get_data(self):\n        return self._data_ag.get_data()\n\n\nclass HwIOStructVld(HwIODataVld):\n    \"\"\"\n    A handshaked interface which has a data signal of type specified in configuration of this interface\n    \"\"\"\n\n    def hwConfig(self):\n        self.T: HdlType = HwParam(None)\n\n    @override\n    def hwDeclr(self):\n        assert isinstance(self.T, HdlType), (self.T, self._name)\n        self._dtype = self.T\n        self.data = HdlType_to_HwIO().apply(self.T)\n        self.vld = HwIOSignal()\n\n    @override\n    def _initSimAgent(self, sim:HdlSimulator):\n        self._ag = HwIOStructVldAgent(sim, self)\n\n\nclass HwIOStructVldAgent(HwIODataVldAgent):\n\n    def __init__(self, sim:HdlSimulator, hwIO:HwIOStructVld, allowNoReset=False):\n        HwIODataVldAgent.__init__(self, sim, hwIO, allowNoReset=allowNoReset)\n        hwIO.data._initSimAgent(sim)\n        self._data_ag = hwIO.data._ag\n\n    @override\n    def set_data(self, data):\n        return self._data_ag.set_data(data)\n\n    @override\n    def get_data(self):\n        return self._data_ag.get_data()\n\n\nclass HwIOStructRdVld(HwIORdVldSync):\n    \"\"\"\n    A handshaked interface which has a data signal of type specified in configuration of this interface\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.T: HdlType = HwParam(None)\n\n    @override\n    def hwDeclr(self):\n        assert isinstance(self.T, HdlType), (self.__class__, self._name, \"does not have correct initialization of T\", self.T,)\n        self._dtype = self.T\n        self.data = HdlType_to_HwIO().apply(self.T)\n        HwIORdVldSync.hwDeclr(self)\n\n    @override\n    def _initSimAgent(self, sim:HdlSimulator):\n        self._ag = HwIOStructRdVldAgent(sim, self)\n\n\nclass HwIOStructRdVldAgent(HwIODataRdVldAgent):\n\n    def __init__(self, sim:HdlSimulator, hwIO:HwIOStructRdVld, allowNoReset=False):\n        HwIODataRdVldAgent.__init__(self, sim, hwIO, allowNoReset=allowNoReset)\n        hwIO.data._initSimAgent(sim)\n        self._data_ag = hwIO.data._ag\n\n    @override\n    def set_data(self, data):\n        return self._data_ag.set_data(data)\n\n    @override\n    def get_data(self):\n        return self._data_ag.get_data()\n"
  },
  {
    "path": "hwt/hwIOs/hwIOTristate.py",
    "content": "from hwt.hdl.types.bits import HBits\nfrom hwt.hwIO import HwIO\nfrom hwt.hwIOs.std import HwIOSignal, HwIOClk\nfrom hwt.hwParam import HwParam\nfrom hwt.pyUtils.typingFuture import override\nfrom hwtSimApi.agents.peripheral.tristate import TristateAgent, TristateClkAgent\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.constants import DIRECTION\nfrom ipCorePackager.intfIpMeta import IntfIpMetaNotSpecifiedError\n\n\nclass HwIOTristateSig(HwIO):\n    \"\"\"\n    Tristate interface\n\n    :ivar ~.force_vector: in order to make this a vector[0] instead of single bit\n        use FORCE_VECTOR=True\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(1)\n        self.FORCE_VECTOR = False\n\n    @override\n    def hwDeclr(self):\n        t = HBits(self.DATA_WIDTH, force_vector=self.FORCE_VECTOR)\n\n        # connect\n        self.t = HwIOSignal(dtype=t)\n        # input\n        self.i = HwIOSignal(dtype=t, masterDir=DIRECTION.IN)\n        # output\n        self.o = HwIOSignal(dtype=t)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        rst = self._getAssociatedRst()\n        self._ag = TristateAgent(sim, self, (rst, rst._dtype.negated))\n\n\nclass HwIOTristateClk(HwIOClk, HwIOTristateSig):\n\n    @override\n    def hwConfig(self):\n        HwIOClk.hwConfig(self)\n        HwIOTristateSig.hwConfig(self)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        raise IntfIpMetaNotSpecifiedError()\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = TristateClkAgent(sim, self)\n"
  },
  {
    "path": "hwt/hwIOs/hwIOUnion.py",
    "content": "from hwt.hwIOs.agents.union import HwIOUnionSourceAgent\nfrom hwt.hwIOs.hwIOStruct import HwIOStruct\nfrom hwt.hwIOs.std import HwIODataRdVld\nfrom hwt.math import log2ceil\nfrom hwt.pyUtils.typingFuture import override\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass HwIOUnionSink(HwIOStruct):\n    \"\"\"\n    Hardware IO generated from HUnion HDL type\n\n    Used when consumer chooses which member of union should be used.\n    \"\"\"\n\n    @override\n    def hwDeclr(self):\n        HwIOStruct.hwDeclr(self)\n        self._select = HwIODataRdVld()\n        self._select.DATA_WIDTH = log2ceil(len(self._dtype.fields))\n\n\nclass HwIOUnionSource(HwIOUnionSink):\n    \"\"\"\n    Same like `HwIOUnionSink` but producer is selecting member of union\n    which should be used.\n    \"\"\"\n\n    @override\n    def hwDeclr(self):\n        HwIOStruct.hwDeclr(self)\n        self._select = HwIODataRdVld(masterDir=DIRECTION.IN)\n        self._select.DATA_WIDTH = log2ceil(len(self._dtype.fields))\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOUnionSourceAgent(sim, self)\n"
  },
  {
    "path": "hwt/hwIOs/hwIO_map.py",
    "content": "from typing import Union, Tuple, Optional, List\n\nfrom hwt.doc_markers import internal\nfrom hwt.hwIO import HwIO\nfrom hwt.hwIOs.std import HwIOBramPort_noClk, HwIORegCntrl, HwIODataVld, HwIOSignal\nfrom hwt.hwIOs.hwIOStruct import HwIOStruct\nfrom hwt.hwIOs.hwIOUnion import HwIOUnionSink, HwIOUnionSource\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.struct import HStruct, HStructFieldMeta, HStructField\nfrom hwt.mainBases import HwIOBase\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.interfaceLevel.hwModuleImplHelpers import getSignalName\nfrom hwt.synthesizer.typePath import TypePath\n\n\nclass HwIOObjMap(List[\"HwIoMapItem\"]):\n    \"\"\"\n    Container of interface map. The interface map object describes\n    the data type using existing HwIO instances.\n\n    Items can be HwIO/RtlSignal or (type/interface/None/HwIOObjMap, name).\n    None is used for padding.\n    \"\"\"\n    pass\n\n\nHwIoMapCompatibleHwIO = Union[\n    RtlSignalBase,\n    HwIODataVld,\n    HwIORegCntrl,\n    HwIOBramPort_noClk,\n    HwIOStruct,\n    HwIOUnionSink,\n    HwIOUnionSource,\n]\nHwIOMapItem =  Union[\n    Tuple[HdlType, Optional[str]],\n    Tuple[Union[HwIoMapCompatibleHwIO, RtlSignalBase], str],\n    Tuple[List[Union[HwIoMapCompatibleHwIO, RtlSignalBase]], str],\n    HwIoMapCompatibleHwIO\n]\n\n\n@internal\ndef _HTypeFromHwIOObjMap(hwIO: HwIoMapCompatibleHwIO):\n    name = getSignalName(hwIO)\n    if isinstance(hwIO, (RtlSignalBase, HwIOSignal)):\n        dtype = hwIO._dtype\n    elif isinstance(hwIO, HwIODataVld):\n        dtype = hwIO.data._dtype\n    elif isinstance(hwIO, HwIORegCntrl):\n        dtype = hwIO.din._dtype\n    elif isinstance(hwIO, HwIOBramPort_noClk):\n        dtype = HBits(int(hwIO.DATA_WIDTH))[2 ** int(hwIO.ADDR_WIDTH)]\n    else:\n        raise ValueError(hwIO)\n\n    return (dtype, name)\n\n\n@internal\ndef HTypeFromHwIOObjMapItem(hwIOMapItem: HwIOMapItem):\n    isTerminal = False\n    if isinstance(hwIOMapItem, (HwIOBase, RtlSignalBase)):\n        dtype, nameOrPrefix = _HTypeFromHwIOObjMap(hwIOMapItem)\n        isTerminal = True\n    else:\n        typeOrListOfHwIOs, nameOrPrefix = hwIOMapItem\n\n        if isinstance(typeOrListOfHwIOs, list) and \\\n                not isinstance(typeOrListOfHwIOs, HwIOObjMap):\n            # list of HType instances for array\n            parts = []\n            arrayItem_t = None\n\n            for item in typeOrListOfHwIOs:\n                if isinstance(item, HwIOObjMap):\n                    t = HTypeFromHwIOObjMap(item)\n                else:\n                    t = HTypeFromHwIOObjMapItem(item).dtype\n                if arrayItem_t is None:\n                    arrayItem_t = t\n                else:\n                    assert arrayItem_t == t, (\n                        \"all items in array has to have same type\", arrayItem_t, t)\n                parts.append(t)\n\n            dtype = arrayItem_t[len(parts)]\n\n        elif isinstance(typeOrListOfHwIOs, HdlType):\n            dtype = typeOrListOfHwIOs\n            isTerminal = True\n        elif isinstance(typeOrListOfHwIOs,\n                        (HwIOBase, RtlSignalBase)):\n            # renamed interface, ignore original name\n            dtype = _HTypeFromHwIOObjMap(typeOrListOfHwIOs)[0]\n            isTerminal = True\n        elif isinstance(typeOrListOfHwIOs, HwIOObjMap):\n            dtype = HTypeFromHwIOObjMap(typeOrListOfHwIOs)\n        else:\n            # tuple (tuple of interfaces, prefix)\n            assert isinstance(typeOrListOfHwIOs,\n                              tuple), typeOrListOfHwIOs\n            dtype = HTypeFromHwIOObjMap(typeOrListOfHwIOs)\n\n    assert isinstance(nameOrPrefix, str) or nameOrPrefix is None, nameOrPrefix\n    assert isinstance(dtype, HdlType)\n\n    f = HStructField(dtype, nameOrPrefix)\n\n    if not isTerminal:\n        f.meta = HStructFieldMeta(split=True)\n\n    return f\n\n\ndef HTypeFromHwIOObjMap(hwIOMap: HwIOObjMap) -> HStruct:\n    \"\"\"\n    Generate flattened register map for HStruct\n\n    :param hwIOMap: sequence of\n        a tuple (HdlType, name) (will create HStructField) or\n        a tuple (HdlType, None) (will create HStructField as padding) or\n        a tuple (list of HwIO instances, name) (will create HStructField of HStruct type) or\n        an HwIO instance (will create a HStructField for an interface, with a name of interface)\n    :param DATA_WIDTH: width of word\n    :param terminalNodes: None or set where are placed StructField instances\n        which are derived directly from interface\n    :return: generator of tuple (type, name, BusFieldInfo)\n    \"\"\"\n    structFields = []\n\n    for m in hwIOMap:\n        f = HTypeFromHwIOObjMapItem(m)\n        structFields.append(f)\n\n    return HStruct(*structFields)\n\n\ndef isPaddingInHwIOObjMap(item: Union[HdlType, Tuple[object, Optional[str]]]):\n    if isinstance(item, HdlType):\n        return True\n    else:\n        try:\n            if isinstance(item, tuple):\n                _item, name = item\n                if name is None:\n                    return True\n        except ValueError:\n            pass\n\n    return False\n\n\ndef _walkHwIOStructAndHwIOObjMap_unpack(io: Union[HObjList, HwIOStruct, HwIOUnionSink, HwIOUnionSource], hwIOMap):\n    \"\"\"\n    Try to unpack hwIOMap and apply the selection on io\n\n    :return: Optional tuple HwIO, hwIOMap\n    \"\"\"\n    # items are HwIO/RtlSignal or (type/interface/None or list of items, name)\n    if isPaddingInHwIOObjMap(hwIOMap):\n        return\n    elif isinstance(hwIOMap, tuple):\n        item, name = hwIOMap\n    else:\n        item = hwIOMap\n        assert isinstance(item, (HwIOBase, RtlSignalBase)), item\n        name = getSignalName(item)\n\n    if isinstance(item, HdlType):\n        # this part of io was generated from type descriptin\n        # and we are re searching only for those parts which were generated\n        # from HwIO/RtlSignal\n        return\n\n    return getattr(io, name), item\n\n\ndef walkHwIOStructAndHwIOObjMap(io: Union[HObjList, HwIOStruct, HwIOUnionSink, HwIOUnionSource], hwIOMap):\n    \"\"\"\n    Walk HwIOStruct and interface map\n    and yield tuples (HwIO in HwIOStruct, interface in hwIOMap)\n    which are on same place\n\n    :param io: an interface to walk\n    :param hwIOMap: interface map\n\n    :note: typical usecase is when there is HwIOStruct generated from description in hwIOMap\n        and then you need to connect interface from hwIOMap to io\n        and there you can use this function to iterate over interfaces which belongs together\n    \"\"\"\n\n    if isinstance(hwIOMap, (HwIOBase, RtlSignalBase)):\n        yield io, hwIOMap\n        return\n    elif isinstance(hwIOMap, tuple):\n        item = _walkHwIOStructAndHwIOObjMap_unpack(io, hwIOMap)\n        if item is None:\n            # is padding or there is no interface specified for it in hwIOMap\n            return\n        else:\n            io, item = item\n            yield from walkHwIOStructAndHwIOObjMap(io, item)\n    elif isinstance(io, list):\n        io\n        assert len(io) == len(hwIOMap)\n        for sItem, item in zip(io, hwIOMap):\n            yield from walkHwIOStructAndHwIOObjMap(sItem, item)\n    else:\n        assert isinstance(hwIOMap, HwIOObjMap), hwIOMap\n        for item in hwIOMap:\n            _item = _walkHwIOStructAndHwIOObjMap_unpack(io, item)\n            if _item is not None:\n                sItem, _item = _item\n                yield from walkHwIOStructAndHwIOObjMap(sItem, _item)\n\n\ndef HwIOObjMapItem_find_by_name(hwIOMapItem, name: str):\n    if isinstance(hwIOMapItem, HStructField):\n        hwIOMapItem = hwIOMapItem.dtype\n    if isinstance(hwIOMapItem, HwIOObjMap):\n        for x in hwIOMapItem:\n            if isinstance(x, HwIOBase):\n                if x._name == name:\n                    return x\n            elif isinstance(x, RtlSignalBase):\n                if x._hdlName == name:\n                    return x\n            else:\n                v, n = x\n                if n == name:\n                    return v\n        raise KeyError(name)\n    elif isinstance(hwIOMapItem, HStruct):\n        for f in hwIOMapItem.fields:\n            if f.name == name:\n                return f\n        raise KeyError(name)\n    else:\n        raise NotImplementedError(hwIOMapItem)\n\n\ndef HwIOObjMap_get_by_field_path(root: HwIOObjMap, field_path: TypePath):\n    actual = root\n    # find in interfaceMap, skip first because it is the type itself\n    for rec in field_path:\n        # if isinstance(rec, (HwIOBase, RtlSignalBase)):\n        #    shouldEnter, shouldUse = False, True\n        #    return shouldEnter, shouldUse\n        if isinstance(rec, int):\n            actual = actual[rec]\n        elif isinstance(rec, str):\n            actual = HwIOObjMapItem_find_by_name(actual, rec)\n        else:\n            raise NotImplementedError(rec)\n    return  actual\n\n"
  },
  {
    "path": "hwt/hwIOs/signalOps.py",
    "content": "from hwt.doc_markers import internal\n\n\nclass SignalOps(object):\n    \"\"\"\n    Operands for Signal interface,\n    These operands are delegated on RtlSignal object for this interface\n    \"\"\"\n\n    def _auto_cast(self, toT):\n        return self._sig._auto_cast(toT)\n\n    @internal\n    def _cast_sign(self, signed):\n        return self._sig._cast_sign(signed)\n\n    def _signed(self):\n        return self._cast_sign(True)\n\n    def _unsigned(self):\n        return self._cast_sign(False)\n\n    def _vec(self):\n        return self._cast_sign(None)\n\n    def _reinterpret_cast(self, toT):\n        return self._sig._reinterpret_cast(toT)\n\n    # events\n    def _onRisingEdge(self):\n        return self._sig._onRisingEdge()\n\n    def _onFallingEdge(self):\n        return self._sig._onFallingEdge()\n\n    # comparison\n    def _isOn(self):\n        \"\"\"\n        convert this signal to hBool\n        \"\"\"\n        return self._sig._isOn()\n\n    def getMsb(self):\n        return self._sig.getMsb()\n\n    def _eq(self, other):\n        \"\"\"\n        Equality operator \"==\" is not used because it would damage python\n        ecosystem\n        \"\"\"\n        return self._sig._eq(other)\n\n    def __ne__(self, other):\n        \"\"\"!=\"\"\"\n        return self._sig.__ne__(other)\n\n    def __gt__(self, other):\n        \"\"\">\"\"\"\n        return self._sig.__gt__(other)\n\n    def __lt__(self, other):\n        \"\"\"<\"\"\"\n        return self._sig.__lt__(other)\n\n    def __ge__(self, other):\n        \"\"\">=\"\"\"\n        return self._sig.__ge__(other)\n\n    def __le__(self, other):\n        \"\"\"<=\"\"\"\n        return self._sig.__le__(other)\n\n    # bitwise\n    def __invert__(self):\n        \"\"\"~ operator - logical negation for one bit signals and hBool\n           bitwise inversion for wider signals \"\"\"\n        return self._sig.__invert__()\n\n    def __and__(self, other):\n        \"\"\"\n        & operator - logical 'and' for one bit signals and hBool\n        bitwise and for wider signals\n        \"\"\"\n        return self._sig.__and__(other)\n\n    def __xor__(self, other):\n        \"\"\"\n        ^ operator - logical '!=' for one bit signals and hBool\n        bitwise and for wider signals\n        \"\"\"\n        return self._sig.__xor__(other)\n\n    def __or__(self, other):\n        \"\"\"\n        | operator - logical 'or' for one bit signals and hBool\n        bitwise and for wider signals\n        \"\"\"\n        return self._sig.__or__(other)\n\n    # arithmetic\n    def __neg__(self):\n        \"- operator (unary minus)\"\n        return self._sig.__neg__()\n\n    def __add__(self, other):\n        \"+ operator\"\n        return self._sig.__add__(other)\n\n    def __sub__(self, other):\n        \"- operator\"\n        return self._sig.__sub__(other)\n\n    def __mul__(self, other):\n        \"* operator\"\n        return self._sig.__mul__(other)\n\n    def __pow__(self, other):\n        \"** operator\"\n        return self._sig.__pow__(other)\n\n    def __mod__(self, other):\n        \"% operator\"\n        return self._sig.__mod__(other)\n\n    def __truediv__(self, other):\n        \"/ operator - floating point division\"\n        return self._sig.__truediv__(other)\n\n    def __floordiv__(self, other):\n        \"// operator - integer division\"\n        return self._sig.__floordiv__(other)\n\n    def __lshift__(self, other):\n        \"<< left shift (on fixed number of bits)\"\n        return self._sig.__lshift__(other)\n\n    def __rshift__(self, other):\n        \">> right shift (on fixed number of bits)\"\n        return self._sig.__rshift__(other)\n\n    # hdl centric\n    def _reversed(self):\n        \"\"\"\n        reverse bitorder\n        \"\"\"\n        # https://stackoverflow.com/questions/27638960/python-reverse-magic-method\n        return self._sig._reversed()\n\n    def _concat(self, *others):\n        \"\"\"\n        concatenate signals to one big one\n        \"\"\"\n        return self._sig._concat(*others)\n\n    def __getitem__(self, key):\n        \"\"\"\n        [] operator key can be slice or index\n        \"\"\"\n        return self._sig.__getitem__(key)\n\n    def _ternary(self, ifTrue, ifFalse):\n        return self._sig._ternary(ifTrue, ifFalse)\n\n    def __call__(self, source, exclude=None, fit=False):\n        \"\"\"\n        connect this signal to driver\n\n        :attention: it is not call of function it is operator of assignment\n        :return: list of assignments\n        \"\"\"\n        assert self._isAccessible, self\n        return self._sig(source, exclude=None, fit=fit)\n\n    def __getattr__(self, name:str):\n        if name == \"_dtype\" or name == \"_setAttrListener\" or self._setAttrListener is not None:\n            raise AttributeError(name)\n\n        try:\n            sigProp = getattr(self._sig, name)\n        except AttributeError:\n            raise AttributeError(name) from None\n        return sigProp\n\n"
  },
  {
    "path": "hwt/hwIOs/std.py",
    "content": "from typing import TypeVar, Generic, Union, Optional, Dict\n\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BIT, BIT_N\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hwIO import HwIO\nfrom hwt.hwIOs.agents.bramPort import HwIOBramPortAgent\nfrom hwt.hwIOs.agents.bramPort import HwIOBramPort_noClkAgent\nfrom hwt.hwIOs.agents.fifo import HwIOFifoReaderAgent\nfrom hwt.hwIOs.agents.fifo import HwIOFifoWriterAgent\nfrom hwt.hwIOs.agents.rdSync import HwIODataRdAgent\nfrom hwt.hwIOs.agents.rdVldSync import HwIORdVldSyncAgent, HwIODataRdVldAgent\nfrom hwt.hwIOs.agents.regCntrl import HwIORegCntrlAgent\nfrom hwt.hwIOs.agents.signal import HwIOSignalAgent\nfrom hwt.hwIOs.agents.vldSync import HwIODataVldAgent\nfrom hwt.hwIOs.signalOps import SignalOps\nfrom hwt.hwParam import HwParam\nfrom hwt.pyUtils.typingFuture import override\nfrom hwtSimApi.agents.clk import ClockAgent\nfrom hwtSimApi.agents.rst import PullDownAgent\nfrom hwtSimApi.agents.rst import PullUpAgent\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.utils import freq_to_period\nfrom ipCorePackager.constants import DIRECTION\n\n\nT = TypeVar(\"T\", bound=HdlType)\n\n\nclass HwIOSignal(SignalOps, HwIO, Generic[T]):\n    \"\"\"\n    Basic wire interface\n\n    :ivar ~._dtype: type of signal\n    :ivar ~._sig: RtlSignal instance (physical representation of this logical signal)\n    :ivar ~._sigInside: _sig after to_rtl conversion is made\n        (after to_rtl conversion _sig is signal for parent module\n        and _sigInside is signal in original module, this separates process\n        of translating modules)\n    :note: _sigInside is None if the body of component was not elaborated yet\n    :ivar _isAccessible: flag which is set False if the signal is inside of some elaborated module\n    \"\"\"\n\n    def __init__(self,\n                 dtype: HdlType=BIT,\n                 masterDir: DIRECTION=DIRECTION.OUT,\n                 hdlName:Optional[Union[str, Dict[str, str]]]=None,\n                 loadConfig: bool=True):\n        self._sig: Optional[\"RtlSignal\"] = None\n        self._sigInside: Optional[\"RtlSignal\"] = None\n        self._isAccessible = True\n        super().__init__(masterDir=masterDir,\n                         hdlName=hdlName,\n                         loadConfig=loadConfig)\n        self._dtype = dtype\n\n    @override\n    def _cleanRtlSignals(self, lockNonExternal=True):\n        \"\"\"\n        :see: :func:`HwIO._clean`\n        \"\"\"\n        self._sigInside = self._sig\n        self._sig = None\n        if lockNonExternal and not self._isExtern:\n            self._isAccessible = False\n        if self._hwIOs:\n            HwIO._cleanRtlSignals(self, lockNonExternal=lockNonExternal)\n\n    @override\n    def __copy__(self):\n        \"\"\"\n        Create new instance of interface of same type and configuration\n        \"\"\"\n        hwIO = self.__class__(masterDir=self._masterDir,\n                              dtype=self._dtype)\n        hwIO._updateHwParamsFrom(self)\n        return hwIO\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOSignalAgent(sim, self)\n\n\ndef HwIOVectSignal(width: int,\n               signed: Union[bool, None]=None,\n               masterDir=DIRECTION.OUT,\n               hdlName:Optional[Union[str, Dict[str, str]]]=None,\n               loadConfig=True):\n    \"\"\"\n    Create basic :class:`.HwIOSignal` interface where type is vector\n    \"\"\"\n    return HwIOSignal(HBits(width, signed, force_vector=width==1),\n                  masterDir,\n                  hdlName,\n                  loadConfig)\n\n\nclass HwIOClk(HwIOSignal):\n    \"\"\"\n    Basic :class:`.HwIOSignal` interface which is interpreted as clock signal\n    \"\"\"\n    DEFAULT_FREQ = int(100e6)\n\n    @override\n    def hwConfig(self):\n        self.FREQ = HwParam(HwIOClk.DEFAULT_FREQ)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_Clk\n        return IP_Clk\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = ClockAgent(sim, self, period=int(freq_to_period(self.FREQ)))\n\n\nclass HwIORst(HwIOSignal[HBits]):\n    \"\"\"\n    Basic :class:`.HwIOSignal` interface which is interpreted as reset signal\n    \"\"\"\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_Rst\n        return IP_Rst\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        clk = self._getAssociatedClk()\n        self._ag = PullDownAgent(sim, self,\n                                 initDelay=int(0.6 * freq_to_period(clk.FREQ)))\n\n\nclass HwIORst_n(HwIOSignal[HBits]):\n    \"\"\"\n    Basic :class:`.HwIOSignal` interface which is interpreted as reset signal\n    with negative polarity (active in 0)\n    \"\"\"\n\n    def __init__(self,\n                 masterDir=DIRECTION.OUT,\n                 dtype=BIT_N,\n                 hdlName:Optional[Union[str, Dict[str, str]]]=None,\n                 loadConfig=True):\n        super(HwIORst_n, self).__init__(masterDir=masterDir,\n                                    dtype=dtype,\n                                    hdlName=hdlName,\n                                    loadConfig=loadConfig)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_Rst_n\n        return IP_Rst_n\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        clk = self._getAssociatedClk()\n        self._ag = PullUpAgent(sim, self,\n                               initDelay=int(0.6 * freq_to_period(clk.FREQ)))\n\n\nclass HwIOVldSync(HwIO):\n\n    @override\n    def hwDeclr(self):\n        self.vld = HwIOSignal()\n\n\nclass HwIODataVld(HwIOVldSync):\n    \"\"\"\n    HwIO data+valid signal, if vld=1 then data are valid and slave should\n    accept them\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(64)\n\n    @override\n    def hwDeclr(self):\n        self.data = HwIOVectSignal(self.DATA_WIDTH)\n        HwIOVldSync.hwDeclr(self)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIODataVldAgent(sim, self)\n\n\nclass HwIORdSync(HwIO):\n\n    @override\n    def hwDeclr(self) -> None:\n        self.rd = HwIOSignal(masterDir=DIRECTION.IN)\n\n\nclass HwIODataRd(HwIORdSync):\n    \"\"\"\n    HwIO data+ready signal, if rd=1 then slave has read data and master\n    should actualize data\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(64)\n\n    @override\n    def hwDeclr(self):\n        self.data = HwIOVectSignal(self.DATA_WIDTH)\n        HwIORdSync.hwDeclr(self)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIODataRdAgent(sim, self)\n\n\nclass HwIORdVldSync(HwIO):\n    \"\"\"\n    Only synchronization interface, like vld+rd signal with meaning\n    like in :class:`.HwIODataRdVld` interface\n\n    :ivar ~.rd: when high slave is ready to receive data\n    :ivar ~.vld: when high master is sending data to slave\n\n    transaction happens when both ready and valid are high\n    \"\"\"\n\n    @override\n    def hwDeclr(self):\n        HwIOVldSync.hwDeclr(self)\n        HwIORdSync.hwDeclr(self)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIORdVldSyncAgent(sim, self)\n\n\nclass HwIODataRdVld(HwIORdVldSync):\n    \"\"\"\n    HwIO data+ready+valid signal, if rd=1 slave is ready to accept data,\n    if vld=1 master is sending data,\n    if rd=1 and vld=1 then data is transfered otherwise master\n    and slave has to wait on each other\n\n    :attention: one rd/vld is set it must not go down until transaction is made\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(64)\n\n    @override\n    def hwDeclr(self):\n        HwIODataVld.hwDeclr(self)\n        HwIORdSync.hwDeclr(self)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIODataRdVldAgent(sim, self)\n\n\nclass HwIOReqDoneSync(HwIO):\n    \"\"\"\n    Synchronization interface, if req=1 slave begins operation and when\n    it's done it asserts done=1 for one clk tick req does not need to stay high\n\n    AMBA CXS Protocol Specification https://developer.arm.com/documentation/ihi0079/latest/  (req=CXSVALID, done=CXSCRDGNT)\n    \"\"\"\n\n    @override\n    def hwConfig(self) -> None:\n        self.CREDIT_CNT = HwParam(1)\n\n    @override\n    def hwDeclr(self):\n        self.req = HwIOSignal()\n        self.done = HwIOSignal(masterDir=DIRECTION.IN)\n\n\nclass HwIOBramPort_noClk(HwIO):\n    \"\"\"\n    Basic BRAM port\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.ADDR_WIDTH = HwParam(32)\n        self.DATA_WIDTH = HwParam(64)\n        self.HAS_R = HwParam(True)\n        self.HAS_W = HwParam(True)\n        self.HAS_BE = HwParam(False)\n\n    @override\n    def hwDeclr(self):\n        assert self.HAS_R or self.HAS_W, \"has to have at least read or write part\"\n\n        self.addr = HwIOVectSignal(self.ADDR_WIDTH)\n        DATA_WIDTH = self.DATA_WIDTH\n        if self.HAS_W:\n            self.din = HwIOVectSignal(DATA_WIDTH)\n\n        if self.HAS_R:\n            self.dout = HwIOVectSignal(DATA_WIDTH, masterDir=DIRECTION.IN)\n\n        self.en = HwIOSignal()\n        if (self.HAS_R and self.HAS_W) or (self.HAS_W and self.HAS_BE):\n            # in write only mode we do not need this as well as we can use \"en\"\n            if self.HAS_BE:\n                assert DATA_WIDTH % 8 == 0, DATA_WIDTH\n                self.we = HwIOVectSignal(DATA_WIDTH // 8)\n            else:\n                self.we = HwIOSignal()\n\n    def _getWordAddrStep(self):\n        \"\"\"\n        :return: size of one word in module of address\n        \"\"\"\n        return 1\n\n    def _getAddrStep(self):\n        \"\"\"\n        :return: how many bits is one module of address (e.g. 8 bits for\n            char * pointer, 36 for 36 bit bram)\n        \"\"\"\n        return int(self.DATA_WIDTH)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_BlockRamPort\n        return IP_BlockRamPort\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOBramPort_noClkAgent(sim, self)\n\n\nclass HwIOBramPort(HwIOBramPort_noClk):\n    \"\"\"\n    BRAM port with it's own clk\n    \"\"\"\n\n    @override\n    def hwDeclr(self):\n        self.clk = HwIOSignal(masterDir=DIRECTION.OUT)\n        with self._associated(clk=self.clk):\n            super().hwDeclr()\n\n        self._make_association(clk=self.clk)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOBramPortAgent(sim, self)\n\n\nclass HwIOFifoWriter(HwIO):\n    \"\"\"\n    FIFO write port interface\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(8)\n\n    @override\n    def hwDeclr(self):\n        self.en = HwIOSignal()\n        self.wait = HwIOSignal(masterDir=DIRECTION.IN)\n        if self.DATA_WIDTH:\n            self.data = HwIOVectSignal(self.DATA_WIDTH)\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOFifoWriterAgent(sim, self)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_FifoWriter\n        return IP_FifoWriter\n\n\nclass HwIOFifoReader(HwIO):\n    \"\"\"\n    FIFO read port interface\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        HwIOFifoWriter.hwConfig(self)\n\n    @override\n    def hwDeclr(self):\n        HwIOFifoWriter.hwDeclr(self)\n        self.en._masterDir = DIRECTION.IN\n        self.wait._masterDir = DIRECTION.OUT\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIOFifoReaderAgent(sim, self)\n\n    @override\n    def _getIpCoreIntfClass(self):\n        from hwt.hwIOs.std_ip_defs import IP_FifoReader\n        return IP_FifoReader\n\n\nclass HwIORegCntrl(HwIO):\n    \"\"\"\n    Register control interface, :class:`.HwIOSignal` for read, :class:`.HwIODataVld`\n    for write\n    \"\"\"\n\n    @override\n    def hwConfig(self):\n        self.DATA_WIDTH = HwParam(8)\n        self.USE_IN = HwParam(True)\n        self.USE_OUT = HwParam(True)\n\n    @override\n    def hwDeclr(self):\n        if self.USE_IN:\n            self.din = HwIOVectSignal(self.DATA_WIDTH, masterDir=DIRECTION.IN)\n        if self.USE_OUT:\n            with self._hwParamsShared():\n                self.dout = HwIODataVld()\n\n    @override\n    def _initSimAgent(self, sim: HdlSimulator):\n        self._ag = HwIORegCntrlAgent(sim, self)\n"
  },
  {
    "path": "hwt/hwIOs/std_ip_defs.py",
    "content": "from typing import List\n\nfrom hwt.hwIOs.std import HwIORst, HwIORst_n, HwIOClk\nfrom hwt.pyUtils.arrayQuery import where\nfrom hwt.serializer.ip_packager import IpPackager\nfrom hwt.hwIO import HwIO\n\nfrom ipCorePackager.component import Component\nfrom ipCorePackager.intfIpMeta import IntfIpMeta, VALUE_RESOLVE\n\n\nclass IP_Clk(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"clock\"\n        self.version = \"1.0\"\n        self.vendor = \"xilinx.com\"\n        self.library = \"signal\"\n        self.map = 'CLK'\n\n    def postProcess(self, component: Component,\n                    packager: IpPackager, thisIf: HwIOClk):\n        rst = where(\n            component.busInterfaces,\n            lambda intf: (isinstance(intf, (HwIORst_n, HwIORst))\n                          and intf._getAssociatedClk() is thisIf))\n        logicName = packager.getInterfaceLogicalName\n        rst = list(rst)\n        if rst:\n            if len(rst) > 1:\n                rst = [intf for intf in rst if intf._getAssociatedClk() is thisIf]\n                if len(rst) > 0:\n                    raise AssertionError(\n                        \"Multiple associated resets for this interface\",\n                        thisIf)\n                elif not rst:\n                    raise AssertionError(\"Multiple reset signals\"\n                                         \" but none of them is associated\",\n                                         thisIf)\n            rst = rst[0]\n            self.addSimpleParam(logicName(thisIf), \"ASSOCIATED_RESET\",\n                                logicName(rst), resolve=VALUE_RESOLVE.NONE)\n        else:\n            rst = None\n        associated_intfs = where(\n            component.busInterfaces,\n            lambda intf: (intf is not rst\n                          and intf is not self\n                          and not isinstance(intf, HwIOClk)\n                          and intf._getAssociatedClk() is thisIf))\n        self.addSimpleParam(logicName(thisIf), \"ASSOCIATED_BUSIF\", \":\".join(\n            map(logicName, associated_intfs)), resolve=VALUE_RESOLVE.NONE)\n        self.addSimpleParam(logicName(thisIf), \"FREQ_HZ\", str(thisIf.DEFAULT_FREQ),\n                            resolve=VALUE_RESOLVE.USER)\n\n    def asQuartusTcl(self, buff: List[str], version: str, component: Component,\n                     packager: IpPackager, thisIf: HwIO):\n        self.quartus_tcl_add_interface(buff, thisIf, packager)\n        name = packager.getInterfacePhysicalName(thisIf)\n        self.quartus_prop(buff, name, \"clockRate\", 0)\n        self.quartus_add_interface_port(buff, name, thisIf, \"clk\", packager)\n\n\nclass IP_Rst(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"reset\"\n        self.version = \"1.0\"\n        self.vendor = \"xilinx.com\"\n        self.library = \"signal\"\n        self.map = \"rst\"\n\n    def postProcess(self, component: Component, packager: IpPackager, thisIf: HwIORst):\n        self.addSimpleParam(packager.getInterfaceLogicalName(thisIf), \"POLARITY\", \"ACTIVE_HIGH\")\n\n    def asQuartusTcl(self, buff: List[str], version: str, component: Component,\n                     packager: IpPackager, thisIf: HwIO):\n        self.quartus_tcl_add_interface(buff, thisIf, packager)\n        name = packager.getInterfacePhysicalName(thisIf)\n        # self.quartus_prop(\"associatedClock\", clock)\n        self.quartus_prop(buff, name, \"synchronousEdges\", \"DEASSERT\")\n        self.quartus_add_interface_port(buff, name, thisIf, \"reset\", packager)\n        clk = thisIf._getAssociatedClk()\n        if clk is not None:\n            self.quartus_prop(buff, name, \"associatedClock\",\n                              packager.getInterfacePhysicalName(clk),\n                              escapeStr=False)\n\n\nclass IP_Rst_n(IP_Rst):\n\n    def postProcess(self, component: Component, packager: IpPackager, thisIf: HwIORst_n):\n        self.addSimpleParam(\n            packager.getInterfaceLogicalName(thisIf), \"POLARITY\", \"ACTIVE_LOW\")\n\n    def asQuartusTcl(self, buff: List[str], version: str, component: Component,\n                     packager: IpPackager, thisIf: HwIO):\n        self.quartus_tcl_add_interface(buff, thisIf, packager)\n        name = packager.getInterfacePhysicalName(thisIf)\n        # [TODO]\n        # self.quartus_prop(\"associatedClock\", clock)\n        self.quartus_prop(buff, name, \"synchronousEdges\", \"DEASSERT\")\n        self.quartus_add_interface_port(buff, name, thisIf, \"reset_n\", packager)\n        clk = thisIf._getAssociatedClk()\n        if clk is not None:\n            self.quartus_prop(buff, name, \"associatedClock\",\n                              packager.getInterfacePhysicalName(clk),\n                              escapeStr=False)\n\n\nclass IP_Handshake(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"handshake\"\n        self.version = \"1.0\"\n        self.vendor = \"hwt\"\n        self.library = \"user\"\n        self.map = {\n            \"vld\": \"valid\",\n            \"rd\": \"ready\",\n            \"data\": \"data\"\n        }\n\n\nclass IP_BlockRamPort(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"bram\"\n        self.version = \"1.0\"\n        self.vendor = \"xilinx.com\"\n        self.library = \"interface\"\n        self.map = {\n            'addr': \"ADDR\",\n            \"clk\": 'CLK',\n            'din': \"DIN\",\n            'dout': \"DOUT\",\n            'en': \"EN\",\n            'we': \"WE\",\n        }\n\n\nclass IP_FifoReader(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"fifo_read\"\n        self.version = \"1.0\"\n        self.vendor = \"xilinx.com\"\n        self.library = \"interface\"\n        self.map = {\n            'data': \"RD_DATA\",\n            \"en\": 'RD_EN',\n            'wait': \"EMPTY\",\n        }\n\n\nclass IP_FifoWriter(IntfIpMeta):\n\n    def __init__(self):\n        super().__init__()\n        self.name = \"fifo_write\"\n        self.version = \"1.0\"\n        self.vendor = \"xilinx.com\"\n        self.library = \"interface\"\n        self.map = {\n            'data': \"WR_DATA\",\n            \"en\": 'WR_EN',\n            'wait': \"FULL\",\n        }"
  },
  {
    "path": "hwt/hwIOs/utils.py",
    "content": "from hwt.constants import NOT_SPECIFIED\nfrom hwt.hwIOs.std import HwIOClk, HwIORst_n, HwIORst\nfrom hwt.mainBases import HwModuleBase, HwIOBase, HwModuleOrHwIOBase\n\n\ndef addClkRstn(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Construct clk, rst_n signal on object (usually HwModule/HwIO instance)\n    * propagate CLK_FREQ to clk.FREQ\n    \"\"\"\n    obj.clk = HwIOClk()\n    freq = getattr(obj, \"CLK_FREQ\", NOT_SPECIFIED)\n    if freq is not NOT_SPECIFIED:\n        obj.clk.FREQ = freq\n    obj.rst_n = HwIORst_n()\n\n\ndef addClkRst(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Construct clk, rst signal on object (usually HwModule/HwIO instance)\n    * propagate CLK_FREQ to clk.FREQ\n    \"\"\"\n    obj.clk = HwIOClk()\n    freq = getattr(obj, \"CLK_FREQ\", NOT_SPECIFIED)\n    if freq is not NOT_SPECIFIED:\n        obj.clk.FREQ = freq\n    obj.rst = HwIORst()\n\n\ndef _tryConnect(src: HwIOBase, module: HwModuleBase, hwIOName: str):\n    \"\"\"\n    Try connect src to interface of specified name on module.\n    Ignore if interface is not present or if it already has driver.\n    \"\"\"\n    try:\n        dst = getattr(module, hwIOName)\n    except AttributeError:\n        return\n    if not dst._sig._rtlDrivers:\n        dst(src)\n    return dst\n\n\ndef propagateClk(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Propagate \"clk\" clock signal to all subcomponents\n    \"\"\"\n    clk = obj.clk\n    for m in obj._subHwModules:\n        dstClk = _tryConnect(clk, m, 'clk')\n        if dstClk is not None:\n            assert dstClk.FREQ == clk.FREQ, (clk, \"->\", dstClk, clk.FREQ, dstClk.FREQ)\n\n\ndef propagateClkRstn(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Propagate \"clk\" clock and negative reset \"rst_n\" signal\n    to all subcomponents\n    \"\"\"\n    clk = obj.clk\n    rst_n = obj.rst_n\n\n    for m in obj._subHwModules:\n        _tryConnect(clk, m, 'clk')\n        _tryConnect(rst_n, m, 'rst_n')\n        _tryConnect(~rst_n, m, 'rst')\n\n\ndef propagateClkRst(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Propagate \"clk\" clock and reset \"rst\" signal to all subcomponents\n    \"\"\"\n    clk = obj.clk\n    rst = obj.rst\n\n    for m in obj._subHwModules:\n        dstClk = _tryConnect(clk, m, 'clk')\n        if dstClk is not None:\n            assert dstClk.FREQ == clk.FREQ, (clk, \"->\", dstClk, clk.FREQ, dstClk.FREQ)\n\n        _tryConnect(~rst, m, 'rst_n')\n        _tryConnect(rst, m, 'rst')\n\n\ndef propagateRstn(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Propagate negative reset \"rst_n\" signal\n    to all subcomponents\n    \"\"\"\n    rst_n = obj.rst_n\n\n    for m in obj._subHwModules:\n        _tryConnect(rst_n, m, 'rst_n')\n        _tryConnect(~rst_n, m, 'rst')\n\n\ndef propagateRst(obj: HwModuleOrHwIOBase):\n    \"\"\"\n    Propagate reset \"rst\" signal\n    to all subcomponents\n    \"\"\"\n    rst = obj.rst\n\n    for m in obj._subHwModules:\n        _tryConnect(~rst, m, 'rst_n')\n        _tryConnect(rst, m, 'rst')\n"
  },
  {
    "path": "hwt/hwModule.py",
    "content": "from copy import copy\nfrom natsort.natsort import natsorted\nfrom typing import Optional, Union\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._structural import HdlCompInst, HdlModuleDec\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.mainBases import HwIOBase\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\nfrom hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwt.synthesizer.interfaceLevel.hwModuleImplHelpers import HwModuleImplHelpers, \\\n    _default_param_updater\nfrom hwt.synthesizer.interfaceLevel.propDeclrCollector import PropDeclrCollector\nfrom hwt.synthesizer.rtlLevel.netlist import RtlNetlist\nfrom hwt.synthesizer.typePath import TypePath\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass HdlConstraintList(list):\n    \"\"\"\n    Containers of hw design constraints\n    \"\"\"\n    pass\n\n\nclass HwModule(PropDeclrCollector, HwModuleImplHelpers):\n    \"\"\"\n    Objects of this class are representation of design in hwt HCL.\n    This object is a container of the netlist with interfaces\n    and internal hierarchical structure.\n\n    :cvar ~._serializeDecision: function to decide if HDL object derived from\n        this unit should be serialized or not, if None all is always serialized\n    :cvar ~._PROTECTED_NAMES: set of names which can not be overridden\n    :ivar ~._hwIOs: all public interfaces\n    :type ~._hwIOs: List[HwIO]\n    :ivar ~._private_hwIOs: all internal interfaces\n        which are not accessible from outside of unit\n    :type _private_hwIOs: List[HwIO]\n    :ivar ~._subHwModules: all units defined on this object\n    :type ~._subHwModules: List[HwModule]\n    :ivar ~._hwParams: all params defined on this object\n    :type ~._hwParams: List[HwParam]\n    :ivar ~._constraints: additional HW specifications\n    :ivar ~._parent: parent object\n    :type ~._parent: Optional[HwModule]\n    :ivar ~._lazy_loaded: container of RTL object which were lazy loaded\n        in implementation phase (this object has to be returned\n        from :func:`~._to_rtl` of parent before it it's own objects)\n    :ivar ~._shared_component_with: Optional tuple of the other :class:`hwt.hwModule.HwModule` instance\n        which produces an exactly same component in HDL and interface\n        signal map current to shared and shared to current\n    :type ~._shared_component_with: Optional[Tuple[HwModule,\n        Dict[Interface, Interface],\n        Dict[Interface, Interface]]]\n    :attention: if :func:`~._shared_component_with` is not None the body\n        of this instance is not generated at all\n        and the component from :func:`~._shared_component_with` is used instead\n    :ivar ~._target_platform: meta-informations about target platform\n    :ivar ~._name: a name of this component\n    :ivar ~._onParentPropertyPath: :see: :class:`HwIO`\n    :ivar ~._hdl_module_name: a name of HDL module for this component\n        (vhdl entity name, Verilog module name)\n    \"\"\"\n\n    _serializeDecision = None\n    # properties which are used internally by this library\n    _PROTECTED_NAMES = {\n        \"_PROTECTED_NAMES\",\n        \"_name\", \"_hdl_module_name\",\n        \"_hwIOs\", \"_private_hwIOs\",\n        \"_units\", \"_hwParams\", \"_parent\", \"_constraints\",\n        \"_lazy_loaded\", \"_rtlCtx\", \"_shared_component_with\",\n        \"_target_platform\", \"_store_manager\",\n    }\n\n    def __init__(self, hdlName:Optional[str]=None):\n        self._parent: Optional[HwModule] = None\n        self._name: Optional[str] = None\n        self._onParentPropertyPath: Optional[TypePath] = None\n        self._shared_component_with = None\n        self._hdl_module_name: Optional[str] = None\n        assert hdlName is None or isinstance(hdlName, str), hdlName\n        self._hdlNameOverride = hdlName\n        self._lazy_loaded: list[Union[HwModule, HwIOBase]] = []\n        self._rtlCtx = RtlNetlist(self)\n        self._constraints = HdlConstraintList()\n        self._loadConfig()\n\n    @internal\n    def _loadHwIODeclarations(self, hwIO: HwIOBase, isExtern: bool):\n        hwIO._loadHwDeclarations()\n        hwIO._setAsExtern(isExtern)\n\n    @internal\n    def _loadHwDeclarations(self):\n        \"\"\"\n        Load all declarations from _decl() method, recursively\n        for all interfaces/units.\n        \"\"\"\n        if not hasattr(self, \"_hwIOs\"):\n            self._hwIOs = []\n        if not hasattr(self, \"_private_hwIOs\"):\n            self._private_hwIOs = []\n        if not hasattr(self, \"_subHwModules\"):\n            self._subHwModules = []\n        self._setAttrListener = self._declrCollector\n        self.hwDeclr()\n        self._setAttrListener = None\n        for hio in self._hwIOs:\n            self._loadHwIODeclarations(hio, True)\n\n        # if I am a unit load subunits\n        for u in self._subHwModules:\n            u._loadHwDeclarations()\n\n    @internal\n    def _registerHwIOInHwImpl(self, hwIOName: str, hwIO: HwIOBase, onParentPath: TypePath):\n        \"\"\"\n        Register interface in implementation phase\n        \"\"\"\n        self._registerHwIO(hwIOName, hwIO, onParentPath, True)\n        self._loadHwIODeclarations(hwIO, False)\n        hwIO._signalsForHwIO(\n            self._rtlCtx, None, self._store_manager.name_scope)\n\n    def _getDefaultName(self) -> str:\n        return self.__class__.__name__\n\n    def _get_hdl_doc(self) -> Optional[str]:\n        if self.__doc__ is not HwModule.__doc__:\n            return self.__doc__\n\n    @internal\n    def _to_rtl(self, target_platform: DummyPlatform,\n                store_manager: \"StoreManager\", add_param_asserts=True):\n        \"\"\"\n        synthesize all subunits, make connections between them,\n        build verilog like module/vhdl like entity and architecture for this unit\n        \"\"\"\n        if self._hdl_module_name is None:\n            if self._hdlNameOverride:\n                self._hdl_module_name = self._hdlNameOverride\n            else:\n                self._hdl_module_name = self._getDefaultName()\n        if self._name is None:\n            self._name = self._getDefaultName()\n        self._target_platform = target_platform\n        self._store_manager = store_manager\n        do_serialize_this, replacement = store_manager.filter.do_serialize(\n            self)\n        if replacement is not None:\n            assert not do_serialize_this\n            assert len(self._hwIOs) == len(replacement._hwIOs), \\\n                \"No lazy loaded interfaces declared in hwImpl()\"\n            copy_HdlModuleDec(replacement, self)\n            yield False, self\n            self._cleanThisSubunitRtlSignals()\n            self._subHwModules = None\n            self._private_hwIOs = None\n            hwIO_map_repl_to_self = sharedCompBuildHwIOMap(\n                replacement, self)\n            hwIO_map_self_to_repl = {\n                v: k\n                for k, v in hwIO_map_repl_to_self.items()}\n            self._shared_component_with = replacement, \\\n                hwIO_map_self_to_repl, hwIO_map_repl_to_self\n            return\n\n        for proc in target_platform.beforeToRtl:\n            proc(self)\n\n        mdec = self._rtlCtx.create_HdlModuleDec(\n            self._hdl_module_name, store_manager, self._hwParams)\n        mdec.origin = self\n        mdec.doc = self._get_hdl_doc()\n\n        # prepare signals for interfaces\n        for hwIO in self._hwIOs:\n            if hwIO._isExtern:\n                ei = self._rtlCtx.hwIOs\n            else:\n                ei = None\n            # we are reversing direction because we are looking\n            # at the interface from inside of component\n            hwIO._signalsForHwIO(\n                self._rtlCtx, ei,\n                store_manager.name_scope, reverse_dir=True)\n        store_manager.hierarchy_pop(mdec)\n\n        if do_serialize_this:\n            # prepare subunits\n            for sm in self._subHwModules:\n                yield from sm._to_rtl(target_platform, store_manager)\n\n            # now every sub unit has a HdlModuleDec prepared\n            for sm in self._subHwModules:\n                subHwModuleName = sm._name\n                sm._signalsForSubHwModuleEntity(self._rtlCtx, \"sig_\" + subHwModuleName)\n\n            for proc in target_platform.beforeToRtlImpl:\n                proc(self)\n\n        try:\n            store_manager.hierarchy_push(mdec)\n            if do_serialize_this:\n                self._loadImpl()\n                yield from self._lazy_loaded\n\n                if not self._rtlCtx.hwIOs:\n                    raise IntfLvlConfErr(\n                        \"Can not find any external interface for unit %s\"\n                        \"- unit without interfaces are not synthesisable\"\n                        % self._name)\n\n            for proc in target_platform.afterToRtlImpl:\n                proc(self)\n\n            mdec.params[:] = natsorted(mdec.params, key=lambda x: x.name)\n            mdec.ports[:] = natsorted(mdec.ports, key=lambda x: x.name)\n            if do_serialize_this:\n                # synthesize signal level context\n                mdef = self._rtlCtx.create_HdlModuleDef(\n                    target_platform, store_manager)\n                mdef.origin = self\n\n            for hwIO in self._hwIOs:\n                if hwIO._isExtern:\n                    # reverse because other components\n                    # looks at this interface from the outside\n                    hwIO._reverseDirection()\n\n            if do_serialize_this:\n                if add_param_asserts and self._hwParams:\n                    mdef.objs.extend(store_manager.as_hdl_ast._as_hdl_HdlModuleDef_param_asserts(mdec))\n                store_manager.write(mdef)\n\n            yield True, self\n\n            # after synthesis clean up interface so this :class:`hwt.hwModule.HwModule` object can be\n            # used elsewhere\n            self._cleanThisSubunitRtlSignals()\n            if do_serialize_this:\n                self._checkCompInstances()\n\n            for proc in target_platform.afterToRtl:\n                proc(self)\n        finally:\n            store_manager.hierarchy_pop(mdec)\n\n    def _updateHwParamsFrom(self, otherObj: PropDeclrCollector,\n                          updater=_default_param_updater,\n                          exclude: Optional[tuple[set[str], set[str]]]=None,\n                          prefix=\"\"):\n        \"\"\"\n        :note: doc in\n            :func:`hwt.synthesizer.interfaceLevel.propDeclCollector._updateHwParamsFrom`\n        \"\"\"\n        return PropDeclrCollector._updateHwParamsFrom(self, otherObj,\n                                                    updater, exclude, prefix)\n\n    @internal\n    def _checkCompInstances(self):\n        cInstances = [o for o in self._rtlCtx.hwModDef.objs\n                      if isinstance(o, HdlCompInst)]\n        cInst_cnt = len(cInstances)\n        unit_cnt = len(self._subHwModules)\n        if cInst_cnt != unit_cnt:\n            # resolve the error message\n            inRtl = set(x.name for x in cInstances)\n            inHwIO = set(x._name for x in self._subHwModules)\n            cls_name = self.__class__.__name__\n            if cInst_cnt > unit_cnt:\n                diff = inRtl - inHwIO\n                raise IntfLvlConfErr(\n                    f\"{cls_name:s}, {self._name:s}: unit(s) were found in HDL but were\"\n                    f\" not registered {diff}\")\n            else:\n                assert cInst_cnt < unit_cnt\n                diff = inHwIO - inRtl\n                raise IntfLvlConfErr(\n                    f\"{cls_name:s}, {self._name:s}: _to_rtl: unit(s) are missing in produced HDL {diff}\")\n\n\ndef copy_HdlModuleDec_HwIO(orig_io: HwIOBase, new_io: HwIOBase,\n                           ports: list[HdlPortItem], new_m: HwModule):\n    new_io._direction = orig_io._direction\n    if orig_io._hdlPort is not None:\n        s = orig_io._sigInside\n        assert s is not None, (\n            \"the component which shares a body with this component\"\n            \" is actually some parent of this component\")\n        pi = copy(orig_io._hdlPort)\n        pi.module = new_m\n        ports.append(pi)\n        d = pi.direction\n        if d == DIRECTION.OUT:\n            pi.dst = None\n        elif d == DIRECTION.IN:\n            pi.src = None\n        else:\n            raise NotImplementedError(d)\n        new_io._hdlPort = pi\n        new_io._sigInside = s\n    elif isinstance(orig_io, HObjList):\n        for hwIO, n_i in zip(orig_io, new_io):\n            copy_HdlModuleDec_HwIO(hwIO, n_i, ports, new_m)\n    else:\n        for hwIO in orig_io._hwIOs:\n            n_i = getattr(new_io, hwIO._name)\n            copy_HdlModuleDec_HwIO(hwIO, n_i, ports, new_m)\n\n\ndef copy_HdlModuleDec(orig_m: HwModule, new_m: HwModule):\n    \"\"\"\n    Copy the HdlModuleDec for HwModule from existing HwModule.\n    This is used when the HwModule implementation was resolved as\n    shared with some other already existing HwModule.\n    (Happens when the body is the same and we want to avoid transpilling the same code again.) \n    \"\"\"\n    assert not new_m._rtlCtx.statements\n    assert not new_m._rtlCtx.hwIOs\n    assert not new_m._rtlCtx.signals\n    assert new_m._rtlCtx.hwModDec is None\n\n    new_m._hdl_module_name = orig_m._hdl_module_name\n    hwModDec = new_m._rtlCtx.hwModDec = copy(orig_m._rtlCtx.hwModDec)\n    hwModDec: HdlModuleDec\n\n    params = []\n    param_by_name = {p._name: p for p in new_m._hwParams}\n    for p in hwModDec.params:\n        p: HdlIdDef\n        new_p_def = copy(p)\n        old_p = new_p_def.origin = param_by_name[p.origin._name]\n        old_p._name = p.origin._name\n        new_p_def.value = old_p.get_hdl_value()\n        params.append(new_p_def)\n\n    hwModDec.params = params\n\n    hwModDec.ports = []\n    for hwO, hwI in zip(orig_m._hwIOs, new_m._hwIOs):\n        if hwO._isExtern:\n            copy_HdlModuleDec_HwIO(hwO, hwI, hwModDec.ports, new_m)\n\n    # params should be already sorted\n    # hwModDec.params[:] = natsorted(hwModDec.params, key=lambda x: x.name)\n    hwModDec.ports[:] = natsorted(hwModDec.ports, key=lambda x: x.name)\n\n\ndef _sharedCompBuildHwIOMapList(replacement: list[HwIOBase],\n                                          substituted: list[HwIOBase],\n                                          res: dict[HwIOBase, HwIOBase]):\n    assert len(replacement) == len(substituted)\n    for r, s in zip(replacement, substituted):\n        assert r._name == s._name, (r._name, s._name)\n        res[r] = s\n        if r._hwIOs:\n            _sharedCompBuildHwIOMapList(\n                r._hwIOs, s._hwIOs, res)\n\n\ndef sharedCompBuildHwIOMap(replacement_m: HwModule, substituted_m: HwModule):\n    \"\"\"\n    Build a dictionary which maps\n    interface of replacement_m to interface of substituted_m\n    \"\"\"\n    res = {}\n    _sharedCompBuildHwIOMapList(\n        replacement_m._hwIOs, substituted_m._hwIOs, res)\n    return res\n"
  },
  {
    "path": "hwt/hwParam.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\nfrom hwt.hdl.types.defs import INT, STR, BOOL, FLOAT64\nfrom hwt.hdl.const import HConst\n\n\nclass HwParam():\n    \"\"\"\n    Class used to mark object as a configuration of HDL module. (\n    The parameter instance will not appear on :class:`hwt.hwModule.HwModule` instance,\n    instead the value will appear.\n    The parameter instance will be stored\n    in ._hwParams property of HwModule/HwIO object)\n\n    :ivar ~._initval: value of the parameter which should be used for initialization\n    :attention: the actual value is then store on parent object instance\n    :ivar ~._name: name of parameter on parent HwModule/HwIO instance\n    :ivar ~._parent: parent object instance\n    \"\"\"\n    __slots__ = [\"_initval\", \"_name\", \"_hdlName\", \"_parent\"]\n\n    def __init__(self, initval):\n        self._initval = initval\n        self._name = None\n        self._hdlName = None\n        self._parent: \"PropDeclrCollector\" = None\n\n    def get_hdl_type(self):\n        v = self.get_value()\n        INT32_MAX = 2 ** (32 - 1) - 1\n        INT32_MIN = -2 ** (32 - 1)\n\n        if isinstance(v, HConst):\n            return v._dtype\n        elif isinstance(v, bool):\n            return BOOL\n        elif isinstance(v, str):\n            return STR\n        elif isinstance(v, int) and v >= INT32_MIN and v <= INT32_MAX:\n            return INT\n        elif isinstance(v, float):\n            return FLOAT64\n        else:\n            return None\n\n    def get_hdl_value(self):\n        t = self.get_hdl_type()\n        v = self.get_value()\n        if t is None:\n            t = STR\n            v = t.from_py(str(v))\n        else:\n            if not isinstance(v, HConst):\n                v = t.from_py(v)\n        return v\n\n    def get_value(self):\n        return getattr(self._parent, self._name)\n\n    def set_value(self, v):\n        setattr(self._parent, self._name, v)\n\n    def __repr__(self):\n        return \"<%s at 0x%x %s=%s>\" % (\n            self.__class__.__name__,\n            id(self),\n            \"<unspecified name>\" if self._name is None else self._name,\n            repr(self.get_value()))\n"
  },
  {
    "path": "hwt/mainBases.py",
    "content": "from typing import TypeVar, Generic, Union\n\nfrom hwt.hdl.types.hdlType import HdlType\n\nT = TypeVar(\"T\", bound=HdlType)\n\n\nclass RtlSignalBase(Generic[T]):\n    \"\"\"\n    Main base class for all rtl signals\n    \"\"\"\n    pass\n\n\nclass HwIOBase():\n    \"\"\"\n    Main base class for all interfaces\n    \"\"\"\n    pass\n\n\nclass HwModuleBase():\n    \"\"\"\n    Main base class for all units\n    \"\"\"\n    pass\n\n\nHwModuleOrHwIOBase = Union[HwModuleBase, HwIOBase]\n"
  },
  {
    "path": "hwt/math.py",
    "content": "from copy import copy\nimport math\nfrom typing import List, Union\n\nfrom hwt.doc_markers import hwt_expr_producer\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.mainBases import HwIOBase\nfrom hwt.mainBases import RtlSignalBase\nfrom pyMathBitPrecise.bit_utils import mask\n\nAnyHValue = Union[HConst, RtlSignalBase, HwIOBase]\n\n\ndef inRange(n: Union[int, AnyHValue], start: Union[int, AnyHValue], end: Union[int, AnyHValue]):\n    \"\"\"\n    Check if n is in range <start, end)\n    \"\"\"\n    res = (n >= start)\n    if isinstance(n, (RtlSignalBase, HwIOBase, HConst)) and\\\n            (not isinstance(end, int) or\n             end < 2 ** n._dtype.bit_length()):\n        res = res & (n < end)\n    return res\n\n\ndef toPow2Ceil(x: int):\n    \"\"\"\n    Get the smallest 2**N where 2**N >= x\n    \"\"\"\n    i = 0\n    while 2 ** i < x:\n        i += 1\n    return 2 ** i\n\n\ndef toPow2Floor(n: int):\n    \"\"\"\n    Get the largest 2**N where 2**N <= x\n    \"\"\"\n    if n < 1:\n        return 0\n    exponent = int(math.log2(n))\n    return 2 ** exponent\n\n\ndef addressAlignBestEffort(record_width: int, bus_data_width: int):\n    \"\"\"\n    Optionally extend the record width to be power of 2 and to consume\n    smallest amount of memory possible.\n    \"\"\"\n    if 2 * record_width <= bus_data_width:\n        # multiple records in bus data word\n        records_in_bus_word = math.floor(bus_data_width / record_width)\n        record_width = bus_data_width // records_in_bus_word\n        bus_words_in_record = 1\n    else:\n        # record in a 1+ bus data words\n        bus_words_in_record = math.ceil(record_width / bus_data_width)\n        # in order to make item indexable we need to have size which is 2**X\n        bus_words_in_record = toPow2Ceil(bus_words_in_record)\n\n        record_width = bus_data_width * bus_words_in_record\n        records_in_bus_word = 1\n\n    return record_width, records_in_bus_word, bus_words_in_record\n\n\ndef log2ceil(x: Union[int, float]):\n    \"\"\"\n    Returns no of bits required to store x-1\n    for example x=8 returns 3\n    \"\"\"\n\n    if not isinstance(x, (int, float)):\n        x = int(x)\n\n    if x == 0 or x == 1:\n        res = 1\n    else:\n        res = math.ceil(math.log2(x))\n\n    return res\n\n\ndef isPow2(num: Union[int, float]) -> bool:\n    \"\"\"\n    Check if number or constant is power of two\n    \"\"\"\n    if not isinstance(num, int):\n        num = int(num)\n    return num != 0 and ((num & (num - 1)) == 0)\n\n\ndef sizeof(_type: HdlType) -> int:\n    \"get size of type in bytes\"\n    s = _type.bit_length()\n    return math.ceil(s / 8)\n\n\ndef shiftIntArray(values: List[Union[int, \"HBitsConst\"]], item_width: int, shift: int):\n    \"\"\"\n    :param values: array of values which will be shifted as a whole\n    :param item_width: a bit length of a single item in array\n    :param shift: specifies how many bits the array should be shifted, << is a positive shift, >> is a negative shift\n    \"\"\"\n    if shift == 0:\n        return copy(values)\n    new_v = []\n    t = HBits(item_width)\n    if shift > 0:\n        # <<\n        for _ in range(shift // item_width):\n            new_v.append(None)\n        prev = None\n        for v in values:\n            if v is None and prev is None:\n                _v = None\n            else:\n                if prev is None:\n                    prev = t.from_py(None)\n                if v is None:\n                    v = t.from_py(None)\n                elif isinstance(prev, HConst) and not isinstance(v, HConst):\n                    v = t.from_py(v)\n                _v = (v << shift) | (prev >> (item_width - shift))\n            new_v.append(_v)\n            prev = v\n        if prev is None:\n            v = None\n        else:\n            v = prev >> (item_width - shift)\n        new_v.append(v)\n    else:\n        # shift < 0, >>\n        nextIt = iter(values)\n        for v in values:\n            try:\n                nv = next(nextIt)\n            except StopIteration:\n                nv = None\n            if nv is None and v is None:\n                _v = None\n            else:\n                if nv is None:\n                    nv = t.from_py(None)\n                if v is None:\n                    v = t.from_py(None)\n                _v = (v >> shift) | (nv & mask(shift))\n            new_v.append(_v)\n\n    return new_v\n\n\n@hwt_expr_producer\ndef hMin(a: AnyHValue, b: AnyHValue):\n    c = a < b\n    if isinstance(c, bool):\n        return a if c else b\n    else:\n        return c._ternary(a, b)\n\n\n@hwt_expr_producer\ndef hMax(a: AnyHValue, b: AnyHValue):\n    c = a > b\n    if isinstance(c, bool):\n        return a if c else b\n    else:\n        return c._ternary(a, b)\n"
  },
  {
    "path": "hwt/mathAutoExt.py",
    "content": "from operator import add, sub\nfrom typing import Callable, Optional\n\nfrom hwt.code import Concat\nfrom hwt.doc_markers import hwt_expr_producer\nfrom hwt.hdl.types.bitConstFunctions import AnyHBitsValue\n\n\n@hwt_expr_producer\ndef extendForNoOverflowAddSub(a: AnyHBitsValue, b: AnyHBitsValue):\n    \"\"\"\n    Increase bitwidth of two variables so overflow can not happen during add/sub\n    \"\"\"\n    aSigned = bool(a._dtype.signed)\n    bSigned = bool(b._dtype.signed)\n    resWidth = max(a._dtype.bit_length(),\n                   b._dtype.bit_length()) + \\\n               1 + (1 if aSigned != bSigned else 0)\n\n    a = a._ext(resWidth)\n    b = b._ext(resWidth)\n    if aSigned != bSigned:\n        if not aSigned:\n            a = a._cast_sign(True)\n        if not bSigned:\n            b = b._cast_sign(True)\n\n    return a, b\n\n\n@hwt_expr_producer\ndef addAutoExt(a: AnyHBitsValue, b: AnyHBitsValue):\n    a, b = extendForNoOverflowAddSub(a, b)\n    return a + b\n\n\n@hwt_expr_producer\ndef addAutoExtMany(*ops: tuple[AnyHBitsValue, ...]):\n    a = ops[0]\n    for b in ops[1:]:\n        a, b = extendForNoOverflowAddSub(a, b)\n        a = a + b\n    return a\n\n\n@hwt_expr_producer\ndef subAutoExt(a: AnyHBitsValue, b: AnyHBitsValue):\n    a, b = extendForNoOverflowAddSub(a, b)\n    return a - b\n\n\n@hwt_expr_producer\ndef addShifted(a: AnyHBitsValue, b: AnyHBitsValue, bShift: int, maxResultWidth:Optional[int]=None,\n               addSubFn:Callable[[AnyHBitsValue, AnyHBitsValue], AnyHBitsValue]=add) -> AnyHBitsValue:\n    \"\"\"\n    perform a + (b<<shift) with a minimal or specified bitwidth without overflow\n    \"\"\"\n    aIsSigned = bool(a._dtype.signed)\n    bIsSigned = bool(b._dtype.signed)\n    isSigned = aIsSigned or bIsSigned\n    \n    result: list[AnyHBitsValue] = []\n    if maxResultWidth is not None:\n        # assert maxResultWidth > bShift, (\"sanity check that value is not fully shifted out\", maxResultWidth, bShift)\n        if maxResultWidth <= bShift:\n            return a._extOrTrunc(maxResultWidth)._cast_sign(isSigned)\n\n    if bShift > 0:\n        widthL = a._dtype.bit_length()\n        if bShift >= widthL:\n            # b is shifted entirely before a\n            result.append(a._ext(bShift))\n            if maxResultWidth is not None:\n                b = b._extOrTrunc(maxResultWidth - bShift)\n            result.append(b)\n            return Concat(*reversed(result))._cast_sign(isSigned)\n\n        else:\n            lowBits = a[bShift:]\n            result.append(lowBits)\n            a = a[:bShift]\n    else:\n        assert bShift == 0, bShift\n\n    widthL = a._dtype.bit_length()\n    widthR = b._dtype.bit_length()\n    if maxResultWidth is not None:\n        # trim a, b if it exceeds the result width (after offset is applied)\n        w = maxResultWidth - bShift\n        if widthL > w:\n            a = a[w:]\n            widthL = w\n        if widthR > w:\n            b = b[w:]\n            widthR = w\n\n    numWidth = max(widthL, widthR) + 1 + int(aIsSigned != bIsSigned)\n    if maxResultWidth is not None:\n        numWidth = min(numWidth, maxResultWidth - bShift)\n\n    if widthL < numWidth:\n        a = a._ext(numWidth)\n\n    if widthR < numWidth:\n        b = b._ext(numWidth)\n\n    result.append(addSubFn(a._cast_sign(isSigned), b._cast_sign(isSigned)))\n\n    res = Concat(*reversed(result))\n    if maxResultWidth is not None:\n        assert res._dtype.bit_length() <= maxResultWidth\n\n    return res._cast_sign(isSigned)\n\n\n@hwt_expr_producer\ndef subShifted(a: AnyHBitsValue, b: AnyHBitsValue, bShift: int, maxResultWidth:Optional[int]=None) -> AnyHBitsValue:\n    return addShifted(a, b, bShift, maxResultWidth, sub)\n\n\n@hwt_expr_producer\ndef addShiftedMany(ops:tuple[tuple[AnyHBitsValue, int]], maxResultWidth:Optional[int]=None,\n                   addSubFn:Callable[[AnyHBitsValue, AnyHBitsValue], AnyHBitsValue]=add) -> AnyHBitsValue:\n    a, sh = ops[0]\n    assert sh == 0\n    for b, bShift in ops[1:]:\n        a = addShifted(a, b, bShift, maxResultWidth, addSubFn)\n    return a\n\n@hwt_expr_producer\ndef mulFullWidth(a: AnyHBitsValue, b: AnyHBitsValue) -> AnyHBitsValue:\n    w = a._dtype.bit_length() + b._dtype.bit_length()\n    return a._ext(w) * b._ext(w)\n"
  },
  {
    "path": "hwt/pyUtils/__init__.py",
    "content": "\"\"\"\nThis package contains python utils used in this library.\n\"\"\"\n"
  },
  {
    "path": "hwt/pyUtils/arrayQuery.py",
    "content": "# select = map, groupBy = itertools.groupby\nfrom collections import deque\nfrom itertools import zip_longest\nfrom math import inf\nfrom types import GeneratorType\n\nfrom hdlConvertorAst.to.hdlUtils import iter_with_last\nfrom hwt.constants import NOT_SPECIFIED\nfrom typing import Sequence\n\n\nclass DuplicitValueExc(Exception):\n    \"\"\"\n    Exception which means that there are multiple items which this query\n    selected but it should return only one\n    \"\"\"\n\n\nclass NoValueExc(Exception):\n    \"\"\"\n    Exception which means that query did not selected any item\n    \"\"\"\n\n\ndef single(iterable, fn):\n    \"\"\"\n    Get value from iterable where fn(item) and check\n    if there is not fn(other item)\n\n    :raise DuplicitValueExc: when there are multiple items satisfying fn()\n    :raise NoValueExc: when no value satisfying fn(item) found\n    \"\"\"\n    found = False\n    ret = None\n\n    for i in iterable:\n        if fn(i):\n            if found:\n                raise DuplicitValueExc(i)\n            found = True\n            ret = i\n\n    if not found:\n        raise NoValueExc()\n\n    return ret\n\n\ndef arr_any(iterable, fn):\n    \"\"\"\n    :return: True if fn(item) for any item else False\n    \"\"\"\n    for item in iterable:\n        if fn(item):\n            return True\n    return False\n\n\ndef arr_all(iterable, fn):\n    \"\"\"\n    :return: True if fn(item) for all items in interable or iterable\n        is empty else False\n    \"\"\"\n    for item in iterable:\n        if not fn(item):\n            return False\n    return True\n\n\ndef take(iterrable, howMay):\n    \"\"\"\n    :return: generator of first n items from iterrable\n    \"\"\"\n    assert howMay >= 0\n\n    if not howMay:\n        return\n\n    last = howMay - 1\n    for i, item in enumerate(iterrable):\n        yield item\n        if i == last:\n            return\n\n\ndef where(iterable, fn):\n    \"\"\"\n    :return: generator of items from iterable where fn(item)\n    \"\"\"\n    for i in iterable:\n        if fn(i):\n            yield i\n\n\ndef groupedby(collection, fn):\n    \"\"\"\n    same like itertools.groupby\n\n    :note: This function does not needs initial sorting like itertools.groupby\n\n    :attention: Order of pairs is not deterministic.\n    \"\"\"\n    d = {}\n    for item in collection:\n        k = fn(item)\n        try:\n            arr = d[k]\n        except KeyError:\n            arr = []\n            d[k] = arr\n        arr.append(item)\n\n    yield from d.items()\n\n\ndef flatten(iterables, level=inf):\n    \"\"\"\n    Flatten nested lists, tuples, generators and maps\n\n    :param level: maximum depth of flattening\n    \"\"\"\n    if level >= 0 and isinstance(iterables, (list, tuple, GeneratorType,\n                                             map, zip, set, deque)):\n        level -= 1\n        for i in iterables:\n            yield from flatten(i, level=level)\n    else:\n        yield iterables\n\n\ndef grouper(n: int, iterable: Sequence, padvalue=None):\n    \"\"\"grouper(3, 'abcdefg', 'x') -->\n       ('a','b','c'), ('d','e','f'), ('g','x','x')\n    \"\"\"\n    return zip_longest(*[iter(iterable)] * n, fillvalue=padvalue)\n\n\ndef areSetsIntersets(setA: set, setB: set):\n    \"\"\"\n    Check if intersection of sets is not empty\n    \"\"\"\n    return any(x in setA for x in setB)\n\n\ndef balanced_reduce(arr: Sequence, opFn):\n    while len(arr) > 1:\n        nextArr = []\n        for a, b in grouper(2, arr, NOT_SPECIFIED):\n            if b is NOT_SPECIFIED:\n                # if number of items was odd we have 1 leftover\n                nextArr.append(a)\n            else:\n                nextArr.append(opFn(a, b))\n        arr = nextArr\n\n    return arr[0]\n"
  },
  {
    "path": "hwt/pyUtils/fileHelpers.py",
    "content": "import fnmatch\nimport os\n\n\ndef find_files(directory, pattern, recursive=True):\n    \"\"\"\n    Find files by pattern in directory\n    \"\"\"\n    if not os.path.isdir(directory):\n        if os.path.exists(directory):\n            raise IOError(directory + ' is not directory')\n        else:\n            raise IOError(directory + \" does not exists\")\n    if recursive:\n        for root, _, files in os.walk(directory):\n            for basename in files:\n                if fnmatch.fnmatch(basename, pattern):\n                    filename = os.path.join(root, basename)\n                    yield filename\n    else:\n        root = directory\n        for basename in os.listdir(root):\n            if fnmatch.fnmatch(basename, pattern):\n                filename = os.path.join(root, basename)\n                if os.path.isfile(filename):\n                    yield filename\n"
  },
  {
    "path": "hwt/pyUtils/setList.py",
    "content": "from typing import Generic, TypeVar, Set, Sequence, Optional, Union\n\nT = TypeVar('T')\n\n\nclass SetList(Generic[T], list):\n    \"\"\"\n    List of unique items\n    \"\"\"\n    __slots__ = [\"__s\"]\n\n    def __init__(self, initSeq: Optional[Sequence[T]]=None):\n        super(SetList, self).__init__()\n        self.__s: Set[T] = set()\n        if initSeq is not None:\n            for item in initSeq:\n                self.append(item)\n\n    def append(self, item: T) -> bool:\n        \"\"\"\n        :return: True if the item was newly added\n        \"\"\"\n        if item in self.__s:\n            return False\n        else:\n            self.__s.add(item)\n            list.append(self, item)\n            return True\n\n    def extend(self, items: Sequence[T]):\n        if self is items:\n            return  # will not add any item because all items are already there\n        for item in items:\n            self.append(item)\n\n    def insert(self, i: int, x: T):\n        super(SetList, self).insert(i, x)\n        self.__s.add(x)\n\n    def _get_set(self) -> Set[T]:\n        return self.__s\n\n    def intersection_set(self, other: Set[T]):\n        return self.__s.intersection(other._get_set())\n\n    def discard(self, item: T) -> bool:\n        \"\"\"\n        :return: True if the item was previously in this list\n        \"\"\"\n        if item in self.__s:\n            self.remove(item)\n            return True\n        else:\n            return False\n\n    def remove(self, item: T):\n        self.__s.remove(item)\n        return list.remove(self, item)\n\n    def pop(self, *args, **kwargs) -> T:\n        item = list.pop(self, *args, **kwargs)\n        self.__s.remove(item)\n        return item\n\n    def clear(self):\n        list.clear(self)\n        self.__s.clear()\n\n    def copy(self):\n        c = SetList()\n        c.extend(self)\n        return c\n\n    def __setitem__(self, i: Union[int, slice], v: Union[T, Sequence[T]]):\n        if isinstance(i, slice):\n            if i.start is None and i.step is None and i.stop is None:\n                self.clear()\n                self.extend(v)\n            else:\n                for item in self[i]:\n                    self.__s.remove(item)\n                v = SetList(v)\n                list.__setitem__(self, i, v)\n                self.__s.update(v)\n\n        else:\n            assert isinstance(i, int)\n            cur = self[i]\n            self.__s.remove(cur)\n            list.__setitem__(self, i, v)\n            self.__s.add(v)\n\n    def __copy__(self):\n        return self.copy()\n\n    def __contains__(self, key) -> bool:\n        return key in self.__s\n"
  },
  {
    "path": "hwt/pyUtils/testUtils.py",
    "content": "from itertools import product\n\n# [todo] https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests\nclass TestMatrix():\n    \"\"\"\n    Class which instance is a decorator which executes unittest.TestCase\n    test method with every combination of argumets\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"\n        :note: args, kwargs are lists of arguments which should be passed as a test\n            arguments\n        \"\"\"\n        self.args = args\n        kwargs = sorted(kwargs.items(), key=lambda x: x[0])\n        self.kwargs_keys = [x[0] for x in kwargs]\n        self.kwargs_values = [x[1] for x in kwargs]\n        self.test_arg_values = list(product(*args, *self.kwargs_values))\n\n    def split_args_kwargs(self, args):\n        kwargs_cnt = len(self.kwargs_keys)\n        if kwargs_cnt:\n            _args = args[:kwargs_cnt]\n            kwargs = {k: v for k, v in zip(\n                self.kwargs_keys, args[:kwargs_cnt])}\n            return _args, kwargs\n        else:\n            return args, {}\n\n    def __call__(self, test_fn):\n        test_matrix = self\n\n        def test_wrap(self):\n            for args in test_matrix.test_arg_values:\n                args, kwargs = test_matrix.split_args_kwargs(args)\n                try:\n                    test_fn(self, *args, **kwargs)\n                except Exception as e:\n                    # add note to an exception about which test arguments were\n                    # used\n                    # import traceback\n                    # traceback.print_exc()\n                    msg_buff = []\n                    for a in args:\n                        msg_buff.append(repr(a))\n\n                    for k in test_matrix.kwargs_keys:\n                        msg_buff.append(\"%s=%r\" % (k, kwargs[k]))\n\n                    raise Exception(\n                        \"Test failed %s\" % (\", \".join(msg_buff)), ) from e\n\n        return test_wrap\n"
  },
  {
    "path": "hwt/pyUtils/typingFuture.py",
    "content": "import inspect\nimport re\nRE_CLASS_HEADER = re.compile(r'class.+\\(([^,]*)(?:,\\s*?(([^,]*)))*\\)\\s*\\:')  # match comma separated IDs of base classes\nENABLE_CHECKING = False\n\n\ndef override(method):\n    \"\"\"\n    Check that the method overrides the parent method. A temporal supplement for typing.override from python3.12\n\n    Inspired by https://stackoverflow.com/questions/1167617/in-python-how-do-i-indicate-im-overriding-a-method\n    \"\"\"\n    if ENABLE_CHECKING:\n        # stack()[0]=overrides, stack()[1]=inside class def'n, stack()[2]=outside class def'n\n        stack = inspect.stack()[2]\n        lineWithHeaderOfCurrentlyDefinedClass = stack[4][0]\n        base_classes = RE_CLASS_HEADER.search(lineWithHeaderOfCurrentlyDefinedClass)\n        if not base_classes:\n            raise AssertionError(\"Can not detect base classes for checking if method overrides\", lineWithHeaderOfCurrentlyDefinedClass)\n        base_classes = base_classes.group(1)\n\n        # handle multiple inheritance\n        if not base_classes:\n            raise ValueError('overrides decorator: unable to determine base class', lineWithHeaderOfCurrentlyDefinedClass)\n\n        derived_class_locals = stack[0].f_locals\n\n        for base_class in base_classes.split(','):\n            base_class = base_class.strip()\n            if '.' not in base_class:\n                base_class = derived_class_locals[base_class]\n\n            else:\n                components = base_class.split('.')\n                # obj is either a module or a class\n                obj = derived_class_locals[components[0]]\n\n                for c in components[1:]:\n                    assert(inspect.ismodule(obj) or inspect.isclass(obj))\n                    obj = getattr(obj, c)\n\n                base_class = obj\n\n            if hasattr(base_class, method.__name__):\n                return method  # successfully found the method which is being overridden\n\n        raise AssertionError(\n            f\"Does not override because any base class does not have this method ({method.__name__:s})\")\n    else:\n        return method\n"
  },
  {
    "path": "hwt/serializer/__init__.py",
    "content": "\"\"\"\nThis package contains serializers. Purpose of serializer class\nis to convert hwt representations of designed architecture\nto hdlConvertorAst to convert it to target language (VHDL/Verilog/SystemC...+xdc/ucf/...).\n\nRather than using serializer classes manually it is recommended to use :func:`hwt.synth.to_rtl`\n\nThe serialization process is usually a destructive operation as parts of AST can be rewritten\nto fit target language.\n\"\"\"\n"
  },
  {
    "path": "hwt/serializer/combLoopAnalyzer/__init__.py",
    "content": "from copy import copy\nfrom itertools import chain\nfrom typing import Tuple\n\nfrom hdlConvertorAst.hdlAst._bases import iHdlStatement\nfrom hdlConvertorAst.hdlAst._statements import HdlStmBlock\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDef, HdlCompInst\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.serializer.combLoopAnalyzer.tarjan import StronglyConnectedComponentSearchTarjan\nfrom hwt.serializer.resourceAnalyzer.analyzer import ResourceAnalyzer\nfrom hwt.synthesizer.componentPath import ComponentPath\nfrom hwt.hwModule import HwModule\nfrom ipCorePackager.constants import DIRECTION\n\n\ndef collect_comb_inputs(ctx, seen, input_signal, comb_inputs):\n    if input_signal not in seen:\n        seen.add(input_signal)\n        input_signal._walk_sensitivity(comb_inputs, seen, ctx)\n\n\ndef collect_comb_drivers(path_prefix: Tuple[HwModule, ...],\n                         stm: iHdlStatement,\n                         comb_connection_matrix: dict,\n                         comb_inputs: tuple):\n    if isinstance(stm, HdlAssignmentContainer):\n        ctx = SensitivityCtx()\n        seen = set()\n        # merge condition inputs to current_comb_inputs\n        current_comb_inputs = set(comb_inputs)\n        for inp in stm._inputs:\n            collect_comb_inputs(ctx, seen, inp, current_comb_inputs)\n\n        for o in stm._outputs:\n            o_key = path_prefix / o\n            for i in current_comb_inputs:\n                con = comb_connection_matrix.setdefault(path_prefix / i, set())\n                con.add(o_key)\n\n    elif isinstance(stm, IfContainer):\n        current_comb_inputs = set(comb_inputs)  # intended copy\n        elifs = ((stm.cond, stm.ifTrue), *stm.elIfs)\n        ev_dep_branch = stm._event_dependent_from_branch\n        ctx = SensitivityCtx()\n        seen = set()\n        found_event_dep = False\n        for branch_i, (cond, stms) in enumerate(elifs):\n            # [TODO] check if this works for clock gating\n            if ev_dep_branch is not None and ev_dep_branch == branch_i:\n                found_event_dep = True\n                break\n\n            collect_comb_inputs(ctx, seen, cond, current_comb_inputs)\n\n            for sub_stm in stms:\n                collect_comb_drivers(path_prefix, sub_stm, comb_connection_matrix, current_comb_inputs)\n\n        if not found_event_dep and stm.ifFalse is not None:\n            for sub_stm in stms:\n                collect_comb_drivers(path_prefix, sub_stm, comb_connection_matrix, current_comb_inputs)\n\n    elif isinstance(stm, HdlStmCodeBlockContainer):\n        for sub_stm in stm.statements:\n            collect_comb_drivers(path_prefix, sub_stm, comb_connection_matrix, comb_inputs)\n\n    elif isinstance(stm, SwitchContainer):\n        current_comb_inputs = set(comb_inputs)\n        ctx = SensitivityCtx()\n        seen = set()\n        collect_comb_inputs(ctx, seen, stm.switchOn, current_comb_inputs)\n        cases = stm.cases\n        if stm.default is not None:\n            cases = chain(cases, ((None, stm.default),))\n\n        for (_, case_stms) in cases:\n            for sub_stm in case_stms:\n                collect_comb_drivers(path_prefix, sub_stm, comb_connection_matrix, current_comb_inputs)\n\n    else:\n        raise NotImplementedError(stm)\n\n\nclass CombLoopAnalyzer():\n    \"\"\"\n    Visitor which can walk synthetized hwt :class:`hwt.hwModule.HwModule` instances and detect clusters connected by combinational logic\n    \"\"\"\n\n    def __init__(self):\n        # RtlSignal: Set[RtlSignal]\n        self.comb_connection_matrix = {}\n        # RtlSignal: set of signals in comb loop\n        self._report = {}\n        self.actual_path_prefix = ComponentPath()\n\n    def visit_HwModule(self, m: HwModule):\n        if m._shared_component_with is None:\n            arch = m._rtlCtx.hwModDef\n        else:\n            _m, _, _ = m._shared_component_with\n            arch = _m._rtlCtx.hwModDef\n        assert arch is not None, m\n\n        self.visit_HdlModuleDef(arch)\n\n    def visit_HdlModuleDef(self, m: HdlModuleDef) -> None:\n        ResourceAnalyzer.visit_HdlModuleDef(self, m)\n\n    def visit_HdlStmCodeBlockContainer(self, proc: HdlStmCodeBlockContainer) -> None:\n        collect_comb_drivers(self.actual_path_prefix, proc, self.comb_connection_matrix, tuple())\n\n    def visit_HdlCompInst(self, o: HdlCompInst) -> None:\n        orig_path_prefix = self.actual_path_prefix\n        in_component_path_prefix = orig_path_prefix\n        if o.origin._shared_component_with is not None:\n            in_component_path_prefix = in_component_path_prefix / o.origin\n\n        try:\n            assert o.origin, o\n            self.actual_path_prefix = in_component_path_prefix\n            self.visit_HwModule(o.origin)\n\n            for pm in o.port_map:\n                if pm.direction == DIRECTION.OUT:\n                    k = in_component_path_prefix / pm.src\n                    v = orig_path_prefix / pm.dst\n                elif pm.direction == DIRECTION.IN:\n                    k = orig_path_prefix / pm.src\n                    v = in_component_path_prefix / pm.dst\n                else:\n                    raise NotImplementedError(pm.direction)\n                self.comb_connection_matrix.setdefault(k, set()).add(v)\n\n        finally:\n            self.actual_path_prefix = orig_path_prefix\n\n    def report(self):\n        scc_search = StronglyConnectedComponentSearchTarjan(self.comb_connection_matrix)\n        for scc in scc_search.search_strongly_connected_components():\n            if len(scc) > 1:\n                yield scc\n"
  },
  {
    "path": "hwt/serializer/combLoopAnalyzer/tarjan.py",
    "content": "from typing import Generator\n\n\ndef _tarjan_head(index, lowlink, S, S_set, T, g, v):\n    lowlink[v] = index[v] = len(index)\n    S.append(v)\n    S_set.add(v)\n    it = iter(g.get(v, ()))\n    T.append((it, False, v, None))\n\n\nclass StronglyConnectedComponentSearchTarjan():\n    \"\"\"\n    Tarjan's strongly connected component search graph algorithm for DAGs\n    \n    based on https://github.com/bwesterb/py-tarjan\n    \"\"\"\n\n    def __init__(self, g: dict):\n        \"\"\"\n        :param g: graph represented as a dictionary { <vertex> : <successors of vertex> }.\n        :note: vertex type does not matter but it has to be hashable (implement __eq__ and __hash__)\n        \"\"\"\n        self.g = g\n\n    def search_strongly_connected_components(self) -> Generator:\n        \"\"\"\n        yields the strongly connected components of the graph in a topological order.\n        \"\"\"\n        g = self.g # the graph\n        S = [] # The main stack of the alg.\n        S_set = set() # == set(S) for performance\n        index = {} # { v : <index of v> }\n        lowlink = {} # { v : <lowlink of v> }\n        T = [] # stack to replace recursion\n        main_iter = iter(g)\n        for v in main_iter:\n            if v not in index:\n                _tarjan_head(index, lowlink, S, S_set, T, g, v)\n\n            while T:\n                it, inside, v, w = T.pop()\n                if inside:\n                    lowlink[v] = min(lowlink[w], lowlink[v])\n\n                body_break = False\n                for w in it:\n                    if w not in index:\n                        T.append((it, True, v, w))\n                        _tarjan_head(index, lowlink, S, S_set, T, g, w)\n                        body_break = True\n                        break\n\n                    if w in S_set:\n                        lowlink[v] = min(lowlink[v], index[w])\n\n                if body_break:\n                    continue\n\n                if lowlink[v] == index[v]:\n                    scc = []\n                    w = None\n                    while v != w:\n                        w = S.pop()\n                        scc.append(w)\n                        S_set.remove(w)\n\n                    yield scc\n"
  },
  {
    "path": "hwt/serializer/exceptions.py",
    "content": "\nclass SerializerException(Exception):\n    pass\n\n\nclass UnsupportedEventOpErr(SerializerException):\n    \"\"\"\n    Target HDL can not use event operator in this context, it usually\n    has to be replaced by correct expression of sensitivity list\n    \"\"\"\n"
  },
  {
    "path": "hwt/serializer/generic/__init__.py",
    "content": "\"\"\"\nThis package contains common parts of serializers.\n\"\"\"\n"
  },
  {
    "path": "hwt/serializer/generic/constant_cache.py",
    "content": "from hwt.hdl.const import HConst\nfrom hwt.serializer.generic.tmpVarConstructor import TmpVarConstructor\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass ConstantCache(object):\n    \"\"\"\n    Container of constants for serializer.\n    Used to extract constants as constant variables.\n    \"\"\"\n\n    def __init__(self, toHdlAst, tmpVars: TmpVarConstructor):\n        self.tmpVars = tmpVars\n        self.toHdlAst = toHdlAst\n\n        # {value:usedName}\n        self._cache = {}\n\n    def extract_const_val_as_const_var(self, val: HConst) -> RtlSignalBase:\n        \"\"\"\n        Create a constant variable with a value specified\n        or use existing variable with same value\n        \"\"\"\n        try:\n            return self._cache[val]\n        except KeyError:\n            if isinstance(val.val, int):\n                if val.val < 0:\n                    name = \"const_m%d_\" % -val.val\n                else:\n                    name = f\"const_{val.val:d}_\"\n            else:\n                name = \"const_\"\n\n            toHdlAst = self.toHdlAst\n            cc = toHdlAst.constCache\n            try:\n                # dissable const cache as the value is beeing extracted\n                # and we want to prevent recursion\n                toHdlAst.constCache = None\n                c = self.tmpVars.create_var(name, val._dtype, def_val=val, const=True)\n            finally:\n                toHdlAst.constCache = cc\n\n            self._cache[val] = c\n            return c\n"
  },
  {
    "path": "hwt/serializer/generic/indent.py",
    "content": "_indent = \"    \"\n_indentCache = {}\n\n\ndef getIndent(indentNum: int):\n    \"\"\"\n    Cached indent getter function\n    \"\"\"\n    try:\n        return _indentCache[indentNum]\n    except KeyError:\n        i = \"\".join([_indent for _ in range(indentNum)])\n        _indentCache[indentNum] = i\n        return i\n"
  },
  {
    "path": "hwt/serializer/generic/ops.py",
    "content": "from hdlConvertorAst.hdlAst._expr import HdlOpType\nfrom hwt.hdl.operatorDefs import HwtOps\n\n\nHWT_TO_HDLCONVERTOR_OPS = {\n    **{op: getattr(HdlOpType, op.id) for op in [\n        HwtOps.AND,\n        HwtOps.OR,\n        HwtOps.XOR,\n        HwtOps.CONCAT,\n        HwtOps.DIV,\n        HwtOps.DOWNTO,\n        HwtOps.TO,\n        HwtOps.EQ,\n        HwtOps.GT,\n        HwtOps.GE,\n        HwtOps.LE,\n        HwtOps.POW,\n        HwtOps.LT,\n        HwtOps.SUB,\n        HwtOps.MUL,\n        HwtOps.NE,\n        HwtOps.ADD,\n        HwtOps.TERNARY,\n    ]},\n    HwtOps.UDIV: HdlOpType.DIV,\n    HwtOps.SDIV: HdlOpType.DIV,\n\n    HwtOps.ULE: HdlOpType.LE,\n    HwtOps.ULT: HdlOpType.LT,\n    HwtOps.UGT: HdlOpType.GT,\n    HwtOps.UGE: HdlOpType.GE,\n\n    HwtOps.SLE: HdlOpType.LE,\n    HwtOps.SLT: HdlOpType.LT,\n    HwtOps.SGT: HdlOpType.GT,\n    HwtOps.SGE: HdlOpType.GE,\n\n    HwtOps.NOT: HdlOpType.NEG,\n    HwtOps.MINUS_UNARY: HdlOpType.MINUS_UNARY,\n    HwtOps.RISING_EDGE: HdlOpType.RISING,\n    HwtOps.FALLING_EDGE: HdlOpType.FALLING,\n    HwtOps.CALL: HdlOpType.CALL,\n    HwtOps.DOT: HdlOpType.DOT,\n}\n"
  },
  {
    "path": "hwt/serializer/generic/tmpVarConstructor.py",
    "content": "from typing import Optional, Union, Tuple\n\nfrom hdlConvertorAst.hdlAst import HdlIdDef\nfrom hdlConvertorAst.translate.common.name_scope import NameScope\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.const import HConst\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass TmpVarConstructor():\n\n    def __init__(self, toHdlAst, name_scope: NameScope):\n        self.toHdlAst = toHdlAst\n        self.name_scope = name_scope\n        self.extraVarsHdl = []\n        self.cache = {}\n\n    def create_var_cached(self, suggestedName: str, dtype: HdlType,\n                       const=False,\n                       def_val: Optional[Union[RtlSignalBase, HConst]]=None,\n                       postponed_init=False,\n                       extra_args=None) -> Tuple[bool, RtlSignal]:\n        cache_k = (suggestedName, dtype, const, def_val, extra_args)\n        try:\n            return False, self.cache[cache_k]\n        except KeyError:\n            pass\n        v = self.create_var(suggestedName, dtype, const=const, def_val=def_val, postponed_init=postponed_init)\n        self.cache[cache_k] = v\n        return True, v\n\n    def create_var(self,\n               suggestedName: str,\n               dtype: HdlType,\n               const=False,\n               def_val: Optional[Union[RtlSignalBase, HConst]]=None,\n               postponed_init=False) -> RtlSignal:\n        # create a new tmp variable in current process\n        s: RtlSignal = dtype.getRtlSignalCls()(None, None, dtype, virtual_only=True)\n        s._name = self.name_scope.checked_name(suggestedName, s)\n        s._isUnnamedExpr = False\n        s._const = const\n\n        if def_val is not None:\n            s.def_val = def_val\n            if not (isinstance(def_val, RtlSignalBase) and not def_val._const):\n                s._set_def_val()\n\n        if not postponed_init:\n            self.finish_var_init(s)\n\n        return s\n\n    def finish_var_init(self, var: RtlSignal):\n        hdl = self.extraVarsHdl\n\n        if isinstance(var.def_val, RtlSignalBase) or var.def_val.vld_mask:\n            a = HdlAssignmentContainer(var.def_val, var, virtual_only=True)\n            hdl.append(self.toHdlAst.as_hdl_HdlAssignmentContainer(a))\n        else:\n            assert var._const or var._rtlDrivers, (var, var.def_val)\n\n        as_hdl = self.toHdlAst.as_hdl_HdlSignalItem(var, declaration=True)\n\n        for d in var._rtlDrivers:\n            hdl.append(self.toHdlAst.as_hdl(d))\n\n        hdl.append(as_hdl)\n\n    def sort_hdl_declarations_first(self):\n        self.extraVarsHdl.sort(key=lambda x: not isinstance(x, HdlIdDef))\n\n\nclass TmpVarNotConstructableError(NotImplementedError):\n    pass\n\n\nclass NoTmpVars():\n\n    def create_var_cached(self, suggestedName, dtype, *args, **kwargs):\n        raise TmpVarNotConstructableError(\n            \"Can not create a tmp variable (%s of type %r) in this code section\" % (suggestedName, dtype))\n\n    def create_cached(self, suggestedName, dtype, *args, **kwargs):\n        raise TmpVarNotConstructableError(\n            \"Can not create a tmp variable (%s of type %r) in this code section\" % (suggestedName, dtype))\n\n"
  },
  {
    "path": "hwt/serializer/generic/to_hdl_ast.py",
    "content": "from copy import copy, deepcopy\nfrom typing import Optional, List, Union\n\nfrom hdlConvertorAst.hdlAst import iHdlStatement, iHdlObj, HdlIdDef, \\\n    HdlValueId, HdlTypeType, iHdlExpr, HdlStmBlock, HdlStmIf, HdlStmCase, \\\n    HdlStmProcess, HdlStmAssign, HdlModuleDef, HdlModuleDec, \\\n    HdlCompInst, HdlEnumDef, HdlOp\nfrom hdlConvertorAst.hdlAst._statements import ALL_STATEMENT_CLASSES\nfrom hdlConvertorAst.to.basic_hdl_sim_model._main import ToBasicHdlSimModel\nfrom hdlConvertorAst.translate.common.name_scope import NameScope, WithNameScope\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import \\\n    hdl_index, hdl_map_asoc\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import STR, BOOL\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.hdlType import HdlType, MethodNotOverloaded\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.arrayQuery import arr_any\nfrom hwt.serializer.exceptions import SerializerException\nfrom hwt.serializer.exceptions import UnsupportedEventOpErr\nfrom hwt.serializer.generic.tmpVarConstructor import TmpVarConstructor, \\\n    NoTmpVars\nfrom hwt.serializer.generic.utils import HWT_TO_HDLCONVEROTR_DIRECTION, \\\n    TmpVarsSwap\nfrom hwt.serializer.utils import HdlStatement_sort_key, _natsort_key\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass ToHdlAst():\n    \"\"\"\n    Base class for translators which translates hwt AST to a HDL ast\n\n    :ivar ~.name_scope: name scope for resolution of hdl names for objects\n        and for name colision checking for newly generated objects\n    :ivar ~.tmpVars: A object which is used to create a tmp variable in current scope.\n        It is set if it is possible to create a tmp variable.\n    :ivar ~.constCache: A ConstCache instance used o extract values as a constants.\n    :type ~.constCache: Optional[ConstantCache]\n    \"\"\"\n    # used to filter statems from other object by class without using\n    # isisnstance\n    ALL_STATEMENT_CLASSES = [*ALL_STATEMENT_CLASSES, HdlStmCodeBlockContainer]\n    TMP_VAR_CONSTRUCTOR = TmpVarConstructor\n    _keywords_dict = {}\n\n    @classmethod\n    def getBaseNameScope(cls):\n        \"\"\"\n        Get root of name space\n        \"\"\"\n        s = NameScope.make_top(False)\n        s.update(cls._keywords_dict)\n        return s\n\n    def __init__(self, name_scope: Optional[NameScope]=None):\n        if name_scope is None:\n            name_scope = self.getBaseNameScope()\n        self.name_scope = name_scope\n        self.tmpVars = NoTmpVars()\n        self.constCache = None\n\n    def as_hdl(self, obj) -> iHdlObj:\n        \"\"\"\n        Convert any object to HDL AST\n\n        :param obj: object to convert\n        \"\"\"\n        serFn = getattr(self, \"as_hdl_\" + obj.__class__.__name__, None)\n        if serFn is not None:\n            return serFn(obj)\n        elif isinstance(obj, RtlSignalBase):\n            return self.as_hdl_HdlSignalItem(obj)\n        else:\n            raise SerializerException(self,\n                                      \"Not implemented for obj of\",\n                                      obj.__class__, obj)\n\n    def as_hdl_HdlType(self, typ: HdlType, declaration=False):\n        try:\n            return typ._as_hdl(self, declaration)\n        except MethodNotOverloaded:\n            pass\n\n        if typ == STR:\n            sFn = self.as_hdl_HdlType_str\n        elif isinstance(typ, HBits):\n            sFn = self.as_hdl_HdlType_bits\n        elif isinstance(typ, HEnum):\n            sFn = self.as_hdl_HdlType_enum\n        elif isinstance(typ, HArray):\n            sFn = self.as_hdl_HdlType_array\n        elif isinstance(typ, HSlice):\n            sFn = self.as_hdl_HdlType_slice\n        elif isinstance(typ, HFloat):\n            sFn = self.as_hdl_HdlType_float\n        elif isinstance(typ, HStruct):\n            sFn = self.as_hdl_HdlType_struct\n        else:\n            # [todo] better error msg\n            raise NotImplementedError(\"type declaration is not implemented\"\n                                      \" for type %s\"\n                                      % (HdlType.__repr__(typ)))\n\n        return sFn(typ, declaration=declaration)\n\n    def as_hdl_HdlType_array(self, typ: HArray, declaration=False):\n        ns = self.name_scope\n        if declaration:\n            dec = HdlIdDef()\n            dec.type = HdlTypeType\n            if self.does_type_requires_extra_def(typ.element_t, ()):\n                # problem there is that we do not have a list of already defined types\n                # so we can not just declare an element type\n                raise NotImplementedError(typ.element_t)\n\n            dec.value = hdl_index(self.as_hdl_HdlType(typ.element_t, declaration=False),\n                                  self.as_hdl_int(int(typ.size)))\n            name = getattr(typ, \"name\", \"arr_t_\")\n            dec.name = ns.checked_name(name, typ)\n            return dec\n        else:\n            name = ns.get_object_name(typ)\n            return HdlValueId(name, obj=typ)\n\n    def as_hdl_HdlType_enum(self, typ: HEnum, declaration=False):\n        ns = self.name_scope\n        if declaration:\n            e = HdlEnumDef()\n            e.origin = typ\n            e.name = ns.checked_name(typ.name, typ)\n            e.values = [(ns.checked_name(n, getattr(typ, n)), None)\n                        for n in typ._allValues]\n            dec = HdlIdDef()\n            dec.type = HdlTypeType\n            dec.value = e\n            dec.name = e.name\n            return dec\n        else:\n            name = ns.get_object_name(typ)\n            return HdlValueId(name, obj=None)\n\n    def as_hdl_HdlType_slice(self, typ: HSlice, declaration=False):\n        raise NotImplementedError(self, typ)\n\n    def as_hdl_HdlType_float(self, typ: HFloat, declaration=False):\n        raise NotImplementedError(self, typ)\n\n    def as_hdl_HdlType_struct(self, typ: HStruct, declaration=False):\n        raise NotImplementedError(self, typ)\n\n    def as_hdl_If(self, *args, **kwargs) -> HdlStmIf:\n        return self.as_hdl_IfContainer(*args, **kwargs)\n\n    def as_hdl_cond(self, v, force_bool) -> iHdlExpr:\n        if force_bool and v._dtype != BOOL:\n            v = v._isOn()\n        return self.as_hdl(v)\n\n    def as_hdl_statements(self, stm_list) -> iHdlStatement:\n        if stm_list is None:\n            return None\n        elif len(stm_list) == 1:\n            return self.as_hdl(stm_list[0])\n        else:\n            b = HdlStmBlock()\n            b.body = [self.as_hdl(s) for s in stm_list]\n            return b\n\n    def _as_hdl_HdlAssignmentContainer_auto_conversions(self, a: HdlAssignmentContainer):\n        dst = a.dst\n        src = a.src\n        dst_indexes = a.indexes\n        if a.indexes is not None:\n            dst_indexes = [self.as_hdl(x) for x in dst_indexes]\n            correct = True\n        else:\n            if dst._dtype == a.src._dtype:\n                correct = True\n            else:\n                srcT = a.src._dtype\n                dstT = dst._dtype\n                correct = False\n                if (isinstance(srcT, HBits) and\n                        isinstance(dstT, HBits)):\n                    bl0 = srcT.bit_length()\n                    if bl0 == dstT.bit_length():\n                        if bl0 == 1 and srcT.force_vector != dstT.force_vector:\n                            if srcT.force_vector:\n                                src = src[0]\n                                correct = True\n                            elif dstT.force_vector:\n                                dst_indexes = [self.as_hdl_int(0), ]\n                                correct = True\n                        elif srcT.signed == dstT.signed:\n                            correct = True\n\n        if not correct:\n            raise SerializerException((\n                \"%s <= %s  is not valid assignment\\n\"\n                \" because types are different (%r; %r) \") %\n                (dst, src, dst._dtype, a.src._dtype))\n        return dst, dst_indexes, self.as_hdl_Value(src)\n\n    def as_hdl_HdlAssignmentContainer(self, a: HdlAssignmentContainer):\n        dst, dst_indexes, src = self._as_hdl_HdlAssignmentContainer_auto_conversions(a)\n        dst = self.as_hdl(dst)\n        if dst_indexes:\n            for i in dst_indexes:\n                dst = hdl_index(dst, i)\n        a = HdlStmAssign(src, dst)\n        return a\n\n    def as_hdl_IfContainer(self, ifc: IfContainer) -> HdlStmIf:\n        try:\n            cond = self.as_hdl_cond(ifc.cond, True)\n        except UnsupportedEventOpErr:\n            cond = None\n\n        if cond is None:\n            assert not ifc.elIfs\n            assert not ifc.ifFalse\n            return self.as_hdl_statements(ifc.ifTrue)\n\n        elIfs = []\n        ifTrue = self.as_hdl_statements(ifc.ifTrue)\n        ifFalse = self.as_hdl_statements(ifc.ifFalse)\n\n        for c, statements in ifc.elIfs:\n            try:\n                elIfs.append((self.as_hdl_cond(c, True),\n                              self.as_hdl_statements(statements)))\n            except UnsupportedEventOpErr:\n                if len(ifc.elIfs) == 1 and not ifFalse:\n                    # register expression is in valid format and this\n                    # is just register with asynchronous reset or etc...\n                    ifFalse = self.as_hdl_statements(statements)\n                else:\n                    raise\n\n        i = HdlStmIf()\n        i.cond = cond\n        i.if_true = ifTrue\n        i.elifs = elIfs\n        i.if_false = ifFalse\n        return i\n\n    def as_hdl_Switch(self, *args, **kwargs) -> HdlStmCase:\n        return self.as_hdl_SwitchContainer(*args, **kwargs)\n\n    def as_hdl_FsmBuilder(self, *args, **kwargs) -> HdlStmCase:\n        return self.as_hdl_SwitchContainer(*args, **kwargs)\n\n    def as_hdl_SwitchContainer(self, sw: SwitchContainer) -> HdlStmCase:\n        s = HdlStmCase()\n        s.switch_on = self.as_hdl_cond(sw.switchOn, False)\n        s.cases = cases = []\n        for key, statements in sw.cases:\n            key = self.as_hdl_Value(key)\n            cases.append((key, self.as_hdl_statements(statements)))\n\n        s.default = self.as_hdl_statements(sw.default)\n        return s\n\n    def as_hdl_PortConnection(self, o: HdlPortItem):\n        assert isinstance(o, HdlPortItem), o\n        if o.dst._dtype != o.src._dtype:\n            raise SerializerException(\n                f\"Port map {o._name:s} is not valid (types does not match)  ({o.src._dtype}, {o.dst._dtype}) \"\n                f\"{o.src} => {o.dst}\"\n            )\n\n        intern, outer = o.getInternSig(), o.getOuterSig()\n        intern_hdl = self.as_hdl_Value(intern)\n        intern_hdl.obj = o\n        outer_hdl = self.as_hdl_Value(outer)\n        pm = hdl_map_asoc(intern_hdl, outer_hdl)\n        return pm\n\n    def as_hdl_HdlCompInst(self, o: HdlCompInst) -> HdlCompInst:\n        new_o = copy(o)\n        param_map = []\n        for p in o.param_map:\n            p: HdlIdDef\n            assert isinstance(p, HdlIdDef), p\n            pm = hdl_map_asoc(HdlValueId(p.name, obj=p), self.as_hdl(p.value))\n            param_map.append(pm)\n        new_o.param_map = param_map\n\n        port_map = []\n        for pi in o.port_map:\n            pi: HdlPortItem\n            pm = self.as_hdl_PortConnection(pi)\n            port_map.append(pm)\n        new_o.port_map = port_map\n        return new_o\n\n    def as_hdl_GenericItem(self, o: HdlIdDef):\n        assert not self.does_type_requires_extra_def(o.type, tuple())\n        return self.as_hdl_HdlModuleDef_variable(o, None, None, None, None, None)\n\n    def as_hdl_HdlPortItem(self, o: HdlPortItem):\n        var = HdlIdDef()\n        var.direction = HWT_TO_HDLCONVEROTR_DIRECTION[o.direction]\n        s = o.getInternSig()\n        var.name = s._name\n        var.origin = o\n        var.type = o._dtype\n        return self.as_hdl_HdlModuleDef_variable(var, (), None, None, None, None)\n\n    def as_hdl_HdlModuleDec(self, o: HdlModuleDec):\n        # :attention: name_scope should be already set to body of module\n        # with WithNameScope(self, self.name_scope.get_child(o._name)):\n\n        new_o = copy(o)\n\n        # convert types, exprs\n        new_o.params = [self.as_hdl_GenericItem(p) for p in o.params]\n        new_o.ports = [self.as_hdl_HdlPortItem(p) for p in o.ports]\n\n        return new_o\n\n    def does_type_requires_extra_def(self, t: HdlType, other_types: list):\n        try:\n            return t._as_hdl_requires_def(self, other_types)\n        except MethodNotOverloaded:\n            pass\n        return isinstance(t, (HEnum, HArray)) and t not in other_types\n\n    def as_hdl_HdlModuleDef_variable(\n            self, v, types, hdl_types, hdl_variables,\n            processes, component_insts):\n        t = v.type\n        # if type requires extra definition\n        if self.does_type_requires_extra_def(t, types):\n            _t = self.as_hdl_HdlType(t, declaration=True)\n            hdl_types.append(_t)\n            types.add(t)\n\n        return self.as_hdl_HdlSignalItem(v, declaration=True)\n\n    def _as_hdl_HdlModuleDef(self, new_m: HdlModuleDef) -> HdlModuleDef:\n        # with WithNameScope(self,\n        # self.name_scope.get_child(o.module_name.val)):\n        hdl_types, hdl_variables, processes, component_insts, others = \\\n            ToBasicHdlSimModel.split_HdlModuleDefObjs(self, new_m.objs)\n        if len(hdl_variables) > 1:\n            hdl_variables.sort(key=lambda x: (_natsort_key(x.name), x.origin._instId))\n        if len(processes) > 1:\n            processes.sort(key=HdlStatement_sort_key)\n        if len(component_insts) > 1:\n            component_insts.sort(key=lambda x: _natsort_key(x.name))\n\n        types = set()\n\n        extraVars = self.TMP_VAR_CONSTRUCTOR(self, self.name_scope)\n\n        with TmpVarsSwap(self, extraVars):\n            return self._as_hdl_HdlModuleDef_body(\n                new_m, types, hdl_types, hdl_variables, extraVars,\n                processes, component_insts, others)\n\n    def _as_hdl_HdlModuleDef_body(\n            self, new_m, types, hdl_types, hdl_variables,\n            extraVars: TmpVarConstructor, processes: List[iHdlStatement],\n            component_insts: List[HdlCompInst], others: List[Union[HdlOp, iHdlStatement]]):\n\n        _hdl_variables = []\n        for v in hdl_variables:\n            new_v = self.as_hdl_HdlModuleDef_variable(\n                v, types, hdl_types, hdl_variables,\n                processes, component_insts)\n            _hdl_variables.append(new_v)\n        hdl_variables = _hdl_variables\n\n        processes = [self.as_hdl_HdlStmCodeBlockContainer(p) for p in processes]\n\n        component_insts = [self.as_hdl_HdlCompInst(c)\n                           for c in component_insts]\n        extraVars.sort_hdl_declarations_first()\n        new_m.objs = hdl_types + hdl_variables + \\\n            extraVars.extraVarsHdl + component_insts + processes + others\n        return new_m\n\n    def as_hdl_HdlModuleDef(self, o: HdlModuleDef) -> HdlModuleDef:\n        # :attention: name_scope should be already set to body of module\n        new_m = copy(o)\n        if o.dec is not None:\n            new_m.dec = self.as_hdl_HdlModuleDec(o.dec)\n        return self._as_hdl_HdlModuleDef(new_m)\n\n    def has_to_be_process(self, proc: iHdlStatement):\n        raise NotImplementedError(\n            \"This method should be overloaded in child class\")\n\n    def can_pop_process_wrap(self, statements, hasToBeVhdlProcess):\n        raise NotImplementedError(\n            \"This method should be overloaded in child class\")\n\n    def as_hdl_HdlStmCodeBlockContainer(self, proc: HdlStmCodeBlockContainer) -> iHdlStatement:\n        \"\"\"\n        Serialize HdlStmCodeBlockContainer objects as process if top statement\n        \"\"\"\n        if isinstance(proc, ALL_STATEMENT_CLASSES):\n            return proc\n        assert proc.parentStm is None, proc\n        body = proc.statements\n\n        hasToBeVhdlProcess = self.has_to_be_process(proc)\n\n        with WithNameScope(self, self.name_scope.level_push(proc.name)):\n            tmpVars = self.TMP_VAR_CONSTRUCTOR(self, self.name_scope)\n            with TmpVarsSwap(self, tmpVars):\n                statements = [self.as_hdl(s) for s in body]\n\n                hasToBeVhdlProcess |= bool(tmpVars.extraVarsHdl)\n\n                if hasToBeVhdlProcess:\n                    tmpVars.sort_hdl_declarations_first()\n                    statements = tmpVars.extraVarsHdl + statements\n\n                if self.can_pop_process_wrap(statements, hasToBeVhdlProcess):\n                    return statements[0]\n                else:\n                    p = HdlStmProcess()\n                    p.labels.append(proc.name)\n\n                    if not statements:\n                        pass  # no body\n                    elif len(statements) == 1:\n                        # body made of just a singe statement\n                        p.body = statements[0]\n                    else:\n                        p.body = HdlStmBlock()\n                        assert isinstance(statements, list)\n                        p.body.body = statements\n                    anyIsEventDependnt = arr_any(\n                        proc._sensitivity, lambda s: isinstance(s, HOperatorNode))\n                    p.sensitivity = sorted([\n                        self.sensitivityListItem(s, anyIsEventDependnt)\n                        for s in proc._sensitivity])\n                    return p\n\n    def _static_assert_false(self, msg:str):\n        raise NotImplementedError(\"Should be implemented in child class\")\n\n    def _static_assert_symbol_eq(self, symbol_name:str, v):\n        raise NotImplementedError(\"Should be implemented in child class\")\n\n    def _as_hdl_HdlModuleDef_param_asserts(self, new_m: HdlModuleDec) -> List[iHdlStatement]:\n        return []\n\n    def _as_hdl_HdlModuleDef_param_asserts_real(self, new_m: HdlModuleDec) -> List[iHdlStatement]:\n        res = []\n        for p in new_m.params:\n            p: HdlIdDef\n            if p.value is None:\n                continue\n            v = p.value\n            if isinstance(v, (HConst, RtlSignal)):\n                v = self.as_hdl(v)\n            else:\n                v = deepcopy(v)\n            res.append(self._static_assert_symbol_eq(p.name, v))\n\n        return res\n"
  },
  {
    "path": "hwt/serializer/generic/utils.py",
    "content": "from ipCorePackager.constants import DIRECTION\nfrom hdlConvertorAst.hdlAst._expr import HdlDirection\nfrom hwt.doc_markers import internal\n\nHWT_TO_HDLCONVEROTR_DIRECTION = {\n    DIRECTION.IN: HdlDirection.IN,\n    DIRECTION.INOUT: HdlDirection.INOUT,\n    DIRECTION.OUT: HdlDirection.OUT,\n}\n\n\n@internal\nclass TmpVarsSwap():\n    \"\"\"\n    An object which is used as a context manager for tmpVars inside of :class:`~.ToHdlAst`\n    \"\"\"\n\n    def __init__(self, ctx, tmpVars):\n        self.ctx = ctx\n        self.tmpVars = tmpVars\n\n    def __enter__(self):\n        self.orig = self.ctx.tmpVars\n        self.ctx.tmpVars = self.tmpVars\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        self.ctx.tmpVars = self.orig\n"
  },
  {
    "path": "hwt/serializer/generic/value.py",
    "content": "from copy import copy\nfrom typing import Union\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlValueInt, HdlDirection\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import INT, BOOL, FLOAT64\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.function import HFunction, HFunctionConst\nfrom hwt.hdl.types.slice import HSlice\nfrom hwt.hdl.types.string import HString\nfrom hwt.hdl.types.stringConst import HStringConst\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.exceptions import SerializerException\nfrom pyMathBitPrecise.bit_utils import mask\n\n\nINT32_MAX = mask(32-1)\nINT32_MIN = -INT32_MAX - 1\n\nclass ToHdlAst_Value():\n\n    def is_suitable_for_const_extract(self, val: HConst):\n        \"\"\"\n        :return: True if an value should be extracted as a constant if possible\n        \"\"\"\n        return False\n\n    def as_hdl_Value(self, val):\n        \"\"\"\n        :param dst: is signal connected with value\n        :param val: value object, can be instance of Signal or HConst\n        \"\"\"\n        t = val._dtype\n        if isinstance(val, RtlSignalBase):\n            return self.as_hdl_HdlSignalItem(val)\n\n        # try to extract value as constant\n        cc = self.constCache\n        if cc is not None:\n            if self.is_suitable_for_const_extract(val):\n                c = cc.extract_const_val_as_const_var(val)\n                if c is not None:\n                    return self.as_hdl(c)\n\n        if isinstance(t, HSlice):\n            return self.as_hdl_HSliceConst(val)\n        elif isinstance(t, HArray):\n            return self.as_hdl_HArrayConst(val)\n        elif isinstance(t, HBits):\n            return self.as_hdl_HBitsConst(val)\n        elif isinstance(t, HEnum):\n            return self.as_hdl_HEnumConst(val)\n        elif isinstance(t, HString):\n            return self.as_hdl_HStringConst(val)\n        elif isinstance(t, HFloat):\n            return self.as_hdl_HFloatConst(val)\n        elif isinstance(t, HFunction):\n            return self.as_hdl_HFunctionConst(val)\n        else:\n            raise SerializerException(\n                \"can not resolve value serialization for %r\"\n                % (val))\n\n    def as_hdl_int(self, val: int):\n        assert isinstance(val, int), val\n        return HdlValueInt(val, None, None)\n\n    def Value_try_extract_as_const(self, val):\n        return None\n\n    def as_hdl_IntegerVal(self, val: HBitsConst):\n        return self.as_hdl_int(int(val.val))\n\n    def as_hdl_HBitsConst(self, val: HBitsConst):\n        t = val._dtype\n        if t == INT:\n            if val < INT32_MAX and val > INT32_MIN:\n                return self.as_hdl_IntegerVal(val)\n        elif t == BOOL:\n            return self.as_hdl_HBoolConst(val)\n        \n        w = t.bit_length()\n        return self.as_hdl_BitString(val.val, w, t.force_vector,\n                                     val.vld_mask, t.signed)\n\n    def as_hdl_HStringConst(self, val: HStringConst):\n        return val.val\n\n    def as_hdl_HFunctionConst(self, val: HFunctionConst):\n        return val.val\n\n    def as_hdl_HFloatConst(self, val):\n        if val._dtype != FLOAT64:\n            raise NotImplementedError(val._dtype)\n        return float(val)\n\n    def as_hdl_HdlSignalItem(self, si: Union[HdlSignalItem, HdlIdDef],\n                          declaration=False):\n        if declaration:\n            if isinstance(si, HdlIdDef):\n                var = copy(si)\n                si = si.origin\n            else:\n                var = HdlIdDef()\n                var.name = si._name\n                var.origin = si\n                var.value = si._val\n                var.type = si._dtype\n                var.is_const = si._const\n            v = var.value\n            if isinstance(si, RtlSignalBase):\n                if si.virtual_only:\n                    var.is_latched = True\n                elif si._rtlDrivers or var.direction != HdlDirection.UNKNOWN:\n                    # has drivers or is port/param\n                    pass\n                elif si._rtlEndpoints:\n                    if not v.vld_mask:\n                        raise SerializerException(\n                            f\"Signal {si._name:s} is constant and has undefined value\")\n                    var.is_const = True\n                else:\n                    raise SerializerException(\n                        f\"Signal {si._name:s} should be declared but it is not used\")\n\n            if v is None:\n                pass\n            elif isinstance(v, RtlSignalBase):\n                if v._const:\n                    var.value = self.as_hdl(v)\n                else:\n                    # default value has to be set by reset,\n                    # because it is not resolvable in compile time\n                    var.value = None\n                    pass\n            elif isinstance(v, HConst):\n                if v.vld_mask or var.is_const:\n                    orig_const_cache = self.constCache\n                    try:\n                        self.constCache = None\n                        var.value = self.as_hdl_Value(v)\n                    finally:\n                        self.constCache = orig_const_cache\n                else:\n                    # remove value if it is entirely undefined\n                    var.value = None\n            else:\n                raise NotImplementedError(v)\n            var.type = self.as_hdl_HdlType(var.type)\n            return var\n        else:\n            if si._isUnnamedExpr and si._rtlObjectOrigin is not None:\n                # hidden signal, render it's driver instead\n                return self.as_hdl(si._rtlObjectOrigin)\n            return HdlValueId(si._name, obj=si)\n"
  },
  {
    "path": "hwt/serializer/hwt/__init__.py",
    "content": "\"\"\"\nHwt serializer converts  HDL objects back to code in python for hwt.\n\"\"\"\nfrom hdlConvertorAst.hdlAst import iHdlObj\nfrom hdlConvertorAst.to.hwt._main import ToHwt\nfrom hwt.serializer.exceptions import SerializerException\nfrom hwt.serializer.hwt.serializer import ToHdlAstHwt\nfrom hwt.serializer.serializer_config import DummySerializerConfig\n\n\nclass HwtSerializer(DummySerializerConfig):\n    fileExtension = '.py'\n    TO_HDL_AST = ToHdlAstHwt\n    TO_HDL = ToHwt\n\n\nclass ToHdlAstDebugHwt(ToHdlAstHwt):\n    CONVERT_UNKNOWN_OPS_TO_FN_CALL = True\n\n    def as_hdl(self, obj) -> iHdlObj:\n        try:\n            return super(ToHdlAstDebugHwt, self).as_hdl(obj)\n        except SerializerException:\n            return obj.__repr__()\n\n\nclass HwtDebugSerializer(DummySerializerConfig):\n    fileExtension = '.py'\n    TO_HDL_AST = ToHdlAstDebugHwt\n    TO_HDL = ToHwt\n"
  },
  {
    "path": "hwt/serializer/hwt/context.py",
    "content": "class ValueWidthRequirementScope():\n    \"\"\"\n    Context manager which temporarily swaps the _valueWidthRequired on specified context \n\n    .. code-block:: python\n\n        with ValueWidthRequirementScope(ctx, True):\n            #...\n    \"\"\"\n\n    def __init__(self, ctx, val):\n        self.ctx = ctx\n        self.val = val\n\n    def __enter__(self):\n        self.orig = self.ctx._valueWidthRequired\n        self.ctx._valueWidthRequired = self.val\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        self.ctx._valueWidthRequired = self.orig\n"
  },
  {
    "path": "hwt/serializer/hwt/ops.py",
    "content": "from hdlConvertorAst.hdlAst._expr import HdlOp, HdlValueId\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_getattr, \\\n    hdl_call\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.serializer.hwt.context import ValueWidthRequirementScope\nfrom hwt.serializer.simModel.value import ToHdlAstSimModel_value\n\n\nclass ToHdlAstHwt_ops():\n    CONVERT_UNKNOWN_OPS_TO_FN_CALL = False\n    CONCAT = HdlValueId(\"Concat\", obj=LanguageKeyword())\n    op_transl_dict = ToHdlAstSimModel_value.op_transl_dict\n    _cast_ops = ToHdlAstSimModel_value._cast_ops\n\n    def as_hdl_HOperatorNode(self, op: HOperatorNode):\n        ops = op.operands\n        o = op.operator\n\n        with ValueWidthRequirementScope(self, o == HwtOps.CONCAT):\n            if o in self._cast_ops:\n                op0 = hdl_getattr(self.as_hdl(ops[0]), \"_reinterpret_cast\")\n                op1 = self.as_hdl_HdlType(op.result._dtype)\n                return hdl_call(op0, [op1, ])\n            elif o == HwtOps.EQ:\n                return hdl_call(hdl_getattr(self.as_hdl(ops[0]), \"_eq\"),\n                                [self.as_hdl(ops[1])])\n            elif o == HwtOps.CONCAT:\n                return hdl_call(self.CONCAT,\n                                [self.as_hdl(o2) for o2 in ops])\n            elif o == HwtOps.ZEXT or o == HwtOps.SEXT or o == HwtOps.TRUNC:\n                op0, newWidth = ops\n                newWidth = int(newWidth)\n                with ValueWidthRequirementScope(self, True):\n                    op0 = self.as_hdl(op0)\n                op1 = self.as_hdl_int(newWidth)\n                fnName = \"_zext\" if o == HwtOps.ZEXT else \\\n                         \"_sext\" if o == HwtOps.SEXT else \\\n                         \"_trunc\"\n                return hdl_call(hdl_getattr(op0, fnName), [op1])\n\n            elif o == HwtOps.TERNARY:\n                cond, op0, op1 = ops\n                cond = self.as_hdl(cond)\n                with ValueWidthRequirementScope(self, True):\n                    op0 = self.as_hdl(op0)\n                    op1 = self.as_hdl(op1)\n                return hdl_call(hdl_getattr(cond, \"_ternary\"), [op0, op1])\n            else:\n\n                _o = self.op_transl_dict.get(o, None)\n                if self.CONVERT_UNKNOWN_OPS_TO_FN_CALL:\n                    if _o is None:\n                        return hdl_call(HdlValueId(o.id, obj=o._evalFn),\n                                        [self.as_hdl(o2) for o2 in ops])\n\n                assert _o is not None, o\n                return HdlOp(_o, [self.as_hdl(o2)\n                                 for o2 in ops])\n"
  },
  {
    "path": "hwt/serializer/hwt/serializer.py",
    "content": "\nfrom typing import Optional, Union\n\nfrom hdlConvertorAst.hdlAst import HdlStmBlock\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDef\nfrom hdlConvertorAst.to.hwt.keywords import HWT_KEYWORDS\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword, NameScope\nfrom hwt.code import CodeBlock\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.serializer.generic.to_hdl_ast import ToHdlAst\nfrom hwt.serializer.hwt.ops import ToHdlAstHwt_ops\nfrom hwt.serializer.hwt.types import ToHdlAstHwt_types\nfrom hwt.serializer.hwt.value import ToHdlAstHwt_value\nfrom hwt.serializer.simModel.serializer import ToHdlAstSimModel\nfrom hwt.hdl.variables import HdlSignalItem\n\n\nclass ToHdlAstHwt(ToHdlAstHwt_value, ToHdlAstHwt_ops,\n                  ToHdlAstHwt_types, ToHdlAst):\n    \"\"\"\n    Serializer which converts HWT objects back to HWT code\n    for debugging purposes/code ports\n\n    :ivar ~._valueWidthRequired: flag which tells if the values are required to have\n        the width specified\n    \"\"\"\n    _keywords_dict = {kw: LanguageKeyword() for kw in HWT_KEYWORDS}\n\n    def __init__(self, name_scope: Optional[NameScope]=None):\n        super(ToHdlAstHwt, self).__init__(name_scope=name_scope)\n        self._valueWidthRequired = False\n        self.currentHwModule = None\n        self.debug = False\n\n    def has_to_be_process(self, proc):\n        return True\n\n    def can_pop_process_wrap(self, statements, hasToBeVhdlProcess: bool):\n        return False\n\n    def _as_hdl_HdlModuleDef(self, new_m: HdlModuleDef) -> HdlModuleDef:\n        return ToHdlAstSimModel._as_hdl_HdlModuleDef(self, new_m)\n\n    def sensitivityListItem(self, item: Union[HdlSignalItem, HOperatorNode], anyIsEventDependent: bool):\n        if isinstance(item, HOperatorNode):\n            op = item.operator\n            assert op in (HwtOps.RISING_EDGE, HwtOps.FALLING_EDGE), item\n            assert not item.operands[0]._isUnnamedExpr, item\n            return self.as_hdl_HOperatorNode(item)\n        else:\n            return HdlValueId(item._name, obj=item)\n\n    def as_hdl_CodeBlock(self, o: CodeBlock):\n        res = HdlStmBlock()\n        for _o in o.statements:\n            res.body.append(self.as_hdl(_o))\n        return res\n\n"
  },
  {
    "path": "hwt/serializer/hwt/types.py",
    "content": "from hdlConvertorAst.hdlAst._expr import HdlValueId, HdlValueInt\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call, \\\n    hdl_map_asoc, hdl_index\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import BITS_DEFAUTL_SIGNED, BITS_DEFAUTL_FORCEVECTOR, \\\n    BITS_DEFAUTL_NEGATED, HBits\nfrom hwt.hdl.types.defs import BOOL, INT, STR\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.hdlType import MethodNotOverloaded\n\n\nclass ToHdlAstHwt_types():\n    \"\"\"\n    part of ToHdlAstSimModel responsible for type serialization\n    \"\"\"\n    BOOL = HdlValueId(\"BOOL\", obj=BOOL)\n    INT = HdlValueId(\"INT\", obj=INT)\n    BITS = HdlValueId(\"HBits\", obj=HBits)\n    STR = HdlValueId(\"STR\", obj=STR)\n\n    def does_type_requires_extra_def(self, t, other_types):\n        try:\n            return t._as_hdl_requires_def(self, other_types)\n        except MethodNotOverloaded:\n            pass\n        return isinstance(t, HEnum) and t not in other_types\n\n    def as_hdl_HdlType_str(self, typ, declaration=False):\n        assert not declaration\n        return self.STR\n\n    def as_hdl_HdlType_array(self, typ: HArray, declaration=False):\n        assert not declaration, \"declaration should not be required\"\n        t = self.as_hdl_HdlType(typ.element_t, declaration=declaration)\n        return hdl_index(t, HdlValueInt(int(typ.size), None, None))\n\n    def as_hdl_HdlType_bits(self, typ: HBits, declaration=False):\n        if declaration:\n            raise NotImplementedError()\n        elif typ == BOOL:\n            return self.BOOL\n        elif typ == INT:\n            return self.INT\n\n        w = typ.bit_length()\n        assert isinstance(w, int), w\n\n        def add_kw(name, val):\n            kw = hdl_map_asoc(HdlValueId(name),\n                              HdlValueInt(val, None, None))\n            args.append(kw)\n\n        args = [HdlValueInt(w, None, None)]\n        if typ.signed is not BITS_DEFAUTL_SIGNED:\n            add_kw(\"signed\", typ.signed)\n        if typ.force_vector is not BITS_DEFAUTL_FORCEVECTOR and w <= 1:\n            add_kw(\"force_vector\", typ.force_vector)\n        if typ.negated is not BITS_DEFAUTL_NEGATED:\n            add_kw(\"negated\", typ.negated)\n\n        return hdl_call(self.BITS, args)\n\n    def as_hdl_HdlType_float(self, typ: HFloat, declaration=False):\n        return hdl_call(HdlValueId(\"HFloat\"), typ.exponent_w, typ.mantisa_w)\n"
  },
  {
    "path": "hwt/serializer/hwt/value.py",
    "content": "from copy import copy\nfrom typing import Union\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueInt, HdlOp, HdlOpType, \\\n    HdlValueId\nfrom hdlConvertorAst.translate.common.name_scope import ObjectForNameNotFound\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_getattr, \\\n    hdl_call\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.arrayConst import HArrayConst\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import SLICE\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.enumConst import HEnumConst\nfrom hwt.hdl.types.sliceConst import HSliceConst\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.serializer.generic.value import ToHdlAst_Value\nfrom hwt.serializer.simModel.value import ToHdlAstSimModel_value\n\n\nclass ToHdlAstHwt_value(ToHdlAst_Value):\n    NONE = HdlValueId(\"None\")\n    SLICE = HdlValueId(\"SLICE\", obj=SLICE)\n\n    def is_suitable_for_const_extract(self, val: HConst):\n        # full valid values can be represented as int and do not have any\n        # constructor overhead, entirely invalid values can be represented by None\n        return not val._is_full_valid() and not isinstance(val._dtype, HEnum)\n\n    def as_hdl_HBitsConst(self, val: HBitsConst):\n        isFullVld = val._is_full_valid()\n        if not self._valueWidthRequired:\n            if isFullVld:\n                return HdlValueInt(val.val, None, 16)\n            elif val.vld_mask == 0:\n                return self.NONE\n\n        t = self.as_hdl_HdlType_bits(val._dtype, declaration=False)\n        c = hdl_getattr(t, \"from_py\")\n        args = [HdlValueInt(val.val, None, 16), ]\n        if not isFullVld:\n            args.append(HdlValueInt(val.vld_mask, None, 16))\n\n        return hdl_call(c, args)\n\n    def as_hdl_HdlSignalItem(self, si: Union[HdlSignalItem, HdlIdDef], declaration=False):\n        if declaration:\n            if isinstance(si, HdlIdDef):\n                new_si = copy(si)\n                new_si.type = self.as_hdl_HdlType(si.type)\n                if si.value is not None:\n                    new_si.value = self.as_hdl_Value(si.value)\n                return new_si\n            else:\n                raise NotImplementedError()\n        else:\n            # if isinstance(si, HdlSignalItem) and si._const:\n            #    # to allow const cache to extract constants\n            #    return self.as_hdl_Value(si._val)\n            if si._isUnnamedExpr and si._rtlObjectOrigin is not None:\n                return self.as_hdl(si._rtlObjectOrigin)\n            else:\n                return HdlValueId(si._name, obj=si)\n\n    def as_hdl_HDictConst(self, val):\n        return ToHdlAstSimModel_value.as_hdl_HDictConst(self, val)\n\n    def as_hdl_HArrayConst(self, val: HArrayConst):\n        if not val.vld_mask:\n            return self.NONE\n        # else:\n        #    if len(val.val) == val._dtype.size:\n        #        allValuesSame = True\n        #        values = iter(val.val.values())\n        #        reference = next(values)\n        #         for v in values:\n        #             if allValuesSame:\n        #                 allValuesSame = isSameHConst(reference, v)\n        #             else:\n        #                 break\n        #        if allValuesSame:\n        #            # all values of items in array are same, use generator\n        #            # exression\n        #            raise NotImplementedError()\n        #            return \"[%s for _ in range(%d)]\" % (self.Value(reference))\n\n        # if value can not be simplified it is required to serialize it item\n        # by item\n        return self.as_hdl_HDictConst(val.val)\n\n    def as_hdl_HSliceConst(self, val: HSliceConst):\n        if val._is_full_valid():\n            return HdlOp(\n                HdlOpType.DOWNTO, [\n                    HdlValueInt(int(val.val.start), None, None),\n                    HdlValueInt(int(val.val.stop), None, None)\n                ])\n        else:\n            raise NotImplementedError()\n            return \"HSliceConst(slice(%s, %s, %s), SLICE, %d)\" % (\n                self.as_hdl_Value(val.val.start),\n                self.as_hdl_Value(val.val.stop),\n                self.as_hdl_Value(val.val.step),\n                val.vld_mask)\n\n    def as_hdl_HEnumConst(self, val: HEnumConst):\n        try:\n            t_name = self.name_scope.get_object_name(val._dtype)\n        except ObjectForNameNotFound:\n            if self.debug:\n                t_name = val._dtype.name\n            else:\n                raise\n\n        if val.vld_mask:\n            try:\n                name = self.name_scope.get_object_name(val)\n            except ObjectForNameNotFound:\n                if self.debug:\n                    name = val.val\n                else:\n                    raise\n\n            return hdl_getattr(HdlValueId(t_name, obj=val._dtype), name)\n        else:\n            return hdl_call(hdl_getattr(HdlValueId(t_name, obj=val._dtype), \"from_py\"),\n                            [None, ])\n"
  },
  {
    "path": "hwt/serializer/ip_packager.py",
    "content": "from io import StringIO\nimport math\nfrom typing import List, Tuple, Union\n\nfrom hdlConvertorAst.hdlAst import HdlValueId\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.to.vhdl.vhdl2008 import ToVhdl2008\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, STR, BIT, INT\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.hwIO import HwIO\nfrom hwt.hwModule import HwModule\nfrom hwt.hwParam import HwParam\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.store_manager import SaveToFilesFlat\nfrom hwt.serializer.vhdl import Vhdl2008Serializer, ToHdlAstVhdl2008\nfrom hwt.synth import to_rtl\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\nfrom hwt.synthesizer.interfaceLevel.hwModuleImplHelpers import getSignalName\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom ipCorePackager.intfIpMeta import VALUE_RESOLVE\nfrom ipCorePackager.otherXmlObjs import Value\nfrom ipCorePackager.packager import IpCorePackager\n\n\nclass ToHdlAstVivadoTclExpr(ToHdlAstVhdl2008):\n    _spirit_decode = HdlValueId(\"spirit:decode\")\n    _id = HdlValueId(\"id\")\n\n    def as_hdl_HdlSignalItem(self, si: HdlSignalItem, declaration=False):\n        assert(declaration == False)\n        if si._isUnnamedExpr:\n            assert si._rtlObjectOrigin is not None, si\n            return self.as_hdl(si._rtlObjectOrigin)\n        else:\n            id_ = hdl_call(self._id, [f'MODELPARAM_VALUE.{si._name}'])\n            return hdl_call(self._spirit_decode, [id_])\n\n\nclass IpPackager(IpCorePackager):\n    \"\"\"\n    IP-core packager\n\n    :summary: Packs HDL, constraint and other files to IP-Core package\n        for distribution and simple integration\n\n    \"\"\"\n\n    def __init__(self, topHwModule: HwModule, name: str=None,\n                 extra_files: List[str]=[],\n                 serializer_cls=Vhdl2008Serializer,\n                 target_platform=DummyPlatform()):\n        \"\"\"\n        :param topObj: :class:`hwt.hwModule.HwModule` instance of top component\n        :param name: optional name of top\n        :param extra_files: list of extra HDL/constrain file names for files\n            which should be distributed in this IP-core\n            (\\\\*.v - verilog, \\\\*.sv,\\\\*.svh -system verilog, \\\\*.vhd - vhdl, \\\\*.xdc - XDC)\n        :param serializer: serializer which specifies target HDL language\n        :param target_platform: specifies properties of target platform, like available resources, vendor, etc.\n        \"\"\"\n        if not name:\n            name = topHwModule._getDefaultName()\n\n        super(IpPackager, self).__init__(\n            topHwModule, name, extra_files)\n        self.serializer = serializer_cls\n        self.target_platform = target_platform\n\n    @internal\n    def toHdlConversion(self, top, topName: str, saveTo: str) -> List[str]:\n        \"\"\"\n        :param top: object which is representation of design\n        :param topName: name which should be used for ipcore\n        :param saveTo: path of directory where generated files should be stored\n\n        :return: list of file names in correct compile order\n        \"\"\"\n        ser = self.serializer\n        store = SaveToFilesFlat(ser, saveTo)\n        to_rtl(top, name=topName, store_manager=store,\n              target_platform=self.target_platform)\n        return store.files\n\n    @internal\n    def paramToIpValue(self, idPrefix: str, g: HdlIdDef, resolve) -> Value:\n        val = Value()\n        val.id = idPrefix + g.name\n        if resolve is not VALUE_RESOLVE.NONE:\n            val.resolve = resolve\n        v = g.value\n        t = g.type\n\n        def getVal():\n            if v.vld_mask:\n                return v.val\n            else:\n                return 0\n\n        def bitString(w):\n            val.format = \"bitString\"\n            digits = math.ceil(w / 4)\n            val.text = ('0x%0' + str(digits) + 'X') % getVal()\n            val.bitStringLength = str(w)\n\n        if t == BOOL:\n            val.format = \"bool\"\n            val.text = str(bool(getVal())).lower()\n        elif t == INT:\n            val.format = \"long\"\n            val.text = str(getVal())\n        elif t == STR:\n            val.format = \"string\"\n            val.text = v.val\n        elif isinstance(t, HBits):\n            bitString(t.bit_length())\n        else:\n            raise NotImplementedError(\n                f\"Not implemented for datatype {t}\")\n        return val\n\n    @internal\n    def getParamPhysicalName(self, p: HdlIdDef):\n        return p.name\n\n    @internal\n    def getParamType(self, p: HdlIdDef) -> HdlType:\n        assert p.type in [INT, BOOL, STR], p\n        return p.type\n\n    @internal\n    def iterParams(self, module: HwModule):\n        return module._rtlCtx.hwModDec.params\n\n    @internal\n    def iterInterfaces(self, top: HwModule):\n        return top._hwIOs\n\n    @internal\n    def serializeType(self, hdlType: HdlType) -> str:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        buff = StringIO()\n        to_ast = ToHdlAstVhdl2008()\n        hdl = to_ast.as_hdl_HdlType(hdlType)\n        ser = ToVhdl2008(buff)\n        ser.visit_iHdlObj(hdl)\n        return buff.getvalue()\n\n    @internal\n    def getVectorFromType(self, dtype) -> Union[bool, None, Tuple[int, int]]:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        if dtype == BIT:\n            return False\n        elif isinstance(dtype, HBits):\n            return [dtype.bit_length() - 1, INT.from_py(0)]\n\n    @internal\n    def getInterfaceType(self, hwIO: HwIO) -> HdlType:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        return hwIO._dtype\n\n    @internal\n    def getInterfaceLogicalName(self, hwIO: HwIO):\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        return getSignalName(hwIO)\n\n    @internal\n    def getInterfacePhysicalName(self, hwIO: HwIO):\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        return hwIO._sigInside._name\n\n    @internal\n    def getInterfaceDirection(self, thisHwIO: HwIO):\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        return thisHwIO._direction\n\n    @internal\n    def getTypeWidth(self, dtype: HdlType, do_eval=False)\\\n            -> Tuple[int, Union[int, RtlSignal], bool]:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        width = dtype.bit_length()\n        widthStr = str(width)\n        return width, widthStr, False\n\n    @internal\n    def getObjDebugName(self, obj: Union[HwIO, HwModule, HwParam]) -> str:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        return obj._getFullName()\n\n    @internal\n    def serialzeValueToTCL(self, val, do_eval=False) -> Tuple[str, str, bool]:\n        \"\"\"\n        :see: doc of method on parent class\n        \"\"\"\n        if isinstance(val, int):\n            val = INT.from_py(val)\n        if do_eval:\n            val = val.staticEval()\n\n        buff = StringIO()\n        to_hdl = ToHdlAstVivadoTclExpr()\n        ser = Vhdl2008Serializer.TO_HDL(buff)\n\n        hdl = to_hdl.as_hdl(val)\n        ser.visit_iHdlObj(hdl)\n        tclVal = buff.getvalue()\n\n        if isinstance(val, RtlSignalBase):\n            buff = StringIO()\n            hdl = to_hdl.as_hdl(val.staticEval())\n            ser = Vhdl2008Serializer.TO_HDL(buff)\n            ser.visit_iHdlObj(hdl)\n            tclValVal = buff.getvalue()\n\n            return tclVal, tclValVal, False\n        else:\n            return tclVal, tclVal, True\n"
  },
  {
    "path": "hwt/serializer/mode.py",
    "content": "\"\"\"\nSerializer mode specifies if hdl objects derived from parent unit\nshould be serialized to target HDL or not\n\nuse serialize* methods to specify serialization mode for unit class\n\n.. code-block:: python\n\n    @serializeExclude\n    class MyHwModule(HwModule):\n        # ...\n        pass\n\n\"\"\"\n\nfrom collections import namedtuple\nfrom typing import Type\n\nfrom hwt.doc_markers import internal\n\n\n@internal\ndef freeze_dict(data):\n    keys = sorted(data.keys())\n    if keys:\n        frozen_type = namedtuple(''.join(keys), keys)\n    else:\n        return tuple()\n    return frozen_type(**data)\n\n\n@internal\ndef hwParamsToValTuple(module: \"HwModule\"):\n    # [TODO] check sub params\n    d = {}\n    for p in module._hwParams:\n        v = p.get_value()\n        d[p._name] = v\n    return freeze_dict(d)\n\n\ndef serializeExclude(cls: Type[\"HwModule\"]):\n    \"\"\"\n    Never serialize HDL objects from this class\n    \"\"\"\n    cls._serializeDecision = staticmethod(_serializeExclude_eval)\n    return cls\n\n\ndef serializeOnce(cls: Type[\"HwModule\"]):\n    \"\"\"\n    Serialize HDL objects only once per class\n    \"\"\"\n    cls._serializeDecision = staticmethod(_serializeOnce_eval)\n    return cls\n\n\ndef serializeParamsUniq(cls: Type[\"HwModule\"]):\n    \"\"\"\n    Decide to serialize only when parameters are unique\n    \"\"\"\n    cls._serializeDecision = staticmethod(_serializeParamsUniq_eval)\n    return cls\n\n\n@internal\ndef _serializeExclude_eval(parentModule: \"HwModule\", priv):\n    \"\"\"\n    Always decide not to serialize obj\n\n    :param priv: private data for this function first unit of this class\n    :return: tuple (do serialize this object, next priv, replacement unit)\n    \"\"\"\n\n    # do not use this :class:`hwt.hwModule.HwModule` instance and do not use any replacement\n    # (useful when the :class:`hwt.hwModule.HwModule` instance is a placeholder for something\n    #  which already exists in hdl word)\n    if priv is None:\n        priv = parentModule\n        return False, priv, None\n    else:\n        return False, priv, priv\n\n\n@internal\ndef _serializeOnce_eval(parentModule: \"HwModule\", priv):\n    \"\"\"\n    Decide to serialize only first obj of it's class\n\n    :param priv: private data for this function\n        (first object with class == obj.__class__)\n\n    :return: tuple (do serialize this object, next priv, replacement unit)\n        where priv is private data for this function\n        (first object with class == obj.__class__)\n    \"\"\"\n    if priv is None:\n        priv = parentModule\n        serialize = True\n        replacement = None\n        # use this :class:`hwt.hwModule.HwModule` instance and store it for later use\n    else:\n        # use existing :class:`hwt.hwModule.HwModule` instance\n        serialize = False\n        replacement = priv\n\n    return serialize, priv, replacement\n\n\n@internal\ndef _serializeParamsUniq_eval(parentModule: \"HwModule\", priv):\n    \"\"\"\n    Decide to serialize only objs with unique parameters and class\n\n    :param priv: private data for this function\n        ({frozen_params: obj})\n\n    :return: tuple (do serialize this object, next priv, replacement unit)\n    \"\"\"\n\n    params = hwParamsToValTuple(parentModule)\n\n    if priv is None:\n        priv = {}\n\n    try:\n        prevModule = priv[params]\n    except KeyError:\n        priv[params] = parentModule\n        # serialize new\n        return True, priv, None\n\n    # use previous :class:`hwt.hwModule.HwModule` instance with same config\n    return False, priv, prevModule\n"
  },
  {
    "path": "hwt/serializer/resourceAnalyzer/__init__.py",
    "content": "\"\"\"\nResource analyzer has serializer API, but it's output is resource report.\n\"\"\"\n"
  },
  {
    "path": "hwt/serializer/resourceAnalyzer/analyzer.py",
    "content": "from itertools import chain\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDef, \\\n    HdlCompInst\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode, isConst\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.types.array import HArray\nfrom hwt.serializer.resourceAnalyzer.utils import ResourceContext\nfrom hwt.hwModule import HwModule\nfrom hwt.synthesizer.rtlLevel.mark_visibility_of_signals_and_check_drivers import walk_assignments\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\n@internal\ndef _count_mux_inputs_for_outputs(stm: HdlStatement, cnt):\n    if isinstance(stm, HdlAssignmentContainer):\n        cnt[stm.dst] += 1\n    else:\n        for _stm in stm._iter_stms():\n            if isinstance(_stm, HdlAssignmentContainer):\n                cnt[_stm.dst] += 1\n            else:\n                _count_mux_inputs_for_outputs(_stm, cnt)\n\n\n@internal\ndef count_mux_inputs_for_outputs(stm):\n    cnt = {o: 0 for o in stm._outputs}\n    _count_mux_inputs_for_outputs(stm, cnt)\n    return cnt\n\n\n# operators which do not consume a hw resorce directly\nIGNORED_OPERATORS = {\n    HwtOps.BitsAsSigned,\n    HwtOps.BitsAsUnsigned,\n    HwtOps.BitsAsVec,\n    HwtOps.RISING_EDGE,\n    HwtOps.FALLING_EDGE,\n}\n\n\nclass ResourceAnalyzer():\n    \"\"\"\n    Serializer which does not products any output just collect informations\n    about used resources\n\n    :attention: Use instance of ResourceAnalyzer instead of class\n    \"\"\"\n    _keywords_dict = {}\n\n    def __init__(self):\n        self.context = ResourceContext(None)\n\n    @internal\n    def visit_HdlStmCodeBlockContainer_operators(self, sig: RtlSignal, synchronous):\n        ctx = self.context\n        seen = ctx.seen\n        for d in sig._rtlDrivers:\n            if (not isinstance(d, HOperatorNode)\n                    or d in seen):\n                continue\n\n            skip_op = d.operator in IGNORED_OPERATORS\n            if not skip_op:\n                if d.operator == HwtOps.EQ:\n                    o1 = d.operands[1]\n                    if (isinstance(o1, HConst)\n                            and o1._dtype.bit_length() == 1\n                            and o1.val):\n                        # to bool conversion\n                        skip_op = True\n                elif d.operator == HwtOps.INDEX:\n                    o1 = d.operands[1]\n                    skip_op = True\n                    if isConst(o1):\n                        # constant signal slice\n                        pass\n                    else:\n                        o0 = d.operands[0]\n                        if isinstance(o0._dtype, HArray):\n                            ctx.registerRAM_read_port(o0, o1, synchronous)\n                        else:\n                            ctx.registerMUX(d, sig, 2)\n                elif d.operator == HwtOps.TERNARY:\n                    o1 = d.operands[1]\n                    o2 = d.operands[2]\n                    if (isConst(o1)\n                            and bool(o1)\n                            and isConst(o2)\n                            and not bool(o2)):\n                        # to bit conversion\n                        skip_op = True\n                    else:\n                        raise NotImplementedError(\"Ternary as mux\")\n\n            if not skip_op:\n                ctx.registerOperator(d)\n\n            for op in d.operands:\n                if (not isinstance(op, RtlSignal)\n                        or not op._isUnnamedExpr\n                        or op in seen):\n                    continue\n                self.visit_HdlStmCodeBlockContainer_operators(op, synchronous)\n\n    def visit_HdlStmCodeBlockContainer(self, proc: HdlStmCodeBlockContainer) -> None:\n        \"\"\"\n        Guess resource usage from HdlStmCodeBlockContainer\n        \"\"\"\n        ctx = self.context\n        seen = ctx.seen\n        for stm in proc.statements:\n            encl = stm._enclosed_for\n            full_ev_dep = stm._event_dependent_from_branch == 0\n            now_ev_dep = stm._event_dependent_from_branch is not None\n            ev_dep = full_ev_dep or now_ev_dep\n\n            out_mux_dim = count_mux_inputs_for_outputs(stm)\n            for o in stm._outputs:\n                if o in seen:\n                    continue\n\n                i = out_mux_dim[o]\n                if isinstance(o._dtype, HArray):\n                    assert i == 1, (o, i, \" only one ram port per HdlStmCodeBlockContainer\")\n                    for a in walk_assignments(stm, o):\n                        assert len(a.indexes) == 1, (\"has to have single address per RAM port\", a.indexes)\n                        addr = a.indexes[0]\n                    ctx.registerRAM_write_port(o, addr, ev_dep)\n                elif ev_dep:\n                    ctx.registerFF(o)\n                    if i > 1:\n                        ctx.registerMUX(stm, o, i)\n                elif o not in encl:\n                    ctx.registerLatch(o)\n                    if i > 1:\n                        ctx.registerMUX(stm, o, i)\n                elif i > 1:\n                    ctx.registerMUX(stm, o, i)\n                else:\n                    # just a connection\n                    continue\n\n            if isinstance(stm, SwitchContainer):\n                caseEqs = set([stm.switchOn._eq(c[0]) for c in stm.cases])\n                inputs = chain(\n                    [sig for sig in stm._inputs if sig not in caseEqs], [stm.switchOn])\n            else:\n                inputs = stm._inputs\n\n            for i in inputs:\n                # discover only internal signals in this statements for\n                # operators\n                if not i._isUnnamedExpr or i in seen:\n                    continue\n\n                self.visit_HdlStmCodeBlockContainer_operators(i, ev_dep)\n\n    def visit_HdlModuleDef(self, m: HdlModuleDef) -> None:\n        for o in m.objs:\n            if isinstance(o, HdlStmCodeBlockContainer):\n                self.visit_HdlStmCodeBlockContainer(o)\n            elif isinstance(o, HdlCompInst):\n                self.visit_HdlCompInst(o)\n            else:\n                assert isinstance(o, HdlIdDef), o\n\n    def visit_HdlCompInst(self, o: HdlCompInst) -> None:\n        raise NotImplementedError()\n\n    # [TODO] constant to ROMs\n    def visit_HwModule(self, m: HwModule):\n        self.visit_HdlModuleDef(m._rtlCtx.hwModDef)\n\n    def report(self):\n        ctx = self.context\n        ctx.finalize()\n        return ctx.resources\n"
  },
  {
    "path": "hwt/serializer/resourceAnalyzer/resourceTypes.py",
    "content": "\n\nclass ResourceError(Exception):\n    \"\"\"\n    An error which means that the resource of this kind\n    does not exists in current hardware.\n    \"\"\"\n\n\nclass RtlResourceType():\n    \"\"\"\n    A base class for resource type descriptions.\n    \"\"\"\n\n\nclass ResourceMUX(RtlResourceType):\n\n    def __init__(self, bitWidth, inputs):\n        self.bitWidth = bitWidth\n        self.inputs = inputs\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} {self.bitWidth:d} bits, {self.inputs} inputs>\"\n\n\nclass ResourceFF(RtlResourceType):\n    pass\n\n\nclass ResourceLatch(RtlResourceType):\n    pass\n\n\nclass ResourceRAM(RtlResourceType):\n    \"\"\"\n    Specifier of type of RAM like memory\n    \"\"\"\n\n    def __init__(self, width, items,\n                 rwSync: int, rSync: int, wSync: int, rSync_wAsync: int,\n                 rwAsync: int, rAsync: int, wAsync: int, rAsync_wSync: int):\n        \"\"\"\n        :param width: width of word in RAM/ROM\n        :param items: number of words in RAM/ROM\n        :param rwSync: count of read + write synchronous ports\n        :param rSync: count of read only synchronous ports\n        :param wSync: count of write only synchronous ports\n        :param rSync_wAsync: count of synchronous read + asynchronous write ports\n        :param rwAsync: count of read + write asynchronous ports\n        :param rAsync: count of read only asynchronous ports\n        :param wAsync: count of write only asynchronous ports\n        :param rAsync_wSync: count of asynchronous read + synchronous write ports\n        \"\"\"\n        self.width = width\n        self.items = items\n        self.rwSync = rwSync\n        self.rSync = rSync\n        self.wSync = wSync\n        self.rSync_wAsync = rSync_wAsync\n        self.rwAsync = rwAsync\n        self.rAsync = rAsync\n        self.wAsync = wAsync\n        self.rAsync_wSync = rAsync_wSync\n\n    def __hash__(self):\n        return hash((\n            self.width, self.items,\n            self.rwSync, self.rSync, self.wSync,\n            self.rSync_wAsync,\n            self.rwAsync, self.rAsync, self.wAsync,\n            self.rAsync_wSync))\n\n    def __eq__(self, other):\n        return isinstance(other, ResourceRAM) and (\n            self.width == other.width and\n            self.items == other.items and\n            self.rwSync == other.rwSync and\n            self.rSync == other.rSync and\n            self.wSync == other.wSync and\n            self.rSync_wAsync == other.rSync_wAsync and\n            self.rwAsync == other.rwAsync and\n            self.rAsync == other.rAsync and\n            self.wAsync == other.wAsync and\n            self.rAsync_wSync == other.rAsync_wSync\n        )\n\n    def __repr__(self):\n        return (\"<%s, %dbit x %d, syncPorts: (rw:%d, r:%d, w:%d), asyncPorts:\"\n                \" (rw:%d, r:%d, w:%d), rSync_wAsyncPorts: %d,\"\n                \" rAsync_wSyncPorts: %d>\") % (\n            self.__class__.__name__, self.width, self.items,\n            self.rwSync, self.rSync, self.wSync,\n            self.rwAsync, self.rAsync, self.wAsync,\n            self.rSync_wAsync, self.rAsync_wSync\n        )\n"
  },
  {
    "path": "hwt/serializer/resourceAnalyzer/utils.py",
    "content": "from typing import Union\n\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.serializer.resourceAnalyzer.resourceTypes import \\\n    ResourceFF, ResourceMUX, ResourceLatch, ResourceRAM\nfrom hwt.hwModule import HwModule\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass ResourceContext():\n    \"\"\"\n    Container of informations about resources used in architecture\n\n    :ivar ~.module: optional module for which is this context build\n    :ivar ~.seen: set of seen objects\n    :ivar ~.resources: dictionary {type of resource: cnt}\n    :ivar ~.discoveredRamSignals: set of signals which seems to be some kind\n        of RAM/ROM memory\n    \"\"\"\n\n    def __init__(self, module: HwModule):\n        self.module = module\n        self.seen = set()\n        self.resources = {}\n        # {RtlSignal or Statement or HOperatorNode: HwResource or typle (HwResource, cnt)}\n        self.resource_for_object = {}\n        # {(mem, addr, syncFlag, r/w): cnt}\n        self.memories = {}\n\n    def registerOperator(self, op: HOperatorNode):\n        w = op.operands[0]._dtype.bit_length()\n        res = self.resources\n        k = (op.operator, w)\n        res[k] = res.get(k, 0) + 1\n\n        self.resource_for_object[op] = k\n\n    def registerMUX(self, stm: Union[HdlStatement, HOperatorNode], sig: RtlSignal,\n                    inputs_cnt: int):\n        \"\"\"\n        mux record is in format (self.MUX, n, m)\n        where n is number of bits of this mux\n        and m is number of possible inputs\n        \"\"\"\n        assert inputs_cnt > 1\n        res = self.resources\n        w = sig._dtype.bit_length()\n        k = (ResourceMUX, w, inputs_cnt)\n        res[k] = res.get(k, 0) + 1\n\n        self.resource_for_object[(stm, sig)] = k\n\n    def registerFF(self, ff):\n        res = self.resources\n        w = ff._dtype.bit_length()\n        ffs = res.get(ResourceFF, 0)\n        res[ResourceFF] = ffs + w\n\n        self.resource_for_object[ff] = (ResourceFF, w)\n\n    def registerLatch(self, latch: RtlSignal):\n        res = self.resources\n        w = latch._dtype.bit_length()\n        latches = res.get(ResourceLatch, 0)\n        res[ResourceLatch] = latches + w\n\n        self.resource_for_object[latch] = (ResourceLatch, w)\n\n    def registerRAM_write_port(self, mem: RtlSignal, addr: RtlSignal,\n                               synchronous: bool):\n        res = self.memories\n        addresses = res.get(mem, {})\n        res[mem] = addresses\n\n        # [rSycn, wSync, rAsync, wAsync]\n        portCnts = addresses.get(addr, [0, 0, 0, 0])\n        if synchronous:\n            portCnts[1] += 1\n        else:\n            portCnts[3] += 1\n        addresses[addr] = portCnts\n\n    def registerRAM_read_port(self, mem: RtlSignal, addr: RtlSignal,\n                              synchronous: bool):\n        res = self.memories\n        addresses = res.get(mem, {})\n        res[mem] = addresses\n\n        # [rSycn, wSync, rAsync, wAsync]\n        portCnts = addresses.get(addr, [0, 0, 0, 0])\n        if synchronous:\n            portCnts[0] += 1\n        else:\n            portCnts[2] += 1\n        addresses[addr] = portCnts\n\n    def finalize(self):\n        \"\"\"\n        Resolve ports of discovered memories\n        \"\"\"\n        ff_to_remove = 0\n        res = self.resources\n        for m, addrDict in self.memories.items():\n            rwSyncPorts, rSyncPorts, wSyncPorts = 0, 0, 0\n            rwAsyncPorts, rAsyncPorts, wAsyncPorts = 0, 0, 0\n            rSync_wAsyncPorts, rAsync_wSyncPorts = 0, 0\n\n            for _, (rSync, wSync, rAsync, wAsync) in addrDict.items():\n                if rSync:\n                    ff_to_remove += rSync * m._dtype.element_t.bit_length()\n\n                # resolve port count for this addr signal\n                rwSync = min(rSync, wSync)\n                rSync -= rwSync\n                wSync -= rwSync\n\n                rwAsync = min(rAsync, wAsync)\n                rAsync -= rwAsync\n                wAsync -= rwAsync\n\n                rSync_wAsync = min(rSync, wAsync)\n                rSync -= rSync_wAsync\n                wAsync -= rSync_wAsync\n\n                rAsync_wSync = min(rAsync, wSync)\n                rAsync -= rAsync_wSync\n                wSync -= rAsync_wSync\n\n                # update port counts for mem\n                rwSyncPorts += rwSync\n                rSyncPorts += rSync\n                wSyncPorts += wSync\n                rwAsyncPorts += rwAsync\n                rAsyncPorts += rAsync\n                wAsyncPorts += wAsync\n\n                rSync_wAsyncPorts += rSync_wAsync\n                rAsync_wSyncPorts += rAsync_wSync\n            k = ResourceRAM(m._dtype.element_t.bit_length(),\n                            int(m._dtype.size),\n                            rwSyncPorts, rSyncPorts, wSyncPorts,\n                            rSync_wAsyncPorts,\n                            rwAsyncPorts, rAsyncPorts, wAsyncPorts,\n                            rAsync_wSyncPorts)\n            res[k] = res.get(k, 0) + 1\n\n        self.memories.clear()\n\n        # remove register on read ports which will be merged into ram\n        if ff_to_remove:\n            ff_cnt = res[ResourceFF]\n            ff_cnt -= ff_to_remove\n            if ff_cnt:\n                res[ResourceFF] = ff_cnt\n            else:\n                del res[ResourceFF]\n"
  },
  {
    "path": "hwt/serializer/serializer_config.py",
    "content": "from hwt.serializer.generic.to_hdl_ast import ToHdlAst\n\n\nclass DummySerializerConfig():\n    \"\"\"\n    The serializer which does not do any additional code transformations\n    and does not produce any output. It is used to generate just internal representation\n    of RTL code.\n    \"\"\"\n    fileExtension = None\n    TO_HDL_AST = ToHdlAst\n    TO_HDL = None\n    TO_CONSTRAINTS = None\n"
  },
  {
    "path": "hwt/serializer/serializer_filter.py",
    "content": "from typing import Optional, Tuple\n\nfrom hwt.serializer.mode import _serializeExclude_eval\nfrom hwt.hwModule import HwModule\n\n\nclass SerializerFilter(object):\n    \"\"\"\n    Base class for filters used to exclude some :class:`hwt.hwModule.HwModule` instances from\n    target HDL (in order to prevent code duplication, archetype colisions etc.)\n\n    This base implementation keeps track about others objects and calls\n    _serializeDecision on the :class:`hwt.hwModule.HwModule` instance to decide if instance should be excluded.\n\n    :ivar serializedClasses: dict {moduleCls : moduleObj}\n    :ivar serializedConfiguredHwModules: (moduleCls, paramsValues) : moduleObj\n            where paramsValues are named tuple name:value\n    \"\"\"\n    def __init__(self):\n        self.serializedClasses = {}  # type: Type[HwModule]: HwModule\n        # (hwModuleCls, paramsValues) : unitObj\n        # where paramsValues are dict name:value\n        self.serializedConfiguredHwModules = {}\n\n    def do_serialize(self, module: HwModule) -> Tuple[bool, Optional[HwModule]]:\n        \"\"\"\n        Decide if this module should be serialized or not eventually fix name\n        to fit same already serialized module\n\n        :param module: object to serialize\n        \"\"\"\n        assert isinstance(module, HwModule)\n        sd = module._serializeDecision\n        if sd is None:\n            # the :class:`hwt.hwModule.HwModule` instance does not have any filter function\n            return True, None\n        else:\n            # use HwModuleInstance filer function\n            prevPriv = self.serializedClasses.get(module.__class__, None)\n            do_serialize, nextPriv, replacement = sd(module, prevPriv)\n            self.serializedClasses[module.__class__] = nextPriv\n            return do_serialize, replacement\n\n\nclass SerializerFilterAll(SerializerFilter):\n    \"\"\"\n    Ignore any serialization constraints and dump everything\n    \"\"\"\n    def do_serialize(self, module: HwModule) -> bool:\n        return True, None\n\n\nclass SerializerFilterDoNotExclude(SerializerFilter):\n    \"\"\"\n    Use all serialization specifications except @serializeExclude\n    Useful when it is required to dump all components for sim etc.\n    \"\"\"\n    def do_serialize(self, module: HwModule) -> bool:\n        orig = module._serializeDecision\n        if orig is _serializeExclude_eval:\n            module._serializeDecision = None\n        try:\n            return super(SerializerFilterDoNotExclude, self).do_serialize(module)\n        finally:\n            module._serializeDecision = orig\n"
  },
  {
    "path": "hwt/serializer/simModel/__init__.py",
    "content": "\"\"\"\nSim model serializer serialize HDL objects to simulation model writen in python.\nFor hwtSimApi.basic_rtl_simulator\n\"\"\"\nfrom hdlConvertorAst.to.basic_hdl_sim_model._main import ToBasicHdlSimModel\nfrom hwt.serializer.serializer_config import DummySerializerConfig\nfrom hwt.serializer.simModel.serializer import ToHdlAstSimModel\n\n\nclass SimModelSerializer(DummySerializerConfig):\n    fileExtension = '.py'\n    TO_HDL_AST = ToHdlAstSimModel\n    TO_HDL = ToBasicHdlSimModel\n"
  },
  {
    "path": "hwt/serializer/simModel/serializer.py",
    "content": "from copy import copy\nfrom typing import Optional, List\n\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlValueInt, HdlOp, \\\n    HdlOpType\nfrom hdlConvertorAst.hdlAst._statements import HdlStmIf, HdlStmAssign, \\\n    HdlStmProcess, HdlStmBlock\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDec, HdlModuleDef\nfrom hdlConvertorAst.to.basic_hdl_sim_model.keywords import SIMMODEL_KEYWORDS\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword, NameScope\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_getattr, \\\n    hdl_map_asoc, hdl_call\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.serializer.generic.constant_cache import ConstantCache\nfrom hwt.serializer.generic.to_hdl_ast import ToHdlAst\nfrom hwt.serializer.simModel.tmpVarConstructorConstOnly import TmpVarConstructorConstOnly\nfrom hwt.serializer.simModel.types import ToHdlAstSimModel_types\nfrom hwt.serializer.simModel.value import ToHdlAstSimModel_value\nfrom hwt.mainBases import RtlSignalBase\nfrom hwtSimApi.basic_hdl_simulator.sim_utils import sim_eval_cond\n\n\nclass ToHdlAstSimModel(ToHdlAstSimModel_value, ToHdlAstSimModel_types,\n                       ToHdlAst):\n    \"\"\"\n    Serializer which converts :class:`hwt.hwModule.HwModule` instances to simulator code\n    \"\"\"\n    _keywords_dict = {kw: LanguageKeyword() for kw in SIMMODEL_KEYWORDS}\n    SIM_EVAL_COND = HdlValueId(\"sim_eval_cond\", obj=sim_eval_cond)\n    C = HdlValueId(\"c\", obj=LanguageKeyword())\n    CVLD = HdlValueId(\"cVld\", obj=LanguageKeyword())\n    TMP_VAR_CONSTRUCTOR = TmpVarConstructorConstOnly\n\n    def __init__(self, name_scope: Optional[NameScope]=None):\n        super(ToHdlAstSimModel, self).__init__(name_scope)\n        self.currentHwModule = None\n        self.stm_outputs = {}\n\n    def as_hdl_HdlModuleDec(self, o: HdlModuleDec):\n        # convert types, exprs\n        # delete params because they should not be used in expressions and thus\n        # are useless\n        new_o = copy(o)\n        new_o.params = []\n        new_o.ports = [self.as_hdl_HdlPortItem(p) for p in o.ports]\n        return new_o\n\n    def as_hdl_PortConnection(self, o: HdlPortItem):\n        assert isinstance(o, HdlPortItem), o\n        intern, outer = o.getInternSig(), o.getOuterSig()\n        assert not intern._isUnnamedExpr, intern\n        assert not outer._isUnnamedExpr, outer\n        intern_hdl = HdlValueId(intern._name, obj=intern)\n        outer_hdl = HdlValueId(outer._name, obj=outer)\n        pm = hdl_map_asoc(intern_hdl, outer_hdl)\n        return pm\n\n    def as_hdl_HdlAssignmentContainer(self, a: HdlAssignmentContainer):\n        dst, dst_indexes, src = self._as_hdl_HdlAssignmentContainer_auto_conversions(a)\n        ev = HdlValueInt(int(a._event_dependent_from_branch == 0), None, None)\n        if dst_indexes is not None:\n            src = (src, dst_indexes, ev)\n        else:\n            src = (src, ev)\n        hdl_dst = hdl_getattr(hdl_getattr(self.SELF_IO, dst._name), \"val_next\")\n        hdl_a = HdlStmAssign(src, hdl_dst)\n        hdl_a.is_blocking = dst.virtual_only\n        return hdl_a\n\n    def as_hdl_IfContainer_out_invalidate_section(self,\n                                                  outputs: List[RtlSignalBase],\n                                                  parent: IfContainer):\n        outputInvalidateStms = []\n        for o in outputs:\n            # [TODO] look up indexes\n            indexes = None\n            v = o._dtype.from_py(None)\n            oa = HdlAssignmentContainer(v, o, indexes,\n                            virtual_only=True, parentStm=parent,\n                            event_dependent_from_branch=parent._event_dependent_from_branch)\n            outputInvalidateStms.append(self.as_hdl_HdlAssignmentContainer(oa))\n\n        if len(outputInvalidateStms) == 1:\n            return outputInvalidateStms[0]\n        else:\n            b = HdlStmBlock()\n            b.body = outputInvalidateStms\n            return b\n\n    def as_hdl_IfContainer_cond_eval(self, cond):\n        \"\"\"\n        constructs condition evaluation statement\n        c, cVld = sim_eval_cond(cond)\n        \"\"\"\n        c, cVld = self.C, self.CVLD\n        cond = self.as_hdl_cond(cond, True)\n        cond_eval = hdl_call(self.SIM_EVAL_COND, [cond])\n        cond_eval = HdlStmAssign(cond_eval, (c, cVld))\n        cond_eval.is_blocking = True\n        return c, cVld, cond_eval\n\n    def as_hdl_IfContainer(self, ifc: IfContainer) -> HdlStmIf:\n        \"\"\"\n        .. code-block:: python\n\n            if cond:\n                ...\n            else:\n                ...\n\n        will become\n\n        .. code-block:: python\n\n            c, cVld = sim_eval_cond(cond)\n            if not cVld:\n                # ivalidate outputs\n            elif c:\n                ... # original if true branch\n            else:\n                ... # original if else brach\n        \"\"\"\n        invalidate_block = self.as_hdl_IfContainer_out_invalidate_section(\n            ifc._outputs, ifc)\n        c, cVld, cond_eval = self.as_hdl_IfContainer_cond_eval(ifc.cond)\n        _if = HdlStmIf()\n        res = HdlStmBlock()\n        res.body = [cond_eval, _if]\n\n        _if.cond = HdlOp(HdlOpType.NEG_LOG, [cVld, ])\n        _if.if_true = invalidate_block\n\n        if_true = self.as_hdl_statements(ifc.ifTrue)\n        _if.elifs.append((c, if_true))\n        elifs = iter(ifc.elIfs)\n        for eif_c, eif_stms in elifs:\n            c, cVld, cond_eval = self.as_hdl_IfContainer_cond_eval(eif_c)\n            newIf = HdlStmIf()\n            newIf.cond = HdlOp(HdlOpType.NEG_LOG, [cVld, ])\n            newIf.if_true = invalidate_block\n\n            if_true = self.as_hdl_statements(eif_stms)\n            newIf.elifs.append((c, if_true))\n\n            _if.if_false = HdlStmBlock()\n            _if.if_false.body = [cond_eval, newIf]\n            _if = newIf\n\n        _if.if_false = self.as_hdl_statements(ifc.ifFalse)\n\n        return res\n\n    def as_hdl_SwitchContainer(self, sw: SwitchContainer) -> HdlStmIf:\n        \"switch -> if\"\n        switchOn = sw.switchOn\n\n        def mkCond(c):\n            return switchOn._eq(c)\n\n        elIfs = []\n\n        for key, statements in sw.cases[1:]:\n            elIfs.append((mkCond(key), statements))\n        ifFalse = sw.default\n\n        topCond = mkCond(sw.cases[0][0])\n        topIf = IfContainer(topCond,\n                            ifTrue=sw.cases[0][1],\n                            ifFalse=ifFalse,\n                            elIfs=elIfs)\n\n        topIf._sensitivity = sw._sensitivity\n        topIf._inputs = sw._inputs\n        topIf._outputs = sw._outputs\n\n        return self.as_hdl_IfContainer(topIf)\n\n    def sensitivityListItem(self, item, anyEventDependent):\n        if isinstance(item, HOperatorNode):\n            op = item.operator\n            if op == HwtOps.RISING_EDGE:\n                sens = HdlOpType.RISING\n            elif op == HwtOps.FALLING_EDGE:\n                sens = HdlOpType.FALLING\n            else:\n                raise TypeError(\"This is not an event sensitivity\", op)\n\n            return HdlOp(sens, [HdlValueId(item.operands[0]._name)])\n        else:\n            return HdlValueId(item._name)\n\n    def has_to_be_process(self, proc):\n        return True\n\n    def can_pop_process_wrap(self, statements, hasToBeVhdlProcess):\n        return False\n\n    def as_hdl_HdlStmCodeBlockContainer(self, proc: HdlStmCodeBlockContainer) -> HdlStmProcess:\n        p = ToHdlAst.as_hdl_HdlStmCodeBlockContainer(self, proc)\n        self.stm_outputs[p] = sorted(\n            [HdlValueId(o._name, obj=o)\n             for o in proc._outputs]\n        )\n        return p\n\n    def as_hdl_extraVarsInit(self, extraVars):\n        return []\n\n    def _as_hdl_HdlModuleDef_body(self, *args) -> HdlModuleDef:\n        orig_const_cache = self.constCache\n        try:\n            self.constCache = ConstantCache(self, self.tmpVars)\n            return ToHdlAst._as_hdl_HdlModuleDef_body(self, *args)\n        finally:\n            self.constCache = orig_const_cache\n"
  },
  {
    "path": "hwt/serializer/simModel/tmpVarConstructorConstOnly.py",
    "content": "from hwt.serializer.generic.tmpVarConstructor import TmpVarConstructor\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass TmpVarConstructorConstOnly(TmpVarConstructor):\n\n    def finish_var_init(self, var: RtlSignal):\n        hdl = self.extraVarsHdl\n        as_hdl = self.toHdlAst.as_hdl_HdlSignalItem(var, declaration=True)\n        hdl.append(as_hdl)\n\n    def sort_hdl_declarations_first(self):\n        pass  # always sorted\n"
  },
  {
    "path": "hwt/serializer/simModel/types.py",
    "content": "from hdlConvertorAst.hdlAst import HdlValueId, HdlValueInt\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call, \\\n    hdl_getattr\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.slice import HSlice\nfrom pyMathBitPrecise.bits3t import Bits3t\n\n\nclass ToHdlAstSimModel_types():\n    \"\"\"\n    part of ToHdlAstSimModel responsible for type serialization\n    \"\"\"\n    SELF = HdlValueId(\"self\", obj=LanguageKeyword())\n    BITS3T = HdlValueId(\"Bits3t\", obj=Bits3t)\n    SLICE = HdlValueId(\"slice\", obj=slice)\n\n    def as_hdl_HdlType_bits(self, typ: HBits, declaration=False):\n        assert not declaration\n        w = typ.bit_length()\n        if isinstance(w, int):\n            pass\n        else:\n            w = int(w)\n\n        return hdl_call(self.BITS3T, [HdlValueInt(w, None, None),\n                                      HdlValueInt(int(bool(typ.signed)), None, None)])\n\n    def as_hdl_HdlType_slice(self, typ: HSlice, declaration=False):\n        if declaration:\n            raise NotImplementedError()\n        else:\n            return self.SLICE\n\n    def as_hdl_HdlType_array(self, typ, declaration=False):\n        if declaration:\n            return super(ToHdlAstSimModel_types, self).as_hdl_HdlType_array(typ, declaration=declaration)\n        else:\n            t_name = self.name_scope.get_object_name(typ)\n            return hdl_getattr(self.SELF, t_name)\n\n    def as_hdl_HdlType_enum(self, typ, declaration=False):\n        if declaration:\n            return super(ToHdlAstSimModel_types, self).as_hdl_HdlType_enum(typ, declaration=True)\n        else:\n            t_name = self.name_scope.get_object_name(typ)\n            return hdl_getattr(self.SELF, t_name)\n"
  },
  {
    "path": "hwt/serializer/simModel/value.py",
    "content": "from typing import Union\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOp, HdlOpType\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call, \\\n    hdl_getattr\nfrom hwt.code import Concat\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import BIT\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.enumConst import HEnumConst\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.generic.ops import HWT_TO_HDLCONVERTOR_OPS\nfrom hwt.serializer.generic.value import ToHdlAst_Value\nfrom pyMathBitPrecise.array3t import Array3val\nfrom pyMathBitPrecise.bits3t import Bits3val, Bits3t, bitsBitOp__lshr, \\\n    bitsBitOp__rol, bitsBitOp__ror, bitsBitOp__ashr\n\nzero, one = BIT.from_py(0), BIT.from_py(1)\n\n\nclass ToHdlAstSimModel_value(ToHdlAst_Value):\n    Bits3val = HdlValueId(\"Bits3val\", obj=Bits3val)\n    Bits3t = HdlValueId(\"Bits3t\", obj=Bits3t)\n    SELF = HdlValueId(\"self\", obj=LanguageKeyword())\n    Array3val = HdlValueId(\"Array3val\", obj=Array3val)\n    SLICE = HdlValueId(\"slice\", obj=slice)\n    TRUE = HdlValueId(\"True\", obj=True)\n    FALSE = HdlValueId(\"False\", obj=False)\n    Bits3val = HdlValueId(\"Bits3val\", obj=Bits3val)\n    ABits3t = HdlValueId(\"Bits3t\", obj=Bits3t)\n    SELF_IO = hdl_getattr(HdlValueId(\"self\", obj=LanguageKeyword()), \"io\")\n    CONCAT = HdlValueId(\"Concat\", obj=Concat)\n    FN_bitsBitOp__ashr = HdlValueId(\"bitsBitOp__ashr\", obj=bitsBitOp__ashr)\n    FN_bitsBitOp__lshr = HdlValueId(\"bitsBitOp__lshr\", obj=bitsBitOp__lshr)\n    FN_bitsBitOp__rol = HdlValueId(\"bitsBitOp__rol\", obj=bitsBitOp__rol)\n    FN_bitsBitOp__ror = HdlValueId(\"bitsBitOp__ror\", obj=bitsBitOp__ror)\n\n    op_transl_dict = {\n        **HWT_TO_HDLCONVERTOR_OPS,\n        HwtOps.INDEX: HdlOpType.INDEX,\n    }\n    _cast_ops = {\n        HwtOps.BitsAsSigned,\n        HwtOps.BitsAsUnsigned,\n        HwtOps.BitsAsVec,\n    }\n\n    def is_suitable_for_const_extract(self, val: HConst):\n        return not isinstance(val._dtype, HEnum) or val.vld_mask == 0\n\n    @override\n    def as_hdl_HdlSignalItem(self, si: Union[HdlSignalItem, HdlIdDef],\n                          declaration=False):\n        if not declaration and not si._isUnnamedExpr:\n            if si._const:\n                return hdl_getattr(self.SELF, si._name)\n            else:\n                return hdl_getattr(hdl_getattr(self.SELF_IO, si._name), \"val\")\n        else:\n            return super(ToHdlAstSimModel_value, self).as_hdl_HdlSignalItem(\n                si, declaration=declaration)\n\n    @override\n    def as_hdl_HBitsConst(self, val: HBitsConst):\n        dtype = val._dtype\n        as_hdl_int = self.as_hdl_int\n        t = hdl_call(self.Bits3t, [\n            as_hdl_int(dtype.bit_length()), as_hdl_int(int(bool(dtype.signed)))])\n        return hdl_call(self.Bits3val, [t,\n                                        as_hdl_int(val.val),\n                                        as_hdl_int(val.vld_mask)])\n\n    def as_hdl_HDictConst(self, val):\n        return {\n            self.as_hdl_int(int(k)): self.as_hdl_Value(v)\n            for k, v in val.items()\n        }\n\n    @override\n    def as_hdl_HArrayConst(self, val):\n        return hdl_call(self.Array3val, [\n            self.as_hdl_HdlType(val._dtype),\n            self.as_hdl_HDictConst(val.val),\n            self.as_hdl_int(val.vld_mask)\n        ])\n\n    @override\n    def as_hdl_HSliceConst(self, val):\n        args = (\n            val.val.start,\n            val.val.stop,\n            val.val.step\n        )\n        return hdl_call(self.SLICE, [self.as_hdl_int(int(a)) for a in args])\n\n    @override\n    def as_hdl_HEnumConst(self, val: HEnumConst):\n        t_name = self.name_scope.get_object_name(val._dtype)\n        if val.vld_mask:\n            name = self.name_scope.get_object_name(val)\n            return hdl_getattr(hdl_getattr(self.SELF, t_name), name)\n        else:\n            return hdl_call(hdl_getattr(hdl_getattr(self.SELF, t_name), \"from_py\"),\n                            [None, ])\n\n    @override\n    def as_hdl_HOperatorNode(self, op: HOperatorNode):\n        ops = op.operands\n        o = op.operator\n\n        if o == HwtOps.EQ:\n            op0 = self.as_hdl_Value(ops[0])\n            op1 = self.as_hdl_Value(ops[1])\n            return hdl_call(hdl_getattr(op0, \"_eq\"), [op1, ])\n        elif o == HwtOps.TERNARY:\n            if ops[1] == one and ops[2] == zero:\n                # ignore redundant x ? 1 : 0\n                return self.as_hdl_cond(ops[0], True)\n            else:\n                op0 = self.as_hdl_cond(ops[0], True)\n                op1 = self.as_hdl_Value(ops[1])\n                op2 = self.as_hdl_Value(ops[2])\n                return hdl_call(hdl_getattr(op0, \"_ternary\"), [op1, op2])\n        elif o == HwtOps.RISING_EDGE or o == HwtOps.FALLING_EDGE:\n            if o == HwtOps.RISING_EDGE:\n                fn = \"_onRisingEdge\"\n            else:\n                fn = \"_onFallingEdge\"\n            op0 = self.as_hdl_Value(ops[0])\n            # pop .val\n            op0 = op0.ops[0]\n            return hdl_call(hdl_getattr(op0, fn), [])\n        elif o in self._cast_ops:\n            op0, = ops\n            do_cast = bool(op0._dtype.signed) != bool(op.result._dtype.signed)\n\n            op_hdl = self.as_hdl_Value(op0)\n            if do_cast:\n                if bool(op.result._dtype.signed):\n                    sign = self.TRUE\n                else:\n                    sign = self.FALSE\n                return hdl_call(hdl_getattr(op_hdl, \"_cast_sign\"), [sign, ])\n            else:\n                return op_hdl\n        elif o == HwtOps.CONCAT:\n            return hdl_call(hdl_getattr(self.as_hdl_Value(ops[0]), \"_concat\"),\n                            [self.as_hdl_Value(ops[1]), ])\n        elif o == HwtOps.ZEXT or o == HwtOps.SEXT or o == HwtOps.TRUNC:\n            v, newWidth = ops\n            newWidth = int(newWidth)\n            v = self.as_hdl_Value(v)\n            op1 = self.as_hdl_int(newWidth)\n            fnName = \"_zext\" if o == HwtOps.ZEXT else \\\n                     \"_sext\" if o == HwtOps.SEXT else \\\n                     \"_trunc\"\n            return hdl_call(hdl_getattr(v, fnName), [op1, ])\n            \n        elif o == HwtOps.EQ:\n            return hdl_call(hdl_getattr(self.as_hdl_Value(ops[0]), \"_eq\"),\n                            [self.as_hdl_Value(ops[1]), ])\n        else:\n            _o = o.hdlConvertoAstOp\n            if _o is None:\n                o = self.op_transl_dict[o]\n            else:\n                o = _o\n\n            if o == HdlOpType.SRL and isinstance(ops[0]._dtype, HBits):\n                return hdl_call(self.FN_bitsBitOp__lshr,\n                            [self.as_hdl_Value(o2) for o2 in ops])\n            elif o == HdlOpType.SRA and isinstance(ops[0]._dtype, HBits):\n                return hdl_call(self.FN_bitsBitOp__ashr,\n                            [self.as_hdl_Value(o2) for o2 in ops])\n            elif o == HdlOpType.ROL and isinstance(ops[0]._dtype, HBits):\n                return hdl_call(self.FN_bitsBitOp__rol,\n                            [self.as_hdl_Value(o2) for o2 in ops])\n            elif o == HdlOpType.ROR and isinstance(ops[0]._dtype, HBits):\n                return hdl_call(self.FN_bitsBitOp__ror,\n                            [self.as_hdl_Value(o2) for o2 in ops])\n\n            return HdlOp(o, [self.as_hdl_Value(o2)\n                               for o2 in ops])\n"
  },
  {
    "path": "hwt/serializer/store_manager.py",
    "content": "from io import StringIO\nimport os\nfrom typing import Type, Optional, Union\n\nfrom hdlConvertorAst.hdlAst import HdlModuleDef\nfrom hdlConvertorAst.hdlAst._bases import iHdlObj\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDec\nfrom hdlConvertorAst.translate.common.name_scope import NameScope\nfrom hwt.hwModule import HdlConstraintList\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.serializer.serializer_config import DummySerializerConfig\nfrom hwt.serializer.serializer_filter import SerializerFilter\n\n\nclass StoreManager(object):\n    \"\"\"\n    A base class for an objects which manage\n    how the output of the serialization is stored by serializer_cls\n    \"\"\"\n\n    def __init__(self,\n                 serializer_cls: DummySerializerConfig,\n                 _filter: Type[\"SerializerFilter\"]=None,\n                 name_scope: Optional[NameScope]=None):\n        self.serializer_cls = serializer_cls\n        self.as_hdl_ast = serializer_cls.TO_HDL_AST(name_scope=name_scope)\n        self.name_scope = self.as_hdl_ast.name_scope\n        if _filter is None:\n            _filter = SerializerFilter()\n        self.filter = _filter\n\n    def hierarchy_push(self, obj: Union[HdlModuleDec, HdlModuleDef]) -> NameScope:\n        c = self.name_scope.level_push(obj.name)\n        self.name_scope = c\n        return c\n\n    def hierarchy_pop(self, obj: Union[HdlModuleDec, HdlModuleDef]) -> NameScope:\n        p = self.name_scope.parent\n        assert p is not None\n        self.name_scope = p\n        return p\n\n    def write(self, obj: Union[iHdlObj, HdlConstraintList]):\n        pass\n\n\nclass SaveToStream(StoreManager):\n    \"\"\"\n    Store all produced code to an output stream\n    \"\"\"\n\n    def __init__(self,\n                 serializer_cls: DummySerializerConfig,\n                 stream: StringIO,\n                 _filter: \"SerializerFilter\"=None,\n                 name_scope: Optional[NameScope]=None):\n        super(SaveToStream, self).__init__(\n            serializer_cls, _filter=_filter, name_scope=name_scope)\n        self.stream = stream\n        ser = self.ser = self.serializer_cls.TO_HDL(self.stream)\n        if hasattr(ser, \"stm_outputs\"):\n            ser.stm_outputs = self.as_hdl_ast.stm_outputs\n\n    def write(self, obj: Union[iHdlObj, HdlConstraintList]):\n        self.as_hdl_ast.name_scope = self.name_scope\n        if isinstance(obj, HdlConstraintList):\n            if self.serializer_cls.TO_CONSTRAINTS is not None:\n                to_constr = self.serializer_cls.TO_CONSTRAINTS(self.stream)\n                to_constr.visit_HdlConstraintList(obj)\n        else:\n            hdl = self.as_hdl_ast.as_hdl(obj)\n            self.ser.visit_iHdlObj(hdl)\n\n\nclass SaveToFilesFlat(StoreManager):\n    \"\"\"\n    Store all produced code to a single directory, file per component.\n    \"\"\"\n\n    def __init__(self,\n                 serializer_cls: DummySerializerConfig,\n                 root: str,\n                 _filter: \"SerializerFilter\"=None,\n                 name_scope: Optional[NameScope]=None):\n        super(SaveToFilesFlat, self).__init__(\n            serializer_cls, _filter=_filter, name_scope=name_scope)\n        self.root = root\n        self.files = SetList()\n        self.module_path_prefix = None\n        os.makedirs(root, exist_ok=True)\n\n    def write(self, obj: Union[iHdlObj, HdlConstraintList]):\n        if isinstance(obj, HdlConstraintList):\n            f_name = \"constraints\" + self.serializer_cls.TO_CONSTRAINTS.fileExtension\n        else:\n            if isinstance(obj, HdlModuleDef):\n                name = obj.module_name.val\n            else:\n                name = obj.name\n            f_name = name + self.serializer_cls.fileExtension\n\n        fp = os.path.join(self.root, f_name)\n        if fp in self.files:\n            m = 'a'\n        else:\n            m = 'w'\n            self.files.append(fp)\n\n        with open(fp, m) as f:\n            s = SaveToStream(self.serializer_cls, f,\n                             self.filter, self.name_scope)\n            s.ser.module_path_prefix = self.module_path_prefix\n            s.write(obj)\n\n\nclass SaveToSingleFiles(StoreManager):\n    \"\"\"\n    Store all produced code to a single directory, all component source code to single file\n    and all constrains to single file.\n    \"\"\"\n\n    def __init__(self,\n                 serializer_cls: DummySerializerConfig,\n                 root: str,\n                 name: str,\n                 _filter: \"SerializerFilter\"=None,\n                 name_scope: Optional[NameScope]=None):\n        super(SaveToSingleFiles, self).__init__(\n            serializer_cls, _filter=_filter, name_scope=name_scope)\n        self.root = root\n        self.comp_name = name\n        self.file_const = os.path.join(self.root, self.comp_name + self.serializer_cls.TO_CONSTRAINTS.fileExtension)\n        self.file_src = os.path.join(self.root, self.comp_name + self.serializer_cls.fileExtension)\n        self.files = SetList()\n        self.module_path_prefix = None\n        os.makedirs(root, exist_ok=True)\n\n    def write(self, obj: Union[iHdlObj, HdlConstraintList]):\n        if isinstance(obj, HdlConstraintList):\n            f_name = self.file_const\n        else:\n            f_name = self.file_src\n\n        if f_name not in self.files:\n            m = 'w'\n            self.files.append(f_name)\n        else:\n            m = 'a'\n\n        with open(f_name, m) as f:\n            s = SaveToStream(self.serializer_cls, f,\n                             self.filter, self.name_scope)\n            s.ser.module_path_prefix = self.module_path_prefix\n            s.write(obj)\n"
  },
  {
    "path": "hwt/serializer/systemC/__init__.py",
    "content": "\"\"\"\nSystemC serializer serializes HDL objects to systemC code.\n\"\"\"\nfrom hdlConvertorAst.to.systemc._main import ToSystemc\nfrom hwt.serializer.serializer_config import DummySerializerConfig\nfrom hwt.serializer.systemC.serializer import ToHdlAstSystemC\nfrom hwt.serializer.xdc.serializer import XdcSerializer\n\n\nclass SystemCSerializer(DummySerializerConfig):\n    fileExtension = '.cpp'\n    TO_HDL_AST = ToHdlAstSystemC\n    TO_HDL = ToSystemc\n    TO_CONSTRAINTS = XdcSerializer\n"
  },
  {
    "path": "hwt/serializer/systemC/expr.py",
    "content": "from typing import Union\n\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOp, HdlOpType\nfrom hdlConvertorAst.to.hdlUtils import bit_string\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call, \\\n    hdl_getattr\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.types.bitConstFunctions import AnyHBitsValue\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import SLICE\nfrom hwt.hdl.types.enumConst import HEnumConst\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.pyUtils.typingFuture import override\nfrom hwt.serializer.generic.value import ToHdlAst_Value\nfrom hwt.serializer.hwt.ops import ToHdlAstHwt_ops\nfrom hwt.serializer.systemC.utils import systemCTypeOfSig\nfrom hwt.serializer.verilog.context import SignalTypeSwap\nfrom hwt.serializer.verilog.ops import ToHdlAstVerilog_ops\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass ToHdlAstSystemC_expr(ToHdlAst_Value):\n    static_cast = HdlValueId(\"static_cast\", obj=LanguageKeyword())\n    op_transl_dict = ToHdlAstVerilog_ops.op_transl_dict\n\n    def as_hdl_Value(self, v):\n        if isinstance(v, tuple):\n            return tuple((self.as_hdl(o2) for o2 in v))\n        return super(ToHdlAstSystemC_expr, self).as_hdl_Value(v)\n\n    def as_hdl_operand(self, operand: Union[RtlSignal, HConst], i: int,\n                       operator: HOperatorNode):\n        return self.as_hdl(operand)\n\n    def as_hdl_HOperatorNode_INDEX(self, op: HOperatorNode):\n        ops = op.operands\n        assert len(ops) == 2\n        o0, o1 = ops\n        if o1._dtype == SLICE:\n            # index to .range(x, y)\n            o0_hdl = self.as_hdl_operand(o0, 0, op)\n            o0_hdl = hdl_getattr(o0_hdl, \"range\")\n            return hdl_call(o0_hdl, [self.as_hdl_Value(o1.val.start),\n                                     self.as_hdl_Value(o1.val.stop)])\n        else:\n            op0_t = ops[0]._dtype\n            if isinstance(op0_t, HBits) and op0_t.bit_length() == 1 and not op0_t.force_vector:\n                assert int(ops[1]) == 0, ops\n                # drop whole index operator when indexing on 1b vector\n                return self.as_hdl_operand(ops[0], 0, op)\n\n            _o = self.op_transl_dict[op.operator]\n            res = HdlOp(_o, [self.as_hdl_operand(o2, i, op)\n                              for i, o2 in enumerate(ops)])\n\n            op0_t = ops[0]._dtype\n            if isinstance(op0_t, HBits) and op0_t.signed:\n                # cast to signed if necesary\n                t = self.as_hdl_HdlType(op.result._dtype)\n                return hdl_call(\n                    HdlOp(HdlOpType.PARAMETRIZATION, [self.static_cast, t]), [res, ])\n\n            return res\n\n    def as_hdl_HOperatorNode_BITSCAST(self, op: HOperatorNode):\n\n        ops = op.operands\n        if op.operator == HwtOps.TRUNC:\n            assert len(ops) == 2, ops\n        else:\n            assert len(ops) == 1, ops\n        t = self.as_hdl_HdlType(op.result._dtype)\n        return hdl_call(\n            HdlOp(HdlOpType.PARAMETRIZATION, [self.static_cast, t]),\n            [self.as_hdl_Value(ops[0]), ])\n\n    def as_hdl_HOperatorNode_TERNARY(self, op: HOperatorNode, ops: list[AnyHBitsValue]):\n        return ToHdlAstVerilog_ops.as_hdl_HOperatorNode_TERNARY(self, op, ops)\n\n    def as_hdl_HOperatorNode(self, op: HOperatorNode):\n        ops = op.operands\n        o = op.operator\n\n        if o == HwtOps.INDEX:\n            return self.as_hdl_HOperatorNode_INDEX(op)\n        elif o in ToHdlAstHwt_ops._cast_ops or o == HwtOps.TRUNC:\n            return self.as_hdl_HOperatorNode_BITSCAST(op)\n        elif o == HwtOps.CONCAT:\n            isNew, o = self.tmpVars.create_var_cached(\"tmpConcat_\",\n                                                      op.result._dtype,\n                                                      postponed_init=True,\n                                                      extra_args=(HwtOps.CONCAT, op.result))\n            if isNew:\n                o._rtlDrivers.append(HdlAssignmentContainer(op, o, virtual_only=True))\n                self.tmpVars.finish_var_init(o)\n\n            return self.as_hdl(o)\n\n        elif o == HwtOps.SEXT or o == HwtOps.ZEXT:\n            t = self.as_hdl_HdlType(op.result._dtype)\n            isSigned = op.result._dtype.signed\n            isSignedExt = o == HwtOps.SEXT\n            _op0 = self.as_hdl_Value(ops[0])\n            if isSignedExt != bool(isSigned):\n                # must cast first to signed, then to larger result type\n                # the sign/unsigned ext is driven by src type\n                # https://docs.oracle.com/cd/E19205-01/819-5265/bjamz/index.html\n                signFixedTy = self.as_hdl_HdlType(ops[0]._dtype._createMutated(signed=isSignedExt))\n                _op0 = hdl_call(\n                    HdlOp(HdlOpType.PARAMETRIZATION, [self.static_cast, signFixedTy]),\n                    [_op0, ])\n\n            res = hdl_call(\n                HdlOp(HdlOpType.PARAMETRIZATION, [self.static_cast, t]),\n                [_op0, ])\n\n            return res\n\n        else:\n            return ToHdlAstVerilog_ops.as_hdl_HOperatorNode(self, op)\n\n    @override\n    def as_hdl_HdlSignalItem(self, si: HdlSignalItem, declaration=False):\n        if declaration:\n            sigType = systemCTypeOfSig(si)\n            with SignalTypeSwap(self, sigType):\n                return ToHdlAst_Value.as_hdl_HdlSignalItem(self, si, declaration=True)\n        else:\n            if si._isUnnamedExpr and si._rtlObjectOrigin is not None:\n                return self.as_hdl(si._rtlObjectOrigin)\n            else:\n                sigType = systemCTypeOfSig(si)\n                _si = HdlValueId(si._name, obj=si)\n                if self._in_sensitivity_list or self._is_target or sigType is SIGNAL_TYPE.REG:\n                    return _si\n                else:\n                    return hdl_call(hdl_getattr(_si, \"read\"), [])\n\n    def as_hdl_HBitsConst(self, val):\n        t = val._dtype\n        w = t.bit_length()\n        _v = bit_string(val.val, w, val.vld_mask)\n        t = self.as_hdl_HdlType_bits(HBits(w, signed=t.signed))\n        return hdl_call(t, [_v, ])\n\n    def as_hdl_HEnumConst(self, val: HEnumConst):\n        i = val._dtype._allValues.index(val.val)\n        assert i >= 0\n        return self.as_hdl_int(i)\n\n    def as_hdl_HArrayConst(self, val):\n        return [self.as_hdl_Value(v) for v in val]\n"
  },
  {
    "path": "hwt/serializer/systemC/serializer.py",
    "content": "from copy import copy\nfrom typing import Optional\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOp, HdlOpType\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDec, HdlCompInst\nfrom hdlConvertorAst.to.systemc.keywords import SYSTEMC_KEYWORDS\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword, NameScope\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hwIOs.std import HwIOClk\nfrom hwt.serializer.generic.to_hdl_ast import ToHdlAst, \\\n    HWT_TO_HDLCONVEROTR_DIRECTION\nfrom hwt.serializer.simModel.serializer import ToHdlAstSimModel\nfrom hwt.serializer.systemC.expr import ToHdlAstSystemC_expr\nfrom hwt.serializer.systemC.statements import ToHdlAstSystemC_statements\nfrom hwt.serializer.systemC.type import ToHdlAstSystemC_type\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass ToHdlAstSystemC(ToHdlAstSystemC_expr, ToHdlAstSystemC_type,\n                      ToHdlAstSystemC_statements,\n                      ToHdlAst):\n    \"\"\"\n    Serialized used to convert HWT design to SystemC code\n    \"\"\"\n    _keywords_dict = {kw: LanguageKeyword() for kw in SYSTEMC_KEYWORDS}\n    sc_in_clk = HdlValueId(\"sc_in_clk\", obj=LanguageKeyword())\n    sc_out_clk = HdlValueId(\"sc_out_clk\", obj=LanguageKeyword())\n    sc_inout_clk = HdlValueId(\"sc_inout_clk\", obj=LanguageKeyword())\n    sc_in = HdlValueId(\"sc_in\", obj=LanguageKeyword())\n    sc_out = HdlValueId(\"sc_out\", obj=LanguageKeyword())\n    sc_inout = HdlValueId(\"sc_inout\", obj=LanguageKeyword())\n\n    def __init__(self, name_scope: Optional[NameScope]=None):\n        ToHdlAst.__init__(self, name_scope=name_scope)\n        self._is_target = False\n        self._in_sensitivity_list = False\n        self.signalType = None\n\n    def as_hdl_HdlModuleDec(self, o: HdlModuleDec):\n        return ToHdlAstSimModel.as_hdl_HdlModuleDec(self, o)\n\n    def as_hdl_HdlPortItem(self, o: HdlPortItem):\n        i = o.getInternSig()._hwIO\n        d = o.direction\n        if isinstance(i, HwIOClk):\n            assert i._dtype.bit_length() == 1, i\n            if d == DIRECTION.IN:\n                t = self.sc_in_clk\n            elif d == DIRECTION.OUT:\n                t = self.sc_out_clk\n            elif d == DIRECTION.INOUT:\n                t = self.sc_inout_clk\n            else:\n                raise ValueError(d)\n        else:\n            if d == DIRECTION.IN:\n                pt = self.sc_in\n            elif d == DIRECTION.OUT:\n                pt = self.sc_out\n            elif d == DIRECTION.INOUT:\n                pt = self.sc_inout\n            else:\n                raise ValueError(d)\n            t = self.as_hdl_HdlType(o._dtype)\n            t = HdlOp(HdlOpType.PARAMETRIZATION, [pt, t])\n\n        var = HdlIdDef()\n        var.direction = HWT_TO_HDLCONVEROTR_DIRECTION[o.direction]\n        s = o.getInternSig()\n        var.name = s._name\n        var.origin = o\n        var.type = t\n        return var\n\n    def as_hdl_HdlCompInst(self, o: HdlCompInst) -> HdlCompInst:\n        new_o = copy(o)\n        new_o.param_map = []\n\n        orig_is_target = self._is_target\n        try:\n            self._is_target = True\n            port_map = []\n            for pi in o.port_map:\n                pm = self.as_hdl_PortConnection(pi)\n                port_map.append(pm)\n            new_o.port_map = port_map\n        finally:\n            self._is_target = orig_is_target\n\n        return new_o\n"
  },
  {
    "path": "hwt/serializer/systemC/statements.py",
    "content": "from hdlConvertorAst.hdlAst._bases import iHdlStatement\nfrom hdlConvertorAst.hdlAst._statements import HdlStmAssign, HdlStmCase, \\\n    HdlStmBlock, HdlStmBreak\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_getattr, \\\n    hdl_call\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.serializer.exceptions import SerializerException\nfrom hwt.serializer.systemC.utils import systemCTypeOfSig\nfrom hwt.serializer.verilog.value import ToHdlAstVerilog_Value\n\n\nclass ToHdlAstSystemC_statements():\n\n    def has_to_be_process(self, proc: iHdlStatement):\n        return True\n\n    def can_pop_process_wrap(self, statements, hasToBeVhdlProcess):\n        return False\n\n    def sensitivityListItem(self, item, anyIsEventDependent):\n        orig_in_sensitivity_list = self._in_sensitivity_list\n        try:\n            self._in_sensitivity_list = True\n            return ToHdlAstVerilog_Value.sensitivityListItem(\n                self, item, anyIsEventDependent)\n        finally:\n            self._in_sensitivity_list = orig_in_sensitivity_list\n\n    def as_hdl_SwitchContainer(self, sw: SwitchContainer) -> HdlStmCase:\n        \"\"\"\n        Same as parent as_hdl_SwitchContainer but add \"break\" to all cases\n        \"\"\"\n        sw_hdl = super(ToHdlAstSystemC_statements, self).as_hdl_SwitchContainer(sw)\n        new_cases = []\n        for c, stm in sw_hdl.cases:\n            if not isinstance(stm, HdlStmBlock):\n                _stm = HdlStmBlock()\n                _stm.body.append(stm)\n                stm = _stm\n\n            stm.body.append(HdlStmBreak())\n            new_cases.append((c, stm))\n        sw_hdl.cases = new_cases\n        return sw_hdl\n\n    @internal\n    def _as_hdl_HdlAssignmentContainer(self, dst, typeOfDst, src):\n\n        orig_is_target = self._is_target\n        try:\n            self._is_target = True\n            dst_hdl = self.as_hdl(dst)\n        finally:\n            self._is_target = orig_is_target\n\n        src_hdl = self.as_hdl_Value(src)\n        if typeOfDst == SIGNAL_TYPE.REG:\n            return HdlStmAssign(src_hdl, dst_hdl)\n        else:\n            return hdl_call(hdl_getattr(dst_hdl, \"write\"), [src_hdl, ])\n\n    def as_hdl_HdlAssignmentContainer(self, a: HdlAssignmentContainer):\n        dst = a.dst\n        assert isinstance(dst, HdlSignalItem)\n        # assert not dst.virtual_only, \"should not be required\"\n\n        if a.indexes is not None:\n            for i in a.indexes:\n                dst = dst[i]\n\n        typeOfDst = systemCTypeOfSig(dst)\n        if dst.virtual_only and isinstance(a.src, HOperatorNode):\n            assert a.src.operator == HwtOps.CONCAT\n            return self._as_hdl_HdlAssignmentContainer(dst, typeOfDst, a.src.operands)\n\n        if dst._dtype == a.src._dtype or (\n                isinstance(dst._dtype, HBits) and a.src._dtype == BOOL):\n            return self._as_hdl_HdlAssignmentContainer(dst, typeOfDst, a.src)\n        else:\n            raise SerializerException(\"%r <= %r  is not valid assignment\\n\"\n                                      \" because types are different (%r; %r) \"\n                                      % (dst, a.src, dst._dtype, a.src._dtype))\n"
  },
  {
    "path": "hwt/serializer/systemC/type.py",
    "content": "from hdlConvertorAst.hdlAst._expr import HdlOp, HdlOpType, HdlValueId\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_index\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import FLOAT64\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.hdlType import MethodNotOverloaded\nfrom hwt.serializer.verilog.types import ToHdlAstVerilog_types\n\n\nclass ToHdlAstSystemC_type():\n    sc_int = HdlValueId(\"sc_int\", obj=LanguageKeyword())\n    sc_uint = HdlValueId(\"sc_uint\", obj=LanguageKeyword())\n    sc_bigint = HdlValueId(\"sc_bigint\", obj=LanguageKeyword())\n    sc_biguint = HdlValueId(\"sc_biguint\", obj=LanguageKeyword())\n    sc_signal = HdlValueId(\"sc_signal\", obj=LanguageKeyword())\n    STRING = HdlOp(HdlOpType.DOUBLE_COLON, HdlValueId(\"string\", obj=LanguageKeyword()))\n\n    def does_type_requires_extra_def(self, t, other_types):\n        try:\n            return t._as_hdl_requires_def(self, other_types)\n        except MethodNotOverloaded:\n            pass\n        return False\n\n    def as_hdl_HdlType_str(self, typ, declaration=False):\n        assert not declaration\n        return self.STRING\n\n    def as_hdl_HdlType_bits(self, typ: HBits, declaration=False):\n        if declaration:\n            raise NotImplementedError()\n\n        w = typ.bit_length()\n\n        if w <= 64:\n            if typ.signed:\n                typeBaseName = self.sc_int\n            else:\n                typeBaseName = self.sc_uint\n        else:\n            if typ.signed:\n                typeBaseName = self.sc_bigint\n            else:\n                typeBaseName = self.sc_biguint\n\n        t = HdlOp(HdlOpType.PARAMETRIZATION,\n                    [typeBaseName, self.as_hdl_int(w)])\n        if self.signalType == SIGNAL_TYPE.WIRE:\n            t = HdlOp(HdlOpType.PARAMETRIZATION, [self.sc_signal, t])\n        return t\n\n    def as_hdl_HdlType_array(self, typ: HArray, declaration=False):\n        if declaration:\n            return super(ToHdlAstSystemC_type, self).as_hdl_HdlType_array(\n                self, typ, declaration=declaration)\n        else:\n            _int = self.as_hdl_int\n            size = _int(int(typ.size))\n            return hdl_index(self.as_hdl_HdlType(typ.element_t), size)\n\n    def as_hdl_HdlType_enum(self, typ: HEnum, declaration=False):\n        return ToHdlAstVerilog_types.as_hdl_HdlType_enum(\n            self, typ, declaration=declaration)\n\n    def as_hdl_HdlType_float(self, typ: HFloat, declaration=False):\n        if typ == FLOAT64:\n            return HdlValueId(\"double\")\n        else:\n            raise NotImplementedError(typ)\n"
  },
  {
    "path": "hwt/serializer/systemC/utils.py",
    "content": "from hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.pyUtils.arrayQuery import arr_any\nfrom hwt.hwParam import HwParam\nfrom ipCorePackager.constants import DIRECTION\n\n\ndef systemCTypeOfSig(s):\n    \"\"\"\n    Check if is register or wire\n    \"\"\"\n    if isinstance(s, HdlIdDef):\n        s = s.origin\n\n    if isinstance(s, HdlPortItem):\n        if s.direction == DIRECTION.IN or s.direction == DIRECTION.INOUT:\n            return SIGNAL_TYPE.PORT_WIRE\n\n        t = systemCTypeOfSig(s.getInternSig())\n        if t == SIGNAL_TYPE.WIRE:\n            return SIGNAL_TYPE.PORT_WIRE\n        elif t == SIGNAL_TYPE.REG:\n            return SIGNAL_TYPE.PORT_REG\n        else:\n            raise ValueError(t)\n    elif isinstance(s, HwParam):\n        return SIGNAL_TYPE.PORT_REG\n    elif s._const or\\\n        arr_any(s._rtlDrivers,\n                lambda d: isinstance(d, HdlStatement)\n                and d._event_dependent_from_branch is not None):\n\n        return SIGNAL_TYPE.REG\n    else:\n        return SIGNAL_TYPE.WIRE\n"
  },
  {
    "path": "hwt/serializer/utils.py",
    "content": "from natsort.natsort import natsort_keygen\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.mainBases import RtlSignalBase\n\n\n@internal\ndef getMaxStmIdForStm(stm: HdlStatement):\n    \"\"\"\n    Get maximum _instId from all assignments in statement,\n    used for sorting of processes in architecture\n    \"\"\"\n    maxId = 0\n    if isinstance(stm, HdlAssignmentContainer):\n        return stm._instId\n    else:\n        for _stm in stm._iter_stms():\n            maxId = max(maxId, getMaxStmIdForStm(_stm))\n        return maxId\n\n\n_natsort_key = natsort_keygen()\n\n\ndef RtlSignal_sort_key(s: RtlSignalBase):\n    return (_natsort_key(s._name), s._instId)\n\n\ndef HdlStatement_sort_key(stm: HdlStatement):\n    if isinstance(stm, HdlStmCodeBlockContainer) and stm.name is not None:\n        return (_natsort_key(stm.name), getMaxStmIdForStm(stm))\n    else:\n        return (_natsort_key(\"\"), getMaxStmIdForStm(stm))\n"
  },
  {
    "path": "hwt/serializer/verilog/__init__.py",
    "content": "\"\"\"\nVerilog serializer serializes HDL objects to verilog code.\n\"\"\"\nfrom hdlConvertorAst.to.verilog.verilog2005 import ToVerilog2005\nfrom hwt.serializer.serializer_config import DummySerializerConfig\nfrom hwt.serializer.verilog.serializer import ToHdlAstVerilog\nfrom hwt.serializer.xdc.serializer import XdcSerializer\n\n\nclass VerilogSerializer(DummySerializerConfig):\n    fileExtension = '.v'\n    TO_HDL_AST = ToHdlAstVerilog\n    TO_HDL = ToVerilog2005\n    TO_CONSTRAINTS = XdcSerializer"
  },
  {
    "path": "hwt/serializer/verilog/context.py",
    "content": "from hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\n\n\nclass SignalTypeSwap():\n    \"\"\"\n    An object which is used as a context manager for signalType\n    inside of :class:`hwt.serializer.verilog.serializer.ToHdlAstVerilog`\n    \"\"\"\n\n    def __init__(self, ctx, signalType: SIGNAL_TYPE):\n        self.ctx = ctx\n        self.signalType = signalType\n\n    def __enter__(self):\n        self.orig = self.ctx.signalType\n        self.ctx.signalType = self.signalType\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        self.ctx.signalType = self.orig\n"
  },
  {
    "path": "hwt/serializer/verilog/ops.py",
    "content": "from builtins import isinstance\nfrom typing import Union\n\nfrom hdlConvertorAst.hdlAst import HdlValueInt\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOpType, HdlOp\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call\nfrom hwt.hdl.commonConstants import b1, b0\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.types.bitConstFunctions import AnyHBitsValue\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import INT, SLICE\nfrom hwt.serializer.exceptions import UnsupportedEventOpErr\nfrom hwt.serializer.generic.ops import HWT_TO_HDLCONVERTOR_OPS\nfrom hwt.serializer.vhdl.ops import matchFullWidthMul\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass ToHdlAstVerilog_ops():\n    SIGNED = HdlValueId(\"$signed\", obj=LanguageKeyword())\n    UNSIGNED = HdlValueId(\"$unsigned\", obj=LanguageKeyword())\n    op_transl_dict = {\n        **HWT_TO_HDLCONVERTOR_OPS,\n        HwtOps.INDEX: HdlOpType.INDEX,\n    }\n\n    def _operandIsAnotherOperand(self, operand):\n        return isinstance(operand, RtlSignal) and operand._isUnnamedExpr\\\n                and isinstance(operand._rtlObjectOrigin, HOperatorNode)\n\n    def as_hdl_operand(self, operand: Union[RtlSignal, HConst], i: int,\n                       operator: HOperatorNode):\n\n        # [TODO] if operand is concatenation and parent operator\n        #        is not concatenation operand should be extracted\n        #        as tmp variable\n        #        * maybe flatten the concatenations\n        if operator.operator != HwtOps.CONCAT\\\n                and self._operandIsAnotherOperand(operand)\\\n                and operand._rtlObjectOrigin.operator == HwtOps.CONCAT:\n            _, tmpVar = self.tmpVars.create_var_cached(\"tmp_concat_\", operand._dtype, def_val=operand)\n            # HdlAssignmentContainer(tmpVar, operand, virtual_only=True)\n            operand = tmpVar\n        elif operator.operator in (HwtOps.INDEX, HwtOps.TRUNC) and i == 0 and self._operandIsAnotherOperand(operand):\n            tmpVarName = \"tmp_index_\" if operator.operator == HwtOps.INDEX else \"tmp_trunc_\"\n            _, tmpVar = self.tmpVars.create_var_cached(tmpVarName, operand._dtype, def_val=operand)\n            operand = tmpVar\n        elif self._operandIsAnotherOperand(operand)\\\n                and operand._rtlObjectOrigin.operator == HwtOps.MUL:\n            _, tmpVar = self.tmpVars.create_var_cached(\"tmp_mul_\", operand._dtype, def_val=operand)\n            operand = tmpVar\n\n        oper = operator.operator\n        width = None\n        if not isinstance(operand, RtlSignal) and operand._dtype == INT and\\\n           oper not in [HwtOps.BitsAsUnsigned,\n                        HwtOps.BitsAsVec,\n                        HwtOps.BitsAsSigned,\n                        HwtOps.INDEX] and\\\n                operator.result is not None and\\\n                not operator.result._dtype == INT:\n            # have to lock the width\n            for o in operator.operands:\n                try:\n                    bl = o._dtype.bit_length\n                except AttributeError:\n                    bl = None\n                if bl is not None:\n                    width = bl()\n                    break\n\n            assert width is not None, (operator, operand)\n\n        hdl_op = self.as_hdl_Value(operand)\n        if width is not None:\n            if isinstance(hdl_op, HdlValueInt):\n                assert isinstance(width, int), width\n                hdl_op.bits = width\n            else:\n                return HdlOp(HdlOpType.APOSTROPHE, [self.as_hdl_int(width), hdl_op])\n        return hdl_op\n\n    def as_hdl_HOperatorNode_TERNARY(self, op: HOperatorNode, ops: list[AnyHBitsValue]):\n        if ops[1] == b1 and ops[2] == b0:\n            # ignore redundant x ? 1 : 0\n            return self.as_hdl_cond(ops[0], True)\n        else:\n            op0 = self.as_hdl_cond(ops[0], True)\n            op1 = self.as_hdl_operand(ops[1], 1, op)\n            op2 = self.as_hdl_operand(ops[2], 2, op)\n            return HdlOp(HdlOpType.TERNARY, [op0, op1, op2])\n\n    def as_hdl_HOperatorNode_BITSCAST(self, op: HOperatorNode):\n        op0, = op.operands\n        do_cast = bool(op0._dtype.signed) != bool(op.result._dtype.signed)\n\n        op_hdl = self.as_hdl_operand(op0, 0, op)\n        if do_cast:\n            if bool(op.result._dtype.signed):\n                cast = self.SIGNED\n            else:\n                cast = self.UNSIGNED\n            return hdl_call(cast, [op_hdl, ])\n        else:\n            return op_hdl\n\n    def as_hdl_HOperatorNode_TRUNC(self, op: HOperatorNode):\n        ops = op.operands\n        # convert trunc to slice\n        resWidth = int(ops[1])\n        res = HdlOp(HdlOpType.INDEX, [\n            self.as_hdl_operand(ops[0], 0, op),\n            self.as_hdl_HSliceConst(SLICE.from_py(slice(resWidth, 0, -1)))\n        ])\n        op0_t = ops[0]._dtype\n        if isinstance(op0_t, HBits) and op0_t.signed:\n            return hdl_call(self.SIGNED, [res, ])\n        return res\n\n    def as_hdl_HOperatorNode_SEXT_ZEXT(self, op: HOperatorNode):\n        ops = op.operands\n        # convert sext to concat with repliacation, zext to concat 0\n        # x4b._sext(8) -> { {8-4{x[4-1]}}, x }; # replication operator\n        resWidth = int(ops[1])\n        srcWidth = ops[0]._dtype.bit_length()\n        prefixLen = resWidth - srcWidth\n        if op.operator == HwtOps.ZEXT:\n            prefix = self.as_hdl_HBitsConst(HBits(prefixLen).from_py(0))\n        else:\n            if srcWidth == 1:\n                msb = self.as_hdl_operand(ops[0], 0, op)\n                return HdlOp(HdlOpType.REPL_CONCAT, [\n                    self.as_hdl_int(resWidth),\n                    msb,\n                ])\n            else:\n                msb = self.as_hdl_operand(ops[0][srcWidth - 1]._vec(), 0, op)\n                # :note: can not construct HdlOp directly because verilog slice operator can not be applied to any value without tmp variable\n                # HdlOp(HdlOpType.INDEX, [\n                #    self.as_hdl_operand(ops[0], 0, op),\n                #    self.as_hdl_int(srcWidth - 1),\n                # ])\n            if prefixLen == 1:\n                prefix = msb\n            else:\n                prefix = HdlOp(HdlOpType.REPL_CONCAT, [\n                    self.as_hdl_int(prefixLen),\n                    msb,\n                ])\n        res = HdlOp(HdlOpType.CONCAT, [\n            prefix,\n            self.as_hdl_operand(ops[0], 0, op)\n        ])\n        resT = op.result._dtype\n        if isinstance(resT, HBits) and resT.signed:\n            _, tmpVar = self.tmpVars.create_var_cached(f\"tmp_{op.operator.id}_signCast\", resT, def_val=res)\n            return hdl_call(self.SIGNED, [tmpVar, ])\n        return res\n\n    def as_hdl_HOperatorNode_INDEX(self, op: HOperatorNode):\n        ops = op.operands\n        op0_t = ops[0]._dtype\n        if isinstance(op0_t, HBits) and op0_t.bit_length() == 1 and not op0_t.force_vector:\n            assert int(ops[1]) == 0, ops\n            # drop whole index operator when indexing on 1b vector\n            return self.as_hdl_operand(ops[0], 0, op)\n\n        _o = self.op_transl_dict[op.operator]\n        res = HdlOp(_o, [self.as_hdl_operand(o2, i, op)\n                          for i, o2 in enumerate(ops)])\n\n        op0_t = ops[0]._dtype\n        if isinstance(op0_t, HBits) and op0_t.signed:\n            return hdl_call(self.SIGNED, [res, ])\n\n        return res\n\n    def as_hdl_HOperatorNode(self, op: HOperatorNode):\n        ops = op.operands\n        o = op.operator\n\n        if o == HwtOps.TERNARY:\n            return self.as_hdl_HOperatorNode_TERNARY(op, ops)\n        elif o == HwtOps.RISING_EDGE or o == HwtOps.FALLING_EDGE:\n            raise UnsupportedEventOpErr()\n        elif o in (HwtOps.BitsAsUnsigned, HwtOps.BitsAsVec, HwtOps.BitsAsSigned):\n            return self.as_hdl_HOperatorNode_BITSCAST(op)\n        elif o == HwtOps.TRUNC:\n            return self.as_hdl_HOperatorNode_TRUNC(op)\n        elif o in (HwtOps.SEXT, HwtOps.ZEXT):\n            return self.as_hdl_HOperatorNode_SEXT_ZEXT(op)\n        elif o == HwtOps.INDEX:\n            return self.as_hdl_HOperatorNode_INDEX(op)\n        else:\n            if o == HwtOps.MUL:\n                op0, op1 = ops\n                # optionally drop zext/sext and add casts\n                ops = matchFullWidthMul(op0, op1)\n\n            _o = o.hdlConvertoAstOp\n            if _o is None:\n                _o = self.op_transl_dict[o]\n\n            res = HdlOp(_o, [self.as_hdl_operand(o2, i, op)\n                              for i, o2 in enumerate(ops)])\n\n            return res\n"
  },
  {
    "path": "hwt/serializer/verilog/serializer.py",
    "content": "from copy import copy\nfrom typing import Optional, List\n\nfrom hdlConvertorAst.hdlAst import HdlStmIf, HdlOp, \\\n    HdlOpType, HdlValueId, HdlModuleDec, iHdlStatement\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlTypeAuto\nfrom hdlConvertorAst.hdlAst._statements import HdlStmProcess, HdlStmBlock, HdlStmAssign, \\\n    HdlStmWait\nfrom hdlConvertorAst.to.verilog.keywords import IEEE1800_2017_KEYWORDS\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword, NameScope\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.defs import STR, INT, BOOL\nfrom hwt.serializer.generic.to_hdl_ast import ToHdlAst\nfrom hwt.serializer.verilog.context import SignalTypeSwap\nfrom hwt.serializer.verilog.ops import ToHdlAstVerilog_ops\nfrom hwt.serializer.verilog.statements import ToHdlAstVerilog_statements\nfrom hwt.serializer.verilog.types import ToHdlAstVerilog_types\nfrom hwt.serializer.verilog.utils import SIGNAL_TYPE, verilogTypeOfSig\nfrom hwt.serializer.verilog.value import ToHdlAstVerilog_Value\n\n\nclass ToHdlAstVerilog(ToHdlAstVerilog_types,\n                      ToHdlAstVerilog_Value, ToHdlAstVerilog_statements,\n                      ToHdlAstVerilog_ops, ToHdlAst):\n    _keywords_dict = {kw: LanguageKeyword() for kw in IEEE1800_2017_KEYWORDS}\n\n    def __init__(self, name_scope: Optional[NameScope]=None):\n        ToHdlAst.__init__(self, name_scope=name_scope)\n        self.signalType = SIGNAL_TYPE.PORT_WIRE\n\n    def as_hdl_HdlModuleDef_variable(\n            self, v, types, hdl_types, hdl_variables,\n            processes, component_insts):\n        new_v = copy(v)\n        with SignalTypeSwap(self, verilogTypeOfSig(v.origin)):\n            t = v.type\n            # if type requires extra definition\n            if self.does_type_requires_extra_def(t, types):\n                _t = self.as_hdl_HdlType(t, declaration=True)\n                hdl_types.append(_t)\n                types.add(t)\n            new_v.type = self.as_hdl_HdlType(t, declaration=False)\n            # this is a array variable which requires value intialization in init\n            # process\n            if isinstance(t, HArray):\n                if v.value.vld_mask:\n                    rom = v.origin\n                    p = HdlStmProcess()\n                    label = self.name_scope.checked_name(rom._name + \"_rom_init\", p)\n                    p.labels.append(label)\n                    p.body = HdlStmBlock()\n                    body = p.body.body\n                    for i, _v in enumerate(rom.def_val):\n                        a = HdlStmAssign(self.as_hdl(_v),\n                                         self.as_hdl(rom[i]))\n                        a.is_blocking = True\n                        body.append(a)\n                    w = HdlStmWait()\n                    w.val = []  # initial process\n                    body.append(w)\n                    processes.append(p)\n                # because we would not be able to initialize const/localparam variable later\n                new_v.is_const = False\n                new_v.value = None\n            elif new_v.value is not None:\n                if new_v.value.vld_mask:\n                    new_v.value = self.as_hdl_Value(new_v.value)\n                else:\n                    # 'x' is a default value no need to specify it extra\n                    new_v.value = None\n            return new_v\n\n    def _static_assert_false(self, msg:str):\n        return hdl_call(HdlValueId(\"$error\"), [f\"%m {msg:s}\"])\n\n    def _static_assert_symbol_eq(self, symbol_name:str, v):\n        i = HdlStmIf()\n        i.in_preproc = True\n        # [TODO] this actually requires SV>=2009\n        # generate\n        # if (p==x) begin\n        #     $error(\"%m Generated only for this param value\");\n        # end\n        # endgenerate\n        i.cond = HdlOp(HdlOpType.NE, [HdlValueId(symbol_name), v])\n        i.if_true = hdl_call(HdlValueId(\"$error\"), [\n             \"%m Generated only for this param value\",\n             ])\n        return i\n\n    def as_hdl_GenericItem(self, g: HdlIdDef):\n        with SignalTypeSwap(self, SIGNAL_TYPE.PORT_WIRE):\n            new_v = copy(g)\n            v = g.value\n            if v._dtype == STR or v._dtype == INT or v._dtype == BOOL:\n                t = HdlTypeAuto\n            else:\n                t = self.as_hdl_HdlType(v._dtype)\n            new_v.type = t\n            assert new_v.value is not None, g\n            new_v.value = self.as_hdl_Value(v)\n            return new_v\n\n    def as_hdl_HdlPortItem(self, pi: HdlPortItem):\n        with SignalTypeSwap(self, verilogTypeOfSig(pi)):\n            v = super(ToHdlAstVerilog, self).as_hdl_HdlPortItem(pi)\n            v.is_latched = self.signalType == SIGNAL_TYPE.PORT_REG\n        return v\n\n    def _as_hdl_HdlModuleDef_param_asserts(self, new_m: HdlModuleDec) -> List[iHdlStatement]:\n        return ToHdlAst._as_hdl_HdlModuleDef_param_asserts_real(self, new_m)\n"
  },
  {
    "path": "hwt/serializer/verilog/statements.py",
    "content": "from hdlConvertorAst.hdlAst._bases import iHdlStatement\nfrom hdlConvertorAst.hdlAst._expr import HdlAll\nfrom hdlConvertorAst.hdlAst._statements import HdlStmProcess, HdlStmWait, \\\n    HdlStmBlock\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.serializer.verilog.utils import verilogTypeOfSig\n\n\nclass ToHdlAstVerilog_statements():\n\n    def as_hdl_HdlAssignmentContainer(self, a: HdlAssignmentContainer):\n        blocking = False\n        ver_sig_t = verilogTypeOfSig(a.dst)\n        if ver_sig_t in (SIGNAL_TYPE.REG, SIGNAL_TYPE.PORT_REG):\n            evDep = False\n            for driver in a.dst._rtlDrivers:\n                if driver._event_dependent_from_branch is not None:\n                    evDep = True\n                    break\n\n            if not evDep or a.dst.virtual_only:\n                blocking = True\n        elif ver_sig_t in (SIGNAL_TYPE.WIRE, SIGNAL_TYPE.PORT_WIRE):\n            blocking = True\n        else:\n            raise ValueError(ver_sig_t)\n\n        a = super(ToHdlAstVerilog_statements, self).as_hdl_HdlAssignmentContainer(a)\n        a.is_blocking = blocking\n        return a\n\n    def can_pop_process_wrap(self, stms, hasToBeVhdlProcess):\n        if hasToBeVhdlProcess:\n            return False\n        else:\n            assert len(stms) == 1\n            return True\n\n    def has_to_be_process(self, proc: HdlStmCodeBlockContainer):\n        for o in proc._outputs:\n            if verilogTypeOfSig(o) in (SIGNAL_TYPE.REG, SIGNAL_TYPE.PORT_REG):\n                return True\n\n        return False\n\n    def as_hdl_HdlStmCodeBlockContainer(self, proc: HdlStmCodeBlockContainer) -> iHdlStatement:\n        p = super(ToHdlAstVerilog_statements,\n                  self).as_hdl_HdlStmCodeBlockContainer(proc)\n        if isinstance(p, HdlStmProcess):\n            no_wait = True\n            if isinstance(p.body, HdlStmWait):\n                no_wait = False\n            elif isinstance(p.body, HdlStmBlock):\n                for _o in p.body.body:\n                    if isinstance(_o, HdlStmWait):\n                        no_wait = False\n                        break\n\n            if no_wait and not p.sensitivity:\n                # all input are constant and that is why this process does not have\n                # any sensitivity\n                p.sensitivity = [HdlAll, ]\n\n            # add label\n            if not isinstance(p.body, HdlStmBlock):\n                b = p.body\n                p.body = HdlStmBlock()\n                p.body.body.append(b)\n            p.body.labels.extend(p.labels)\n            p.labels.clear()\n        return p\n"
  },
  {
    "path": "hwt/serializer/verilog/types.py",
    "content": "from hdlConvertorAst.hdlAst._expr import HdlTypeAuto, HdlValueId, HdlOp, \\\n    HdlOpType\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_index, \\\n    hdl_downto\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import INT, FLOAT64\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.hdlType import HdlType, MethodNotOverloaded\nfrom hwt.serializer.verilog.utils import SIGNAL_TYPE\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass ToHdlAstVerilog_types():\n    INT = HdlValueId(\"int\", obj=int)\n    REG = HdlValueId(\"reg\", obj=LanguageKeyword())\n    WIRE = HdlValueId(\"wire\", obj=LanguageKeyword())\n\n    def does_type_requires_extra_def(self, t: HdlType, other_types: list):\n        try:\n            return t._as_hdl_requires_def(self, other_types)\n        except MethodNotOverloaded:\n            pass\n        return False\n\n    def as_hdl_HdlType_bits(self, typ: HBits, declaration=False):\n        isVector = typ.force_vector or typ.bit_length() > 1\n        sigType = self.signalType\n\n        if typ == INT:\n            t = self.INT\n        elif sigType is SIGNAL_TYPE.PORT_WIRE:\n            t = HdlTypeAuto\n        elif sigType is SIGNAL_TYPE.REG or sigType is SIGNAL_TYPE.PORT_REG:\n            t = self.REG\n        elif sigType is SIGNAL_TYPE.WIRE:\n            t = self.WIRE\n        else:\n            raise ValueError(sigType)\n\n        if typ.signed is None or typ.signed == False:\n            # [yosys] do not produce unsigned type as yosys support is limited\n            is_signed = None\n        else:\n            is_signed = self.as_hdl_int(int(typ.signed))\n\n        if isVector:\n            w = typ.bit_length()\n            assert isinstance(w, int) or (isinstance(w, RtlSignal) and w._const), w\n            w = hdl_downto(self.as_hdl(w - 1),\n                           self.as_hdl_int(0))\n        else:\n            w = None\n\n        return HdlOp(HdlOpType.PARAMETRIZATION, [t, w, is_signed])\n\n    def as_hdl_HdlType_array(self, typ: HArray, declaration=False):\n        if declaration:\n            raise NotImplementedError()\n        else:\n            _int = self.as_hdl_int\n            size = HdlOp(HdlOpType.DOWNTO, [_int(0),\n                                                 _int(int(typ.size) - 1)])\n            return hdl_index(self.as_hdl_HdlType(typ.element_t), size)\n\n    def as_hdl_HdlType_enum(self, typ, declaration=False):\n        if declaration:\n            raise TypeError(\n                \"Target language does not use enum types, this library should uses HBits instead\"\n                \" (this should not be required because it should have been filtered before)\")\n        else:\n            valueCnt = len(typ._allValues)\n            return self.as_hdl_HdlType_bits(HBits(valueCnt.bit_length()),\n                                            declaration=declaration)\n\n    def as_hdl_HdlType_float(self, typ: HFloat, declaration=False):\n        if typ == FLOAT64:\n            return HdlValueId(\"real\")\n        else:\n            raise NotImplementedError(typ)\n"
  },
  {
    "path": "hwt/serializer/verilog/utils.py",
    "content": "from typing import Union\n\nfrom hdlConvertorAst.hdlAst import iHdlStatement\nfrom hdlConvertorAst.to.verilog.constants import SIGNAL_TYPE\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.variables import HdlSignalItem\nfrom ipCorePackager.constants import DIRECTION\n\n\n@internal\ndef verilogTypeOfSig(s: Union[HdlSignalItem, HdlPortItem]):\n    \"\"\"\n    Check if is register or wire\n    \"\"\"\n    if isinstance(s, HdlPortItem):\n        if s.direction == DIRECTION.IN or s.direction == DIRECTION.INOUT:\n            return SIGNAL_TYPE.PORT_WIRE\n\n        t = verilogTypeOfSig(s.getInternSig())\n        if t == SIGNAL_TYPE.WIRE:\n            return SIGNAL_TYPE.PORT_WIRE\n        elif t == SIGNAL_TYPE.REG:\n            return SIGNAL_TYPE.PORT_REG\n        else:\n            raise ValueError(t)\n\n    driver_cnt = len(s._rtlDrivers)\n    if driver_cnt == 1:\n        d = s._rtlDrivers[0]\n        if isinstance(d, HdlPortItem):\n            # input port\n            return SIGNAL_TYPE.WIRE\n        elif isinstance(d, HdlAssignmentContainer)\\\n                and d.parentStm is None\\\n                and not d.indexes\\\n                and d._event_dependent_from_branch is None\\\n                and (isinstance(d.src, HConst) or not d.src._isUnnamedExpr):\n            # primitive assignment\n            return SIGNAL_TYPE.WIRE\n        elif isinstance(d, iHdlStatement) and d.in_preproc:\n            return SIGNAL_TYPE.WIRE\n\n    return SIGNAL_TYPE.REG\n"
  },
  {
    "path": "hwt/serializer/verilog/value.py",
    "content": "from typing import Optional\n\nfrom hdlConvertorAst.hdlAst._expr import HdlValueInt, HdlOpType, \\\n    HdlOp\nfrom hdlConvertorAst.to.hdlUtils import bit_string\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_downto, \\\n    hdl_call\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import BOOL, BIT\nfrom hwt.hdl.types.enumConst import HEnumConst\nfrom hwt.hdl.types.sliceConst import HSliceConst\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.generic.ops import HWT_TO_HDLCONVERTOR_OPS\nfrom hwt.serializer.generic.value import ToHdlAst_Value\nfrom hwt.serializer.verilog.context import SignalTypeSwap\nfrom hwt.serializer.verilog.utils import verilogTypeOfSig\n\n\nclass ToHdlAstVerilog_Value(ToHdlAst_Value):\n\n    # TRUE = HdlValueId(\"true\", obj=LanguageKeyword())\n    # FALSE = HdlValueId(\"false\", obj=LanguageKeyword())\n\n    def as_hdl_HBoolConst(self, val: HBitsConst):\n        return self.as_hdl_int(val.val)\n\n    def as_hdl_cond(self, c, forceBool):\n        assert isinstance(c, (RtlSignalBase, HConst))\n        if not forceBool or c._dtype == BOOL:\n            return self.as_hdl(c)\n        elif c._dtype == BIT:\n            return self.as_hdl(c)\n        elif isinstance(c._dtype, HBits):\n            return self.as_hdl(c != 0)\n        else:\n            raise NotImplementedError()\n\n    def as_hdl_HEnumConst(self, val: HEnumConst):\n        i = val._dtype._allValues.index(val.val)\n        assert i >= 0\n        return HdlValueInt(i, None, None)\n\n    def as_hdl_HdlSignalItem(self, si, declaration=False):\n        if declaration:\n            with SignalTypeSwap(self, verilogTypeOfSig(si)):\n                return ToHdlAst_Value.as_hdl_HdlSignalItem(self, si, declaration=declaration)\n        else:\n            return ToHdlAst_Value.as_hdl_HdlSignalItem(self, si, declaration=declaration)\n\n    def as_hdl_HSliceConst(self, val: HSliceConst):\n        upper = val.val.start - 1\n        return hdl_downto(self.as_hdl_Value(upper),\n                          self.as_hdl_Value(val.val.stop))\n\n    def sensitivityListItem(self, item, anyIsEventDependent):\n        if isinstance(item, HOperatorNode):\n            return HdlOp(HWT_TO_HDLCONVERTOR_OPS[item.operator],\n                           [self.as_hdl(item.operands[0]), ])\n        elif anyIsEventDependent:\n            if item._dtype.negated:\n                op = HdlOpType.FALLING\n            else:\n                op = HdlOpType.RISING\n            return HdlOp(op, [self.as_hdl(item), ])\n\n        return self.as_hdl(item)\n\n    def as_hdl_HArrayConst(self, val):\n        raise ValueError(\n            \"Verilog do not have a array constants(they are part of SV)\"\n            \" and that is why array constants should converted to initialization\"\n            \" in initial processes\")\n\n    @internal\n    def as_hdl_BitString(self, v: int, width: int, force_vector: bool, vld_mask: int, signed: Optional[int]):\n        v = bit_string(v, width, vld_mask=vld_mask)\n        if signed:\n            return hdl_call(self.SIGNED, [v, ])\n        else:\n            return v\n"
  },
  {
    "path": "hwt/serializer/vhdl/__init__.py",
    "content": "\"\"\"\nVHDL serializer serializes HDL objects to VHDL code.\n\"\"\"\nfrom hdlConvertorAst.to.vhdl.vhdl2008 import ToVhdl2008\nfrom hwt.serializer.vhdl.serializer import ToHdlAstVhdl2008\nfrom hwt.serializer.xdc.serializer import XdcSerializer\n\n\nclass Vhdl2008Serializer():\n    fileExtension = '.vhd'\n    TO_HDL_AST = ToHdlAstVhdl2008\n    TO_HDL = ToVhdl2008\n    TO_CONSTRAINTS = XdcSerializer\n"
  },
  {
    "path": "hwt/serializer/vhdl/ops.py",
    "content": "from typing import Union, Optional\n\nfrom hdlConvertorAst.hdlAst import HdlValueInt\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOp, HdlOpType, \\\n    HDLCONVERTAST_OPS_SHIFT_AND_ROT, HdlOthers\nfrom hdlConvertorAst.hdlAst._statements import HdlStmAssign\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call, \\\n    hdl_index, hdl_downto\nfrom hwt.code import If\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.commonConstants import b0, b1\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps, CAST_OPS, HOperatorDef\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.hdl.types.bitConstFunctions import AnyHBitsValue\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.bitsRtlSignal import HBitsRtlSignal\nfrom hwt.hdl.types.defs import BOOL, INT, BIT\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.hwt.ops import ToHdlAstHwt_ops\nfrom hwt.serializer.vhdl.types import ToHdlAstVhdl2008_types\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom pyMathBitPrecise.bit_utils import ctlz, get_bit\n\n\n@internal\ndef isResultOfTypeConversionForIndex(sig: RtlSignal):\n    if len(sig._rtlDrivers) != 1:\n        return False\n\n    if sig._isUnnamedExpr:\n        d = sig.singleDriver()\n        return d.operator not in (HwtOps.INDEX, HwtOps.TRUNC)\n\n    return False\n\n\ndef matchZextOrSextArg(op: Union[RtlSignal, HConst]) -> tuple[Optional[AnyHBitsValue], Optional[bool]]:\n    \"\"\"\n    Check if the value is zext or sext to double width\n    :returns: base operand, isSigned or None, None if not matched\n    \"\"\"\n    if isinstance(op, HConst):\n        if not op._is_full_valid():\n            return None, None\n\n        width = op._dtype.bit_length()\n        isSigned = op._dtype.signed\n        msb = bool(get_bit(op.val, width - 1))\n        if msb:\n            prefixLen = ctlz(~op.val, width)\n        else:\n            prefixLen = ctlz(op.val, width)\n\n        if prefixLen == width:\n            # this is x * 0 or x * -1, this should have been optimized before, we do not do any opt there\n            return None, None\n\n        if isSigned:\n            prefixLen -= 1  # msb 0/1 must stay to mark signed\n\n        return op[prefixLen:], False\n\n    elif op._isUnnamedExpr:\n        try:\n            d = op.singleDriver()\n        except SignalDriverErr:\n            return None, None\n\n        casts = []\n        # drop unnecessary casts\n        while isinstance(d, HOperatorNode) and d.operator in CAST_OPS:\n            casts.append(d.operator)\n            d = d.operands[0].singleDriver()\n\n        if isinstance(d, HOperatorNode) and d.operator in (HwtOps.ZEXT, HwtOps.SEXT):\n            src = d.operands[0]\n            return src, d.operator == HwtOps.SEXT\n\n    return None, None\n\n\ndef matchFullWidthMul(op0: Union[RtlSignal, HConst], op1: Union[RtlSignal, HConst])\\\n     ->tuple[Union[RtlSignal, HConst], Union[RtlSignal, HConst]]:\n        # result of multiplication in VHDL has 2x width, while in hwt has same width as operands have\n    # truncatenation is required,\n    # * first we check if operands are not zero extended to double width\n    #   if this is the case we can use original operands and avoid any cast\n    _op0, _op0SignExtended = matchZextOrSextArg(op0)\n    if _op0 is not None:\n        _op1, _op1SignExtended = matchZextOrSextArg(op1)\n        if _op1 is not None:\n            if _op0SignExtended == _op1SignExtended:\n                op0 = _op0._cast_sign(_op0SignExtended)\n                op1 = _op1._cast_sign(_op1SignExtended)\n\n    # * else we need to truncatenate result to width of operand\n    return op0, op1\n\n\nclass ToHdlAstVhdl2008_ops(ToHdlAstVhdl2008_types):\n    op_transl_dict = {\n        **ToHdlAstHwt_ops.op_transl_dict,\n        HwtOps.RISING_EDGE: HdlOpType.RISING,\n        HwtOps.FALLING_EDGE: HdlOpType.FALLING,\n    }\n\n    TO_INTEGER = HdlValueId(\"TO_INTEGER\", obj=LanguageKeyword())\n    _cast_ops = {\n        HwtOps.BitsAsSigned: ToHdlAstVhdl2008_types.SIGNED,\n        HwtOps.BitsAsUnsigned: ToHdlAstVhdl2008_types.UNSIGNED,\n        HwtOps.BitsAsVec: ToHdlAstVhdl2008_types.STD_LOGIC_VECTOR,\n    }\n\n    RESIZE = HdlValueId(\"RESIZE\", obj=LanguageKeyword())\n    SHIFT_LEFT = HdlValueId(\"SHIFT_LEFT\", obj=LanguageKeyword())\n    SHIFT_RIGHT = HdlValueId(\"SHIFT_RIGHT\", obj=LanguageKeyword())\n    ROTATE_LEFT = HdlValueId(\"ROTATE_LEFT\", obj=LanguageKeyword())\n    ROTATE_RIGHT = HdlValueId(\"ROTATE_RIGHT\", obj=LanguageKeyword())\n    # :note: bool in HDLCONVERTORAST_TO_VHDL value marks if shift is arithmetical or logical\n    HDLCONVERTORAST_TO_VHDL = {\n        HdlOpType.SLL: (SHIFT_LEFT, False),  # shift left logical\n        HdlOpType.SRL: (SHIFT_RIGHT, False),  # shift right logical\n        HdlOpType.SLA: (SHIFT_LEFT, True),  # shift left arithmetical\n        HdlOpType.SRA: (SHIFT_RIGHT, True),  # shift right arithmetical\n        HdlOpType.ROL: (ROTATE_LEFT, False),  # rotate left\n        HdlOpType.ROR: (ROTATE_RIGHT, False),  # rotate right\n    }\n\n    @internal\n    def _tmp_var_for_ternary(self, val: RtlSignal) -> RtlSignal:\n        \"\"\"\n        Optionally convert boolean to std_logic_vector\n        \"\"\"\n        isNew, o = self.tmpVars.create_var_cached(\n            \"tmpTernary_\",\n            val._dtype,\n            postponed_init=True,\n            extra_args=(val, bool, 1, 0))\n        if isNew:\n            cond, ifTrue, ifFalse = val._rtlDrivers[0].operands\n            if_ = If(cond)\n            if_.ifTrue.append(HdlAssignmentContainer(ifTrue, o,\n                                         virtual_only=True,\n                                         parentStm=if_))\n            if_.ifFalse = ListOfHdlStatement()\n            if_.ifFalse.append(HdlAssignmentContainer(ifFalse, o,\n                                          virtual_only=True,\n                                          parentStm=if_))\n            if_._outputs.append(o)\n            for obj in (cond, ifTrue, ifFalse):\n                if isinstance(obj, RtlSignalBase):\n                    if_._inputs.append(obj)\n            o._rtlDrivers.append(if_)\n            if_._discover_enclosure()\n            self.tmpVars.finish_var_init(o)\n\n        return o\n\n    @internal\n    def _tmp_var_for_arrayAggregate(self, val: RtlSignal) -> RtlSignal:\n        \"\"\"\n        Create tmp variable for expression which will be converted to VHDL aggreate expression:\n        .. code-block::\n           x = x1b._sext(10)\n           xTmp10b := (0=> x1b, others=>x1b);\n            \n        \"\"\"\n        # [todo]: _as_Bits_vec\n        _, o = self.tmpVars.create_var_cached(\n            \"tmpAggregate_\",\n            val._dtype,\n            def_val=val,\n            extra_args=(val, HdlOpType.MAP_ASSOCIATION))\n        return o\n\n    def _as_Bits(self, val: Union[RtlSignal, HConst]):\n        if val._dtype == BOOL:\n            isNew, o = self.tmpVars.create_var_cached(\n                \"tmpBool2std_logic_\",\n                BIT,\n                postponed_init=True,\n                extra_args=(val, int, 1, 0))\n            if isNew:\n                ifTrue, ifFalse = b1, b0\n                if_ = If(val)\n                if_.ifTrue.append(HdlAssignmentContainer(ifTrue, o, virtual_only=True, parentStm=if_))\n                if_.ifFalse = []\n                if_.ifFalse.append(HdlAssignmentContainer(ifFalse, o, virtual_only=True, parentStm=if_))\n                if_._outputs.append(o)\n                o._rtlDrivers.append(if_)\n                self.tmpVars.finish_var_init(o)\n            return o\n        else:\n            assert isinstance(val._dtype, HBits), val._dtype\n            return val\n\n    def _as_Bits_vec(self, val: Union[RtlSignal, HConst]):\n        val = self._as_Bits(val)\n        t = val._dtype\n        if not t.force_vector and t.bit_length() == 1:\n            # std_logic -> std_logic_vector\n            std_logic_vector = HBits(1, signed=t.signed, force_vector=True)\n            isNew, o = self.tmpVars.create_var_cached(\n                \"tmp_std_logic2vector_\",\n                std_logic_vector,\n                postponed_init=True,\n                extra_args=(val, std_logic_vector))\n            if isNew:\n                o._rtlDrivers.append(HdlAssignmentContainer(val, o, virtual_only=True))\n                self.tmpVars.finish_var_init(o)\n            return o\n        else:\n            # already a std_logic_vector\n            return val\n\n    def as_hdl_operand(self, operand: Union[RtlSignal, HConst]):\n        # automatically extract some operators as tmp variable\n        # * nested ternary in expressions like\n        #   ( '1'  WHEN r = f ELSE  '0' ) & \"0\"\n        # * nested array aggregate expressions\n        #   (0=>x, 1=>y) & \"0\"\n        isTernaryOp = False\n        isArrayAggregateOp = False\n        try:\n            if operand._isUnnamedExpr:\n                d = operand._rtlDrivers[0]\n                o = d.operator\n                if o == HwtOps.TERNARY:\n                    isTernaryOp = True\n                elif o == HwtOps.SEXT or o == HwtOps.ZEXT:\n                    op0T = d.operands[0]._dtype\n                    if op0T.signed is None and op0T.bit_length() == 1 and not op0T.force_vector:\n                        # :note: == if this is not SEXT/ZEXT implemented using VHDL resize()\n                        isArrayAggregateOp = True\n\n        except (AttributeError, IndexError):\n            pass\n\n        if isTernaryOp:\n            # rewrite ternary operator as if\n            operand = self._tmp_var_for_ternary(operand)\n        elif isArrayAggregateOp:\n            operand = self._tmp_var_for_arrayAggregate(operand)\n\n        return self.as_hdl(operand)\n\n    def apply_cast(self, t: HdlValueId, op):\n        return hdl_call(t, [op, ])\n\n    def _wrapConcatInTmpVariable(self, op):\n        if isinstance(op, RtlSignalBase) and op._isUnnamedExpr:\n            # if left operand is concatenation and this is not concatenation we must extract it as tmp variable\n            # because VHDL would not be able to resolve type of concatenated signal otherwise\n            try:\n                d = op.singleDriver()\n            except SignalDriverErr:\n                d = None\n\n            if d is not None and isinstance(d, HOperatorNode) and d.operator is HwtOps.CONCAT:\n                _, op = self.tmpVars.create_var_cached(\"tmpConcatExpr_\", op._dtype, def_val=op)\n        return op\n\n    def _as_hdl_HOperatorNode_mulWithTrunc(self, op: HOperatorNode,\n                                           src0Type: HBits, src1Type: HBits,\n                                           resType: HBits,\n                                           _op0: HdlOp, _op1: HdlOp):\n        # new tmp variable must be created because downto may be applied only on ID and not expression\n        width = src0Type.bit_length() + src1Type.bit_length()\n        resWidth = resType.bit_length()\n        if not src0Type.strict_width or not src1Type.strict_width or width == resWidth:\n            return HdlOp(HdlOpType.MUL, [_op0, _op1])\n\n        signed = src0Type.signed or src1Type.signed\n        assert signed == resType.signed\n        isNew, tmpMulTruncVar = self.tmpVars.create_var_cached(\n            \"tmpMulTrunc_\" if width > resWidth else \"tmpMulExt_\",\n            HBits(width, signed),\n            postponed_init=True,\n            extra_args=(op,))\n        if isNew:\n            hdl = self.tmpVars.extraVarsHdl\n            hdl_a = HdlStmAssign(HdlOp(HdlOpType.MUL, [_op0, _op1]), self.as_hdl_HdlSignalItem(tmpMulTruncVar))\n            hdl_a.is_blocking = True\n            hdl.append(hdl_a)\n            as_hdl = self.as_hdl_HdlSignalItem(tmpMulTruncVar, declaration=True)\n            hdl.append(as_hdl)\n\n        res = self.as_hdl_HdlSignalItem(tmpMulTruncVar)\n        if width > resWidth:\n            res = hdl_index(res, hdl_downto(self.as_hdl_int(resWidth - 1), self.as_hdl_int(0)))\n        else:\n            assert width < resWidth\n            _op1 = self.as_hdl_int(resWidth)\n            res = hdl_call(self.RESIZE, [res, _op1])\n\n        return res\n\n    def _as_hdl_HOperatorNode_castArg(self, op0: Union[HBitsConst, HBitsRtlSignal]):\n        if isinstance(op0, RtlSignalBase) and op0._isUnnamedExpr:\n            _, op0 = self.tmpVars.create_var_cached(\"tmpCastExpr_\", op0._dtype, def_val=op0)\n        return op0\n\n    def as_hdl_HOperatorNode_indexRhs(self, op1: Union[HBitsConst, HBitsRtlSignal]):\n        if isinstance(op1._dtype, HBits) and op1._dtype != INT:\n            if op1._dtype.signed is None:\n                if op1._dtype.bit_length() == 1 and not op1._dtype.force_vector:\n                    _, op1 = self.tmpVars.create_var_cached(\"tmp1bToUnsigned_\", HBits(1, force_vector=True), def_val=op1)\n                    _op1 = self.as_hdl_operand(op1)\n                    _op1 = self.apply_cast(self.UNSIGNED, _op1)\n                else:\n                    _op1 = self.as_hdl_operand(op1._unsigned())\n            else:\n                _op1 = self.as_hdl_operand(op1)\n\n            return self.apply_cast(self.TO_INTEGER, _op1)\n        else:\n            return self.as_hdl_operand(op1)\n\n    def as_hdl_HOperatorNode_TRUNC_SEXT_ZEXT(self, op: HOperatorNode, o: HOperatorDef):\n        op0, op1 = op.operands\n        op1 = int(op1)\n        assert op1 >= 1, op\n        resultSign = op.result._dtype.signed\n        signedForVhdlResize = o == HwtOps.SEXT  # :note: VHDL std_numeric.resize supports only signed or unsinged\n        if o == HwtOps.TRUNC:\n            if isinstance(op0, RtlSignalBase) and isResultOfTypeConversionForIndex(op0):\n                _, op0 = self.tmpVars.create_var_cached(\"tmpTypeConv_\", op0._dtype, def_val=op0)\n\n            if resultSign is None:\n                _op0 = self.as_hdl_operand(self._as_Bits(op0))\n                # prefer downto notation over resize with casts\n                op1 = int(op1)\n                assert op1 >= 1, op\n                if op1 == 1 and not op.result._dtype.force_vector:\n                    _sliceOp = self.as_hdl_int(0)\n                else:\n                    _sliceOp = HdlOp(HdlOpType.DOWNTO, [self.as_hdl_int(op1 - 1),\n                                                        self.as_hdl_int(0)])\n\n                return HdlOp(HdlOpType.INDEX, [_op0, _sliceOp])\n\n            signedForVhdlResize = resultSign  # it does not matter if trunc is signed/unsigned, but we preffer less casting\n        else:\n        #    _op0 = self.as_hdl_operand(self._as_Bits(op0))\n            op0 = self._as_Bits(op0)\n\n        op0T = op0._dtype\n        if o != HwtOps.TRUNC and\\\n           op0T.signed is None and\\\n           op0T.bit_length() == 1 and\\\n           not op0T.force_vector:\n\n            _op0 = self.as_hdl_operand(op0)\n            # use aggregate expression\n            if o == HwtOps.SEXT:\n                msb = _op0\n                return [HdlOp(HdlOpType.MAP_ASSOCIATION, [HdlOthers, msb]), ]\n            else:\n                msb = self.as_hdl_HBitsConst(b0)\n                return [\n                    HdlOp(HdlOpType.MAP_ASSOCIATION, [self.as_hdl_int(0), _op0]),\n                    HdlOp(HdlOpType.MAP_ASSOCIATION, [HdlOthers, msb]),\n                ]\n\n        else:\n            # use vhdl RESIZE()\n            if resultSign != signedForVhdlResize:\n                op0 = op0._cast_sign(signedForVhdlResize)\n\n            # :note: this must be done after sign casts on on RtlNetlist level because\n            #  otherwise the operands of cast may not recognize that tmp variable must be used for operand\n            _op0 = self.as_hdl_operand(op0)\n            _op1 = self.as_hdl_int(op1)\n            res = hdl_call(self.RESIZE, [_op0, _op1])\n\n            if resultSign != signedForVhdlResize:\n                res = self.apply_cast(self._sign_flag_to_cast_id[resultSign], res)\n\n        return res\n\n    def as_hdl_HOperatorNode_INDEX(self, op: HOperatorNode):\n        ops = op.operands\n        op0, op1 = ops\n        if isinstance(op0, RtlSignalBase) and isResultOfTypeConversionForIndex(op0):\n            _, op0 = self.tmpVars.create_var_cached(\"tmpTypeConv_\", op0._dtype, def_val=op0)\n        if isinstance(op1, RtlSignalBase) and isResultOfTypeConversionForIndex(op1):\n            _, op1 = self.tmpVars.create_var_cached(\"tmpIndexTypeConv_\", op1._dtype, def_val=op1)\n\n        # if the op0 is not signal or other index index operator it is extracted\n        # as tmp variable\n        op0 = self.as_hdl_operand(op0)\n        op0_t = ops[0]._dtype\n        if isinstance(op0_t, HBits) and op0_t.bit_length() == 1 and not op0_t.force_vector:\n            assert int(ops[1]) == 0, ops\n            # drop whole index operator because it is useless\n            return op0\n        _op1 = self.as_hdl_HOperatorNode_indexRhs(op1)\n\n        return HdlOp(HdlOpType.INDEX, [op0, _op1])\n\n    def as_hdl_HOperatorNode_TERNARY(self, op: HOperatorNode):\n        _c, _op0, _op1 = op.operands\n        op0 = self.as_hdl_cond(_c, True)\n        op1 = self.as_hdl_operand(_op0)\n        t0 = _op0._dtype\n        t1 = _op1._dtype\n        if not (t0 == t1):\n            assert isinstance(t0, HBits) and\\\n                   isinstance(t1, HBits) and\\\n                   t0.bit_length() == t1.bit_length() and\\\n                   bool(t0.signed) == bool(t1.signed), (t0, t1)\n            _, _op1 = self.tmpVars.create_var_cached(\"tmpTernaryAutoCast_\", t0, def_val=_op1)\n\n        op2 = self.as_hdl_operand(_op1)\n        return HdlOp(HdlOpType.TERNARY, [op0, op1, op2])\n\n    def as_hdl_HOperatorNode_asVhdlFn(self, op: HOperatorNode, vhldFn: HdlValueId, isArithmetical: Optional[bool]):\n        ops = op.operands\n        op0, op1 = ops\n        op0Signed = op0._dtype.signed\n        if isArithmetical:\n            if not op0Signed:\n                op0 = op0._cast_sign(True)\n                _, op0 = self.tmpVars.create_var_cached(\"tmpOpFnArgCast_\", op0._dtype, def_val=op0)\n        else:\n            if op0Signed or op0Signed is None:\n                op0 = op0._cast_sign(False)\n                _, op0 = self.tmpVars.create_var_cached(\"tmpOpFnArgCast_\", op0._dtype, def_val=op0)\n\n        _op0 = self.as_hdl_Value(op0)\n        _op1 = self.as_hdl_HOperatorNode_indexRhs(op1)\n        res = hdl_call(vhldFn, [_op0, _op1])\n        resSigned = op.result._dtype.signed\n        if op0Signed != isArithmetical:\n            res = self.apply_cast(self._sign_flag_to_cast_id[resSigned], res)\n\n        return res\n\n    def as_hdl_HOperatorNode(self, op: HOperatorNode):\n        o = op.operator\n\n        if o == HwtOps.INDEX:\n            return self.as_hdl_HOperatorNode_INDEX(op)\n        elif o == HwtOps.TRUNC or o == HwtOps.SEXT or o == HwtOps.ZEXT:\n            return self.as_hdl_HOperatorNode_TRUNC_SEXT_ZEXT(op, o)\n        elif o == HwtOps.TERNARY:\n            return self.as_hdl_HOperatorNode_TERNARY(op)\n        else:\n            ops = op.operands\n            _o = self._cast_ops.get(o, None)\n            if _o is not None:\n                op0 = ops[0]\n                op0 = self._as_Bits_vec(op0)\n                if isinstance(op0, RtlSignalBase) and op0._isUnnamedExpr:\n                    _, op0 = self.tmpVars.create_var_cached(\"tmpCastExpr_\", op0._dtype, def_val=op0)\n                return self.apply_cast(_o, self.as_hdl_operand(op0))\n\n            _o = o.hdlConvertoAstOp\n            if _o is None:\n                o = self.op_transl_dict[o]\n            else:\n                vhldFn, isArithmetical = self.HDLCONVERTORAST_TO_VHDL.get(_o, (None, None))\n                if vhldFn is not None:\n                    return self.as_hdl_HOperatorNode_asVhdlFn(op, vhldFn, isArithmetical)\n                o = _o\n\n            if len(ops) == 2:\n                res_t = op.result._dtype\n                op0, op1 = ops\n\n                if o == HdlOpType.MUL:\n                    # optionally drop zext/sext and add casts\n                    op0, op1 = matchFullWidthMul(op0, op1)\n\n                if o != HdlOpType.CONCAT:\n                    op0 = self._wrapConcatInTmpVariable(op0)\n                    op1 = self._wrapConcatInTmpVariable(op1)\n\n                if isinstance(res_t, HBits) and res_t != BOOL:\n                    op0 = self._as_Bits(op0)\n                    op1 = self._as_Bits(op1)\n\n                _op0 = self.as_hdl_operand(op0)\n                _op1 = self.as_hdl_operand(op1)\n                if o == HdlOpType.EQ and isinstance(_op0, HdlValueId) and\\\n                        (isinstance(_op0.obj._dtype, HBits) and self._expandBitsOperandType(_op0.obj) == BOOL) and\\\n                        isinstance(_op1, HdlValueInt) and\\\n                        _op1.val == 1:\n                    # drop unnecessary casts\n                    return _op0\n                elif o == HdlOpType.MUL:\n                    return self._as_hdl_HOperatorNode_mulWithTrunc(op, op0._dtype, op1._dtype, res_t, _op0, _op1)\n                else:\n                    assert o not in HDLCONVERTAST_OPS_SHIFT_AND_ROT, (o, \"shifts and rotations should have been handled sooner in this function\")\n                    return HdlOp(o, [_op0, _op1])\n\n            return HdlOp(o, [self.as_hdl_operand(o2)\n                             for o2 in ops])\n"
  },
  {
    "path": "hwt/serializer/vhdl/serializer.py",
    "content": "from natsort.natsort import natsorted\nimport re\nfrom typing import List\n\nfrom hdlConvertorAst.hdlAst import HdlOp, HdlModuleDec, HdlOpType, iHdlStatement\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlAll\nfrom hdlConvertorAst.hdlAst._statements import HdlImport, \\\n    HdlStmIf, HdlStmBlock, HdlStmFor, HdlStmForIn\nfrom hdlConvertorAst.hdlAst._structural import HdlLibrary, HdlModuleDef, \\\n    HdlCompInst, HdlContext\nfrom hdlConvertorAst.to.vhdl.keywords import VHLD2008_KEYWORDS\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword, NameScope\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_call\nfrom hwt.pyUtils.arrayQuery import groupedby\nfrom hwt.serializer.generic.to_hdl_ast import ToHdlAst\nfrom hwt.serializer.vhdl.ops import ToHdlAstVhdl2008_ops\nfrom hwt.serializer.vhdl.statements import ToHdlAstVhdl2008_statements\nfrom hwt.serializer.vhdl.types import ToHdlAstVhdl2008_types\nfrom hwt.serializer.vhdl.value import ToHdlAstVhdl2008_Value\n\n\nclass VhdlNameScope(NameScope):\n    RE_MANY_UNDERSCORES = re.compile(r\"(_{2,})\")\n\n    def checked_name(self, suggested_name, actualObj):\n        suggested_name = self._sanitize_name(suggested_name)\n        suggested_name = self.RE_MANY_UNDERSCORES.sub(r\"_\", suggested_name)\n        if suggested_name[0] == \"_\":\n            suggested_name = \"u\" + suggested_name\n        return NameScope.checked_name(self, suggested_name, actualObj)\n\n\nIEEE = HdlValueId(\"IEEE\", obj=LanguageKeyword())\nstd_logic_1164 = HdlValueId(\"std_logic_1164\", obj=LanguageKeyword())\nnumeric_std = HdlValueId(\"numeric_std\", obj=LanguageKeyword())\n\n\nclass ToHdlAstVhdl2008(ToHdlAstVhdl2008_Value,\n                       ToHdlAstVhdl2008_ops, ToHdlAstVhdl2008_types,\n                       ToHdlAstVhdl2008_statements, ToHdlAst):\n    \"\"\"\n    :ivar ~.name_scope: name scope used to generate a unique names for tmp variables\n        (all object should be registered in namescope before serialization)\n    \"\"\"\n    _keywords_dict = {kw: LanguageKeyword() for kw in VHLD2008_KEYWORDS}\n\n    DEFAULT_IMPORTS = [\n        HdlLibrary(\"IEEE\"),\n        HdlImport([IEEE, std_logic_1164, HdlAll]),\n        HdlImport([IEEE, numeric_std, HdlAll]),\n    ]\n    ASSERT = HdlValueId(\"assert\")\n    FAILURE = HdlValueId(\"failure\")\n\n    @classmethod\n    def getBaseNameScope(cls):\n        s = VhdlNameScope.make_top(True)\n        s.update(cls._keywords_dict)\n        return s\n\n    @staticmethod\n    def _find_HdlCompInst(o):\n        if isinstance(o, (list, tuple)):\n            for _o in o:\n                yield from ToHdlAstVhdl2008._find_HdlCompInst(_o)\n        if isinstance(o, HdlCompInst):\n            yield o\n        elif isinstance(o, HdlStmBlock) and o.in_preproc:\n            yield from ToHdlAstVhdl2008._find_HdlCompInst(o.body)\n        elif isinstance(o, HdlStmIf) and o.in_preproc:\n            if o.if_true:\n                yield from ToHdlAstVhdl2008._find_HdlCompInst(o.if_true)\n            for _, stms in o.elifs:\n                yield from ToHdlAstVhdl2008._find_HdlCompInst(stms)\n            if o.if_false:\n                yield from ToHdlAstVhdl2008._find_HdlCompInst(o.if_false)\n        elif isinstance(o, (HdlStmFor, HdlStmForIn)) and o.in_preproc:\n            if o.body:\n                yield from ToHdlAstVhdl2008._find_HdlCompInst(o.body)\n\n    def _static_assert_false(self, msg:str):\n        return hdl_call(self.ASSERT, [\n                 self.FALSE,\n                 msg,\n                 self.FAILURE])\n\n    def _static_assert_symbol_eq(self, symbol_name:str, v):\n        return hdl_call(self.ASSERT, [\n                 HdlOp(HdlOpType.EQ, [HdlValueId(symbol_name), v]),\n                 \"Generated only for this value\",\n                 self.FAILURE])\n\n    def _as_hdl_HdlModuleDef_param_asserts(self, new_m: HdlModuleDec) -> List[iHdlStatement]:\n        return ToHdlAst._as_hdl_HdlModuleDef_param_asserts_real(self, new_m)\n\n    def as_hdl_HdlModuleDef(self, o: HdlModuleDef):\n        \"\"\"\n        Translate hwt types and expressions to HDL AST and add explicit components\n        \"\"\"\n        _o = super(ToHdlAstVhdl2008, self).as_hdl_HdlModuleDef(o)\n        component_insts = []\n        for c in _o.objs:\n            component_insts.extend(self._find_HdlCompInst(c))\n\n        # select component instances with an unique module_name\n        components = [\n            x[1][0] for x in\n            groupedby(component_insts, lambda c: c.module_name)\n        ]\n        components = natsorted(components, key=lambda c: c.module_name)\n        components = [self.as_hdl_HldComponent(c)\n                      for c in components]\n        if components:\n            # :note: it is important that the asserts are at the end because\n            # we are detecting the declarations from the beginning and assert there would\n            # disturb that\n            objs = [*components, *_o.objs]\n            _o.objs = objs\n\n        res = HdlContext()\n        res.objs.extend(self.DEFAULT_IMPORTS)\n        res.objs.append(_o)\n        return res\n\n    def as_hdl_HldComponent(self, o: HdlCompInst):\n        c = self.as_hdl_HdlModuleDec(o.origin._rtlCtx.hwModDec)\n        return c\n"
  },
  {
    "path": "hwt/serializer/vhdl/statements.py",
    "content": "from copy import copy\n\nfrom hdlConvertorAst.hdlAst import HdlStmCase\nfrom hdlConvertorAst.hdlAst._statements import HdlStmAssign\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, BIT\nfrom hwt.hdl.types.sliceConst import HSliceConst\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.serializer.exceptions import SerializerException\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr\n\n\nclass ToHdlAstVhdl2008_statements():\n    \n    @staticmethod\n    def _expandBitsOperandType(v):\n        if v._dtype == BIT and isinstance(v, RtlSignalBase) and v._isUnnamedExpr:\n            try:\n                d = v.singleDriver()\n            except SignalDriverErr:\n                d = None\n            if d is not None and isinstance(d, HOperatorNode) and d.operator is HwtOps.INDEX and d.operands[0]._dtype == BOOL:\n                return BOOL\n        return v._dtype\n    \n    def as_hdl_HdlAssignmentContainer(self, a: HdlAssignmentContainer):\n        _dst = dst = a.dst\n        assert isinstance(dst, HdlSignalItem)\n\n        if a.indexes is not None:\n            for i in a.indexes:\n                if isinstance(i, HSliceConst):\n                    i = i.__copy__()\n                dst = dst[i]\n\n        src = a.src\n        dst_t = dst._dtype\n        correct = False\n        src_t = self._expandBitsOperandType(src)\n            \n        if dst_t == src_t:\n            correct = True\n        else:\n            src = a.src\n            if (isinstance(dst_t, HBits) and isinstance(src_t, HBits)):\n                # std_logic <-> boolean <->  std_logic_vector(0 downto 0) auto conversions\n                while not (dst_t == src_t):\n                    # while is used because the casting could be required multiple times\n                    correct = False\n                    if dst_t.bit_length() == src_t.bit_length() == 1:\n                        if dst_t.force_vector and not src_t.force_vector:\n                            dst = dst[0]\n                            correct = True\n                        elif not dst_t.force_vector and src_t.force_vector:\n                            src = src[0]\n                            correct = True\n                        elif src_t == BOOL:\n                            src = src._ternary(BIT.from_py(1), BIT.from_py(0))\n                            correct = True\n                    elif not src_t.strict_width:\n                        if isinstance(src, HConst):\n                            src = copy(src)\n                            if a.indexes:\n                                raise NotImplementedError()\n\n                            src._dtype = dst_t\n                            correct = True\n                        else:\n                            raise NotImplementedError()\n                            pass\n\n                    src_t = src._dtype\n                    dst_t = dst._dtype\n\n                    if not correct:\n                        # automatic type cast can not be performed\n                        break\n        if correct:\n            src = self.as_hdl(src)\n            hdl_a = HdlStmAssign(src, self.as_hdl(dst))\n            hdl_a.is_blocking = _dst.virtual_only\n            return hdl_a\n\n        raise SerializerException(\n            f\"{dst} = {a.src}  is not valid assignment\\n\"\n            f\" because types are different ({dst._dtype}; {a.src._dtype})\")\n\n    def as_hdl_SwitchContainer(self, sw: SwitchContainer) -> HdlStmCase:\n        s = HdlStmCase()\n        switchOn = sw.switchOn\n        if isinstance(switchOn, RtlSignalBase) and switchOn._isUnnamedExpr:\n            _, switchOn = self.tmpVars.create_var_cached(\"tmpTypeConv_\", switchOn._dtype, def_val=switchOn)\n\n        s.switch_on = self.as_hdl_cond(switchOn, False)\n        s.cases = cases = []\n        for key, statements in sw.cases:\n            key = self.as_hdl_Value(key)\n            cases.append((key, self.as_hdl_statements(statements)))\n\n        s.default = self.as_hdl_statements(sw.default)\n        return s\n\n    def can_pop_process_wrap(self, stms, hasToBeVhdlProcess):\n        if hasToBeVhdlProcess or len(stms) > 1:\n            return False\n        else:\n            assert len(stms) == 1, stms\n            return True\n\n    def has_to_be_process(self, proc: HdlStmCodeBlockContainer):\n        for x in proc.statements:\n            if isinstance(x, (IfContainer, SwitchContainer)):\n                return True\n        return False\n"
  },
  {
    "path": "hwt/serializer/vhdl/types.py",
    "content": "from hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId, HdlOp, HdlOpType, \\\n    HdlTypeType\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hdlConvertorAst.translate.verilog_to_basic_hdl_sim_model.utils import hdl_index, \\\n    hdl_downto\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.defs import BOOL, INT, FLOAT64\nfrom hwt.hdl.types.float import HFloat\nfrom hwt.hdl.types.string import HString\n\n\nclass ToHdlAstVhdl2008_types():\n    BOOLEAN = HdlValueId(\"BOOLEAN\", obj=LanguageKeyword())\n    INTEGER = HdlValueId(\"INTEGER\", obj=LanguageKeyword())\n    STRING = HdlValueId(\"STRING\", obj=LanguageKeyword())\n    STD_LOGIC_VECTOR = HdlValueId(\"STD_LOGIC_VECTOR\", obj=LanguageKeyword())\n    STD_LOGIC = HdlValueId(\"STD_LOGIC\", obj=LanguageKeyword())\n    SIGNED = HdlValueId(\"SIGNED\", obj=LanguageKeyword())\n    UNSIGNED = HdlValueId(\"UNSIGNED\", obj=LanguageKeyword())\n\n  \n    _sign_flag_to_cast_id = {\n        None: STD_LOGIC_VECTOR,\n        True: SIGNED,\n        False: UNSIGNED,\n    }\n    def as_hdl_HdlType_str(self, typ: HString, declaration=False):\n        assert not declaration\n        return self.STRING\n\n    def as_hdl_HdlType_bits(self, typ: HBits, declaration=False):\n        if declaration:\n            raise NotImplementedError()\n        if typ == BOOL:\n            return self.BOOLEAN\n        if typ == INT:\n            return self.INTEGER\n\n        bitLength = typ.bit_length()\n        w = typ.bit_length()\n        isVector = typ.force_vector or bitLength > 1\n\n        if typ.signed is None:\n            if isVector:\n                name = self.STD_LOGIC_VECTOR\n            else:\n                return self.STD_LOGIC\n        elif typ.signed:\n            name = self.SIGNED\n        else:\n            name = self.UNSIGNED\n\n        return HdlOp(HdlOpType.CALL, [\n            name,\n            HdlOp(HdlOpType.DOWNTO, [\n                self.as_hdl(w - 1),\n                self.as_hdl_int(0)\n            ])])\n\n    def as_hdl_HdlType_array(self, typ: HArray, declaration=False):\n        if declaration:\n            v = HdlIdDef()\n            name = getattr(typ, \"name\", None)\n            if name is None:\n                name = \"arr_t_\"\n            v.name = self.name_scope.checked_name(name, typ)\n            v.type = HdlTypeType\n            v.origin = typ\n            size = hdl_downto(\n                self.as_hdl_int(int(typ.size) - 1),\n                self.as_hdl_int(0)\n            )\n            if self.does_type_requires_extra_def(typ.element_t, ()):\n                raise NotImplementedError(typ.element_t)\n            e_t = self.as_hdl_HdlType(typ.element_t, declaration=False)\n            v.value = hdl_index(e_t, size)\n            return v\n        else:\n            return super(ToHdlAstVhdl2008_types, self).as_hdl_HdlType_array(typ, declaration)\n\n    def as_hdl_HdlType_float(self, typ: HFloat, declaration=False):\n        if typ == FLOAT64:\n            return HdlValueId(\"real\")\n        else:\n            raise NotImplementedError(typ)\n"
  },
  {
    "path": "hwt/serializer/vhdl/value.py",
    "content": "from hdlConvertorAst.hdlAst import HdlValueId, HdlValueInt, HdlOp, \\\n    HdlOpType\nfrom hdlConvertorAst.to.hdlUtils import bit_string\nfrom hdlConvertorAst.translate.common.name_scope import LanguageKeyword\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import BOOL, BIT\nfrom hwt.hdl.types.enumConst import HEnumConst\nfrom hwt.hdl.types.sliceConst import HSliceConst\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.generic.value import ToHdlAst_Value\n\n\nclass ToHdlAstVhdl2008_Value(ToHdlAst_Value):\n\n    TRUE = HdlValueId(\"TRUE\", obj=LanguageKeyword())\n    FALSE = HdlValueId(\"FALSE\", obj=LanguageKeyword())\n    # TO_UNSIGNED = HdlValueId(\"TO_UNSIGNED\", obj=LanguageKeyword())\n    # TO_SIGNED = HdlValueId(\"TO_SIGNED\", obj=LanguageKeyword())\n\n    def as_hdl_cond(self, c, forceBool):\n        assert isinstance(c, (RtlSignalBase, HConst)), c\n        if not forceBool or c._dtype == BOOL:\n            return self.as_hdl(c)\n        elif c._dtype == BIT:\n            return self.as_hdl(c._eq(1))\n        elif isinstance(c._dtype, HBits):\n            return self.as_hdl(c != 0)\n        else:\n            raise NotImplementedError()\n\n    def as_hdl_HEnumConst(self, val: HEnumConst):\n        name = self.name_scope.get_object_name(val)\n        return HdlValueId(name, obj=val)\n\n    def as_hdl_HArrayConst(self, val):\n        return [self.as_hdl_Value(v) for v in val]\n\n    def sensitivityListItem(self, item, anyIsEventDependnt):\n        if isinstance(item, HOperatorNode):\n            item = item.operands[0]\n        return self.as_hdl(item)\n\n    def as_hdl_BitString(self, v, width: int,\n                         force_vector: bool, vld_mask: int, signed):\n        is_bit = not force_vector and width == 1\n        # if vld_mask != mask(width) or width >= 32 or is_bit:\n        v = bit_string(v, width, vld_mask)\n        if is_bit:\n            v.base = 256\n            return v\n        if signed is None:\n            return v\n        elif signed:\n            cast = self.SIGNED\n        else:\n            cast = self.UNSIGNED\n        return HdlOp(HdlOpType.APOSTROPHE, [cast, v])\n\n        # else:\n        #    v = HdlValueInt(v, None, None)\n        #\n        #    if signed is None:\n        #        return v\n        #    elif signed:\n        #        cast_fn = self.TO_SIGNED\n        #    else:\n        #        cast_fn = self.TO_UNSIGNED\n        #    return hdl_call(cast_fn, [v, HdlValueInt(width, None, None)])\n\n    def as_hdl_HBoolConst(self, val: HBitsConst):\n        if val.val:\n            return self.TRUE\n        else:\n            return self.FALSE\n\n    def as_hdl_HBitsConst(self, val: HBitsConst):\n        t = val._dtype\n        v = super(ToHdlAstVhdl2008_Value, self).as_hdl_HBitsConst(val)\n        # handle '1' vs \"1\" difference (bit literal vs vector)\n        if not t.force_vector and t.bit_length() == 1 and t != BOOL:\n            if isinstance(v, HdlValueInt):\n                v.base = 256\n            else:\n                # assert is cast\n                assert isinstance(v, HdlOp) and v.fn == HdlOpType.CALL, v\n                _v = v.ops[1]\n                if isinstance(_v, HdlValueInt):\n                    _v.base = 256\n                else:\n                    raise NotImplementedError()\n        return v\n\n    def as_hdl_HSliceConst(self, val: HSliceConst):\n        upper = val.val.start\n        if int(val.val.step) == -1:\n            if isinstance(upper, HConst):\n                upper = HdlValueInt(int(upper) - 1, None, None)\n            else:\n                upper = HdlOp(HdlOpType.SUB, [self.as_hdl_Value(upper),\n                                                   HdlValueInt(1, None, None)])\n        else:\n            raise NotImplementedError(val.val.step)\n\n        return HdlOp(HdlOpType.DOWNTO, [upper, self.as_hdl(val.val.stop)])\n"
  },
  {
    "path": "hwt/serializer/xdc/__init__.py",
    "content": ""
  },
  {
    "path": "hwt/serializer/xdc/serializer.py",
    "content": "from itertools import islice\nfrom typing import Union, Tuple\n\nfrom hwt.constraints import set_max_delay, set_false_path, \\\n    set_async_reg, get_clock_of, iHdlConstrain\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.pyUtils.arrayQuery import iter_with_last\nfrom hwt.hwIO import HwIO\nfrom hwt.hwModule import HwModule\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\nclass XdcSerializer():\n    \"\"\"\n    Convert constrains containers to a XDC format (For Xilinx Vivado)\n    \"\"\"\n    fileExtension = \".xdc\"\n\n    def __init__(self, out):\n        self.out = out\n\n    def _get(self, o: Union[Tuple[HwModule, RtlSignal, HwIO], iHdlConstrain], only_first=False):\n        \"\"\"\n        :param only_first: if true select only first bit from vector, else select whole vector\n        \"\"\"\n        if isinstance(o, iHdlConstrain):\n            return self.visit_iHdlConstrain(o)\n\n        is_reg = False\n        _o = o[-1]\n        if isinstance(_o, RtlSignal):\n            q = \"get_cells\"\n            for d in _o._rtlDrivers:\n                if d._event_dependent_from_branch is not None:\n                    is_reg = True\n\n        elif isinstance(_o, HwIO):\n            q = \"get_pins\"\n\n        else:\n            raise NotImplementedError(o)\n\n        w = self.out.write\n        w(q)\n        w(\" -hier -filter {NAME =~ */\")\n        path = o\n        # [TODO] find out how to make select with ip top module/entity name\n        for last, p in iter_with_last(islice(path, 1, None)):\n            if isinstance(p, HwModule):\n                w(p._name)\n                w(\"_inst\")\n            elif isinstance(p, RtlSignal):\n                w(p._name)\n            elif isinstance(p, HwIO):\n                w(p._name)\n            else:\n                raise NotImplementedError(p)\n            if not last:\n                w(\"/\")\n\n        t = _o._dtype\n        if is_reg:\n            w(\"_reg\")\n        if isinstance(t, HBits) and (t.bit_length() > 1 or t.force_vector):\n            # * on end because of Vivado _replica\n            if only_first:\n                w(\"[0]*\")\n            else:\n                w(\"[*]*\")\n        w(\"}\")\n\n    def visit_get_clock_of(self, o: get_clock_of):\n        w = self.out.write\n        if isinstance(o.obj[-1], RtlSignal) and o.obj[-1]._rtlNextSig is not None:\n            w(\"get_clocks -of [\")\n            self._get(o.obj)\n            w(\"]\")\n        else:\n            raise NotImplementedError()\n\n    def visit_iHdlConstrain(self, o):\n        visitFn = getattr(self, \"visit_\" + o.__class__.__name__, None)\n        if visitFn is None:\n            return o.to_xdc(self, o)\n        else:\n            return visitFn(o)\n\n    def visit_HdlConstraintList(self, o_list):\n        return [self.visit_iHdlConstrain(o) for o in o_list]\n\n    def visit_set_async_reg(self, o: set_async_reg):\n        w = self.out.write\n        w(\"set_property ASYNC_REG TRUE [\")\n        self._get(o.sig)\n        w(\"]\\n\")\n\n    def visit_set_false_path(self, o: set_false_path):\n        w = self.out.write\n        w(\"set_false_path\")\n        if o.start is not None:\n            w(\" -from [\")\n            self._get(o.start)\n            w(\"]\")\n        if o.end is not None:\n            w(\" -to [\")\n            self._get(o.end)\n            w(\"]\")\n        w(\"\\n\")\n\n    def visit_set_max_delay(self, o: set_max_delay):\n        w = self.out.write\n        w(\"set_max_delay -from [\")\n        self._get(o.start)\n        w(\"] -to [\")\n        self._get(o.end)\n        w(\"]\")\n        if o.datapath_only:\n            w(\" -datapath_only\")\n        w(f\" {o.time_ns:f}\\n\")\n"
  },
  {
    "path": "hwt/simulator/__init__.py",
    "content": "\"\"\"\nA package for binding to simulators and simulation utils.\n\n:note: hwt package does not contain any RTL simulator, this is just an api to simulators.\n\"\"\"\n"
  },
  {
    "path": "hwt/simulator/agentBase.py",
    "content": "from hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwtSimApi.agents.base import AgentBase, SyncAgentBase as pcSyncAgentBase, \\\n    AgentWitReset as pcAgentWitReset\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.process_utils import OnRisingCallbackLoop\n\n\nclass AgentWitReset(pcAgentWitReset):\n\n    def __init__(self, sim: HdlSimulator, hwIO, allowNoReset=False):\n        pcAgentWitReset.__init__(self, sim, hwIO, (None, False))\n        self.rst, self.rstOffIn = self._discoverReset(hwIO, allowNoReset)\n\n    @classmethod\n    def _discoverReset(cls, hwIO, allowNoReset: bool):\n        try:\n            rst = hwIO._getAssociatedRst()\n            rstOffIn = int(rst._dtype.negated)\n            rst = rst._sigInside\n        except IntfLvlConfErr:\n            rst = None\n            rstOffIn = True\n            if not allowNoReset:\n                raise\n        return (rst, rstOffIn)\n\n    def notReset(self):\n        if self.rst is None:\n            return True\n        else:\n            rstVal = self.rst.read()\n            rstVal = int(rstVal)\n            return rstVal == self.rstOffIn\n\n\nclass SyncAgentBase(AgentWitReset, pcSyncAgentBase):\n    \"\"\"\n    Agent which discovers clk, rst signal and runs only\n    at specified edge of clk\n\n    :attention: requires clk and rst/rstn signal\n        (if you do not have any create simulation wrapper with it)\n    \"\"\"\n    SELECTED_EDGE_CALLBACK = OnRisingCallbackLoop\n\n    def __init__(self, sim: HdlSimulator, hwIO, allowNoReset=False):\n        self.hwIO = hwIO\n        clk = self.hwIO._getAssociatedClk()\n        rst = self._discoverReset(hwIO, allowNoReset)\n        pcSyncAgentBase.__init__(\n            self, sim, hwIO, clk, rst)\n\n"
  },
  {
    "path": "hwt/simulator/agentConnector.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.constants import INTF_DIRECTION\nfrom hwt.hwModule import HwModule\nfrom hwtSimApi.hdlSimulator import HdlSimulator\n\n\n@internal\ndef autoAddAgents(module: HwModule, sim: HdlSimulator):\n    \"\"\"\n    Walk all interfaces on module and instantiate agent for every interface.\n\n    :return: all monitor/driver functions which should be added to simulation\n         as processes\n    \"\"\"\n    for hio in module._hwIOs:\n        assert hio._isExtern, hio\n\n        hio._initSimAgent(sim)\n        assert hio._ag is not None, hio\n\n\n@internal\ndef collect_processes_from_sim_agents(module: HwModule):\n    proc = []\n    for hio in module._hwIOs:\n        a = hio._ag\n        if not hio._isExtern or a is None:\n            continue\n\n        if hio._direction == INTF_DIRECTION.MASTER:\n            agProcs = a.getMonitors()\n        elif hio._direction == INTF_DIRECTION.SLAVE:\n            agProcs = a.getDrivers()\n        else:\n            raise NotImplementedError(f\"hio._direction {hio._direction} for {hio}\")\n\n        proc.extend(agProcs)\n\n    return proc\n\n"
  },
  {
    "path": "hwt/simulator/rtlSimulator.py",
    "content": "from datetime import datetime\nimport importlib\nfrom io import StringIO\nimport os\nimport sys\nfrom types import ModuleType\nfrom typing import Union, Optional, Set, Tuple, Callable\n\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hwIO import HwIO\nfrom hwt.hwModule import HwModule\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.serializer.serializer_filter import SerializerFilterDoNotExclude\nfrom hwt.serializer.simModel import SimModelSerializer\nfrom hwt.serializer.store_manager import SaveToStream, SaveToFilesFlat\nfrom hwt.synth import to_rtl\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwtSimApi.basic_hdl_simulator.model import BasicRtlSimModel\nfrom hwtSimApi.basic_hdl_simulator.proxy import BasicRtlSimProxy\nfrom hwtSimApi.basic_hdl_simulator.rtlSimulator import BasicRtlSimulator\nfrom hwtSimApi.basic_hdl_simulator.sim_utils import ValueUpdater, \\\n    ArrayValueUpdater\nfrom pyDigitalWaveTools.vcd.common import VCD_SIG_TYPE\nfrom pyDigitalWaveTools.vcd.value_format import VcdBitsFormatter, \\\n    VcdEnumFormatter\nfrom pyDigitalWaveTools.vcd.writer import VcdVarWritingScope, \\\n    VarAlreadyRegistered\nfrom pyMathBitPrecise.bits3t import Bits3t\nfrom pyMathBitPrecise.enum3t import Enum3t\n\n\nclass BasicRtlSimulatorWithSignalRegisterMethods(BasicRtlSimulator):\n    supported_type_classes = tuple()\n\n    def __init__(self, model_cls, synthesised_unit):\n        \"\"\"\n        Only store variables for later construction\n        \"\"\"\n        self.model_cls = model_cls\n        self.synthesised_unit = synthesised_unit\n        self.wave_writer = None\n        self._obj2scope = {}\n        self._traced_signals = set()\n\n    def __call__(self) -> \"BasicRtlSimulatorVcd\":\n        \"\"\"\n        Create and initialize the BasicRtlSimulatorWithVCD object\n        \"\"\"\n        sim = self.__class__(self.model_cls, self.synthesised_unit)\n        super(BasicRtlSimulatorWithSignalRegisterMethods, sim).__init__()\n        model = self.model_cls(sim)\n        model._init_body()\n        sim.bound_model(model)\n        return sim\n\n    def _init_listeners(self):\n        self.logPropagation = False\n        self.logApplyingValues = False\n\n    @classmethod\n    def build(cls,\n              module: HwModule,\n              unique_name: str,\n              build_dir: Optional[str],\n              target_platform=DummyPlatform(),\n              do_compile=True) -> \"BasicRtlSimulatorVcd\":\n        \"\"\"\n        Create a hwtSimApi.basic_hdl_simulator based simulation model\n        for specified unit and load it to python\n\n        :param module: interface level unit which you wont prepare for simulation\n        :param unique_name: unique name for build directory and python module with simulator\n        :param target_platform: target platform for this synthesis\n        :param build_dir: directory to store sim model build files,\n            if None sim model will be constructed only in memory\n        \"\"\"\n        if unique_name is None:\n            unique_name = module._getDefaultName()\n\n        _filter = SerializerFilterDoNotExclude()\n        if build_dir is None or not do_compile:\n            buff = StringIO()\n            store_man = SaveToStream(SimModelSerializer, buff, _filter=_filter)\n        else:\n            if not os.path.isabs(build_dir):\n                build_dir = os.path.join(os.getcwd(), build_dir)\n            build_private_dir = os.path.join(build_dir, unique_name)\n            store_man = SaveToFilesFlat(SimModelSerializer,\n                                        build_private_dir,\n                                        _filter=_filter)\n            store_man.module_path_prefix = unique_name\n\n        to_rtl(module,\n               name=unique_name,\n               target_platform=target_platform,\n               store_manager=store_man)\n\n        if build_dir is not None:\n            d = build_dir\n            dInPath = d in sys.path\n            if not dInPath:\n                sys.path.insert(0, d)\n            if unique_name in sys.modules:\n                del sys.modules[unique_name]\n            simModule = importlib.import_module(\n                unique_name + \".\" + unique_name,\n                package='simModule_' + unique_name)\n\n            if not dInPath:\n                sys.path.pop(0)\n        else:\n            simModule = ModuleType('simModule_' + unique_name)\n            # python supports only ~100 opened brackets; MemoryError: s_push: parser stack overflow\n            # python supports only ~100 levels of indentation; IndentationError: too many levels of indentation\n            exec(buff.getvalue(),\n                 simModule.__dict__)\n\n        model_cls = simModule.__dict__[module._name]\n        # can not use just function as it would get bounded to class\n        return cls(model_cls, module)\n\n    @internal\n    @staticmethod\n    def _get_rtl_instance_name_from_submodule_name(name: str):\n        name = name.replace(\".\", \"_\") + \"_inst\"\n        if name.startswith(\"_\"):\n            return \"v\" + name\n        return name\n\n    @internal\n    @staticmethod\n    def get_trace_formatter(t)\\\n            ->Tuple[str, int, Callable[[RtlSignalBase, HConst], str]]:\n        \"\"\"\n        :return: (vcd type name, vcd width, formatter fn)\n        \"\"\"\n        if isinstance(t, (Bits3t, HBits)):\n            return (VCD_SIG_TYPE.WIRE, t.bit_length(), VcdBitsFormatter())\n        elif isinstance(t, (Enum3t, HEnum)):\n            return (VCD_SIG_TYPE.REAL, 1, VcdEnumFormatter())\n        else:\n            raise ValueError(t)\n\n    def set_trace_file(self, file_name, trace_depth):\n        self.create_wave_writer(file_name)\n        ww = self.wave_writer\n        if ww is not None:\n            ww.date(datetime.now())\n            ww.timescale(1)\n\n            empty_hiearchy_containers = set()\n            self._collect_empty_hiearchy_containers(self.synthesised_unit, self.model, empty_hiearchy_containers)\n            self._wave_register_signals(self.synthesised_unit, self.model, None, empty_hiearchy_containers)\n\n            ww.enddefinitions()\n\n    def create_wave_writer(self, file_name: str):\n        self.wave_writer = None\n\n    def finalize(self):\n        pass\n\n    def _collect_empty_hiearchy_containers(self,\n                                   obj: Union[HwIO, HwModule],\n                                   model: BasicRtlSimModel,\n                                   res: Set[Union[HwModule, HwIO]]):\n        hwIOs = getattr(obj, \"_hwIOs\", None)\n        isEmpty = True\n        if hwIOs or isinstance(obj, HObjList):\n            for chHwIO in hwIOs:\n                isEmpty &= self._collect_empty_hiearchy_containers(chHwIO, model, res)\n\n            if isinstance(obj, HwModule):\n                seenNames: Set[str] = set()\n                for chHwIO in obj._private_hwIOs:\n                    # skip io without name and with duplicit name\n                    if chHwIO._name is not None and chHwIO._name not in seenNames:\n                        seenNames.add(chHwIO._name)\n                        isEmpty &= self._collect_empty_hiearchy_containers(chHwIO, model, res)\n\n                for sm in obj._subHwModules:\n                    m = getattr(model, self._get_rtl_instance_name_from_submodule_name(sm._name))\n                    if sm._shared_component_with is not None:\n                        sm, _, _ = sm._shared_component_with\n                    isEmpty &= self._collect_empty_hiearchy_containers(sm, m, res)\n            if isEmpty:\n                res.add(obj)\n        else:\n            s = obj._sigInside\n            if s is not None:\n                # _sigInside is None if the signal was optimized out\n                sig_name = s._name if isinstance(s, RtlSignal) else s._hdlName\n                s = getattr(model.io, sig_name, None)\n                if s is not None:\n                    return False\n        return isEmpty\n\n    def _wave_register_signals(self,\n                              obj: Union[HwIO, HwModule],\n                              model: BasicRtlSimModel,\n                              parent: Optional[VcdVarWritingScope],\n                              empty_hiearchy_containers: Set[Union[HwModule, HwIO]]):\n        \"\"\"\n        Register signals from interfaces for HwIO or :class:`hwt.hwModule.HwModule` instances\n        \"\"\"\n        if obj in empty_hiearchy_containers:\n            return\n        if obj._hwIOs:\n            # if HwModules may be shared components, for them the top name is the one of shared and not this module name\n            name = model._name if isinstance(obj, HwModule) else obj._name\n            parent_ = self.wave_writer if parent is None else parent\n\n            subScope = parent_.varScope(name)\n            self._obj2scope[obj] = subScope\n\n            with subScope:\n                # register all subinterfaces\n                for chHwIO in obj._hwIOs:\n                    self._wave_register_signals(chHwIO, model, subScope, empty_hiearchy_containers)\n                if isinstance(obj, HwModule):\n                    for chHwIO in obj._private_hwIOs:\n                        # skip io without name and with duplicit name\n                        if chHwIO._name is not None and chHwIO._name not in subScope.children:\n                            self._wave_register_signals(chHwIO, model, subScope, empty_hiearchy_containers)\n\n                    # register interfaces from all subunits\n                    for sm in obj._subHwModules:\n                        m = getattr(model, self._get_rtl_instance_name_from_submodule_name(sm._name))\n                        if sm._shared_component_with is not None:\n                            sm, _, _ = sm._shared_component_with\n                        self._wave_register_signals(sm, m, subScope, empty_hiearchy_containers)\n\n                    self._wave_register_remaining_signals(subScope, model, empty_hiearchy_containers)\n        else:\n            t = obj._dtype\n            if obj._sigInside is not None and isinstance(t, self.supported_type_classes):\n                s = obj._sigInside\n                sig_name = s._name if isinstance(s, RtlSignal) else s._hdlName\n                s = getattr(model.io, sig_name, None)\n                if s is not None:\n                    tName, width, formatter = self.get_trace_formatter(t)\n                    try:\n                        parent.addVar(s, sig_name, tName, width, formatter)\n                    except VarAlreadyRegistered:\n                        pass\n\n    def _wave_register_remaining_signals(self, unitScope,\n                                        model: BasicRtlSimModel,\n                                        interface_signals: Set[BasicRtlSimProxy]):\n        for s in model._hwIOs:\n            if s not in interface_signals and s not in self.wave_writer._idScope:\n                t = s._dtype\n                if isinstance(t, self.supported_type_classes):\n                    tName, width, formatter = self.get_trace_formatter(t)\n                    try:\n                        unitScope.addVar(s, s._hdlName, tName, width, formatter)\n                    except VarAlreadyRegistered:\n                        pass\n\n    def logChange(self, nowTime: int,\n                  sig: BasicRtlSimProxy,\n                  nextVal: HConst,\n                  valueUpdater: Union[ValueUpdater, ArrayValueUpdater]):\n        \"\"\"\n        This method is called for every value change of any signal.\n        \"\"\"\n        pass\n"
  },
  {
    "path": "hwt/simulator/rtlSimulatorJson.py",
    "content": "from typing import Tuple, Callable, Union\n\nfrom pyMathBitPrecise.array3t import Array3t\nfrom pyMathBitPrecise.bits3t import Bits3t\nfrom pyMathBitPrecise.enum3t import Enum3t\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.const import HConst\nfrom hwt.simulator.rtlSimulator import BasicRtlSimulatorWithSignalRegisterMethods\nfrom hwt.mainBases import RtlSignalBase\nfrom pyDigitalWaveTools.json.writer import JsonWriter\nfrom pyDigitalWaveTools.vcd.common import VCD_SIG_TYPE\nfrom hwtSimApi.basic_hdl_simulator.proxy import BasicRtlSimProxy\nfrom hwtSimApi.basic_hdl_simulator.sim_utils import ValueUpdater, \\\n    ArrayValueUpdater\nfrom pyDigitalWaveTools.json.value_format import JsonBitsFormatter,\\\n    JsonEnumFormatter, JsonArrayFormatter\n\n\nclass BasicRtlSimulatorJson(BasicRtlSimulatorWithSignalRegisterMethods):\n    supported_type_classes = (HBits, HEnum, HArray, Bits3t, Enum3t, Array3t)\n\n    @internal\n    def get_trace_formatter(self, t: HdlType)\\\n            -> Tuple[str, int, Callable[[RtlSignalBase, HConst], str]]:\n        \"\"\"\n        :return: (vcd type name, vcd width, formatter fn)\n        \"\"\"\n        if isinstance(t, (Bits3t, HBits)):\n            return (VCD_SIG_TYPE.WIRE, t.bit_length(), JsonBitsFormatter())\n        elif isinstance(t, (Enum3t, HEnum)):\n            return (VCD_SIG_TYPE.ENUM, 1, JsonEnumFormatter())\n        elif isinstance(t, (HArray, Array3t)):\n            dimensions = []\n            while isinstance(t, (HArray, Array3t)):\n                dimensions.append(t.size)\n                t = t.element_t\n            _, _, elm_format = self.get_trace_formatter(t)\n            return (VCD_SIG_TYPE.ARRAY,\n                    dimensions + [t.bit_length(), ],\n                    JsonArrayFormatter(dimensions, elm_format))\n        else:\n            raise ValueError(t)\n\n    def create_wave_writer(self, data):\n        self.wave_writer = JsonWriter(data)\n\n    def logChange(self, nowTime: int,\n                  sig: BasicRtlSimProxy, \n                  nextVal: HConst,\n                  valueUpdater: Union[ValueUpdater, ArrayValueUpdater]):\n        \"\"\"\n        This method is called for every value change of any signal.\n        \"\"\"\n        try:\n            self.wave_writer.logChange(nowTime, sig, nextVal, valueUpdater)\n        except KeyError:\n            # not every signal has to be registered\n            # (if it is not registered it means it is ignored)\n            pass\n"
  },
  {
    "path": "hwt/simulator/rtlSimulatorVcd.py",
    "content": "\nimport sys\nfrom typing import Union\n\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.enum import HEnum\nfrom hwt.hdl.const import HConst\nfrom hwt.simulator.rtlSimulator import BasicRtlSimulatorWithSignalRegisterMethods\nfrom hwtSimApi.basic_hdl_simulator.proxy import BasicRtlSimProxy\nfrom hwtSimApi.basic_hdl_simulator.sim_utils import ValueUpdater, \\\n    ArrayValueUpdater\nfrom pyDigitalWaveTools.vcd.writer import VcdWriter\n#from pyMathBitPrecise.array3t import Array3t\nfrom pyMathBitPrecise.bits3t import Bits3t\nfrom pyMathBitPrecise.enum3t import Enum3t\n\n\nclass BasicRtlSimulatorVcd(BasicRtlSimulatorWithSignalRegisterMethods):\n    supported_type_classes = (HBits, HEnum, Bits3t, Enum3t,\n                              #Array3t\n                              )\n\n    def create_wave_writer(self, file_name):\n        self.wave_writer = VcdWriter(open(file_name, \"w\"))\n        self.logChange = self._logChange\n\n    def finalize(self):\n        # because set_trace_file() may not be called\n        # and it this case the vcd config is not set\n        if self.wave_writer is None:\n            return\n\n        f = self.wave_writer._oFile\n        if f not in (sys.__stderr__, sys.__stdin__, sys.__stdout__):\n            f.close()\n\n    def _logChange(self, nowTime: int,\n                  sig: BasicRtlSimProxy,\n                  nextVal: HConst,\n                  valueUpdater: Union[ValueUpdater, ArrayValueUpdater]):\n        \"\"\"\n        This method is called for every value change of any signal.\n        \"\"\"\n        try:\n            self.wave_writer.logChange(nowTime, sig, nextVal, valueUpdater)\n        except KeyError:\n            # not every signal has to be registered\n            # (if it is not registered it means it is ignored)\n            pass\n"
  },
  {
    "path": "hwt/simulator/simTestCase.py",
    "content": "import os\nfrom random import Random\nfrom typing import Optional\nimport unittest\n\nfrom hwt.simulator.agentConnector import autoAddAgents, \\\n    collect_processes_from_sim_agents\nfrom hwt.simulator.rtlSimulatorVcd import BasicRtlSimulatorVcd\nfrom hwt.simulator.utils import reconnectHwModuleSignalsToModel, Bits3valToInt, \\\n    allHConstsToInts\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\nfrom hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwt.hwModule import HwModule\nfrom hwtSimApi.constants import CLK_PERIOD\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom hwtSimApi.triggers import Timer\nfrom hwtSimApi.utils import freq_to_period\n\n\nclass DummySimPlatform(DummyPlatform):\n    \"\"\"\n    DummyPlatform which ignores the constraints\n    (hardware constranints which specifying something for circuit synthesis for a vendor tool)\n    \"\"\"\n\n\n_UNSPECIFIED = object()\n\n\nclass SimTestCase(unittest.TestCase):\n    \"\"\"\n    This is TestCase class contains methods which are usually used during\n    hdl simulation.\n\n    :attention: self.procs has to be specified before runSim()\n    :cvar _defaultSeed: default seed for random generator\n    :cvar rtl_simulator_cls: class for RTL simulator to use\n        (constructed in compileSim())\n    :ivar ~.dut: instance of current :class:`hwt.hwModule.HwModule` for test, created in restartSim()\n    :ivar ~.rtl_simulator: RTL simulator used for simulation of unit,\n        created in restartSim()\n    :ivar ~.hdl_simulator: the simulator which manages the communication\n        between Python code and rtl_simulator instance\n    :ivar ~.procs: list of simulation processes (Python generator instances),\n        created in restartSim()\n    :ivar ~.DEFAULT_BUILD_DIR: default directory where files for simulation should be stored\n    :ivar ~.DEFAULT_LOG_DIR: default directory where simulation outputs should be stored\n    :ivar ~.DEFAULT_SIMULATOR: default RTL simulator generator used on background of the test\n    :ivar ~.RECOMPILE: if False the compilation of the simulation is dissabled.\n        This is useful while debugging of the simulation because compilation of simulation\n        may take significant amount of time and may not be required.\n    \"\"\"\n    # value chosen because in this position bits are changing frequently\n    _defaultSeed = 317\n    RECOMPILE = True\n    rtl_simulator_cls = None\n    hdl_simulator = None\n    DEFAULT_BUILD_DIR = None  # \"tmp\"\n    DEFAULT_LOG_DIR = \"tmp\"\n    DEFAULT_SIMULATOR = BasicRtlSimulatorVcd\n\n    def assertValEqual(self, first, second, msg=None):\n        try:\n            first = first.read()\n        except AttributeError:\n            pass\n\n        if not isinstance(first, int) and first is not None:\n            first = Bits3valToInt(first)\n\n        return unittest.TestCase.assertEqual(self, first, second, msg=msg)\n\n    def assertEmpty(self, val, msg=None):\n        return unittest.TestCase.assertEqual(self, len(val), 0, msg=msg)\n\n    def assertValSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):\n        \"\"\"\n        An equality assertion for ordered sequences (like lists and tuples).\n        For the purposes of this function, a valid ordered sequence type is one\n        which can be indexed, has a length, and has an equality operator.\n\n        Args:\n\n        :param seq1: can contain instance of values or nested list of them\n        :param seq2: items are not converted, if item is None it is not checked\n        :param seq_type: The expected data type of the sequences, or None if no\n            data type should be enforced.\n        :param msg: Optional message to use on failure instead of a list of\n            differences.\n        \"\"\"\n        seq1 = allHConstsToInts(seq1)\n        if len(seq1) == len(seq2):\n            _seq2 = []\n            # replace None in seq2 with values from seq1\n            for v1, v2 in zip(seq1, seq2):\n                if v2 is None:\n                    v2 = v1\n                _seq2.append(v2)\n            seq2 = _seq2\n\n        self.assertSequenceEqual(seq1, seq2, msg, seq_type)\n\n    def getTestName(self):\n        className, testName = self.id().split(\".\")[-2:]\n        return f\"{className:s}_{testName:s}\"\n\n    def runSim(self, until: int, name=None):\n        \"\"\"\n        Collect sim. processes from iterface agents and run simulation\n        \"\"\"\n        if name is None:\n            if self.DEFAULT_LOG_DIR is None:\n                outputFileName = None\n            else:\n                outputFileName = os.path.join(self.DEFAULT_LOG_DIR,\n                                              self.getTestName() + \".vcd\")\n        else:\n            outputFileName = name\n\n        if outputFileName is not None:\n            d = os.path.dirname(outputFileName)\n            if d:\n                os.makedirs(d, exist_ok=True)\n\n            self.rtl_simulator.set_trace_file(outputFileName, -1)\n        procs = collect_processes_from_sim_agents(self.dut)\n        # run simulation, stimul processes are register after initial\n        # initialization\n        self.hdl_simulator.run(until=until, extraProcesses=self.procs + procs)\n        self.rtl_simulator.finalize()\n        return self.hdl_simulator\n\n    def randomize(self, hwIO):\n        \"\"\"\n        Randomly disable and enable interface for testing purposes\n        \"\"\"\n        assert hwIO._isExtern, hwIO\n        assert hwIO._ag is not None, hwIO\n        try:\n            clk = hwIO._getAssociatedClk()\n        except IntfLvlConfErr:\n            clk = None\n        clk_period = int(freq_to_period(clk.FREQ))\n        randomEnProc = simpleRandomizationProcess(self, hwIO._ag, timeQuantum=clk_period)\n        self.procs.append(randomEnProc())\n\n    def restartSim(self):\n        \"\"\"\n        Set simulator to initial state and connect it to\n\n        :return: tuple (fully loaded HwModule with connected simulator,\n            connected simulator,\n            simulation processes\n            )\n        \"\"\"\n        rtl_simulator = self.rtl_simulator_cls()\n        hdl_simulator = HdlSimulator(rtl_simulator)\n\n        dut = self.dut\n        reconnectHwModuleSignalsToModel(dut, rtl_simulator)\n        autoAddAgents(dut, hdl_simulator)\n        self.procs = []\n        self.dut, self.rtl_simulator, self.hdl_simulator = \\\n            dut, rtl_simulator, hdl_simulator\n\n        return dut, rtl_simulator, self.procs\n\n    def rmSim(self):\n        \"\"\"\n        Remove all buid sim objects from this object\n\n        :note: Can be used to avoid unnecessary sim initialization (from prev. test) before next test.\n        \"\"\"\n        self.dut = None\n        self.__class__.dut = None\n        try:\n            delattr(self, \"rtl_simulator_cls\")\n        except AttributeError:\n            pass\n        self.__class__.rtl_simulator_cls = None\n        self.rtl_simulator = None\n        self.hdl_simulator = None\n        self.__class__.hdl_simulator = None\n\n    @classmethod\n    def get_unique_name(cls, module: HwModule):\n        uniq_name = module._getDefaultName()\n        return f\"{cls.__name__:s}__{uniq_name:s}\"\n\n    @classmethod\n    def compileSim(cls, dut: HwModule, build_dir: Optional[str]=_UNSPECIFIED,\n                   unique_name: Optional[str]=None, onAfterToRtl=None,\n                   target_platform=DummySimPlatform()):\n        \"\"\"\n        Create simulation model and connect it with interfaces of original unit\n        and decorate it with agents\n\n        :param dut: interface level unit which you wont prepare for simulation\n        :param target_platform: target platform for this synthesis\n        :param build_dir: folder to where to put sim model files,\n            if None temporary folder is used and then deleted\n            (or simulator will be constructed in memory if possible)\n        :param unique_name: name which is used as name of the dut for simulation\n            (if is None it is automatically generated)\n        :param onAfterToRtl: callback fn(unit) which will be called\n            after unit will be synthesised to RTL\n            and before :class:`hwt.hwModule.HwModule` instance signals are replaced\n            with simulator specific ones\n        \"\"\"\n        if build_dir == _UNSPECIFIED:\n            build_dir = cls.DEFAULT_BUILD_DIR\n\n        if unique_name is None:\n            unique_name = cls.get_unique_name(dut)\n\n        cls.rtl_simulator_cls = cls.DEFAULT_SIMULATOR.build(\n            dut,\n            unique_name=unique_name,\n            build_dir=build_dir,\n            target_platform=target_platform,\n            do_compile=cls.RECOMPILE)\n\n        if onAfterToRtl:\n            onAfterToRtl(dut)\n\n        cls.dut = dut\n\n    def compileSimAndStart(\n            self,\n            dut: HwModule,\n            build_dir: Optional[str]=_UNSPECIFIED,\n            unique_name: Optional[str]=None,\n            onAfterToRtl=None,\n            target_platform=DummySimPlatform()):\n        \"\"\"\n        Use this method if you did not used compileSim()\n        to setup the simulator and DUT\n        \"\"\"\n        if unique_name is None:\n            t_name = self.getTestName()\n            u_name = dut._getDefaultName()\n            unique_name = f\"{t_name:s}__{u_name:s}\"\n        self.dut = dut\n        self.compileSim(dut, build_dir, unique_name,\n                        onAfterToRtl, target_platform)\n        SimTestCase.setUp(self)\n        return self.dut\n\n    def setUp(self):\n        self._rand = Random(self._defaultSeed)\n        if self.rtl_simulator_cls is not None:\n            # if the simulator is not compiled it is expected\n            # that it will be compiled in the test and this function\n            # will be called later\n            self.restartSim()\n\n\ndef simpleRandomizationProcess(tc: SimTestCase, agent, timeQuantum=CLK_PERIOD):\n    \"\"\"\n    A process for simulator which will randomly enable/dissable the egent for an interface\n    \"\"\"\n    seed = tc._rand.getrandbits(64)\n    random = Random(seed)\n\n    def randomEnProc():\n        # small space at start to modify agents when they are inactive\n        yield Timer(timeQuantum // 4)\n        while True:\n            en = random.random() < 0.5\n            if agent.getEnable() != en:\n                agent.setEnable(en)\n            delay = int(random.random() * 2) * timeQuantum\n            yield Timer(delay)\n\n    return randomEnProc\n"
  },
  {
    "path": "hwt/simulator/utils.py",
    "content": "from collections import deque\nfrom inspect import isgenerator\nimport sys\nfrom typing import Union, Sequence\n\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.arrayConst import HArrayConst\nfrom hwt.hwModule import HwModule\nfrom hwt.mainBases import HwIOBase, HwModuleOrHwIOBase\nfrom hwt.serializer.generic.indent import getIndent\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom hwtSimApi.basic_hdl_simulator.proxy import BasicRtlSimProxy\nfrom pyMathBitPrecise.bit_utils import ValidityError\nfrom pyMathBitPrecise.bits3t import Bits3val\n\n\ndef pprintHwIO(hwio: Union[HwModule, HwIOBase], indent:int=0, prefix:str=\"\", file=sys.stdout):\n    \"\"\"\n    Pretty print interface\n    \"\"\"\n    try:\n        s = hwio._sig\n    except AttributeError:\n        s = None\n    if s is None:\n        s = \"\"\n    else:\n        s = \" \" + repr(s)\n\n    file.write(\"\".join([getIndent(indent), prefix, repr(hwio._getFullName()),\n                        s]))\n    file.write(\"\\n\")\n\n    if isinstance(hwio, HObjList):\n        for chHwIO, p in enumerate(hwio):\n            # interfaces have already name of this array and index in it's name\n            pprintHwIO(p, indent=indent + 1, prefix=prefix, file=file)\n    else:\n        for chHwIO in hwio._hwIOs:\n            pprintHwIO(chHwIO, indent=indent + 1, file=file)\n\n\ndef pprintAgents(hwModuleOrHwIO: HwModuleOrHwIOBase, indent:int=0, prefix:str=\"\", file=sys.stdout):\n    if isinstance(hwModuleOrHwIO, HwIOBase):\n        ag = hwModuleOrHwIO._ag\n    elif isinstance(hwModuleOrHwIO, HObjList):\n        for i, item in enumerate(hwModuleOrHwIO):\n            item_prefix = f\"{prefix}_{i:d}\"\n            pprintAgents(item, indent=indent + 1, prefix=item_prefix, file=file)\n        return\n    else:\n        ag = None\n\n    if ag is not None:\n        indent_str = getIndent(indent)\n        file.write(f\"{indent_str:s}{prefix:s}{ag}\\n\")\n\n    for hio in hwModuleOrHwIO._hwIOs:\n        pprintAgents(hio, indent + 1, file=file)\n\n\n@internal\ndef reconnectHwModuleSignalsToModel(synthesisedHwModuleOrHwIO: HwModuleOrHwIOBase, rtl_simulator):\n    \"\"\"\n    Reconnect model signals to unit to run simulation with simulation model\n    but use original unit interfaces for communication\n\n    :param synthesisedHwModuleOrHwIO: interface where should be signals\n        replaced from signals from modelCls\n    :param rtl_simulator: RTL simulator form where signals\n        for synthesisedHwModuleOrHwIO should be taken\n    \"\"\"\n    obj = synthesisedHwModuleOrHwIO\n\n    for hwio in obj._hwIOs:\n        if hwio._hwIOs or isinstance(hwio, HObjList):\n            reconnectHwModuleSignalsToModel(hwio, rtl_simulator)\n        else:\n            # reconnect signal from model\n            si = hwio._sigInside\n            if isinstance(si, RtlSignal):\n                name = si._name\n            else:\n                assert isinstance(si, BasicRtlSimProxy), si\n                name = si._hdlName\n\n            # update name and dtype\n            s = getattr(rtl_simulator.io, name, None)\n            if s is None:\n                raise AttributeError()\n            if s._dtype is None:\n                s._dtype = hwio._dtype\n            s._name = hwio._name\n            s._hdlName = name\n            hwio.read = s.read\n            hwio.write = s.write\n            hwio.wait = s.wait\n            hwio._sigInside = s\n\n\ndef HConstSequenceToInts(values: Sequence[HConst]):\n    \"\"\"\n    Iterable of values to ints (nonvalid = None)\n    \"\"\"\n    return [Bits3valToInt(d) for d in values]\n\n\ndef agentDataToInts(interface):\n    \"\"\"\n    Convert all values which has agent collected in time >=0 to integer array.\n    Invalid value will be None.\n    \"\"\"\n    return HConstSequenceToInts(interface._ag.data)\n\n\ndef Bits3valToInt(v: HConst):\n    try:\n        return int(v)\n    except ValidityError:\n        return None\n\n\ndef allHConstsToInts(sequenceOrVal):\n    \"\"\"\n    Convert HConst instances to int recursively (for sequences)\n    \"\"\"\n    if isinstance(sequenceOrVal, HArrayConst):\n        sequenceOrVal = sequenceOrVal.val\n\n    if isinstance(sequenceOrVal, (HConst, Bits3val)):\n        return Bits3valToInt(sequenceOrVal)\n    elif not sequenceOrVal:\n        return sequenceOrVal\n    elif (isinstance(sequenceOrVal, (list, tuple, deque))\n          or isgenerator(sequenceOrVal)):\n        seq = []\n        for i in sequenceOrVal:\n            seq.append(allHConstsToInts(i))\n\n        if isinstance(sequenceOrVal, tuple):\n            return tuple(seq)\n\n        return seq\n    else:\n        return sequenceOrVal\n"
  },
  {
    "path": "hwt/synth.py",
    "content": "# -*- coding: utf-8 -*-\n\nfrom io import StringIO\n\nfrom hwt.constraints import _get_absolute_path\nfrom hwt.hwModule import HwModule, HdlConstraintList\nfrom hwt.serializer.serializer_config import DummySerializerConfig\nfrom hwt.serializer.serializer_filter import SerializerFilterDoNotExclude\nfrom hwt.serializer.store_manager import SaveToStream, StoreManager\nfrom hwt.serializer.vhdl import Vhdl2008Serializer\nfrom hwt.synthesizer.componentPath import ComponentPath\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\n\n\ndef to_rtl(hmodule_or_cls: HwModule, store_manager: StoreManager,\n           name: str=None,\n           target_platform=DummyPlatform()):\n    \"\"\"\n    Convert unit to RTL using specified serializer\n\n    :param unitOrCls: unit instance or class, which should be converted\n    :param name: name override of top unit (if is None name is derived\n        form class name)\n    :param target_platform: meta-informations about target platform, distributed\n        on every unit under _target_platform attribute\n        before HwModule.hwImpl() is called\n    \"\"\"\n    if isinstance(hmodule_or_cls, HwModule):\n        m = hmodule_or_cls\n    else:\n        m = hmodule_or_cls()\n\n    m._target_platform = target_platform\n    m._store_manager = store_manager\n    m._loadHwDeclarations()\n    if name is not None:\n        assert isinstance(name, str)\n        m._hdl_module_name = m._name = name\n\n    # serialize all unit instances to HDL code\n    constraints = HdlConstraintList()\n    for _, obj in m._to_rtl(target_platform, store_manager):\n        obj: HwModule\n        # collect constraints directly in current component\n        constraints.extend(obj._constraints)\n\n        if obj._shared_component_with:\n            # if the instance is shared with something else make\n            # the paths in constraints relative to a component\n            assert obj._shared_component_with[0]._shared_component_with is None\n            path_old = _get_absolute_path(obj._shared_component_with[0])\n            path_new = _get_absolute_path(obj)\n            for c in _HwModule_constraints_copy_recursively(\n                    obj, path_old, path_new):\n                constraints.append(c)\n\n    if constraints:\n        # serialize all constraints in design\n        store_manager.write(constraints)\n\n    return store_manager\n\n\ndef _HwModule_constraints_copy_recursively(m: HwModule, path_orig: ComponentPath, path_new: ComponentPath):\n    if m._shared_component_with:\n        assert not m._constraints\n        assert not m._subHwModules\n        orig_u, _, _ = m._shared_component_with\n        _path_orig = _get_absolute_path(orig_u)\n        yield from _HwModule_constraints_copy_recursively(\n            orig_u, _path_orig, path_new)\n    else:\n        for c in m._constraints:\n            yield c._copy_with_root_upadate(path_orig, path_new)\n\n        for su in m._subHwModules:\n            yield from _HwModule_constraints_copy_recursively(\n                su, ComponentPath(*path_orig, su), ComponentPath(*path_new, su))\n\n\ndef to_rtl_str(hwmodule_or_cls: HwModule,\n               serializer_cls=Vhdl2008Serializer, name: str=None,\n               target_platform=DummyPlatform()):\n    \"\"\"\n    Generate HDL string and return it\n    \"\"\"\n    buff = StringIO()\n    store_manager = SaveToStream(serializer_cls, buff)\n    to_rtl(hwmodule_or_cls, store_manager, name, target_platform)\n    return buff.getvalue()\n\n\ndef serializeAsIpcore(m: HwModule, folderName=\".\", name=None,\n                      serializer_cls=Vhdl2008Serializer,\n                      target_platform=DummyPlatform()):\n    \"\"\"\n    Create an IPCore package\n    \"\"\"\n    from hwt.serializer.ip_packager import IpPackager\n    p = IpPackager(m, name=name,\n                   serializer_cls=serializer_cls,\n                   target_platform=target_platform)\n    p.createPackage(folderName)\n    return p\n\n\ndef synthesised(m: HwModule, target_platform=DummyPlatform()):\n    \"\"\"\n    Elaborate design without producing any HDL\n    \"\"\"\n    sm = StoreManager(DummySerializerConfig,\n                      _filter=SerializerFilterDoNotExclude())\n    \n    if not hasattr(m, \"_hwIOs\"):\n        m._target_platform = target_platform\n        m._store_manager = sm\n        m._loadHwDeclarations()\n\n    for _ in m._to_rtl(target_platform, sm):\n        pass\n    return m\n"
  },
  {
    "path": "hwt/synthesizer/__init__.py",
    "content": "\"\"\"\nSythesizer converts :class:`hwt.hwModule.HwModule` instances to HDL objects.\n\n:func:`hwt.synth.to_rtl` function is one of examples how to use this module.\nThe conversion of :class:`hwt.hwModule.HwModule` instances happens mainly in\n:meth:`hwt.hwModule.Hmodule._to_rtl` which calls other optimization and transformations\nstored in :Py:attr:`:hwt.hwModule.HwModule._target_platform`.\n\"\"\"\n"
  },
  {
    "path": "hwt/synthesizer/componentPath.py",
    "content": "from copy import deepcopy\n\nfrom hwt.hwIO import HwIO\nfrom hwt.hwModule import HwModule\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\ndef to_tuple_of_names(objs):\n    res = []\n    for o in objs:\n        name = getattr(o, \"_name\", None)\n        if name is None:\n            name = repr(o)\n        res.append(name)\n    return tuple(res)\n\n\nclass ComponentPath(tuple):\n\n    def __new__ (cls, *objs):\n        return super(ComponentPath, cls).__new__(cls, objs)\n\n    def __truediv__(self, other):\n        if isinstance(other, ComponentPath):\n            return ComponentPath(*self, *other)\n        else:\n            return ComponentPath(*self, other)\n\n    def resolve(self) -> \"ComponentPath\":\n        \"\"\"\n        Make the path absolute\n\n        The ComponentPath is in absolute format only if:\n\n        * The first member is a top component or path is empty\n        * All members except the last are :class:`hwt.hwModule.HwModule` instances (last can be RtlSignal/HwIO)\n        * Each successor member is instantiated in predecessor except for :class:`hwt.hwModule.HwModule` instance with shared component\n        * If member is a :class:`hwt.hwModule.HwModule` instance with shared component the successor must be an interface of this instance or an object from shared component\n        \"\"\"\n        it = iter(reversed(self))\n        try:\n            obj = next(it)\n        except StopIteration:\n            # empty path\n            return self\n\n        path = []\n        while obj is not None:\n            _handle = next(it, None)\n            if isinstance(_handle, HwModule) and _handle._shared_component_with is not None:\n                handle, _, _ = _handle._shared_component_with\n            else:\n                handle = _handle\n\n            if obj is not handle:\n                if isinstance(obj, RtlSignal):\n                    # to not modify path if it is already in absolute format\n                    if not path or path[-1] is not obj:\n                        path.append(obj)\n                    obj = obj._rtlCtx.parent\n\n                while isinstance(obj, HwIO):\n                    if not path:\n                        path.append(obj)\n                    if obj is handle:\n                        break\n                    obj = obj._parent\n\n                while obj is not handle:\n                    assert isinstance(obj, HwModule), obj\n                    # to not modify path if it is already in absolute format\n                    if not path or path[-1] is not obj:\n                        path.append(obj)\n\n                    obj = obj._parent\n\n            obj = _handle\n\n        return ComponentPath(*reversed(path))\n\n    def is_absolute(self):\n        \"\"\"\n        :return: True if path starts with a top component else False\n        \"\"\"\n        m = self[0]\n        return isinstance(m, HwModule) and m._parent is None\n\n    def update_prefix(self, old_path_prefix: \"ComponentPath\", new_path_prefix: \"ComponentPath\"):\n        \"\"\"\n        Update prefix of the path tuple\n        \"\"\"\n        assert len(self) >= len(old_path_prefix), (self, old_path_prefix)\n        for p, op in zip(self, old_path_prefix):\n            assert p is op, (self, old_path_prefix)\n\n        return ComponentPath(*new_path_prefix, *self[len(old_path_prefix):])\n\n    def __getitem__(self, key):\n        if isinstance(key, slice):\n            return self.__class__(*tuple.__getitem__(self, key))\n        else:\n            return tuple.__getitem__(self, key)\n\n    def __repr__(self):\n        return f\"<{self.__class__.__name__:s} {str(self):s}>\"\n\n    def __str__(self):\n        return \"/\".join(to_tuple_of_names(self))\n\n    def __copy__(self):\n        return self.__class__(*self)\n\n    def __deepcopy__(self, memo):\n        res = self.__class__(*(deepcopy(x, memo) for x in self))\n        memo[self] = res\n        return res\n"
  },
  {
    "path": "hwt/synthesizer/dummyPlatform.py",
    "content": "from typing import List\n\nfrom hwt.synthesizer.rtlLevel.extract_part_drivers import RtlNetlistPassExtractPartDrivers\nfrom hwt.synthesizer.rtlLevel.mark_visibility_of_signals_and_check_drivers import RtlNetlistPassMarkVisibilityOfSignalsAndCheckDrivers\nfrom hwt.synthesizer.rtlLevel.remove_unconnected_signals import RtlNetlistPassRemoveUnconnectedSignals\nfrom hwt.synthesizer.rtlLevel.rtlNetlistPass import RtlNetlistPass\n\n\nclass DummyPlatform():\n    \"\"\"\n    Dummy synthesis platform, base class of all chip and toolset specific platforms.\n    Platform in this context is a set of configurations which do describe the target toolset and chip/node.\n    It can also contains pre/post processing callbacks and optimizations required for this target.\n\n    :note: all processors has to be callable with only one parameter\n        which is actual HwModule/RtlNetlist instance\n    \"\"\"\n\n    def __init__(self):\n        self.beforeToRtl = []\n        self.beforeToRtlImpl = []\n        self.afterToRtlImpl = []\n\n        self.beforeHdlArchGeneration: List[RtlNetlistPass] = [\n            RtlNetlistPassExtractPartDrivers(),\n            RtlNetlistPassRemoveUnconnectedSignals(),\n            RtlNetlistPassMarkVisibilityOfSignalsAndCheckDrivers(),\n        ]\n        self.afterToRtl = []\n"
  },
  {
    "path": "hwt/synthesizer/exceptions.py",
    "content": "from typing import Set\n\n\nclass TypeConversionErr(TypeError):\n    pass\n\n\nclass ConfErr(Exception):\n    pass\n\n\nclass IntfLvlConfErr(ConfErr):\n    \"\"\"\n    Interface level synthesizer user configuration error\n    \"\"\"\n    pass\n\n\nclass SigLvlConfErr(ConfErr):\n    \"\"\"\n    Signal level synthesizer user configuration error\n    \"\"\"\n    pass\n\n\nclass InterfaceStructureErr(IntfLvlConfErr):\n    \"\"\"\n    An exception which means that the two interfaces have non compatible sub-interfaces.\n    (E.g. they do have a differently named signals)\n\n    :ivar exclude: a set of sub-interfaces which should be excluded during the comparison\n    \"\"\"\n\n    def __init__(self, dst: \"HwIOBase\", src: \"HwIOBase\", exclude: Set[\"HwIOBase\"]):\n        super(InterfaceStructureErr, self).__init__()\n        self.src = src\n        self.dst = dst\n        self.exclude = exclude\n\n    def __str__(self):\n        return self.__repr__()\n\n    def __repr__(self):\n        missing_on_src = []\n        missing_on_dst = []\n        dst = self.dst\n        src = self.src\n        exclude = self.exclude\n        srcHwIos = getattr(src, \"_hwIOs\", None)\n        if srcHwIos is None:\n            # src is likely a constant\n            try:\n                for f in src._dtype.fields:\n                    io2 = getattr(dst, f.name, None)\n                    if io2 is None and (not exclude or io2 not in exclude):\n                        missing_on_dst.append(f.name)\n            except AttributeError:\n                # the type of src is unexpected, can not produce any good err msg.\n                pass\n        else:\n            for sHwIO in srcHwIos:\n                io2 = getattr(dst, sHwIO._name, None)\n                if io2 is None and (not exclude or sHwIO not in exclude):\n                    missing_on_dst.append(sHwIO._name)\n\n        for sHwIO in dst._hwIOs:\n            io2 = getattr(src, sHwIO._name, None)\n            if io2 is None and (not exclude or sHwIO not in exclude):\n                missing_on_src.append(sHwIO._name)\n\n        buff = [f\"<{self.__class__.__name__} {dst} <= {src}\"]\n        if missing_on_dst:\n            buff.append(f\", missing on dst: {missing_on_dst}\")\n        if missing_on_src:\n            buff.append(f\", missing on src: {missing_on_src}\")\n        buff.append(\">\")\n        return \"\".join(buff)\n\n    def __copy__(self):\n        return self.__class__(self.dst, self.src, self.exclude)\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/__init__.py",
    "content": "\"\"\"\ninterfaceLevel is responsible for manipulation of high-level interfaces.\n\"\"\"\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/directionFns.py",
    "content": "from hwt.doc_markers import internal\nfrom ipCorePackager.constants import INTF_DIRECTION, DIRECTION\n\n\n@internal\nclass HwIODirectionFns():\n\n    @internal\n    def _setDirectionsLikeIn(self, hioDir: INTF_DIRECTION):\n        assert hioDir in [INTF_DIRECTION.MASTER,\n                           INTF_DIRECTION.SLAVE,\n                           INTF_DIRECTION.TRISTATE], hioDir\n        d = DIRECTION.asIntfDirection(self._masterDir)\n        if hioDir == INTF_DIRECTION.MASTER or d == INTF_DIRECTION.TRISTATE:\n            pass\n        else:\n            d = INTF_DIRECTION.opposite(d)\n\n        self._direction = d\n        for hio in self._hwIOs:\n            hio._setDirectionsLikeIn(d)\n\n    @internal\n    def _setAsExtern(self, isExtern: bool):\n        \"\"\"Set interface as external\"\"\"\n        self._isExtern = isExtern\n        if not isExtern:\n            self._direction = INTF_DIRECTION.UNKNOWN\n        for chHwIO in self._hwIOs:\n            chHwIO._setAsExtern(isExtern)\n            \n\n    @internal\n    def _reverseDirection(self):\n        \"\"\"Reverse direction of this interface in implementation stage\"\"\"\n        self._direction = INTF_DIRECTION.opposite(self._direction)\n        for chHwIO in self._hwIOs:\n            chHwIO._reverseDirection()\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/getDefaultClkRts.py",
    "content": "from hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwt.mainBases import HwModuleBase\n\n\ndef getClk(module: HwModuleBase):\n    \"\"\"\n    Get clock signal from unit instance\n    \"\"\"\n    try:\n        return module.clk\n    except AttributeError:\n        pass\n\n    raise IntfLvlConfErr(f\"Can not find clock signal on module {module}\")\n\n\ndef getRst(module: HwModuleBase):\n    \"\"\"\n    Get reset signal from unit instance\n    \"\"\"\n    try:\n        return module.rst\n    except AttributeError:\n        pass\n\n    try:\n        return module.rst_n\n    except AttributeError:\n        pass\n\n    raise IntfLvlConfErr(f\"Can not find reset signal on module {module}\")\n\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/hwModuleImplHelpers.py",
    "content": "from itertools import chain\nfrom typing import Union, Optional, Tuple\n\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.operatorDefs import HOperatorDef\nfrom hwt.hdl.types.array import HArray\nfrom hwt.hdl.types.defs import BIT\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.struct import HStruct\nfrom hwt.hwIOs.hwIOArray import HwIOArray\nfrom hwt.hwIOs.hwIOStruct import HdlType_to_HwIO, HwIOStruct\nfrom hwt.hwIOs.std import HwIOSignal, HwIOClk, HwIORst, HwIORst_n\nfrom hwt.mainBases import HwModuleBase, HwIOBase\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.interfaceLevel.getDefaultClkRts import getClk, getRst\nfrom hwt.synthesizer.rtlLevel.netlist import RtlNetlist\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom ipCorePackager.constants import INTF_DIRECTION\n\n\ndef getSignalName(sig: RtlSignalBase):\n    \"\"\"\n    Name getter which works for RtlSignal and HwIO instances as well\n    \"\"\"\n    return sig._name\n\n\ndef HwIO_getName(top: HwModuleBase, io: Union[HwIOBase, RtlSignal,\n                                              Tuple[Union[HwIOBase, RtlSignal]]]) -> str:\n    if isinstance(io, HwIOBase):\n        prefix = []\n        parent = io._parent\n        while parent is not None:\n            if parent is top:\n                break\n            try:\n                prefix.append(parent._name)\n            except AttributeError:\n                prefix.append(repr(parent))\n                break\n                \n            parent = parent._parent\n\n        n = io._getFullName()\n        if prefix:\n            prefix.reverse()\n            prefix.append(n)\n            return \".\".join(prefix)\n        else:\n            return n\n    elif isinstance(io, tuple):\n        return f\"({', '.join(HwIO_getName(top, _io) for _io in io)})\"\n    else:\n        return getSignalName(io)\n\n\n@internal\ndef _default_param_updater(self, myP: \"HwParam\", otherP_val):\n    myP.set_value(otherP_val)\n\n\n@internal\ndef _normalize_default_value_dict_for_HwIO_array(root_val: dict,\n                                                val: Union[dict, list, None],\n                                                name_prefix: str,\n                                                hobj_list: HwIOArray,\n                                                neutral_value):\n    \"\"\"\n    This function is called to convert data in format\n    .. code-block:: python\n\n        {\"x\": [3, 4]}\n        # into\n        {\"x_0\": 3, \"x_1\": 4}\n\n    This is required because the items of HwIOArray are stored in _hwIOs as a separate items\n    and thus we can not resolve the value association otherwise.\n    \"\"\"\n\n    for i, intf in enumerate(hobj_list):\n        if val is neutral_value:\n            continue\n        elif isinstance(val, dict):\n            _val = val.get(i, neutral_value)\n        else:\n            _val = val[i]\n        if _val is neutral_value:\n            continue\n\n        elm_name = f\"{name_prefix:s}_{i:d}\"\n        if isinstance(intf, HwIOArray):\n            _normalize_default_value_dict_for_HwIO_array(root_val, _val, elm_name, intf, neutral_value)\n        else:\n            root_val[elm_name] = _val\n\n\n@internal\ndef _instantiate_signals(hwIO: Union[HwIOSignal, HwIOArray, HwIOStruct],\n                         clk: HwIOClk, rst: Union[HwIORst, HwIORst_n],\n                         def_val:Union[int, None, dict, list],\n                         nop_val:Union[int, None, dict, list],\n                         nextSig: Optional[RtlSignalBase], signal_create_fn):\n    hwIO._direction = INTF_DIRECTION.UNKNOWN\n    if isinstance(hwIO, HwIOSignal):\n        name = hwIO._getHdlName()\n        hwIO._sig = signal_create_fn(\n            name,\n            hwIO._dtype,\n            clk, rst, def_val, nop_val, nextSig)\n        hwIO._sig._hwIO = hwIO\n\n    elif isinstance(hwIO, HwIOArray):\n        intf_len = len(hwIO)\n        if isinstance(def_val, dict):\n            for k in def_val.keys():\n                assert k > 0 and k < intf_len, (\"Default value for\", hwIO, \" specifies \", k, \" which is not present on interface\")\n        elif def_val is not None:\n            assert len(def_val) == intf_len, (\"Default value does not have same size, \", len(def_val), intf_len, hwIO)\n\n        if isinstance(nop_val, dict):\n            for k in nop_val.keys():\n                assert k > 0 and k < intf_len, (\"Nop value for\", hwIO, \" specifies \", k, \" which is not present on interface\")\n        elif nop_val is not NOT_SPECIFIED:\n            assert len(nop_val) == intf_len, (\"Nop value does not have same size, \", len(nop_val), intf_len, hwIO)\n\n        for i, elm in enumerate(hwIO):\n            if def_val is None:\n                _def_val = None\n            elif isinstance(def_val, dict):\n                _def_val = def_val.get(i, None)\n            else:\n                _def_val = def_val[i]\n\n            if nop_val is NOT_SPECIFIED:\n                _nop_val = NOT_SPECIFIED\n            elif isinstance(nop_val, dict):\n                _nop_val = nop_val.get(i, NOT_SPECIFIED)\n            else:\n                _nop_val = nop_val[i]\n            if nextSig is NOT_SPECIFIED:\n                _nextSig = NOT_SPECIFIED\n            else:\n                _nextSig = nextSig.get(i, NOT_SPECIFIED)\n            _instantiate_signals(elm, clk, rst, _def_val, _nop_val, _nextSig, signal_create_fn)\n\n    else:\n        if def_val is not None:\n            for k in tuple(def_val.keys()):\n                _i = getattr(hwIO, k, NOT_SPECIFIED)\n                assert _i is not NOT_SPECIFIED, (\"Default value for\", hwIO, \" specifies \", k, \" which is not present on interface\")\n                if isinstance(_i, HwIOArray):\n                    _normalize_default_value_dict_for_HwIO_array(\n                        def_val, def_val[k], k, _i, None)\n\n        if nop_val is not NOT_SPECIFIED:\n            for k in tuple(nop_val.keys()):\n                _i = getattr(hwIO, k, NOT_SPECIFIED)\n                assert _i is not NOT_SPECIFIED, (\"Nop value for\", hwIO, \" specifies \", k, \" which is not present on interface\")\n                if isinstance(_i, HwIOArray):\n                    _normalize_default_value_dict_for_HwIO_array(\n                        nop_val, nop_val[k],\n                        k, _i, NOT_SPECIFIED)\n\n        for elm in hwIO._hwIOs:\n            name = elm._name\n            if def_val is None:\n                _def_val = None\n            else:\n                _def_val = def_val.get(name, None)\n\n            if nop_val is NOT_SPECIFIED:\n                _nop_val = NOT_SPECIFIED\n            else:\n                _nop_val = nop_val.get(name, NOT_SPECIFIED)\n\n            if nextSig is NOT_SPECIFIED:\n                _nextSig = NOT_SPECIFIED\n            else:\n                _nextSig = getattr(nextSig, name)\n            _instantiate_signals(elm, clk, rst, _def_val, _nop_val, _nextSig, signal_create_fn)\n\n\n@internal\ndef _loadHwDeclarations(intf_or_list: HwIOBase, suggested_name: str):\n    if isinstance(intf_or_list, HwIOArray):\n        for i, intf in enumerate(intf_or_list):\n            _loadHwDeclarations(intf, f\"{suggested_name:s}_{i:d}\")\n    else:\n        intf_or_list._name = suggested_name\n        intf_or_list._loadHwDeclarations()\n\n\ndef HwIO_without_registration(\n        parent:HwModuleBase,\n        container: HwIOBase,\n        suggested_name:str,\n        def_val: Union[int, None, dict, list]=None,\n        nop_val: Union[int, None, dict, list, \"NOT_SPECIFIED\"]=NOT_SPECIFIED,\n        nextSig:Optional[RtlSignalBase]=NOT_SPECIFIED):\n    \"\"\"\n    Load all parts of interface and construct signals in RtlNetlist context with an automatic name check,\n    without need to explicitly add the HwIO into _hwIOs list.\n    \"\"\"\n    _loadHwDeclarations(container, suggested_name)\n    _instantiate_signals(\n        container, None, None, def_val, nop_val, nextSig,\n        lambda name, dtype, clk, rst, def_val, nop_val, nextSig: parent._sig(name, dtype,\n                                                                  def_val=def_val,\n                                                                  nop_val=nop_val,\n                                                                  ))\n    container._parent = parent\n    parent._private_hwIOs.append(container)\n    return container\n\n\nclass HwModuleImplHelpers(HwModuleBase):\n\n    def _reg(self, name: str,\n             dtype: HdlType=BIT,\n             def_val: Union[int, None, dict, list]=None,\n             clk: Union[RtlSignalBase, None, Tuple[RtlSignalBase, HOperatorDef]]=None,\n             rst: Optional[RtlSignalBase]=None,\n             nextSig:Optional[RtlSignalBase]=NOT_SPECIFIED) -> RtlSignal:\n        \"\"\"\n        Create RTL FF register in this unit\n\n        :param def_val: s default value of this register,\n            if this value is specified reset signal of this component is used\n            to generate a reset logic\n        :param clk: optional clock signal specification,\n            (signal or tuple(signal, edge type (AllOps.RISING_EDGE/FALLING_EDGE)))\n        :param rst: optional reset signal specification\n        :param nextSig: the signal which should be used as \"next\" signal for this register\n            if is not specified the new signal is generated. (Next signal holds value which should be in register in next clk.)\n        :note: rst/rst_n resolution is done from signal type,\n            if it is negated type the reset signal is interpreted as rst_n\n        :note: if clk or rst is not specified default signal\n            from parent unit instance will be used\n        \"\"\"\n        if clk is None:\n            clk = getClk(self)\n\n        if def_val is None:\n            # if no value is specified reset is not required\n            rst = None\n        elif rst is None:\n            rst = getRst(self)\n\n        if isinstance(dtype, (HStruct, HArray)):\n            container = HdlType_to_HwIO().apply(dtype)\n            _loadHwDeclarations(container, name)\n            _instantiate_signals(\n                container, clk, rst, def_val, nextSig, NOT_SPECIFIED,\n                lambda name, dtype, clk, rst, def_val, nop_val, nextSig: self._reg(name, dtype,\n                                                                                   def_val=def_val,\n                                                                                   clk=clk, rst=rst,\n                                                                                   nextSig=nextSig))\n            container._parent = self\n            return container\n        else:\n            # primitive data type signal\n            return self._rtlCtx.sig(\n                name,\n                dtype=dtype,\n                clk=clk,\n                syncRst=rst,\n                def_val=def_val,\n                nextSig=nextSig,\n            )\n\n    def _sig(self, name: str,\n             dtype: HdlType=BIT,\n             def_val: Union[int, None, dict, list]=None,\n             nop_val: Union[int, None, dict, list, \"NOT_SPECIFIED\"]=NOT_SPECIFIED) -> RtlSignal:\n        \"\"\"\n        Create signal in this unit\n\n        :see: :func:`hwt.synthesizer.rtlLevel.netlist.RtlNetlist.sig`\n        \"\"\"\n        if isinstance(dtype, HStruct):\n            container = HdlType_to_HwIO().apply(dtype)\n            return HwIO_without_registration(self, container, name, def_val=def_val, nop_val=nop_val)\n        else:\n            # primitive data type signal\n            return self._rtlCtx.sig(name, dtype=dtype, def_val=def_val, nop_val=nop_val)\n\n    @internal\n    def _cleanThisSubunitRtlSignals(self):\n        \"\"\"\n        Disconnect internal signals so unit can be reused by parent unit\n        \"\"\"\n        for hwio in chain(self._hwIOs, self._private_hwIOs):\n            hwio._cleanRtlSignals()\n\n    @internal\n    def _signalsForSubHwModuleEntity(self, context: RtlNetlist, prefix: str):\n        \"\"\"\n        generate signals in this context for all ports of this subunit\n        \"\"\"\n        for hio in self._hwIOs:\n            if hio._isExtern:\n                hio._signalsForHwIO(context, None, None, prefix=prefix + hio._NAME_SEPARATOR)\n\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/implDependent.py",
    "content": "from hwt.mainBases import HwModuleBase\nfrom hwt.synthesizer.interfaceLevel.getDefaultClkRts import getRst, getClk\nfrom hwt.synthesizer.interfaceLevel.utils import NotSpecifiedError\nfrom hwtSimApi.hdlSimulator import HdlSimulator\nfrom ipCorePackager.intfIpMeta import IntfIpMetaNotSpecifiedError\n\n\nclass HwIOImplDependentFns():\n    \"\"\"\n    HwIO functions which have high potential to be overloaded\n    in concrete interface implementation\n    \"\"\"\n\n    def _getIpCoreIntfClass(self):\n        raise IntfIpMetaNotSpecifiedError()\n\n    def _initSimAgent(self, sim: HdlSimulator):\n        raise NotSpecifiedError(\"Override this function in your interface\"\n                           \" implementation to have simultion agent\"\n                           f\" specified ({self})\")\n\n    def _getAssociatedRst(self):\n        \"\"\"\n        If interface has associated rst(_n) return it otherwise\n        try to find rst(_n) on parent recursively\n        \"\"\"\n        a = self._associatedRst\n\n        if a is not None:\n            return a\n\n        p = self._parent\n        assert p is not None\n\n        if isinstance(p, HwModuleBase):\n            return getRst(p)\n        else:\n            return p._getAssociatedRst()\n\n    def _getAssociatedClk(self):\n        \"\"\"\n        If interface has associated clk return it otherwise\n        try to find clk on parent recursively\n        \"\"\"\n        a = self._associatedClk\n\n        if a is not None:\n            return a\n\n        p = self._parent\n        assert p is not None\n\n        if isinstance(p, HwModuleBase):\n            return getClk(p)\n        else:\n            return p._getAssociatedClk()\n\n    def __copy__(self):\n        \"\"\"\n        Create new instance of interface of same type and configuration\n        \"\"\"\n        hwIO = self.__class__()\n        hwIO._updateHwParamsFrom(self)\n        return hwIO\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/propDeclrCollector.py",
    "content": "from types import MethodType\nfrom typing import Tuple, Set, Optional, Callable, Self\n\nfrom hdlConvertorAst.translate.common.name_scope import WithNameScope\nfrom hwt.doc_markers import internal\nfrom hwt.hObjList import HObjList\nfrom hwt.hwParam import HwParam\nfrom hwt.mainBases import HwModuleBase, HwIOBase\nfrom hwt.synthesizer.exceptions import IntfLvlConfErr\nfrom hwt.synthesizer.typePath import TypePath\n\n\n@internal\ndef nameAvailabilityCheck(obj: \"PropDeclrCollector\", propName: str, prop: object):\n    \"\"\"\n    Check if not redefining property on obj\n    but allow to cast current property to a HwParam\n    \"\"\"\n    cur = getattr(obj, propName, None)\n    if cur is not None and (not isinstance(prop, HwParam) or cur is not prop._initval):\n        p = getattr(obj, propName)\n        raise IntfLvlConfErr(f\"{obj} already has property {propName:s} old:{p} new:{prop}\")\n\n\n@internal\nclass MakeParamsShared(object):\n    \"\"\"\n    All newly added interfaces and units will share all parametes with unit\n    specified in constructor of this object.\n    \"\"\"\n\n    def __init__(self, module: \"HwModule\", exclude:Optional[Tuple[Set[str], Set[str]]], prefix:str):\n        self.module = module\n        self.exclude = exclude\n        self.prefix = prefix\n\n    def __enter__(self):\n        orig = self.module._setAttrListener\n        self.orig = orig\n        exclude = self.exclude\n        prefix = self.prefix\n\n        def MakeParamsSharedWrap(self: \"HwModule\", iName: str, i: object):\n            if isinstance(i, (HwIOBase, HwModuleBase, HObjList)):\n                i._updateHwParamsFrom(self, exclude=exclude, prefix=prefix)\n            return orig(iName, i)\n\n        self.module._setAttrListener = MethodType(MakeParamsSharedWrap,\n                                                  self.module)\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        if exc_type is None:\n            self.module._setAttrListener = self.orig\n\n\n@internal\nclass MakeClkRstAssociations(object):\n    \"\"\"\n    All newly added interfaces will be associated with clk, rst\n    specified in constructor of this object.\n    \"\"\"\n\n    def __init__(self, module: \"HwModule\", clk=None, rst=None):\n        self.module = module\n        self.clk = clk\n        self.rst = rst\n\n    def __enter__(self):\n        orig = self.module._setAttrListener\n        self.orig = orig\n        clk = self.clk\n        rst = self.rst\n\n        def MakeClkRstAssociationsWrap(self, iName, i):\n            if isinstance(i, (HwIOBase, HObjList)):\n                i._make_association(clk=clk, rst=rst)\n            return orig(iName, i)\n\n        self.module._setAttrListener = MethodType(MakeClkRstAssociationsWrap,\n                                                  self.module)\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        if exc_type is None:\n            self.module._setAttrListener = self.orig\n\n\nclass PropDeclrCollector(object):\n    \"\"\"\n    Class which manages the registration of components and interfaces\n    in specified elaboration phases.\n\n    It uses __setattr__ listeners to detect new properties and then calls\n    a listener function to process the registration.\n\n    Used for HwModule, HwIO classes to detect and load interfaces and components.\n    \"\"\"\n\n    def hwConfig(self) -> None:\n        \"\"\"\n        Configure object parameters\n\n        * setup all parameters on this object,\n          use HwParam class instances to allow use of parameter inheritance\n        * called in __init__ of class\n        \"\"\"\n        pass\n\n    def hwDeclr(self) -> None:\n        \"\"\"\n        In this function user should specify the declaration of interfaces for communication with outside word.\n        It is also better to declare sub components there as it allows for better parallelization during the build.\n\n        * _declr method is called after _config\n        * if this object is :class:`hwt.hwModule.HwModule` all interfaces are treated as externally accessible interfaces\n          if this object is HwIO instance all subinterfaces are loaded as well\n        \"\"\"\n        pass\n\n    def hwImpl(self) -> None:\n        \"\"\"\n        Implementation - construct main body of the component in this function.\n\n        * called after _declr\n        \"\"\"\n        pass\n\n    @internal\n    def __setattr__(self, attr:str, value) -> None:\n        \"\"\"setattr with listener injector\"\"\"\n        try:\n            saListerner = self._setAttrListener\n        except AttributeError:\n            super().__setattr__(attr, value)\n            return\n\n        if saListerner:\n            value = saListerner(attr, value)\n        super().__setattr__(attr, value)\n\n    # configuration phase\n    @internal\n    def _loadConfig(self) -> None:\n        \"\"\"\n        Load params in hwConfig()\n        \"\"\"\n        if not hasattr(self, '_hwParams'):\n            self._hwParams = []\n\n        self._setAttrListener = self._paramCollector\n        self.hwConfig()\n        self._setAttrListener = None\n\n    @internal\n    def _registerParameter(self, pName:str, parameter: HwParam) -> None:\n        \"\"\"\n        Register HwParam object on interface level object\n        \"\"\"\n        nameAvailabilityCheck(self, pName, parameter)\n        # resolve name in this scope\n        assert parameter._name is None, (\n            \"HwParam object is already assigned to %r.%s\"\n            % (parameter.module, parameter._name))\n        # add name in this scope\n        parameter._name = pName\n        parameter._parent = self\n\n        self._hwParams.append(parameter)\n\n    def _hwParamsShared(self,\n                      exclude: Optional[Tuple[Set[str], Set[str]]]=None,\n                      prefix=\"\") -> MakeParamsShared:\n        \"\"\"\n        Auto-propagate params by name to child components and interfaces\n        Usage:\n\n        .. code-block:: python\n\n            with self._hwParamsShared():\n                # your interfaces and unit which should share all params with \"self\" there\n\n        :param exclude: tuple (src param names to exclude, dst param names to exclude)\n        :param prefix: prefix which should be added to name of child parameters\n            before parameter name matching\n        \"\"\"\n        return MakeParamsShared(self, exclude=exclude, prefix=prefix)\n\n    def _make_association(self, clk=None, rst=None) -> None:\n        \"\"\"\n        Associate this object with specified clk/rst\n        \"\"\"\n        if clk is not None:\n            assert self._associatedClk is None, (\"Already associated with clock\", self._associatedClk)\n            self._associatedClk = clk\n\n        if rst is not None:\n            assert self._associatedRst is None, (\"Already associated with reset\", self._associatedRst)\n            self._associatedRst = rst\n\n    def _associated(self, clk=None, rst=None) -> MakeClkRstAssociations:\n        \"\"\"\n        associate newly added interfaces to \"self\" with selected clk, rst\n        (if interface is not associated agents try to find clk/rst by _getAssociatedClk/_getAssociatedRst\n        which will search for any clk/rst on parent recursively)\n        Usage:\n\n        .. code-block:: python\n\n            with self._associated(clk=self.myClk, rst=self.myRst):\n                self.myAxi = Axi4Stream()\n                # this interface is associated with myClk and myRst\n                # simulation agents and component builders will use them\n\n\n        :param exclude: params which should not be shared\n        \"\"\"\n        return MakeClkRstAssociations(self, clk, rst)\n\n    def _updateHwParamsFrom(self,\n                          otherObj: \"PropDeclrCollector\",\n                          updater: Callable[[\"PropDeclrCollector\", HwParam, HwParam], None],\n                          exclude: Optional[Tuple[Set[str], Set[str]]],\n                          prefix: str) -> \"PropDeclrCollector\":\n        \"\"\"\n        Update all parameters which are defined on self from otherObj\n\n        :param otherObj: other object which HwParam instances should be updated\n        :param updater: updater function(self, myParameter, otherParameter)\n        :param exclude: tuple of set of param names for src and dst which\n                        which should be excluded\n        :param prefix: prefix which should be added to name of paramters\n                       of this object before matching parameter name on parent\n        \"\"\"\n        excluded_src = set()\n        excluded_dst = set()\n        if exclude is not None:\n            exclude_src = set(exclude[0])\n            exclude_dst = set(exclude[1])\n\n        for myP in self._hwParams:\n            if exclude is not None and myP._name in exclude_dst:\n                excluded_dst.add(myP._name)\n                continue\n            pPName = prefix + myP._name\n            try:\n                otherP = getattr(otherObj, pPName)\n                # if not isinstance(otherP, HwParam):\n                #     continue\n            except AttributeError:\n                continue\n\n            if exclude is not None and pPName in exclude_src:\n                excluded_src.add(pPName)\n                continue\n            updater(self, myP, otherP)\n\n        if exclude is not None:\n            # assert that what should be excluded really exists\n            assert exclude_src == excluded_src, (exclude_src, excluded_src)\n            assert exclude_dst == excluded_dst, (exclude_dst == excluded_dst)\n        return self\n\n    # declaration phase\n    @internal\n    def _registerSubmodule(self, mName:str, submodule:\"HwModule\", onParentPropertyPath: TypePath):\n        \"\"\"\n        Register unit object on interface level object\n        \"\"\"\n        nameAvailabilityCheck(self, mName, submodule)\n        assert submodule._parent is None\n        submodule._parent = self\n        submodule._name = mName\n        submodule._onParentPropertyPath = onParentPropertyPath\n        self._subHwModules.append(submodule)\n\n    @internal\n    def _registerHwIO(self, hwIOName: str, hwIO: HwIOBase, onParentPropertyPath: TypePath, isPrivate:bool):\n        \"\"\"\n        Register HwIO object on interface level object\n        \"\"\"\n        nameAvailabilityCheck(self, hwIOName, hwIO)\n        assert hwIO._parent is None\n        hwIO._parent = self\n        hwIO._name = hwIOName\n        assert isinstance(onParentPropertyPath, TypePath), onParentPropertyPath\n        hwIO._onParentPropertyPath = onParentPropertyPath\n        hwIO._rtlCtx = self._rtlCtx\n        # _setAsExtern() not used because _hwIOs are not initialized yet\n        if isPrivate:\n            self._private_hwIOs.append(hwIO)\n            hwIO._isExtern = False\n        else:\n            self._hwIOs.append(hwIO)\n            hwIO._isExtern = True\n\n    @internal\n    def _declrCollector(self, name: str, prop: object):\n        if name in (\"_associatedClk\", \"_associatedRst\"):\n            object.__setattr__(self, name, prop)\n            return prop\n\n        onParentPropertyPath = TypePath(name,)\n        if isinstance(prop, HwIOBase):\n            self._registerHwIO(name, prop, onParentPropertyPath, False)\n        elif isinstance(prop, HwModuleBase):\n            self._registerSubmodule(name, prop, onParentPropertyPath)\n        elif isinstance(prop, HObjList):\n            self._registerArray(name, prop, onParentPropertyPath)\n        return prop\n\n    @internal\n    def _registerArray(self, name: Optional[str], items: HObjList[Self], onParentPropertyPath: TypePath):\n        \"\"\"\n        Register array of items on interface level object\n        \"\"\"\n        items._parent = self\n        items._name = name\n        items._on_append = self._registerArray_append\n        assert isinstance(onParentPropertyPath, TypePath), onParentPropertyPath\n        items._onParentPropertyPath = onParentPropertyPath\n\n        for i, item in enumerate(items):\n            self._registerArray_append(items, item, i)\n\n    @internal\n    def _registerArray_append(self, arr: HObjList[Self], item: Self, index: int):\n        \"\"\"\n        Register a single object in the list\n        \"\"\"\n        saListerner = self._setAttrListener\n        if arr is self:\n            # register item in the array (parrent)\n            if saListerner:\n                item = saListerner(f\"{index:d}\", item)\n\n            if isinstance(item, PropDeclrCollector):\n                item._onParentPropertyPath = TypePath(index,)\n        else:\n            # register item for a list which is stored inside of parent\n            setattr(self, f\"{arr._name:s}_{index:d}\", item)\n            if isinstance(item, PropDeclrCollector):\n                item._onParentPropertyPath = arr._onParentPropertyPath / index\n\n    # implementation phase\n    @internal\n    def _loadImpl(self):\n        self._setAttrListener = self._implCollector\n        self.hwImpl()\n        self._setAttrListener = None\n\n    @internal\n    def _registerSubmoduleInImpl(self, name: str, m: HwModuleBase, onParentPropertyPath: TypePath):\n        \"\"\"\n        :attention: unit has to be parametrized before it is registered\n            (some components can change interface by parametrization)\n        \"\"\"\n        self._registerSubmodule(name, m, onParentPropertyPath)\n        m._loadHwDeclarations()\n        sm = self._store_manager\n        with WithNameScope(sm, sm.name_scope.parent):\n            self._lazy_loaded.extend(m._to_rtl(\n                self._target_platform, self._store_manager))\n        m._signalsForSubHwModuleEntity(self._rtlCtx, \"sig_\" + name)\n\n    @internal\n    def _registerHwIOInHwImpl(self, hwIOName: str, hwio: HwIOBase, onParentPropertyPath: TypePath):\n        \"\"\"\n        Register interface in implementation phase\n        \"\"\"\n        raise NotImplementedError()\n\n    @internal\n    def _paramCollector(self, pName: str, prop):\n        if isinstance(prop, HwParam):\n            self._registerParameter(pName, prop)\n            return prop._initval\n        else:\n            return prop\n\n    @internal\n    def _implCollector(self, name: str, prop):\n        \"\"\"\n        Handle property definitions in _impl phase\n        \"\"\"\n        onParentPropertyPath = TypePath(name,)\n        if isinstance(prop, HwIOBase):\n            if prop._parent is self:\n                return prop\n            self._registerHwIOInHwImpl(name, prop, onParentPropertyPath)\n        elif isinstance(prop, HwModuleBase):\n            if prop._parent is self:\n                return prop\n            self._registerSubmoduleInImpl(name, prop, onParentPropertyPath)\n        elif isinstance(prop, HObjList):\n            if prop._parent is self:\n                return prop\n            self._registerArray(name, prop, onParentPropertyPath)\n        return prop\n"
  },
  {
    "path": "hwt/synthesizer/interfaceLevel/utils.py",
    "content": "from collections.abc import Container, Callable\nfrom typing import Union, Optional\n\nfrom hwt.constants import DIRECTION\nfrom hwt.hObjList import HObjList\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.mainBases import HwIOBase\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass NotSpecifiedError(Exception):\n    \"\"\"\n    This error means that you need to implement this function\n    to use this functionality\n\n    e.g. you have to implement Simulation agent for interface\n    when you create new one and you can not use existing\n    \"\"\"\n    pass\n\n\ndef HwIO_walkSignals(hwio: HwIOBase):\n    if hwio._hwIOs or isinstance(hwio, HObjList):\n        for sHwIO in hwio._hwIOs:\n            yield from HwIO_walkSignals(sHwIO)\n    else:\n        yield hwio\n\n\ndef HwIO_connectPacked(srcPacked: RtlSignalBase,\n                       dstInterface: Union[HwIOBase, RtlSignalBase],\n                       exclude:Optional[Container[Union[HwIOBase, RtlSignalBase]]]=None):\n    \"\"\"\n    Connect 1D vector signal to this structuralized interface\n    (LSB of first interface is LSB of result)\n\n    :param packedSrc: vector which should be connected\n    :param dstInterface: structuralized interface where should\n        packedSrc be connected to\n    :param exclude: sub interfaces of self which should be excluded\n    \"\"\"\n    offset = 0\n    connections = []\n    for i in list(HwIO_walkSignals(dstInterface)):\n        if exclude is not None and i in exclude:\n            continue\n        sig = i._sig\n        t = sig._dtype\n        w = t.bit_length()\n        if w == 1:\n            if srcPacked._dtype.bit_length() == 1:\n                # avoid indexing on single bit\n                assert offset == 0, srcPacked\n                s = srcPacked\n            else:\n                # select bit from bit vector\n                assert offset < srcPacked._dtype.bit_length(), (\"Insufficient amount of bits in srcPacked\", srcPacked, w, offset, i)\n                s = srcPacked[offset]\n            offset += 1\n        else:\n            # select bit slice from bit vector\n            assert srcPacked._dtype.bit_length() >= w + offset, (\"Insufficient amount of bits in srcPacked\", srcPacked, w, offset, i)\n            s = srcPacked[(w + offset): offset]  # src is likely to have insufficient amount of bits if\n            offset += w\n\n        assert sig._dtype.bit_length() == s._dtype.bit_length(), (sig, s, sig._dtype, s._dtype)\n        connections.append(sig(s._reinterpret_cast(sig._dtype)))\n\n    return connections\n\n\ndef HwIO_walkFlatten(hwio: HwIOBase, shouldEnterHwIOFn: Optional[Callable[[HwIOBase], tuple[bool, bool]]]):\n    \"\"\"\n    :param shouldEnterHwIOFn: function (actual hwio)\n        returns tuple (shouldEnter, shouldYield)\n    \"\"\"\n    _shouldEnter, _shouldYield = shouldEnterHwIOFn(hwio)\n    if _shouldYield:\n        yield hwio\n\n    if shouldEnterHwIOFn:\n        for sHwIO in hwio._hwIOs:\n            yield from HwIO_walkFlatten(sHwIO, shouldEnterHwIOFn)\n\n\ndef HwIO_pack(hio: HwIOBase,\n              masterDirEqTo=DIRECTION.OUT,\n              exclude:Optional[Container[Union[HwIOBase, RtlSignalBase]]]=None) -> Union[HBitsConst, RtlSignalBase[HBits]]:\n    \"\"\"\n    Concatenate all signals to one big signal, recursively\n    (LSB of first interface is LSB of result)\n\n    :param masterDirEqTo: only signals with this direction are packed\n    :param exclude: sequence of signals/interfaces to exclude\n    \"\"\"\n    if not hio._hwIOs:\n        if hio._masterDir == masterDirEqTo:\n            return hio._sig\n        return None\n\n    res = None\n    for sHwIO in hio._hwIOs:\n        if exclude is not None and sHwIO in exclude:\n            continue\n\n        if sHwIO._hwIOs:\n            if sHwIO._masterDir == DIRECTION.IN:\n                d = DIRECTION.opposite(masterDirEqTo)\n            else:\n                d = masterDirEqTo\n            s = HwIO_pack(sHwIO, masterDirEqTo=d, exclude=exclude)\n        else:\n            if sHwIO._masterDir == masterDirEqTo:\n                s = sHwIO._sig\n            else:\n                s = None\n\n        if s is not None:\n            if not isinstance(s._dtype, HBits) or  s._dtype.signed is not None:\n                s = s._reinterpret_cast(HBits(s._dtype.bit_length()))\n\n            if res is None:\n                res = s\n            else:\n                res = s._concat(res)\n\n    return res\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/__init__.py",
    "content": "\"\"\"\nrtlLevel is responsible for RtlSignal manipulation and design.\n\"\"\"\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/exceptions.py",
    "content": "from enum import Enum\n\n\nclass SignalDriverErrType(Enum):\n    (\n        MISSING_DRIVER,\n        MULTIPLE_COMB_DRIVERS,\n        OUTPUT_WITHOUT_DRIVER,\n        INPUT_WITH_DRIVER\n    ) = range(4)\n\n\nSignalDriverErrType_labels = {\n    SignalDriverErrType.MISSING_DRIVER: \"  missing driver for:\",\n    SignalDriverErrType.MULTIPLE_COMB_DRIVERS: \"  multiple comb. drivers for:\",\n    SignalDriverErrType.OUTPUT_WITHOUT_DRIVER: \"  outputs without driver:\",\n    SignalDriverErrType.INPUT_WITH_DRIVER: \"  inputs with driver:\",\n}\n\n\nclass SignalDriverErr(Exception):\n    \"\"\"\n    Signal has multiple combinational drivers (this is not possible in real word)\n    or signal has no driver specified and it drives something which has effect on any output of component\n    (it needs to have a driver but it does not have one)\n\n    :note: SignalDriverErr([(SignalDriverErrType, sig), ])\n    \"\"\"\n\n    def __str__(self):\n        try:\n            ctx = self.args[0][0][1]._rtlCtx\n            name = ctx.getDebugScopeName()\n            scope_name = f\"{name:s} of class {ctx.parent.__class__}\"\n        except Exception:\n            scope_name = \"<no parent>\"\n\n        b = [f\"{self.__class__} raised in {scope_name:s}\"]\n        err_sigs = sorted(self.args[0], key=lambda x: (x[0].value, x[1]._name))\n        prev_err_t = None\n        for err_t, sig in err_sigs:\n            if prev_err_t is None or prev_err_t != err_t:\n                b.append(SignalDriverErrType_labels[err_t])\n                prev_err_t = err_t\n            if err_t == SignalDriverErrType.MULTIPLE_COMB_DRIVERS or\\\n                    err_t == SignalDriverErrType.INPUT_WITH_DRIVER:\n                b.append(f\"    {sig}: {sig._rtlDrivers}\")\n            else:\n                b.append(f\"    {sig}\")\n\n        return \"\\n\".join(b)\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/extract_part_drivers.py",
    "content": "from itertools import islice\nfrom typing import Dict, List, Tuple, Union, Optional, Sequence\n\nfrom hwt.code import Concat\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operator import isConst\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.bitsConst import HBitsConst\nfrom hwt.hdl.types.defs import SLICE\nfrom hwt.hdl.types.sliceConst import HSliceConst\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.serializer.utils import RtlSignal_sort_key, HdlStatement_sort_key\nfrom hwt.synthesizer.rtlLevel.rtlNetlistPass import RtlNetlistPass\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\ndef _format_indexes(indexes):\n    return tuple(\n        (int(i) + 1, int(i))\n            if isinstance(i, HBitsConst) else\n        (int(i.val.start), int(i.val.stop))\n        for i in indexes)\n\n\n@internal\ndef construct_tmp_dst_sig_for_slice(dst: RtlSignal,\n                                    indexes: List[Union[HBitsConst, HSliceConst]],\n                                    src: Optional[RtlSignal],\n                                    is_signal_needed: bool) -> RtlSignal:\n    \"\"\"\n    Construct a tmp signal or value which will be used instead of slice from original signal\n\n    :param dst: a signal which slice we want to generate tmp signal for\n    :param indexes: a indexes to specify the slice of the dst\n    :param is_signal_needed: True if we need a signal which will we drive later, else returns HConst instance\n        resolved from default and nop value\n    \"\"\"\n    if is_signal_needed:\n        name = dst._name\n\n    def_val = dst.def_val\n    nop_val = dst._nop_val\n    for i in indexes:\n        def_val = def_val[i]\n        if nop_val is not NOT_SPECIFIED:\n            nop_val = nop_val[i]\n\n        if is_signal_needed:\n            dst = dst[i]\n            if isinstance(i, HSliceConst):\n                if int(i.val.step) == -1:\n                    stop = int(i.val.stop)\n                    start = int(i.val.start)\n                    name = f\"{name}_{start - 1:d}downto{stop:d}\"\n                else:\n                    raise NotImplementedError(i.val.step)\n            else:\n                _i = int(i)\n                name = f\"{name:s}_{_i:d}\"\n\n    if is_signal_needed:\n        tmp_sig = dst._rtlCtx.sig(name, dst._dtype, def_val=def_val, nop_val=nop_val)\n        return tmp_sig\n    elif src is not None:\n        return src\n    elif nop_val is not NOT_SPECIFIED:\n        return nop_val\n    else:\n        return def_val\n\n\ndef resolve_splitpoints(s: RtlSignal, parts):\n    split_points = set()\n    add_split_point = split_points.add\n    for i, _, _ in parts:\n        if len(i) != 1:\n            raise NotImplementedError(s, i)\n        i = i[0]\n\n        if isinstance(i, HBitsConst):\n            # index is normal integer\n            i = int(i)\n            add_split_point(i)\n            add_split_point(i + 1)\n        else:\n            # index is slice\n            assert isinstance(i, HSliceConst), (s, i)\n            add_split_point(int(i.val.start))\n            add_split_point(int(i.val.stop))\n\n    if isinstance(s._dtype, HBits):\n        # add boundary points in the case something is unconnected\n        add_split_point(0)\n        add_split_point(s._dtype.bit_length())\n    else:\n        raise NotImplementedError(s._dtype)\n\n    return split_points\n\n\nclass RtlNetlistPassExtractPartDrivers(RtlNetlistPass):\n    \"\"\"\n    Split parts of bit vectors so each segment has an unique variable.\n\n    .. code-block:: verilog\n\n        if (c0)\n            s[0] <= x;\n        if (c1)\n            s[1] <= y;\n\n    to\n\n    .. code-block:: verilog\n\n        wire s_0_tmp;\n        wire s_1_tmp;\n        assign s <= {s_1_tmp, s_0_tmp};\n        if (c0)\n            s_0_tmp <= x;\n        if (c1)\n            s_1_tmp <= y;\n\n    \"\"\"\n\n    @classmethod\n    def find_independent_slice_drivers(cls, stm: HdlStatement):\n        if isinstance(stm, HdlAssignmentContainer):\n            if stm.indexes and len(stm.indexes) == 1 and isinstance(stm.dst._dtype, HBits):\n                dst = stm.dst\n                for i in stm.indexes:\n                    if not isConst(i):\n                        return\n\n                can_directly_replace_with_src_expr = stm.parentStm is None\n                yield (\n                    dst,\n                    tuple(stm.indexes),\n                    can_directly_replace_with_src_expr,\n                    stm.src if can_directly_replace_with_src_expr else None\n                )\n        else:\n            for _stm in stm._iter_stms():\n                yield from cls.find_independent_slice_drivers(_stm)\n\n    @classmethod\n    def find_all_independent_slice_drivers(cls, statements: Sequence[HdlStatement]):\n        for stm in sorted(statements, key=HdlStatement_sort_key):\n            for s, indexes, can_directly_replace_with_src_expr, src in cls.find_independent_slice_drivers(stm):\n                yield s, indexes, can_directly_replace_with_src_expr, src\n\n    @classmethod\n    def _collect_indexes_on_variables(cls, statements: Sequence[HdlStatement]):\n        signal_parts = {}\n        for s, indexes, can_directly_replace_with_src_expr, src in cls.find_all_independent_slice_drivers(statements):\n            signal_parts.setdefault(s, []).append((indexes, can_directly_replace_with_src_expr, src))\n        return signal_parts\n\n    @classmethod\n    def resolve_final_parts_from_splitpoints_and_parts(cls, signal_parts):\n        final_signal_parts: Dict[RtlSignal, Dict[Tuple[Tuple[int, int], ...], Union[HConst, RtlSignal]]] = {}\n        # split part intervals to non-overlapping chunks\n        for s, parts in sorted(signal_parts.items(), key=lambda x: RtlSignal_sort_key(x[0])):\n            split_point = resolve_splitpoints(s, parts)\n            split_point = sorted(split_point)\n            # prepare part signals\n            new_parts = []\n            new_parts_dict = {}\n            split_i = 0\n            end = 0\n            # :attention: parts are likely to contain parts with same indexes\n            for indexes, can_directly_replace_with_src_expr, src in sorted(parts, key=lambda x: x[0]):\n                if len(indexes) != 1:\n                    raise NotImplementedError()\n\n                i = indexes[0]\n                split_p = split_point[split_i]\n                if isinstance(i, HBitsConst):\n                    low = int(i)\n                    high = low + 1\n                    index_key = ((high, low),)\n                else:\n                    assert isinstance(i, HSliceConst), (s, i)\n                    if i.val.step != -1:\n                        raise NotImplementedError(s, i)\n                    high, low = int(i.val.start), int(i.val.stop)\n                    index_key = ((high, low),)\n\n                while split_p < low:\n                    # some parts at the beginning are skipped\n                    # that means that that part is not driven by anything\n                    # and we need to check default and nop value\n                    part_indexes = (SLICE.from_py(slice(low, split_p , -1)),)\n                    _src = construct_tmp_dst_sig_for_slice(s, part_indexes, None, isinstance(s._nop_val, RtlSignal))\n                    new_parts.append(_src)\n                    _index_key = ((low, split_p),)\n                    new_parts_dict[_index_key] = _src, True\n                    split_i += 1\n                    split_p = split_point[split_i]\n\n                this_start_split_p_i = split_i\n                if split_p > low:\n                    # some parts at the beginning were already resolved\n                    # This can happen if there was some part which started on some <= index and overlaps with this part.\n                    try:\n                        _, _can_directly_replace_with_src_expr = new_parts_dict[index_key]\n                        assert not _can_directly_replace_with_src_expr, (s, index_key)\n                        # was already resolved and checked no need to check it again\n                        continue\n                    except KeyError:\n                        pass\n\n                    for i in range(split_i, -1, -1):\n                        _sp = split_point[i]\n                        if _sp == low:\n                            this_start_split_p_i = i\n\n                assert split_point[this_start_split_p_i] == low\n                # just at the start of this slice\n                next_split_p = split_point[this_start_split_p_i + 1]\n                assert next_split_p <= high, \"The next split point can be at most end of current part\"\n                if next_split_p == high:\n                    assert this_start_split_p_i == split_i, \"We should see this part for the first time or the split_i should already be higher\"\n                    # all bits on this slice are alwyas driven at once, we can instantiate whole part\n                    assert split_p == low\n                    _src = construct_tmp_dst_sig_for_slice(s, indexes, src, not can_directly_replace_with_src_expr)\n                    new_parts.append(_src)\n                    assert index_key not in new_parts_dict, (s, index_key)\n                    new_parts_dict[index_key] = _src, can_directly_replace_with_src_expr\n                    split_i += 1\n                else:\n                    # list of part keys for later search\n                    _split_parts = []\n                    prev_sp = split_point[this_start_split_p_i]\n                    dst_offset = low\n                    assert not can_directly_replace_with_src_expr, (indexes, src)\n                    # continue instanciating parts until we reach the end of this part\n                    for sp_i, sp in zip(range(this_start_split_p_i + 1, len(split_point)),\n                                        islice(split_point, this_start_split_p_i + 1, None)):\n                        # need to generate sub slice\n                        # because this slice has actually multiple individualy driven parts\n\n                        # we need to generate all slice parts because there could be a case where only some sub parts are\n                        # driven elsewhere and we would othervise resolve those segments as a constantly driven\n                        # but they are in fact driven from this slice\n                        if sp > high:\n                            break\n\n                        part_key = ((sp, prev_sp),)\n                        if sp_i <= split_i:\n                            # check if the slice is not driven from some top level constant assignment\n                            # which would result is multiple drivers of this slice\n                            assert src is None\n                            existing_part, _can_directly_replace_with_src_expr = new_parts_dict[part_key]\n                            assert not _can_directly_replace_with_src_expr, (s, low, high, existing_part)\n                            assert not can_directly_replace_with_src_expr, (s, low, high, existing_part)\n                            assert isinstance(existing_part, RtlSignal), (s, low, high, existing_part)\n                        else:\n                            assert sp_i == split_i + 1, (s, sp_i, split_i)\n                            # get actual input signal\n                            if src is None:\n                                _src = None\n                            else:\n                                _src = src[sp - dst_offset:prev_sp - dst_offset]\n\n                            part_indexes = (SLICE.from_py(slice(sp, prev_sp, -1)),)\n                            _src = construct_tmp_dst_sig_for_slice(s, part_indexes, _src, True)\n\n                            new_parts.append(_src)\n                            new_parts_dict[part_key] = _src, can_directly_replace_with_src_expr\n\n                            split_i += 1\n                        _split_parts.append(part_key)\n                        prev_sp = sp\n\n                    new_parts_dict[index_key] = _split_parts, False\n\n                end = max(end, high)\n\n            if end < split_point[-1]:\n                # something unconnected at the end\n                high, low = split_point[-1], end\n                part_indexes = (SLICE.from_py(slice(high, low , -1)),)\n                _src = construct_tmp_dst_sig_for_slice(s, part_indexes, None, isinstance(s._nop_val, RtlSignal))\n                new_parts.append(_src)\n                index_key = ((high, low),)\n                new_parts_dict[index_key] = _src, True\n\n            # construct assignment of concatenation from all parts\n            assert new_parts, (s, parts)\n            s(Concat(*reversed(new_parts)))\n            final_signal_parts[s] = new_parts_dict\n\n        return final_signal_parts\n\n    @classmethod\n    def extract_part_drivers_stm(cls, stm: HdlStatement,\n                                 signal_parts: Dict[RtlSignal,\n                                                    List[Tuple[RtlSignal, List[HConst]]]]\n                                 ) -> bool:\n        \"\"\"\n        :return: True if statement was modified\n        \"\"\"\n        if isinstance(stm, HdlAssignmentContainer):\n            dst = stm.dst\n            parts = signal_parts.get(dst, None)\n            if parts is None:\n                return False\n            if stm.indexes and len(stm.indexes) == 1:\n                indexes = _format_indexes(stm.indexes)\n                new_dsts, do_remove_stm = parts[indexes]\n            else:\n                # collect only parts which do not have sub parts (are primitive parts)\n                new_dsts = []\n                for k, d in parts.items():\n                    if not isinstance(d, list):\n                        new_dsts.append(k)\n                new_dsts.sort()\n                do_remove_stm = False\n\n            if isinstance(new_dsts, list):\n                if stm.parentStm is None:\n                    return False\n                assert len(new_dsts) > 1, (dst, new_dsts, stm)\n                # assert not do_remove_stm, (dst, new_dsts, stm)\n                # the driven slice was split to multiple sub slices\n                replacement = []\n                dst_offset = new_dsts[0][-1][1]\n                for i in new_dsts:\n                    new_dst = parts[i][0]\n                    new_src = stm.src\n                    for _i in i:\n                        high, low = _i[0] - dst_offset, _i[1] - dst_offset\n                        assert high > 0 and low >= 0, dst_offset\n                        assert high > low, (dst, stm, (high, low))\n                        new_src = new_src[high:low]\n                    a = new_dst(new_src)\n                    replacement.append(a)\n\n                # it has to have parent statement because it needs to be nested\n                # because otherwise it would not have some overlapping parts driven diferently\n                # under some condition\n                stm.parentStm._replace_child_statement(stm, replacement, False)\n                if do_remove_stm:\n                    stm._destroy()\n\n            elif do_remove_stm:\n                # remove current assignment because we are using src directly\n                # assert stm.parentStm is None, (stm, stm.parentStm)\n                stm._destroy()\n            else:\n                # rewrite the HdlAssignmentContainer instance to use new dst\n                replacement = [new_dsts(stm.src), ]\n                stm.parentStm._replace_child_statement(stm, replacement, False)\n            return True\n\n        elif isinstance(stm, (IfContainer, SwitchContainer, HdlStmCodeBlockContainer)):\n            modified = False\n            for _stm in stm._iter_stms():\n                modified |= cls.extract_part_drivers_stm(_stm, signal_parts)\n            if modified:\n                assert not stm._enclosed_for, \"_enclosed_for is expected not to be initialized yet\"\n                outputs = stm._outputs\n                inputs = stm._inputs\n                stm._outputs = SetList()\n                stm._inputs = SetList()\n                stm._collect_io()\n                if stm.parentStm is None:\n                    for o in outputs:\n                        if o not in stm._outputs:\n                            o._rtlDrivers.remove(stm)\n\n                    for i in inputs:\n                        if i not in stm._inputs:\n                            i._rtlEndpoints.remove(stm)\n\n                return True\n\n        else:\n            raise NotImplementedError(\"Unknown statement \", stm)\n\n        return False\n\n    def runOnRtlNetlist(self, netlist: \"RtlNetlist\"):\n        signal_parts = self._collect_indexes_on_variables(netlist.statements)\n        if not signal_parts:\n            return\n\n        final_signal_parts = self.resolve_final_parts_from_splitpoints_and_parts(signal_parts)\n        for stm in sorted(netlist.statements, key=HdlStatement_sort_key):\n            self.extract_part_drivers_stm(stm, final_signal_parts)\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/fill_stm_list_with_enclosure.py",
    "content": "from typing import Set, List, Dict, Optional, Callable\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass HdlAssignmentContainer_constructor():\n\n    def __init__(self, src, dst):\n        self.dst = dst\n        self.src = src\n\n    def __call__(self) -> HdlAssignmentContainer:\n        return HdlAssignmentContainer(self.src, self.dst)\n\n\n@internal\ndef fill_stm_list_with_enclosure(parentStm: Optional[HdlStatement],\n                                 current_enclosure: Set[RtlSignalBase],\n                                 statements: ListOfHdlStatement,\n                                 do_enclose_for: List[RtlSignalBase],\n                                 enclosure: Dict[RtlSignalBase, Callable[[], HdlStatement]])\\\n        ->ListOfHdlStatement:\n    \"\"\"\n    Apply enclosure on list of statements\n    (fill all unused code branches with assignments from value specified by enclosure)\n\n    :param parentStm: optional parent statement where this list is some branch\n    :param current_enclosure: list of signals for which this statement list is enclosed\n    :param statements: list of statements\n    :param do_enclose_for: selected signals for which enclosure should be used\n    :param enclosure: enclosure values for signals\n\n    :attention: original statements parameter can be modified\n    :return: new statements\n    \"\"\"\n    assert do_enclose_for\n    if statements is None:\n        statements = ListOfHdlStatement()\n\n    for e_sig in do_enclose_for:\n        if e_sig in current_enclosure:\n            continue\n        enclosed = False\n        for stm in statements.iterStatementsWithOutput(e_sig):\n            if e_sig not in stm._enclosed_for:\n                stm._fill_enclosure(enclosure)\n            enclosed = True\n            break\n        # any statement was not related with this signal,\n        if not enclosed:\n            e = enclosure[e_sig]\n            a: HdlStatement = e()\n            assert isinstance(a, HdlStatement), a\n            statements.append(a)\n\n            if parentStm is not None:\n                a._set_parent_stm(parentStm, statements)\n\n    return statements\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/mark_visibility_of_signals_and_check_drivers.py",
    "content": "from typing import Generator, Tuple, List\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErrType, \\\n    SignalDriverErr\nfrom hwt.synthesizer.rtlLevel.rtlNetlistPass import RtlNetlistPass\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom ipCorePackager.constants import DIRECTION\n\n\n@internal\ndef walk_assignments(stm: HdlStatement, dst: RtlSignal)\\\n        ->Generator[HdlAssignmentContainer, None, None]:\n    if isinstance(stm, HdlAssignmentContainer):\n        if dst is stm.dst:\n            yield stm\n    else:\n        for _stm in stm._iter_stms():\n            yield from walk_assignments(_stm, dst)\n\n\n@internal\nclass RtlNetlistPassMarkVisibilityOfSignalsAndCheckDrivers(RtlNetlistPass):\n\n    def runOnRtlNetlist(self, netlist: \"RtlNetlist\"):\n        \"\"\"\n        * check if all signals are driven by something\n        * mark signals with hidden = False if they are connecting statements\n          or if they are external interface\n        \"\"\"\n        signals = netlist.signals\n        ioSignals = netlist.hwIOs\n\n        signals_with_driver_issue: List[Tuple[SignalDriverErrType, RtlSignal]] = []\n        for sig in signals:\n            # if isinstance(sig._nop_val, (RtlSignal, InterfaceBase)):\n            #    sig._nop_val._isUnnamedExpr = False\n\n            driver_cnt = len(sig._rtlDrivers)\n            has_comb_driver = False\n            if driver_cnt > 1:\n                sig._isUnnamedExpr = False\n                for d in sig._rtlDrivers:\n                    if not isinstance(d, HOperatorNode):\n                        sig._isUnnamedExpr = False\n\n                    is_comb_driver = False\n\n                    if isinstance(d, HdlPortItem):\n                        is_comb_driver = True\n                    elif d._event_dependent_from_branch is None:\n                        for a in walk_assignments(d, sig):\n                            if not a.indexes\\\n                                    and a._event_dependent_from_branch != 0:\n                                is_comb_driver = True\n                                break\n\n                    if has_comb_driver and is_comb_driver:\n                        signals_with_driver_issue.append(\n                            (SignalDriverErrType.MULTIPLE_COMB_DRIVERS, sig))\n                        break\n\n                    has_comb_driver |= is_comb_driver\n            elif driver_cnt == 1:\n                if not isinstance(sig._rtlDrivers[0], HOperatorNode):\n                    sig._isUnnamedExpr = False\n            else:\n                sig._isUnnamedExpr = False\n                if sig not in ioSignals.keys():\n                    if not sig.def_val._is_partially_valid():\n                        signals_with_driver_issue.append(\n                            (SignalDriverErrType.MISSING_DRIVER, sig))\n                    sig._const = True\n\n            # chec interface direction if required\n            d = ioSignals.get(sig, None)\n            if d is None:\n                pass\n            elif d is DIRECTION.IN:\n                assert sig._rtlDrivers, sig\n                if len(sig._rtlDrivers) != 1:\n                    signals_with_driver_issue.append(\n                        (SignalDriverErrType.INPUT_WITH_DRIVER, sig))\n            elif d is DIRECTION.OUT:\n                if not sig._rtlDrivers:\n                    signals_with_driver_issue.append(\n                        (SignalDriverErrType.OUTPUT_WITHOUT_DRIVER, sig))\n\n        if signals_with_driver_issue:\n            raise SignalDriverErr(signals_with_driver_issue)\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/netlist.py",
    "content": "from typing import List, Optional, Union, Dict, Set, Type\n\nfrom hdlConvertorAst.hdlAst._defs import HdlIdDef\nfrom hdlConvertorAst.hdlAst._expr import HdlValueId\nfrom hdlConvertorAst.hdlAst._structural import HdlModuleDec, HdlModuleDef, \\\n    HdlCompInst\nfrom hwt.code import If\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operatorDefs import HwtOps\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.types.defs import BIT\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hwParam import HwParam\nfrom hwt.mainBases import HwIOBase\nfrom hwt.serializer.utils import HdlStatement_sort_key, RtlSignal_sort_key\nfrom hwt.synthesizer.dummyPlatform import DummyPlatform\nfrom hwt.synthesizer.exceptions import SigLvlConfErr\nfrom hwt.synthesizer.rtlLevel.rtlNetlistPass import RtlNetlistPass\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal, CREATE_NEXT_SIGNAL\nfrom hwt.synthesizer.rtlLevel.statements_to_HdlStmCodeBlockContainers import statements_to_HdlStmCodeBlockContainers\nfrom ipCorePackager.constants import DIRECTION\n\n\nclass RtlNetlist():\n    \"\"\"\n    Hierarchical container for signals\n\n    :ivar ~.parent: optional parent for debug and late component inspection\n    :ivar ~.signals: set of all signals in this context\n    :ivar ~.statements: list of all statements which are connected to signals in this context\n    :ivar ~.subHwModules: is set of all units in this context\n    :ivar ~.hwIOs: initialized in create_HdlModuleDef\n    :ivar ~.hwModDec: initialized in create_HdlModuleDec\n    :ivar ~.hwModDef: initialized in create_HdlModuleDef\n    \"\"\"\n\n    def __init__(self, parent: Optional[\"HwModule\"]=None):\n        self.parent = parent\n        self.signals: Set[RtlSignal] = set()\n        self.statements: Set[HdlStatement] = set()\n        self.subHwModules: Set[\"HwModule\"] = set()\n        self.hwIOs: Dict[RtlSignal, DIRECTION] = {}\n        self.hwModDec: Optional[HdlModuleDec] = None\n        self.hwModDef: Optional[HdlModuleDef] = None\n\n    def sig(self, name: str, dtype=BIT, clk=None, syncRst=None,\n            def_val=None, nop_val=NOT_SPECIFIED, nextSig=NOT_SPECIFIED) -> Union[RtlSignal, HwIOBase]:\n        \"\"\"\n        Create new signal in this context\n\n        :param clk: clock signal\n        :param syncRst: synchronous reset signal\n        :param def_val: a default value used for reset and initialization\n        :param nop_val: a value which is used to drive the signal if there is no other drive\n            (used to prevent latches and to specify default values for unconnected signals)\n        :param nextSig: the signal which should be used as \"next\" signal for this register\n            if is not specified the new signal is generated. (Next signal holds value which should be in register in next clk.)\n        \n        \"\"\"\n        _def_val = _try_cast_any_to_HValue(def_val, dtype, True)\n        if nop_val is not NOT_SPECIFIED:\n            nop_val = _try_cast_any_to_HValue(nop_val, dtype, False)\n        \n        signalCls: Type[RtlSignal] = dtype.getRtlSignalCls()\n        if clk is not None:\n            if nextSig is not None and isinstance(nextSig, HwIOBase):\n                nextSig = nextSig._sig\n            s = signalCls(self, name, dtype,\n                          _def_val if isinstance(_def_val, HConst) else dtype.from_py(None),\n                          nop_val,\n                          next_signal=CREATE_NEXT_SIGNAL if nextSig is NOT_SPECIFIED else nextSig)\n            if syncRst is not None and def_val is None:\n                raise SigLvlConfErr(\n                    \"Probably forgotten default value on sync signal %s\", name)\n            # dst_resolve_fn is overridden because default assign would assign to the \"next\" signal\n            if syncRst is not None:\n                r = If(syncRst._isOn(),\n                       s(_def_val, dst_resolve_fn=lambda x: x)\n                    ).Else(\n                       s(s._rtlNextSig, dst_resolve_fn=lambda x: x)\n                    )\n            else:\n                r = [\n                    s(s._rtlNextSig, dst_resolve_fn=lambda x: x)\n                ]\n\n            if isinstance(clk, (HwIOBase, RtlSignal)):\n                clk_trigger = clk._onRisingEdge()\n            else:\n                # has to be tuple of (clk_sig, HwtOps.RISING/FALLING_EDGE)\n                clk, clk_edge = clk\n                if clk_edge is HwtOps.RISING_EDGE:\n                    clk_trigger = clk._onRisingEdge()\n                elif clk_edge is HwtOps.FALLING_EDGE:\n                    clk_trigger = clk._onRisingEdge()\n                else:\n                    raise ValueError(\n                        \"Invalid clock edge specification\", clk_edge)\n\n            If(clk_trigger,\n               r\n            )\n        else:\n            if syncRst:\n                raise SigLvlConfErr(\n                    f\"Signal {name:s} has reset but has no clk\")\n            if nextSig is not NOT_SPECIFIED:\n                raise SigLvlConfErr(\n                    f\"Signal {name:s} has nextSig which is used for next register value, but has no clock and thus is not a register.\")\n\n            assert isinstance(_def_val, HConst) or (isinstance(_def_val, RtlSignal) and _def_val._const), (_def_val, \"The default value needs to be constant\")\n            s = signalCls(self, name, dtype, def_val=_def_val, nop_val=nop_val)\n\n        return s\n\n    def create_HdlModuleDec(self, name: str,\n                            store_manager: \"StoreManager\",\n                            params: List[HwParam]):\n        \"\"\"\n        Generate a module header (entity) for this module\n        \"\"\"\n        self.hwModDec = hwModDec = HdlModuleDec()\n        hwModDec.name = store_manager.name_scope.checked_name(name, hwModDec)\n        ns = store_manager.hierarchy_push(hwModDec)\n        # create generics\n        for p in sorted(params, key=lambda x: x._name):\n            hdl_val = p.get_hdl_value()\n            v = HdlIdDef()\n            v.origin = p\n            # sanitize param name\n            v.name = p._name = ns.checked_name(p._name, p)\n            v.type = hdl_val._dtype\n            v.value = hdl_val\n            hwModDec.params.append(v)\n\n        return hwModDec\n\n    def create_HdlModuleDef(self,\n                            target_platform: DummyPlatform,\n                            store_manager: \"StoreManager\"):\n        \"\"\"\n        Generate a module body (architecture) for this module\n\n        * Resolve name collisions\n        * Convert netlist representation to HdlProcesses\n        * Remove unconnected\n        * Mark visibility of signals\n        \"\"\"\n        for optPass in target_platform.beforeHdlArchGeneration:\n            optPass: RtlNetlistPass\n            optPass.runOnRtlNetlist(self)\n\n        ns = store_manager.name_scope\n        mdef = HdlModuleDef()\n        mdef.dec = self.hwModDec\n        mdef.module_name = HdlValueId(self.hwModDec.name, obj=self.hwModDec)\n        mdef.name = \"rtl\"\n\n        processes = sorted(self.statements, key=HdlStatement_sort_key)\n        processes = sorted(statements_to_HdlStmCodeBlockContainers(processes), key=HdlStatement_sort_key)\n\n        # add signals, variables, etc. in architecture\n        for s in sorted((s for s in self.signals\n                        if not s._isUnnamedExpr and\n                        s not in self.hwIOs.keys()),\n                        key=RtlSignal_sort_key):\n            s: RtlSignal\n            assert s._rtlCtx is self, (\"RtlSignals in this context must know that they are in this context\", s)\n            v = HdlIdDef()\n            v.origin = s\n            v.name = s._name = ns.checked_name(s._name, s)\n            v.type = s._dtype\n            v.value = s.def_val\n            v.is_const = s._const\n            mdef.objs.append(v)\n\n        for p in processes:\n            p: HdlStmCodeBlockContainer\n            p.name = ns.checked_name(p.name, p)\n\n        mdef.objs.extend(processes)\n        # instantiate subModules in architecture\n        for sm in self.subHwModules:\n            ci = HdlCompInst()\n            ci.origin = sm\n            ci.module_name = HdlValueId(sm._rtlCtx.hwModDec.name, obj=sm._rtlCtx.hwModDec)\n            ci.name = HdlValueId(ns.checked_name(sm._name + \"_inst\", ci), obj=sm)\n            hwModDec = sm._rtlCtx.hwModDec\n\n            ci.param_map.extend(hwModDec.params)\n            ci.port_map.extend(hwModDec.ports)\n\n            mdef.objs.append(ci)\n\n        self.hwModDef = mdef\n        return mdef\n\n    def getDebugScopeName(self):\n        scope = []\n        p = self.parent\n        while p is not None:\n            scope.append(p._name)\n            try:\n                p = p._parent\n            except AttributeError:\n                break\n\n        return \".\".join(reversed(scope))\n\n\n@internal\ndef _try_cast_any_to_HValue(v, dtype: HdlType, require_const: bool):\n    if isinstance(v, RtlSignal):\n        assert not require_const or v._const, \\\n            \"Initial value of signal has to be a constant\"\n        return v._auto_cast(dtype)\n    elif isinstance(v, HConst):\n        return v._auto_cast(dtype)\n    elif isinstance(v, HwIOBase):\n        return v._sig\n    else:\n        return dtype.from_py(v)\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/reduce_processes.py",
    "content": "from itertools import islice\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.utils.reduction import HdlStatement_merge_statement_lists, \\\n    is_mergable_statement_list\nfrom hwt.pyUtils.arrayQuery import areSetsIntersets, groupedby\nfrom hwt.serializer.utils import HdlStatement_sort_key\n\n\nclass HwtStmIncompatibleStructure(Exception):\n    \"\"\"\n    Statements are not comparable due incompatible structure\n    \"\"\"\n\n\n@internal\ndef checkIfIsTooSimple(proc):\n    \"\"\"check if process is just unconditional assignments\n       and it is useless to merge them\"\"\"\n    try:\n        a, = proc.statements\n        if isinstance(a, HdlAssignmentContainer):\n            return True\n    except ValueError:\n        pass\n    return False\n\n\n@internal\ndef tryToMerge(procA: HdlStmCodeBlockContainer,\n               procB: HdlStmCodeBlockContainer):\n    \"\"\"\n    Try merge procB into procA\n\n    :raise IncompatibleStructure: if merge is not possible\n    :attention: procA is now result if merge has succeed\n    :return: procA which is now result of merge\n    \"\"\"\n    if (areSetsIntersets(procA._outputs, procB._sensitivity) or\n            areSetsIntersets(procB._outputs, procA._sensitivity) or\n            not is_mergable_statement_list(procA.statements, procB.statements)):\n        raise HwtStmIncompatibleStructure()\n\n    procA.statements = HdlStatement_merge_statement_lists(\n        procA.statements, procB.statements)\n    procB.statements = None\n\n    procA._outputs.extend(procB._outputs)\n    procA._inputs.extend(procB._inputs)\n    procA._sensitivity.extend(procB._sensitivity)\n\n    return procA\n\n\n@internal\ndef reduceProcesses(processes):\n    \"\"\"\n    Try to merge processes as much is possible\n\n    :param processes: list of processes instances\n    \"\"\"\n    # sort to make order of merging same deterministic\n    processes.sort(key=HdlStatement_sort_key, reverse=True)\n\n    # now try to reduce processes with nearly same structure of statements into one\n    # to minimize number of processes\n    for _, procs in groupedby(processes, lambda p: p.rank):\n        _procs = []\n        for p in procs:\n            if checkIfIsTooSimple(p):\n                yield p\n            else:\n                _procs.append(p)\n\n        procs = _procs\n        for iA, pA in enumerate(procs):\n            if pA is None:\n                continue\n            for iB, pB in enumerate(islice(procs, iA + 1, None)):\n                if pB is None:\n                    continue\n\n                try:\n                    pA = tryToMerge(pA, pB)\n                except HwtStmIncompatibleStructure:\n                    continue\n                procs[iA + 1 + iB] = None\n                # procs[iA] = pA\n\n        for p in procs:\n            if p is not None:\n                yield p\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/remove_unconnected_signals.py",
    "content": "from collections import deque\nfrom io import StringIO\nfrom typing import Optional\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.ifContainter import IfContainer\nfrom hwt.hdl.statements.statement import HdlStatement\nfrom hwt.hdl.statements.switchContainer import SwitchContainer\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.synthesizer.interfaceLevel.utils import HwIO_walkSignals\nfrom hwt.synthesizer.rtlLevel.rtlNetlistPass import RtlNetlistPass\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\nfrom ipCorePackager.constants import DIRECTION\n\n\n@internal\ndef walkInputsForSpecificOutput(output_sig: RtlSignalBase, stm: HdlStatement):\n    if output_sig not in stm._outputs:\n        return\n\n    elif isinstance(stm, HdlAssignmentContainer):\n        assert stm.dst is output_sig\n        yield from stm._inputs\n        return\n\n    elif isinstance(stm, IfContainer):\n        yield stm.cond\n        for c, _ in stm.elIfs:\n            yield c\n\n    elif isinstance(stm, SwitchContainer):\n        yield stm.switchOn\n\n    elif isinstance(stm, HdlStmCodeBlockContainer):\n        pass\n\n    else:\n        raise NotImplementedError(stm)\n\n    for _stm in stm._iter_stms_for_output(output_sig):\n        yield from walkInputsForSpecificOutput(output_sig, _stm)\n\n\n@internal\nclass RtlNetlistPassRemoveUnconnectedSignals(RtlNetlistPass):\n\n    def __init__(self, traceOutput:Optional[StringIO]=None):\n        self.traceOutput = traceOutput\n\n    def runOnRtlNetlist(self, netlist: \"RtlNetlist\"):\n        \"\"\"\n        Remove signal if does not affect output\n    \n        :attention: does not remove signals in cycles which does not affect outputs\n        \"\"\"\n        trace = self.traceOutput\n        # walk circuit from outputs to inputs and collect seen signals\n        toSearch = deque(s for s, d in netlist.hwIOs.items() if d != DIRECTION.IN)\n        seen = set(toSearch)\n        for c in netlist.subHwModules:\n            for sig in HwIO_walkSignals(c):\n                # if sig._direction == INTF_DIRECTION.SLAVE and sig._masterDir == DIRECTION.OUT:\n                #     continue\n                # if sig._direction == INTF_DIRECTION.MASTER and sig._masterDir == DIRECTION.IN:\n                #     continue\n                s = sig._sig\n                assert s is not None, (netlist.parent, sig, \"broken HwIO instance\")\n                assert s._rtlCtx is netlist, (netlist.parent, s, \"must be in the same netlist\")\n                toSearch.append(s)\n\n        while toSearch:\n            sig = toSearch.popleft()\n\n            for e in sig._rtlDrivers:\n                if isinstance(e, HOperatorNode):\n                    inputs = e.operands\n                elif isinstance(e, HdlPortItem):\n                    # we are already added inputs of all components\n                    continue\n                else:\n                    assert e in netlist.statements, (\"Statement must be registered in the netlist\", e)\n                    inputs = walkInputsForSpecificOutput(sig, e)\n\n                for i in inputs:\n                    if isinstance(i, RtlSignalBase) and i not in seen:\n                        assert i._rtlCtx is not None, (netlist.parent, e, \"input does not have netlist assigned\", i)\n                        assert i._rtlCtx is netlist, (netlist.parent, e, \"all inputs must be in the same netlist\", i)\n                        seen.add(i)\n                        toSearch.append(i)\n\n            nv = sig._nop_val\n            if isinstance(nv, RtlSignalBase):\n                if nv not in seen:\n                    assert nv._rtlCtx is netlist, nv\n                    seen.add(nv)\n                    toSearch.append(nv)\n\n        # add all io because it can not be removed\n        seen.update(s for s, d in netlist.hwIOs.items() if d == DIRECTION.IN)\n        for c in netlist.subHwModules:\n            for sig in HwIO_walkSignals(c):\n                s = sig._sig\n                assert s is not None, (netlist.parent, sig, \"broken HwIO instance after initial scan\")\n                assert s._rtlCtx is netlist, (netlist.parent, s, \"must be in the same netlist\")\n                seen.add(s)\n\n        # remove signals which were not seen\n        for sig in netlist.signals:\n            sig: RtlSignal\n            if sig in seen:\n                # if it was seen it was used and it should not be removed\n                continue\n            if trace is not None:\n                trace.write(\"removing unseen: \")\n                trace.write(repr(sig))\n                trace.write(\"\\n\")\n            assert sig._rtlCtx is netlist, (netlist.parent, sig, \"must be in the same netlist\")\n\n            for e in tuple(sig._rtlDrivers):\n                # drivers of this signal are useless rm them\n                if isinstance(e, HOperatorNode):\n                    removed_e = e\n                elif isinstance(e, HdlPortItem):\n                    raise NotImplementedError(sig)\n                else:\n                    removed_e = e._cut_off_drivers_of(sig)\n\n                if removed_e is not None:\n                    # must not destroy before processing inputs\n                    if trace is not None:\n                        trace.write(\"removing: \")\n                        trace.write(repr(removed_e))\n                        trace.write(\"\\n\")\n                    removed_e._destroy()\n                    \n            hwIO = getattr(sig, \"_hwIO\", None)\n            if hwIO:\n                if hwIO._sig is sig:\n                    hwIO._sig = None\n                else:\n                    assert hwIO._sigInside is None or hwIO._sigInside is sig, (hwIO, hwIO._sigInside, sig)\n                    hwIO._sigInside = None\n\n        netlist.signals = seen\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/rtlNetlistPass.py",
    "content": "\n\nclass RtlNetlistPass():\n\n    def runOnRtlNetlist(self, netlist: \"RtlNetlist\"):\n        raise NotImplementedError(\"Override this function in your implementation of this abstract class\")\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/rtlSignal.py",
    "content": "from copy import copy\nfrom typing import Generator, Dict, Tuple, Set, Union, Self, List, \\\n    Literal, Optional\n\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.operatorDefs import HOperatorDef, HwtOps, CAST_OPS\nfrom hwt.hdl.portItem import HdlPortItem\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.hdl.statements.assignmentContainer import HdlAssignmentContainer\nfrom hwt.hdl.statements.statement import HdlStatement, HwtSyntaxError\nfrom hwt.hdl.types.bitsCastUtils import fitTo_t\nfrom hwt.hdl.types.defs import SLICE, INT\nfrom hwt.hdl.types.hdlType import HdlType\nfrom hwt.hdl.types.typeCast import toHVal\nfrom hwt.hdl.variables import HdlSignalItem\nfrom hwt.mainBases import RtlSignalBase, HwIOBase\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.synthesizer.exceptions import TypeConversionErr\nfrom hwt.synthesizer.rtlLevel.exceptions import SignalDriverErr, \\\n    SignalDriverErrType\n\n\nOperatorCaheKeyType = Union[\n    Tuple['OpDefinition', int, object],\n    Tuple['OpDefinition', int, object, object],\n    Tuple['OpDefinition', int, object, object, object],\n]\n\n\nclass CREATE_NEXT_SIGNAL():\n\n    def __init__(self):\n        raise AssertionError(\"This class should be used as a constant\")\n\n\nclass RtlSignal(RtlSignalBase, HdlSignalItem):\n    \"\"\"\n    RtlSignal signal is a connection between statements and operators in circuit graph.\n\n    :ivar ~._rtlEndpoints: SetList of operators and statements\n        for which this signal is driver.\n    :ivar ~._rtlDrivers: SetList of operators and statements\n        which can drive this signal.\n        If driver is statement tree only top statement is present.\n    :ivar ~._usedOps: A dictionary of used operators which can be reused.\n    :ivar ~._usedOpsAlias: A dictionary tuple of operator and operands to set of tuples of operator and operands,\n        used to resolve which combination of the operator and operands resulted in to same result.\n    :note: The _usedOps, _usedOpsAlias cache record is generated only for the left most signal in expression.\n    :ivar ~._isUnnamedExpr: means that this signal is part of expression\n        and should not be rendered\n    :ivar ~._nop_val: value which is used to fill up statements when no other\n            value is assigned, use NOT_SPECIFIED to disable\n    :ivar ~._const: flag which tell that this signal can not have any other driver\n        than a default value\n\n    :cvar __instCntr: counter used for generating instance ids\n    :ivar ~._instId: internally used only for intuitive sorting of statements\n        in serialized code\n    :ivar ~._rtlObjectOrigin: optionally an object which generated this signal\n    :ivar ~._rtlNextSig: optional signal signal which is used as a next signal if this RtlSignal is actually a FF output.\n    \"\"\"\n    __instCntr = 0\n\n    __slots__ = [\n        \"_ctx\",\n        \"_rtlEndpoints\",\n        \"_rtlDrivers\",\n        \"_usedOps\",\n        \"_usedOpsAlias\",\n        \"_isUnnamedExpr\",\n        \"_hdlName\",\n        \"_hasGenericName\",\n        \"_instId\",\n        \"_nop_val\",\n        \"_const\",\n        \"_hwIO\",\n        \"_rtlObjectOrigin\",\n        \"_rtlNextSig\",\n    ]\n\n    def __init__(self, ctx: 'RtlNetlist',\n                 name: str,\n                 dtype: HdlType,\n                 def_val=None,\n                 nop_val=NOT_SPECIFIED,\n                 next_signal:Union[RtlSignalBase, Literal[NOT_SPECIFIED, CREATE_NEXT_SIGNAL]]=NOT_SPECIFIED,\n                 virtual_only=False,\n                 is_const=False):\n        \"\"\"\n        :param ctx: context - RtlNetlist which is this signal part of\n        :param name: name hint for this signal, if is None name\n            is chosen automatically\n        :param def_val: value which is used for reset and as default value\n            in HDL\n        :param nop_val: value which is used to fill up statements when no other\n            value is assigned, use NOT_SPECIFIED to disable\n        :param is_const: flag which tell that this signal can not have any other driver\n            than a default value\n        \"\"\"\n\n        self._instId: int = RtlSignal._nextInstId()\n        if name is None:\n            name = \"sig_\"\n            self._hasGenericName = True\n        else:\n            self._hasGenericName = False\n\n        assert isinstance(dtype, HdlType)\n        super(RtlSignal, self).__init__(name, dtype, def_val, virtual_only=virtual_only)\n        self._rtlCtx = ctx\n\n        if ctx:\n            # params do not have any context on created\n            # and it is assigned after param is bounded to unit or interface\n            ctx.signals.add(self)\n\n        # set can not be used because hash of items are changing\n        self._rtlEndpoints: SetList[Union[HdlStatement, HdlPortItem, \"Operator\"]] = SetList()\n        self._rtlDrivers: SetList[HdlStatement, HdlPortItem, \"Operator\"] = SetList()\n        self._usedOps: Dict[OperatorCaheKeyType, RtlSignal] = {}\n        self._usedOpsAlias: Dict[OperatorCaheKeyType, Set[OperatorCaheKeyType]] = {}\n        self._isUnnamedExpr: bool = True\n\n        self._nop_val = nop_val\n        self._const = is_const\n        self._rtlObjectOrigin = None\n\n        if nop_val is NOT_SPECIFIED:\n            nop_val = self\n\n        # construct next signal if requested\n        if next_signal is NOT_SPECIFIED:\n            _next_signal = None\n        elif next_signal is CREATE_NEXT_SIGNAL:\n            _next_signal = self.__class__(ctx, name + \"_next\", dtype,\n                              nop_val=nop_val)\n        else:\n            assert isinstance(next_signal, RtlSignalBase), next_signal\n            assert next_signal._dtype is dtype\n            _next_signal = next_signal\n            if _next_signal._nop_val is NOT_SPECIFIED:\n                _next_signal._nop_val = self\n        self._rtlNextSig: Optional[RtlSignal] = _next_signal\n\n    @internal\n    @classmethod\n    def _nextInstId(cls):\n        \"\"\"\n        Get next instance id\n        \"\"\"\n        i = cls.__instCntr\n        cls.__instCntr += 1\n        return i\n\n    def staticEval(self):\n        # operator writes in self._val new value\n        driven_by_def_val = True\n        if self._rtlDrivers:\n            for d in self._rtlDrivers:\n                if isinstance(d, HdlPortItem):\n                    assert d.getInternSig() is self, (d, self)\n                    continue\n                d.staticEval()\n                driven_by_def_val = False\n\n        if driven_by_def_val:\n            if isinstance(self.def_val, RtlSignal):\n                self._val = self.def_val._val.staticEval()\n            else:\n                # _val is invalid initialization value\n                self._val = self.def_val.__copy__()\n\n        if not isinstance(self._val, HConst):\n            raise ValueError(\n                \"Evaluation of signal returned not supported object (%r)\"\n                % (self._val,))\n\n        return self._val\n\n    def singleDriver(self):\n        \"\"\"\n        Returns a first driver if signal has only one driver.\n        \"\"\"\n        d_cnt = len(self._rtlDrivers)\n        if d_cnt == 0:\n            raise SignalDriverErr([(SignalDriverErrType.MISSING_DRIVER, self), ])\n        elif d_cnt > 1:\n            raise SignalDriverErr([(SignalDriverErrType.MULTIPLE_COMB_DRIVERS, self), ])\n\n        return self._rtlDrivers[0]\n\n    @internal\n    def _walk_sensitivity(self, casualSensitivity: Set[RtlSignalBase], seen: Set[RtlSignalBase], ctx: SensitivityCtx):\n        \"\"\"\n        Walk expression and collect signals which is this expression sensitive to.\n        (:see: what is signal sensitivity in vhdl/verilog)\n\n        :param casualSensitivity: set of public signals which is this expression sensitive to but rising/faling edge operator is not present\n        :param seen: set of all seen signals\n        :param ctx: context where sensitivity\n        \"\"\"\n        seen.add(self)\n\n        if self._const:\n            return\n\n        if not self._isUnnamedExpr:\n            casualSensitivity.add(self)\n            return\n\n        try:\n            op = self.singleDriver()\n        except SignalDriverErr:\n            op = None\n\n        if op is None or isinstance(op, HdlStatement):\n            casualSensitivity.add(self)\n            return\n\n        op._walk_sensitivity(casualSensitivity, seen, ctx)\n\n    @internal\n    def _walk_public_drivers(self, seen: set) -> Generator[\"RtlSignal\", None, None]:\n        \"\"\"\n        Walk all non hidden signals in an expression\n        \"\"\"\n        seen.add(self)\n        if not self._isUnnamedExpr:\n            yield self\n            return\n\n        assert self._rtlDrivers, self\n\n        for d in self._rtlDrivers:\n            # d has to be operator otherwise this signal would be public itself\n            assert not isinstance(d, HdlStatement), (d.__class__)\n            yield from d._walk_public_drivers(seen)\n\n    def _auto_cast(self, toType: HdlType):\n        \"\"\"\n        Cast value or signal of this type to another compatible type.\n\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        return self._dtype.auto_cast_RtlSignal(self, toType)\n\n    def _reinterpret_cast(self, toType: HdlType):\n        \"\"\"\n        Cast value or signal of this type to another type of same size.\n\n        :param toType: instance of HdlType to cast into\n        \"\"\"\n        return self._dtype.reinterpret_cast_RtlSignal(self, toType)\n\n    @internal\n    def _create_HOperator(self, operator: HOperatorDef, opCreateDelegate , *otherOps) -> Union[Self, HConst]:\n        \"\"\"\n        Try lookup operator with this parameters in _usedOps\n        if not found create new one and stored it in _usedOps\n\n        :param operator: instance of HOperatorDef\n        :param opCreateDelegate: function (\\\\*ops) to create operator\n        :param otherOps: other operands (ops = self + otherOps)\n\n        :return: RtlSignal which is result of newly created operator\n        \"\"\"\n        indexOfSelfInOperands = 0\n        k = (operator, indexOfSelfInOperands, *otherOps)\n        used = self._usedOps\n        try:\n            return used[k]\n        except KeyError:\n            pass\n\n        o = opCreateDelegate(self, *otherOps)\n        # input operands may be type converted,\n        # search if this happened, and return always same result signal\n        try:\n            op_instantiated = (o._rtlObjectOrigin.operator == operator\n                               and o._rtlObjectOrigin.operands[indexOfSelfInOperands] is self)\n        except AttributeError:\n            op_instantiated = False\n\n        usedOpsAlias = self._usedOpsAlias\n        if op_instantiated:\n            # try check real operands and operator which were used after all default type conversions\n            k_real = (operator, indexOfSelfInOperands, *o._rtlObjectOrigin.operands[1:])\n            if k != k_real:\n                alias = usedOpsAlias[k_real]\n                usedOpsAlias[k] = alias\n                alias.add(k)\n                used[k] = o\n\n        return o\n\n    @internal\n    def _getIndexCascade(self):\n        \"\"\"\n        Find out if this signal is something indexed\n        \"\"\"\n        hwIO = self\n        indexes = []\n        sign_cast_seen = False\n        while True:\n            try:\n                # now self is the result of the index  xxx[xx] <= source\n                # get index op\n                d = hwIO.singleDriver()\n                try:\n                    op = d.operator\n                except AttributeError:\n                    # probably port or statement\n                    break\n\n                if op == HwtOps.INDEX or op == HwtOps.DOT:\n                    # get signal on which is index applied\n                    indexedOn = d.operands[0]\n                    if isinstance(indexedOn, RtlSignalBase):\n                        hwIO = indexedOn\n                        indexes.append(d.operands[1])\n                    else:\n                        raise HwtSyntaxError(\"can not assign to a static value\", indexedOn)\n                \n                elif op == HwtOps.TRUNC:\n                    indexedOn = d.operands[0]\n                    width = int(d.operands[1])\n                    if isinstance(indexedOn, RtlSignalBase):\n                        if hwIO._dtype.bit_length() > 1 or hwIO._dtype.force_vector:\n                            indexes.append(SLICE.from_py(slice(width, 0, -1)))\n                        else:\n                            indexes.append(INT.from_py(width))\n                        hwIO = indexedOn\n                    else:\n                        raise HwtSyntaxError(\"can not assign to a static value\", indexedOn)\n                elif op in CAST_OPS:\n                    sign_cast_seen = True\n                    hwIO = d.operands[0]\n                else:\n                    # the concatenations should have been already resolved before entering of this function\n                    raise HwtSyntaxError(\n                        f\"can not assign to result of operator {d}\")\n\n            except SignalDriverErr:\n                break\n\n        if not indexes:\n            indexes = None\n        else:\n            indexes.reverse()\n\n        return hwIO, indexes, sign_cast_seen\n\n    def _getDestinationSignalForAssignmentToThis(self):\n        \"\"\"\n        :return: a signal which should be used as a destination if assigning to this signal\n        \"\"\"\n        return self if self._rtlNextSig is None else self._rtlNextSig\n\n    def __call__(self, source,\n                 dst_resolve_fn=lambda x: x._getDestinationSignalForAssignmentToThis(),\n                 exclude=None,\n                 fit=False) -> Union[HdlAssignmentContainer, List[HdlAssignmentContainer]]:\n        \"\"\"\n        Create assignment to this signal\n\n        :attention: it is not call of function it is operator of assignment\n        :return: list of assignments\n        \"\"\"\n        assert not self._const, self\n        if exclude is not None and (self in exclude or source in exclude):\n            return []\n\n        if isinstance(source, HwIOBase) and not source._hwIOs:\n            assert source._isAccessible, (source, \"must be a Signal Interface which is accessible in current scope\")\n            source = source._sig\n\n        assert self._dtype.isScalar(), (\"For non scalar types this should be overriden\", self._dtype, self.__class__, self)\n        try:\n            if source is None:\n                requires_type_check = False\n                source = self._dtype.from_py(None)\n            else:\n                requires_type_check = True\n                source = toHVal(source, suggestedType=self._dtype)\n\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n        if requires_type_check:\n            err = False\n            try:\n                if fit:\n                    source = fitTo_t(source, self._dtype)\n                source = source._auto_cast(self._dtype)\n            except TypeConversionErr:\n                err = True\n            if err:\n                raise TypeConversionErr(\n                    \"Can not connect \", source._dtype, \" to \", self._dtype,\n                    \" \", source, self)\n        if self._isUnnamedExpr:\n            try:\n                d = self.singleDriver()\n            except:\n                d = None\n            operator = getattr(d, \"operator\", None)\n            if operator is not None:\n                if operator.allowsAssignTo:\n                    if operator == HwtOps.NOT:\n                        # instead of assigning to negation we assign the negation\n                        return d.operands[0](~source, dst_resolve_fn=dst_resolve_fn, exclude=exclude, fit=fit)\n                    elif operator in CAST_OPS:\n                        # we need to assert that src and dst type matches, but we do not anything else\n                        dst = d.operands[0]\n                        src_sign = source._dtype.signed\n                        dst_sign = dst._dtype.signed\n                        if src_sign == dst_sign:\n                            return dst(source)\n                        elif dst_sign is None:\n                            return dst(source._vec())\n                        elif dst_sign:\n                            return dst(source._signed())\n                        else:\n                            return dst(source._unsigned())\n\n                    elif operator == HwtOps.CONCAT:\n                        offset = 0\n                        res = []\n                        # reversed because LSB first\n                        for op in reversed(d.operands):\n                            w = op._dtype.bit_length()\n                            res.append(op(source[w + offset: offset]))\n                            offset += w\n                        return res\n                else:\n                    raise AssertionError(\"Assignment to operator is not allowed by operator definition\", self,)\n\n        try:\n            mainSig, indexCascade, signCastSeen = self._getIndexCascade()\n            mainSig = dst_resolve_fn(mainSig)\n            if signCastSeen:\n                src_sign = source._dtype.signed\n                dst_sign = mainSig._dtype.signed\n                if src_sign == dst_sign:\n                    pass\n                elif dst_sign is None:\n                    source = source._vec()\n                elif dst_sign:\n                    source = source._signed()\n                else:\n                    source = source._unsigned()\n            return HdlAssignmentContainer(source, mainSig, indexCascade)\n        except Exception as e:\n            # simplification of previous exception traceback\n            e_simplified = copy(e)\n            raise e_simplified\n\n    def _getAssociatedClk(self) -> Self:\n        assert self._rtlNextSig is not None, self\n        d = self.singleDriver()  # this expects a simple if rising_edge(clk)\n        # assert isinstance(d, IfContainer), d\n        cond = d.cond.singleDriver()\n        # assert isinstance(cond, HOperatorNode) and cond.operator is HwtOps.RISING_EDGE, cond\n        return cond.operands[0]\n\n    def _getAssociatedRst(self) -> Self:\n        assert self._rtlNextSig is not None, self\n        d = self.singleDriver()  # this expects a simple if rising_edge(clk)\n        # assert isinstance(d, IfContainer), d\n        # cond = d.cond.singleDriver()\n        # assert isinstance(cond, HOperatorNode) and cond.operator is HwtOps.RISING_EDGE, cond\n        assert len(d.ifTrue) == 1\n        reset_if = d.ifTrue[0]\n        return reset_if.cond\n\n    def _is_full_valid(self) -> bool:\n        return self._const and self._val._is_full_valid()\n\n    def _is_partially_valid(self) -> bool:\n        return self._const and self._val._is_partially_valid()\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/rtlSignalWalkers.py",
    "content": "from hwt.doc_markers import internal\nfrom hwt.hdl.operator import HOperatorNode\nfrom hwt.hdl.operatorDefs import isEventDependentOp\nfrom hwt.hdl.sensitivityCtx import SensitivityCtx\nfrom hwt.mainBases import RtlSignalBase\n\n\n@internal\ndef discoverEventDependency(sig: RtlSignalBase):\n    \"\"\"\n    :return: generator of tuples (event operator, signal)\n    \"\"\"\n\n    try:\n        drivers = sig._rtlDrivers\n    except AttributeError:\n        return\n\n    if len(drivers) == 1:\n        d = drivers[0]\n        if isinstance(d, HOperatorNode):\n            if isEventDependentOp(d.operator):\n                yield (d.operator, d.operands[0])\n            else:\n                for op in d.operands:\n                    yield from discoverEventDependency(op)\n\n\n@internal\ndef discover_sensitivity_of_sig(signal: RtlSignalBase,\n                              seen: set, ctx: SensitivityCtx):\n    casualSensitivity = set()\n    signal._walk_sensitivity(casualSensitivity, seen, ctx)\n    if not ctx.contains_ev_dependency:\n        # if event dependent sensitivity found do not add other sensitivity\n        ctx.extend(casualSensitivity)\n"
  },
  {
    "path": "hwt/synthesizer/rtlLevel/statements_to_HdlStmCodeBlockContainers.py",
    "content": "from copy import copy\nfrom itertools import compress\nfrom typing import Generator, List, Tuple\n\nfrom hwt.constants import NOT_SPECIFIED\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.statements.codeBlockContainer import HdlStmCodeBlockContainer\nfrom hwt.hdl.statements.statement import HwtSyntaxError\nfrom hwt.hdl.statements.utils.listOfHdlStatements import ListOfHdlStatement\nfrom hwt.mainBases import RtlSignalBase\nfrom hwt.pyUtils.setList import SetList\nfrom hwt.synthesizer.rtlLevel.fill_stm_list_with_enclosure import fill_stm_list_with_enclosure, \\\n    HdlAssignmentContainer_constructor\nfrom hwt.synthesizer.rtlLevel.reduce_processes import reduceProcesses\nfrom hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal\n\n\n@internal\ndef cut_off_drivers_of(dstSignal: RtlSignal, statements: ListOfHdlStatement)\\\n        -> Tuple[ListOfHdlStatement, ListOfHdlStatement]:\n    \"\"\"\n    Cut off drivers from statements\n    \"\"\"\n    separated = ListOfHdlStatement()\n    stm_filter = []\n    for stm in statements:\n        stm._clean_signal_meta()\n        d = stm._cut_off_drivers_of(dstSignal)\n        if d is not None:\n            separated.append(d)\n\n        f = d is not stm\n        stm_filter.append(f)\n\n    return ListOfHdlStatement(compress(statements, stm_filter)), separated\n\n\n@internal\ndef name_for_process(outputs: List[RtlSignal]) -> str:\n    \"\"\"\n    Resolve name for process\n    \"\"\"\n    out_names = []\n    for sig in outputs:\n        if not sig._hasGenericName:\n            out_names.append(sig._name)\n\n    if out_names:\n        return min(out_names)\n    else:\n        return \"\"\n\n\n@internal\ndef _statements_to_HdlStmCodeBlockContainers(_statements, tryToSolveCombLoops: bool)\\\n        ->Generator[HdlStmCodeBlockContainer, None, None]:\n    assert _statements\n    # try to simplify statements\n    proc_statements = ListOfHdlStatement()\n    for _stm in _statements:\n        _stm._clean_signal_meta()\n        stms, _ = _stm._try_reduce()\n        proc_statements.extend(stms)\n\n    if not proc_statements:\n        return\n\n    outputs = SetList()\n    _inputs = SetList()\n    sensitivity = SetList()\n    enclosed_for = set()\n    _proc_statements = ListOfHdlStatement()\n    for _stm in proc_statements:\n        seen = set()\n        _stm._discover_sensitivity(seen)\n        _stm._discover_enclosure()\n        if _stm._outputs:\n            # remove a statement entirely if it has no ouput\n            # (empty if statment or something similar)\n            # simulation only processes should not be processed by this function\n            # and process should always drive something, unless it is useless\n            outputs.extend(_stm._outputs)\n            _inputs.extend(_stm._inputs)\n            sensitivity.extend(_stm._sensitivity)\n            enclosed_for.update(_stm._enclosed_for)\n            _proc_statements.append(_stm)\n\n    proc_statements = _proc_statements\n    if not proc_statements:\n        # this can happen e.g. when If does not contains any HdlAssignmentContainer\n        return\n    sensitivity_recompute = False\n    enclosure_recompute = False\n    enclosure_values = {}\n    for sig in outputs:\n        # inject nop_val if needed\n        if sig._nop_val is not NOT_SPECIFIED and sig not in enclosed_for:\n            enclosure_recompute = True\n            n = sig._nop_val\n            enclosure_values[sig] = HdlAssignmentContainer_constructor(n, sig)\n            if isinstance(n, RtlSignalBase):\n                _inputs.append(n)\n                sensitivity_recompute = True\n\n    if enclosure_recompute:\n        # we have some enclosure values, try fill missing code branches with\n        # this values\n        do_enclose_for = [o for o in outputs if o in enclosure_values]\n        fill_stm_list_with_enclosure(None, enclosed_for, proc_statements,\n                                     do_enclose_for, enclosure_values)\n\n    if enclosure_recompute or sensitivity_recompute:\n        for _stm in proc_statements:\n            _stm._clean_signal_meta()\n            seen = set()\n            _stm._discover_sensitivity(seen)\n            _stm._discover_enclosure()\n\n        if sensitivity_recompute:\n            sensitivity.clear()\n            for _stm in proc_statements:\n                sensitivity.extend(_stm._sensitivity)\n\n    for o in outputs:\n        assert not o._isUnnamedExpr, o\n\n    seen = set()\n    inputs = SetList()\n    for i in _inputs:\n        inputs.extend(i._walk_public_drivers(seen))\n\n    intersect = outputs.intersection_set(sensitivity)\n    if intersect:\n        # there is a combinational loop inside a single process which\n        # can not be solved by separation of statments in process\n        if not tryToSolveCombLoops:\n            raise HwtSyntaxError(\n                \"Combinational loop on signal(s)\", intersect)\n\n        # try to solve combinational loops by separating drivers of signals\n        # from statements\n        for sig in intersect:\n            proc_statements, proc_stms_select = cut_off_drivers_of(\n                sig, proc_statements)\n            yield from _statements_to_HdlStmCodeBlockContainers(proc_stms_select, False)\n\n        if proc_statements:\n            yield from _statements_to_HdlStmCodeBlockContainers(proc_statements, False)\n    else:\n        # no combinational loops, wrap current statemetns to a process instance\n\n        name = name_for_process(outputs)\n        yield HdlStmCodeBlockContainer.from_known_io(\n            \"assig_process_\" + name,\n            proc_statements, sensitivity,\n            inputs, outputs)\n\n\n@internal\ndef statements_to_HdlStmCodeBlockContainers(statements: ListOfHdlStatement)\\\n        ->Generator[HdlStmCodeBlockContainer, None, None]:\n    \"\"\"\n    Pack statements into HdlStmCodeBlockContainer instances\n\n    * for each out signal resolve it's drivers and collect them\n    * split statements if there is and combinational loop\n    * merge statements if it is possible\n    * resolve sensitivity lists\n    * wrap into HdlStmCodeBlockContainer instance\n    * for every IO of process generate name if signal has not any\n    \"\"\"\n    # create copy because this set will be reduced\n    statements = copy(statements)\n\n    # process ranks = how many assignments is probably in process\n    # used to minimize number of merge tries\n    processes = []\n    while statements:\n        stm = statements.pop()\n        proc_statements = [stm, ]\n        ps = _statements_to_HdlStmCodeBlockContainers(proc_statements, True)\n        processes.extend(ps)\n\n    yield from reduceProcesses(processes)\n"
  },
  {
    "path": "hwt/synthesizer/typePath.py",
    "content": "from copy import deepcopy\nfrom typing import Union, SupportsIndex, Self\n\n\nclass TypePath(tuple[Union[str, int], ...]):\n    \"\"\"\n    A path in hierarchy of structuralized type\n    \"\"\"\n\n    def __new__ (cls, *objs):\n        return super(TypePath, cls).__new__(cls, objs)\n\n    def __truediv__(self, other: Union[int, str, \"TypePath\"]):\n        if isinstance(other, TypePath):\n            return TypePath(*self, *other)\n        else:\n            assert isinstance(other, (int, str)), other\n            return TypePath(*self, other)\n\n    def getOnObject(self, o):\n        for n in self:\n            if isinstance(n, int):\n                o = o[n]\n            else:\n                assert isinstance(n, str), n\n                o = getattr(o, n)\n        return o\n\n    def __getitem__(self, key:SupportsIndex)->Union[Self, int, str]:\n        if isinstance(key, int):\n            return tuple.__getitem__(self, key)\n        else:\n            return TypePath(*tuple.__getitem__(self, key))\n            \n    def setOnObject(self, o, newV):\n        assert self\n        o = self[:-1].getOnObject(o)\n        n = self[-1]\n        if isinstance(n, int):\n            o[n] = newV\n        else:\n            assert isinstance(n, str), n\n            setattr(o, n, newV)\n\n    def __copy__(self):\n        return self.__class__(*self)\n\n    def __deepcopy__(self, memo):\n        res = self.__class__(*(deepcopy(x, memo) for x in self))\n        memo[self] = res\n        return res\n"
  },
  {
    "path": "hwt/synthesizer/vectorUtils.py",
    "content": "from math import ceil\nfrom typing import Union\n\nfrom hwt.doc_markers import internal\nfrom hwt.hdl.const import HConst\nfrom hwt.hdl.types.bits import HBits\nfrom hwt.hdl.types.utils import walkFlattenFields\nfrom hwt.mainBases import RtlSignalBase\n\n\nclass NotEnoughtBitsErr(Exception):\n    \"\"\"\n    More bits is required for such an operation\n    \"\"\"\n\n\nclass BitWalker():\n    \"\"\"\n    Walker which can walk chunks of bits on signals/values of all types\n\n    :ivar ~.sigOrConst: signal or value to iterate over\n    :ivar ~.fillup: flag that means that if there is not enough bits\n        for last item fill it up with invalid bits (otherwise raise)\n    \"\"\"\n\n    def __init__(self, sigOrConst: Union[RtlSignalBase, HConst],\n                 skipPadding: bool=True,\n                 fillup: bool=False):\n        \"\"\"\n        :param skipPadding: if true padding is skipped in dense types\n        \"\"\"\n        self.it = walkFlattenFields(sigOrConst, skipPadding=skipPadding)\n        self.fillup = fillup\n        self.actuallyHave = 0\n        self.actual = None\n        self.actualOffset = 0\n\n    @internal\n    def _get(self, numberOfBits: int, doCollect: bool):\n        \"\"\"\n        :param numberOfBits: number of bits to get from actual position\n        :param doCollect: if False output is not collected just iterator moves\n            in data structure\n        \"\"\"\n        if not isinstance(numberOfBits, int):\n            numberOfBits = int(numberOfBits)\n\n        while self.actuallyHave < numberOfBits:\n            # accumulate while not has enough\n            try:\n                f = next(self.it)\n            except StopIteration:\n                if self.fillup and self.actual is not None:\n                    break\n                else:\n                    raise NotEnoughtBitsErr()\n\n            thisFieldLen = f._dtype.bit_length()\n            if self.actual is None:\n                if not doCollect and thisFieldLen <= numberOfBits:\n                    numberOfBits -= thisFieldLen\n                else:\n                    self.actual = f\n                    self.actuallyHave = thisFieldLen\n            else:\n                if not doCollect and self.actuallyHave < numberOfBits:\n                    self.actuallyHave = thisFieldLen\n                    self.actual = f\n                else:\n                    self.actuallyHave += thisFieldLen\n                    self.actual = f._concat(self.actual)\n\n        # slice out from actual\n        actual = self.actual\n        actualOffset = self.actualOffset\n\n        if self.actuallyHave < numberOfBits:\n            assert self.fillup\n            if doCollect:\n                t = self.actual._dtype\n                fillupW = numberOfBits - self.actuallyHave\n                padding_t = HBits(fillupW, signed=t.signed, negated=t.negated)\n                padding = padding_t.from_py(None)\n                actual = padding._concat(actual)\n            self.actuallyHave = 0\n            self.actualOffset = 0\n        else:\n            # update about what was taken\n            self.actuallyHave -= numberOfBits\n            self.actualOffset += numberOfBits\n\n        if self.actuallyHave == 0:\n            self.actual = None\n            self.actualOffset = 0\n\n        if doCollect:\n            if numberOfBits == 1:\n                return actual[actualOffset]\n            else:\n                return actual[(actualOffset + numberOfBits):actualOffset]\n\n    def get(self, numberOfBits: int) -> Union[RtlSignalBase, HConst]:\n        \"\"\"\n        :param numberOfBits: number of bits to get from actual position\n        :return: chunk of bits of specified size (instance of Value or RtlSignal)\n        \"\"\"\n        return self._get(numberOfBits, True)\n\n    def skip(self, numberOfBits: int) -> None:\n        \"\"\"\n        Move this iterator without care about item\n\n        :param numberOfBits: number of bits to get from actual position\n        \"\"\"\n        self._get(numberOfBits, False)\n\n    def assertIsOnEnd(self):\n        \"\"\"\n        Assert there is nothing left in this iterator\n        \"\"\"\n        try:\n            next(self.it)\n        except StopIteration:\n            return\n\n        raise AssertionError(\"there are still some items\")\n\n\ndef iterBits(sigOrConst: Union[RtlSignalBase, HConst], bitsInOne: int=1,\n             skipPadding: bool=True, fillup: bool=False):\n    \"\"\"\n    Iterate over bits in vector\n\n    :param sigOrConst: signal or value to iterate over\n    :param bitsInOne: number of bits in one part\n    :param skipPadding: if true padding is skipped in dense types\n    :param fillup: flag that means that if there is not enough bits\n        for last item fill it up with invalid bits (otherwise raise)\n    \"\"\"\n    bw = BitWalker(sigOrConst, skipPadding, fillup)\n    try:\n        bit_len = sigOrConst._dtype.bit_length()\n    except TypeError:\n        bit_len = None\n    if bit_len is None:\n        try:\n            while True:\n                yield bw.get(bitsInOne)\n        except NotEnoughtBitsErr:\n            return\n    else:\n        for _ in range(ceil(bit_len / bitsInOne)):\n            yield bw.get(bitsInOne)\n\n        bw.assertIsOnEnd()\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools >= 77.0.3\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"hwt\"\nversion = \"3.8\"\ndependencies = [\n   \"natsort>=8.4.0\",  # natural sorting for HDL objects with name\n   \"hdlConvertorAst>=1.0\", # conversions to SystemVerilog, VHDL\n   \"ipCorePackager>=0.6\",  # generator of IPcore packages (IP-xact, ...)\n   \"hwtSimApi>=1.3\",  # simulator API\n   \"pyDigitalWaveTools>=1.1\",  # simulator output dump\n]\nrequires-python = \">=3.8\"\nauthors = [\n  {name = \"Michal Orsak\", email = \"Nic30original@gmail.com\"},\n]\n\ndescription = \"A library for a construction and analysis of digital circuits\"\nreadme = \"README.md\"\nlicense = \"MIT\"\nlicense-files = [\"LICENSE\"]\nkeywords = [\n 'hdl', 'vhdl', 'verilog', 'verilog-hdl', 'systemverilog', 'code-generator', 'ipcore',\n 'compiler', 'hardware',  'high-level-synthesis', 'hardware-construction-language' \n]\nclassifiers = [\n        \"Development Status :: 4 - Beta\",\n        \"Intended Audience :: Developers\",\n        \"Operating System :: OS Independent\",\n        \"Programming Language :: Python :: 3 :: Only\",\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Programming Language :: Python :: 3.10\",\n        \"Programming Language :: Python :: 3.11\",\n        \"Programming Language :: Python :: 3.12\",\n        \"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)\",\n        \"Topic :: System :: Hardware\",\n        \"Topic :: System :: Emulators\",\n        \"Topic :: Utilities\"\n]\n\n\n[project.urls]\nHomepage = \"https://github.com/Nic30/hwt\"\nDocumentation = \"https://hwtoolkit.readthedocs.io/en/latest/?badge=latest\"\nRepository = \"https://github.com/Nic30/hwt.git\"\n\"Bug Tracker\" = \"https://github.com/Nic30/hwt/issues\"\n"
  },
  {
    "path": "setup.cfg",
    "content": "[metadata]\ndescription_file = README.md\n\n[options]\nzip_safe = True"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/all.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nfrom hwtLib.tests.all import suite, unittestMain\n\nif __name__ == '__main__':\n    unittestMain(suite)\n"
  }
]