diff --git a/INSTALL.rst b/INSTALL.rst index 42f0af4d..c31482e3 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -22,11 +22,11 @@ It can be installed using the ``--user`` to avoid permission issues:: > pip install --user spydrnet -It can be to upgraded to a newer release use the ``--upgrade`` flag:: +It can be to upgraded to a newer release by using the ``--upgrade`` flag:: - > pip install --upgrade networkx + > pip install --upgrade spydrnet -It can be installed from source archives or distributions avaiable on `GitHub `_ or +It can be installed from source archives or distributions available on `GitHub `_ or `PyPI `_:: > pip install spydrnet-.tar.gz @@ -54,7 +54,7 @@ SpyDrNet can be installed in editable mode from within the directory of its repo > pip install -e . -Editable mode allows modification of the source to be reflected in the use of the module the next time that it is imported into Python. This functionality is convienent for development. +Editable mode allows modification of the source to be reflected in the use of the module the next time that it is imported into Python. This functionality is convenient for development. The project repository can be cloned using `Git `_. The following commands clone the repository and enter its directory:: diff --git a/RELEASE.rst b/RELEASE.rst index dba68ed3..a8a7477d 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,3 +1,11 @@ +SpyDrNet 1.8.2 +-------------- +June 24, 2021 + +* updated tutorial +* improved How To Contribute page +* general documentation improvements + SpyDrNet 1.8.1 -------------- May 21, 2021 diff --git a/docs/source/developer/contribute.rst b/docs/source/developer/contribute.rst index 5b28176a..04749398 100644 --- a/docs/source/developer/contribute.rst +++ b/docs/source/developer/contribute.rst @@ -33,11 +33,15 @@ may mask warnings and errors and ensure the process is smooth. For the release ensure that both: -`make html` +>>> make html and -`make latexpdf` +>>> make latexpdf + +if you are missing packages run: + +>>> make install build the documentation without error as the html version will be put online at the time of release and the pdf should be included in the releases files on @@ -69,7 +73,7 @@ In the examples below, replace 1.5.0 with the version number you want to release **To see the current version number** -`git describe` +>>> git describe **Creation** @@ -79,6 +83,8 @@ In the examples below, replace 1.5.0 with the version number you want to release >>> git push --tags +If you mess up, you can use the following instructions to force update your tag + **Updating** >>> git tag -a v1.5.0 -m "SpyDrNet 1.5.0" -f @@ -106,6 +112,8 @@ The build files will be stored in the following directories spydrnet/build and spydrnet/dist +.. _Build: + Building the documentation -------------------------- @@ -136,20 +144,52 @@ proper release number. A description should be entered as well. It could just be a reiteration of the release notes or other relevant information. +Three files should be added as assets to the new release: + +Two files will be generated when the repository is pushed to Pypi. A tar.gz file and a .whl file. +Uploead these two files after performing the next step of `Publising the packages to Pypi` + +Go to docs/latex folder, copy the `spydrnet_reference.pdf` to the assets under the new release, +and changes its name to `spydrnet_reference-new_release_number.pdf`. If the pdf file doesn't exist, run: + +>>> make latexpdf + +in the /docs folder + Publishing the packages to Pypi ------------------------------- -The packages need to be published to Pypi to be installable via pip. On pypi.org -there is a guide on uploading packages. Follow the instructions there to upload +The packages need to be published to Pypi to be installable via pip. On the `Pypi website `_ +there is a guide on uploading packages. You will need an account for this. Follow the instructions there to upload to the test pip server then the production server. +If you have an account and know what you are doing, use the command below : + +>>> python3 -m twine upload dist/* + +And then input your username and password for Pypi. + +To install the python package to check for success, use: + +>>> python3 -m pip install spydrnet + +Go to the release on the Pypi website through your account. Download the .whl file and the .tar.gz file. +Add them as assets to the new release at GitHub.com + Publishing the documentation ---------------------------- This is easiest on Linux (or at least not Windows, MacOS works fine as well) +Make sure you are still in the Master branch and that everything in the html folder is up-to-date. +If not, re-run the instructions in :ref:`Build`. + Checkout the gh-pages branch create a new folder with the release number as the -name. Copy the `docs/build/html` folder into the newly created folder. +name. Move the `docs/build/html` folder into the newly created folder. +Make sure to delete the html folder after you are finished. + +(If html folder doesn't contain the latest pages, it could be that the html folder wasn't deleted from the previous release, +delete the folder, commit the changes and repeat the steps above) The documentation is built from the stable link so the stable link will need to be updated to point to the newly updated documentation. diff --git a/docs/source/reference/classes/index.rst b/docs/source/reference/classes/index.rst index 478dffce..7fe34162 100644 --- a/docs/source/reference/classes/index.rst +++ b/docs/source/reference/classes/index.rst @@ -22,7 +22,7 @@ The API calls documented here can be used in Python as follows: >>> library = netlist.create_library() >>> -Similarly if the parser is used the calls can be made in the same way: +If the parser is used, the calls can be made in the same way: >>> # parse an edif file in and add an empty library to the netlist. >>> import spydrnet as sdn @@ -54,7 +54,7 @@ Basic object types parse The following three classes are the classes from which the above elements inherit. They are included here for completeness of -documentation and can be used if needed. if the above types will suffice it may be simpler to use them. +documentation and can be used if needed. If the above types will suffice it may be simpler to use them. .. currentmodule:: spydrnet.ir .. autosummary:: diff --git a/docs/source/reference/classes/outerpin.rst b/docs/source/reference/classes/outerpin.rst index 184804e9..7b208a1a 100644 --- a/docs/source/reference/classes/outerpin.rst +++ b/docs/source/reference/classes/outerpin.rst @@ -19,6 +19,7 @@ Methods OuterPin.from_instance_and_inner_pin OuterPin.instance OuterPin.inner_pin + OuterPin.wire OuterPin.clone OuterPin.get_netlists OuterPin.get_libraries diff --git a/docs/source/reference/classes/wire.rst b/docs/source/reference/classes/wire.rst index ebfedf48..05f96728 100644 --- a/docs/source/reference/classes/wire.rst +++ b/docs/source/reference/classes/wire.rst @@ -21,6 +21,7 @@ Methods Wire.connect_pin Wire.disconnect_pin Wire.disconnect_pins_from + Wire.index Wire.clone Wire.get_netlists Wire.get_libraries diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index c34fd0b4..36d87ca0 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -1,9 +1,7 @@ Tutorial ============ -SpyDrNet is a tool for the analysis and transformation of structural netlists. A structural netlist is a static -representation of an electronic circuit. A circuit consists of a number of electrical components and their connections. -Figure :numref:`fig:hierarchical_netlist` shows a graphical representation of a netlist. +SpyDrNet is a tool for the analysis and transformation of structural netlists. A structural netlist is a static representation of an electronic circuit. A circuit consists of a number of electrical components and their connections. Figure :numref:`fig:hierarchical_netlist` shows a graphical representation of a netlist. .. _fig:hierarchical_netlist: .. figure:: figures/hierarchical_netlist.* @@ -11,144 +9,228 @@ Figure :numref:`fig:hierarchical_netlist` shows a graphical representation of a Hierarchical representation of a Netlist -Figure :numref:`fig:hierarchical_netlist` represents a netlist hierarchically. This representation is commonly found in -many schematic views of electronic design automation (EDA) or computer aided design (CAD) tools. It presents a top level -instance of a definition that in turn instances other definitions. Instances are connected accordingly and connections -carry through hierarchical boundaries. +This representation is commonly found in many schematic views of electronic design automation (EDA) or computer aided design (CAD) tools. It presents a top level instance of a definition that in turn instances other definitions. Instances are connected accordingly and connections carry through hierarchical boundaries. -Most hardware description languages and netlist representations are capable of representing a structural netlist -hierarchically. +Tool Flow +---------- -The most basic element of a netlist is a definition. Verilog and System Verilog refer to a definition as -a module. VHDL refers to a definition as an entity. EDIF refers to a definition as a cell. While each language and -framework has a different name, the functioning role of a definition is virtually the same. A definition defines the -interface and contents of a component within a netlist. +Digital designs for FPGAs are represented as netlists, a list of components and connections. Netlists come from various vendors in many different formats. SpyDrNet allows you to look at and alter a netlist in a language inspecific way. -An instance is an instantiation of a definition. +Netlists flow through SpyDrNet in a three step process (see figure below). First, SpyDrNet parses a netlist into an intermediate represention (IR) that is designed to be easily traversed and effortlessly manipulated. Afterwards, the netlist is composed back into a netlist format that a 3rd-party tool can use. SpyDrNet aims to provide the tools you need to accomplish the netlist analysis and transformation tasks you have in mind without having to reinvent the wheel. -Hierarchy organizes larger netlists into -a collection of higher-level and lower-level definitions of smaller netlists. Higher-level definitions instance -lower-level definitions. +This flow is inspired by `LLVM`_ and `Pandoc`_. LLVM has a similar flow for compiling computer programs and Pandoc has a similar flow for converting document formats. Using this flow, SpyDrNet is designed to be able to work on any netlist. -Installation ------------- +.. _LLVM: http://www.aosabook.org/en/llvm.html +.. _Pandoc: https://pandoc.org/ -For installing instructions, please refer :ref:`INSTALL.rst` +.. _fig:flow.2: +.. figure:: /figures/flow.* + :align: center + :alt: SpyDrNet Flow + + Flow of Using SpyDrNet + +**Note:** VHDL is not yet supported by SpyDrNet + +Import Package +--------------- -Working Environment -------------------- +To import SpyDrNet to the project, use the following code: -SpyDrNet is coded in Python, and requires Python 3.5 or newer versions of Python. In order to import SpyDrNet to the project, use the following code: +.. code-block:: - >>> import spydrnet as sdn - >>> + import spydrnet as sdn -In this tutorial, we will use 'sdn' as a shorcut for SpyDrNet to manipulate all the commands. +In this tutorial, we will use 'sdn' as a shorcut to access SpyDrNet commands. Parsing ------- -SpyDrNet currently supports the parsing and composing for EDIF file and Verilog file +The SpyDrNet parser will take an EDIF/Verilog file and put the information into the SpyDrNet data structure. -To parse a file, enter the following command for EDIF file +To parse a file, enter the following command for an EDIF file - >>> netlist = sdn.parse('.edf') +.. code-block:: -Or the following for Verilog file + netlist = sdn.parse('.edf') - >>> netlist = sdn.parse('.v') +Or the following for a Verilog file -Nelist is an intermediate representation (IR). We are able to modify the netlist and add new elements. The following code returns the name of the top isntance of the netlist: +.. code-block:: - >>> netlist.top_instance.name + netlist = sdn.parse('.v') -This creates a new library and the library is added to the nestlist. For the entire documentation of SpyDrNet, please refer :ref:`api_summary` +SpyDrNet has built in example netlists. For this tutorial, we will use the example 'one_counter'. This is the same as if we parsed a netlist named 'one_counter'. - >>> netlist.create_library() +.. code-block:: + netlist = sdn.load_example_netlist("one_counter") +Intermediate Representation (IR) Basics +--------------------------------------- +A SpyDrNet netlist has many parts. The following is a short run through the basics. -Composing ---------- +Netlist: +^^^^^^^^ + This class of Python objects is the netlist element with the highest level of organization (a whole netlist). It contains an ordered collection of libraries and any data associated with the netlist as a whole. + +Library: +^^^^^^^^ + Contains an ordered collection of definitions -To compose a file, enter the following command + Use the following code to see the libraries in our netlist: + + .. code-block:: - >>> sdn.compose(netlist, '.edf') + print(netlist.libraries) -A new file named '.edf' should be generated in the working directory. + This returns the library objects. To see the names of the libraries, use: + + .. code-block:: -Examples --------- + for library in netlist.get_libraries(): + print("Library:", library.name) -Creating from scratch -^^^^^^^^^^^^^^^^^^^^^ + As seen in this example, most objects have a name and can be accessed using '.name' -We can also create the hardware design from scratch - >>> import spydrnet as sdn - >>> nelist = sdn.Netlist('myNetlist') - >>> instance = sdn.Instance() +Definition: +^^^^^^^^^^^ + Holds information about an element like its ports, pins, etc. (note: the pins are inner pins...see below). Verilog and System Verilog refer to a definition as a module, VHDL refers to a definition as an entity, and EDIF refers to a definition as a cell. -For full details regarding the initialization of a Netlist obejct, see :ref:`netlist` + To see the definitions in the first library, use: + + .. code-block:: -Renaming an objects -^^^^^^^^^^^^^^^^^^^ + print(netlist.libraries[0].definitions) - >>> instance.name = "my_instance" + As before, we can use '.name' to see the name of each definition: + + .. code-block:: -Setting properties -^^^^^^^^^^^^^^^^^^ + for definition in netlist.libraries[0].get_definitions(): + print("Definition:", definition.name) + +Ports: +^^^^^^ + The input/output ‘slots’ of each definition (e.g. A,B, and Q of a simple AND gate) + + To see the ports for the first definition in the first library, run the following: + + .. code-block:: + + definition_1 = netlist.libraries[0].definitions[0] + for port in definition_1.ports: + print("Port", port.name) + +Pins: +^^^^^ + Found on ports. There are two types of pins: inner and outer (see the following explanation). Most of the time, you don't need to worry about what type a pin is because SpyDrNet takes care of it for you. + + **InnerPin**: + Inner pins are in definitions. Every definition has only one set of inner pins. + **OuterPin**: + Outer pins are on instances. Each instance has a set of outer pins that corresponds to its reference definition’s inner pins. Because of this, a definition may have several sets of outer pins. For example, if a definition is instanced five times, it will have five sets of outer pins. + + Run the following code to see the types of pins for the instances and definitions in your netlist: + + .. code-block:: + + for instance in netlist.get_instances(): + print("Instance:",instance.name," Reference definition:",instance.reference.name) + print('\t',"Instance's pins' types") + for pin in instance.pins: + print('\t\t',pin.__class__) + print('\t',"Definition's pins' types") + for pin in instance.reference.get_pins(): + print('\t\t',pin.__class__) + +Wires: +^^^^^^ + Wires connect pins to pins and thus connect elements to each other. Wires can connect to as many pins as desired (not just two). + +Cables: +^^^^^^^ + Cables are bundles of wires. Wires are inside cables. - >>> instance['NAME'] = "name" +Instances: +^^^^^^^^^^ + An instance of a definition. It holds pointers to the definition which it instances (its reference), and contains its own set of pins (outer pins, specifically). -For more of the functionality, features, and uses of SpyDrNet, please visit :ref:`sec:examples` + An instance is also known as a **'child'**. + The definition instanced is the **'reference'**. + The definition that instances the other definition is the **'parent'**. + + To see the instances in the 'work' library, or library[2], use the following code: + + .. code-block:: + for instance in netlist.libraries[2].get_instances(): + print("Instance:", instance.name) + print("Instance's Parent:",instance.parent.name) + print("Instance's Reference Definition:",instance.reference.name) + print('\n') -Below is a list of all the intermediate representations (IR) used by SpyDrNet. See :ref:`api_summary` for API specification. + In the previous code, we saw that the definition '*counter*' instances the definition '*MUXCY_L*' as '*count_cry[0]*'. + So '*counter*' is the **parent**, '*MUXCY_L*' is the **reference**, and '*count_cry[0]*' is the **instance** and **child** of 'counter'. -Intermediate Representation ----------------------------- -SpyDrNet's intermediate representation of netlists (IR) is what sets it apart for other EDA tools. The IR is structured to house netlists in a generic way while allowing for format specific constructs to be preserved. +.. _fig:IR_2: +.. figure:: /figures/IR.* + :align: center + :alt: SpyDrNet Intermediate Representation -:class:`Element` - Most IR classes inherit from this Python class. Objects of this class are referred to as a netlist elements. A netlist + Summary of the SpyDrNet IR + +Other IR Parts +^^^^^^^^^^^^^^^ + +**Element** + Most IR classes inherit from this Python class. Objects of this class are referred to as netlist elements. A netlist element contains a dictionary for storing data specific to itself. This is accomplished using Python get/set item functions, (see :ref:`sec:element-data`). -:class:`Netlist` - This class of Python objects is the netlist element with the highest level of organization (a whole netlist). It - contains an ordered collection of libraries and any data associated with the netlist as a whole. - -:class:`Library` - This netlist element contains an ordered collection of cell or module definitions associated with a library. +**Bundle** + The Bundle class is a parent class of ports and cables. This class defines the structure that helps us properly represent array objects in netlists including the width, direction (to or downto) and starting index. As a parent class this class is not directly instantiated in netlist. + +More detail on the IR is provided in :ref:`api_summary`. + +Modifying Netlists +------------------ + + Modifying netlists is made possible through SpyDrNet. + + **Renaming**: -:class:`Definition` - A Definition outlines the contents of each component that can be instantiated elsewhere in the design. It holds information that is pertinent to all instances of itself including subcomponents ports and connections. + .. code-block:: -:class:`Instance` - This element holds pointers to the definition which it instances (the reference), and contains its own set of pins to be connected to within the definition that holds the instance (the parent). The instance is also called a "child" of the parent. + definition_1.name = "a_new_name" -:class:`Bundle` - The Bundle class is a parent class of Ports and Cables because each can be thought of as an array. This class defines the structure that helps us properly represent array objects in netlists including the width, direction (to or downto) and starting index. As a parent class this class is not directly instantiated in netlist. + **Creating**: + The following creates a new library in our netlist and then creates a new definition inside that library. -:class:`Port` - The Port element inherits from the Bundles class and can be thought of as containing the information on how a Definition connects the outside world to the elements it contains. + .. code-block:: -:class:`Cable` - Cables are bundles of connectors between components within a definition. They connect ports to their destination pins. + new_library = netlist.create_library(name="new_library") + new_library.create_definition(name="new_definition") -:class:`Pin` - The Pin class is also a parent class, inherited from by the inner pin and outer pin objects. Unlike the Element and Bundle objects, Pins are useful because they can hide some of the implementation details of the underlying inner pins and outer pins. + **Changing Values:** + From the example :ref:`sphx_glr_auto_examples_vivado_AND_to_OR.py` in the examples tab, the following line of code "[changes] the value in the properties of the LUT2 instance" + + .. code-block:: -:class:`InnerPin` - These pins are collected in Ports and are contained on the inside of the definitions. There is one set of inner pins per definition but they could refer to several sets of OuterPins. + properties[0]["value"] = "4'h" + str(hex(LUT_CONFIG)).upper()[2:] -:class:`OuterPin` - These pins are collected on instances. They let us distinguish between connections to multiple instances of a single definition. These objects remove the need to carefuly track hierarchy while navigating a netlist. + **See** :ref:`sphx_glr_auto_examples` **for more examples of modifying and viewing netlists.** -:class:`Wire` - Wires are grouped inside cables and are elements that help hold connection information between single pins on instances within a definition and within its ports. +Composing +--------- - -More detail on the IR is provided in :ref:`api_summary`. +To compose a file from a SpyDrNet netlist, enter the following command: + +.. code-block:: + + sdn.compose(netlist, '.edf') + +A new EDIF file named '.edf' will be generated in the working directory. +To compose a Verilog file, replace 'edf' with 'v'. \ No newline at end of file diff --git a/examples/advanced/README.rst b/examples/advanced/README.rst new file mode 100644 index 00000000..1f8b2f82 --- /dev/null +++ b/examples/advanced/README.rst @@ -0,0 +1,2 @@ +More Advanced +------------- \ No newline at end of file diff --git a/examples/special/plot_connectivity_graph.py b/examples/advanced/plot_connectivity_graph.py similarity index 100% rename from examples/special/plot_connectivity_graph.py rename to examples/advanced/plot_connectivity_graph.py diff --git a/examples/basic/display_info.py b/examples/basic/display_info.py index 1551fd2f..27e2b8f0 100644 --- a/examples/basic/display_info.py +++ b/examples/basic/display_info.py @@ -6,7 +6,7 @@ Some example functions that can be run to display information in a netlist: 1) print the hierarchy in a netlist 2) print each library with its definitions in a netlist - 3) print wire connections between ports in a netlist + 3) print connections between ports of each instance in a netlist 4) print the number of times each primitive is instanced Note: because the hierarchy function uses recursion, the maximum recursion depth may be exceeded if used for large designs @@ -16,6 +16,7 @@ """ import spydrnet as sdn +from spydrnet.util.selection import Selection #print the hierarchy of a netlist def hierarchy(current_instance,indentation=""): @@ -29,34 +30,25 @@ def libraries_definitions(my_netlist): definitions = list(definition.name for definition in library.definitions) print("DEFINITIONS IN '",library.name,"':",definitions) -#print the connections in a netlist +#prints each instance and it's connections (what inputs to it and what it outputs to) def print_connections(current_netlist): print("CONNECTIONS:") for instance in current_netlist.get_instances(): print("Instance name:",instance.name) - for pin in instance.pins: - IN = "EXTERNAL" - OUT = "EXTERNAL" - for pin in pin.wire.pins: - instance = list(instance.name for instance in pin.get_instances()) - for port in pin.get_ports(): - #for each pin, get the associated port and check the direction - if port.direction is sdn.IN: - if IN is "EXTERNAL": - IN = port.name + " of " + str(instance) - else: - IN = IN + ", " + port.name + " of " + str(instance) - elif port.direction is sdn.OUT: - if OUT is "EXTERNAL": - OUT = port.name + " of " + str(instance) - else: - OUT = OUT + ", " + port.name + " of " + str(instance) - print("\t",OUT,"---->",IN) + for out_going_pin in instance.get_pins(selection = Selection.OUTSIDE,filter=lambda x: x.inner_pin.port.direction is sdn.OUT): + if out_going_pin.wire: + next_instances = list(str(pin2.inner_pin.port.name + ' of ' + pin2.instance.name) for pin2 in out_going_pin.wire.get_pins(selection = Selection.OUTSIDE, filter = lambda x: x is not out_going_pin)) + print('\t','Port',out_going_pin.inner_pin.port.name,'---->',next_instances) + for in_coming_pin in instance.get_pins(selection = Selection.OUTSIDE,filter=lambda x: x.inner_pin.port.direction is sdn.IN): + if in_coming_pin.wire: + previous_instances = list(pin2 for pin2 in in_coming_pin.wire.get_pins(selection = Selection.OUTSIDE, filter = lambda x: x is not in_coming_pin)) + checked_previous_instances = list(str(x.inner_pin.port.name + ' of ' + x.instance.name) for x in previous_instances if (x.inner_pin.port.direction is sdn.OUT or (x.inner_pin.port.direction is sdn.IN and not x.instance.is_leaf()))is True) + print('\t',checked_previous_instances,'---->','Port',in_coming_pin.inner_pin.port.name) #print the number of times each primitive is instanced def instance_count(current_netlist): print("Number of times each primitive is instanced:") - primitives_library = next(netlist.get_libraries("hdi_primitives"),None) + primitives_library = next(current_netlist.get_libraries("hdi_primitives"),None) for primitive in primitives_library.get_definitions(): count = 0 for instance in current_netlist.get_instances(): diff --git a/examples/basic/plot_flatten.py b/examples/basic/plot_flatten.py index c33094d7..a4958e13 100644 --- a/examples/basic/plot_flatten.py +++ b/examples/basic/plot_flatten.py @@ -1,6 +1,6 @@ """ ===================================== -Flattens a netlist +Flatten A Netlist ===================================== Remove hierarchy from a netlist. The original hierarchy and new hierarchy (after flattening) will be printed. diff --git a/examples/basic/plot_single_use_definitions.py b/examples/basic/plot_single_use_definitions.py index 6e97bedb..55267ad0 100644 --- a/examples/basic/plot_single_use_definitions.py +++ b/examples/basic/plot_single_use_definitions.py @@ -1,6 +1,6 @@ """ ===================================== -Make Instances unique +Make Instances Unique ===================================== Creates definitions for non-leaf instances so each instance has its own definition. Each library in both the original and the uniquified netlist will be printed along with each's definitions. diff --git a/examples/special/README.rst b/examples/special/README.rst deleted file mode 100644 index b498609a..00000000 --- a/examples/special/README.rst +++ /dev/null @@ -1,2 +0,0 @@ -Special -------- \ No newline at end of file diff --git a/spydrnet/composers/__init__.py b/spydrnet/composers/__init__.py index 5a4f892d..6a1fa32d 100644 --- a/spydrnet/composers/__init__.py +++ b/spydrnet/composers/__init__.py @@ -2,7 +2,7 @@ def compose(netlist, filename): - """To compose a file into a netlit format""" + """To compose a file into a netlist format""" extension = os.path.splitext(filename)[1] extension_lower = extension.lower() if extension_lower in {".edf", ".edif"}: diff --git a/spydrnet/parsers/edif/tokenizer.py b/spydrnet/parsers/edif/tokenizer.py index c6f5e5d4..fe45132e 100644 --- a/spydrnet/parsers/edif/tokenizer.py +++ b/spydrnet/parsers/edif/tokenizer.py @@ -4,12 +4,13 @@ import io import os + class EdifTokenizer: @staticmethod def from_stream(stream): tokenizer = EdifTokenizer(stream) return tokenizer - + @staticmethod def from_string(string): string_stream = io.StringIO(string) @@ -20,7 +21,7 @@ def from_string(string): def from_filename(filename): tokenizer = EdifTokenizer(filename) return tokenizer - + def __init__(self, input_source): self.token = None self.next_token = None @@ -30,12 +31,12 @@ def __init__(self, input_source): if zipfile.is_zipfile(input_source): zip = zipfile.ZipFile(input_source) filename = os.path.basename(input_source) - filename = filename[:filename.rindex(".")] + filename = filename[: filename.rindex(".")] stream = zip.open(filename) stream = io.TextIOWrapper(stream) self.input_stream = stream else: - self.input_stream = open(input_source, 'r') + self.input_stream = open(input_source, "r") else: if isinstance(input_source, io.TextIOBase) is False: self.input_stream = io.TextIOWrapper(input_source) @@ -77,37 +78,38 @@ def generate_tokens(self): token_buffer = list() for buffer in iter(partial(self.input_stream.read, 32768), ""): for ch in buffer: - if ch == '\n': self.line_number += 1 + if ch == "\n": + self.line_number += 1 if in_quote: if ch in {"\n", "\r"}: continue token_buffer.append(ch) if ch == '"': in_quote = False - token = ''.join(token_buffer) + token = "".join(token_buffer) token_buffer.clear() yield token elif ch == '"': in_quote = True token_buffer.append(ch) - elif ch in {'(', ')'}: + elif ch in {"(", ")"}: if token_buffer: - token = ''.join(token_buffer) + token = "".join(token_buffer) token_buffer.clear() yield token yield ch - elif ch in {'\r', '\n', '\t', ' '}: + elif ch in {"\r", "\n", "\t", " "}: if token_buffer: - token = ''.join(token_buffer) + token = "".join(token_buffer) token_buffer.clear() yield token else: token_buffer.append(ch) if token_buffer: - token = ''.join(token_buffer) - token_buffer.clear() - yield token + token = "".join(token_buffer) + token_buffer.clear() + yield token finally: self.input_stream.close() @@ -117,15 +119,19 @@ def close(self): def expect(self, other): if not self.token_equals(other): - raise RuntimeError("Parse error: Expecting {} on line {}, recieved {}".format(other, self.line_number, self.token)) + raise RuntimeError( + "Parse error: Expecting {} on line {}, recieved {}".format( + other, self.line_number, self.token + ) + ) def peek_equals(self, other): peek_token = self.peek() return self.equals(peek_token, other) - + def token_equals(self, other): return self.equals(self.token, other) - + @staticmethod def equals(this, that): if this == that: @@ -140,7 +146,11 @@ def equals(this, that): def expect_valid_identifier(self): if self.is_valid_identifier() is False: - raise RuntimeError("Parse error: Expecting EDIF identifier on line {}, recieved {}".format(self.line_number, self.token)) + raise RuntimeError( + "Parse error: Expecting EDIF identifier on line {}, recieved {}".format( + self.line_number, self.token + ) + ) def is_valid_identifier(self): if re.match(r"[a-zA-Z]|&\a*", self.token) and len(self.token) <= 256: @@ -149,7 +159,11 @@ def is_valid_identifier(self): def expect_valid_integerToken(self): if self.is_valid_integerToken() is False: - raise RuntimeError("Parse error: Expecting integerToken on line {}, recieved {}".format(self.line_number, self.token)) + raise RuntimeError( + "Parse error: Expecting integerToken on line {}, recieved {}".format( + self.line_number, self.token + ) + ) def is_valid_integerToken(self): if re.match(r"[-+]?\d+", self.token): @@ -158,23 +172,16 @@ def is_valid_integerToken(self): def expect_valid_stringToken(self): if self.is_valid_stringToken() is False: - raise RuntimeError("Parse error: Expecting stringToken on line {}, recieved {}".format(self.line_number, self.token)) + raise RuntimeError( + "Parse error: Expecting stringToken on line {}, recieved {}".format( + self.line_number, self.token + ) + ) def is_valid_stringToken(self): - if re.match(r'"(?:[a-zA-Z]|(?:%[ \t\n\r]*(?:(?:[-+]?\d+[ \t\n\r]+)*(?:[-+]?\d+))*[ \t\n\r]*%)|[0-9]|[\!\#\$\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]|[ \t\n\r])*"', self.token): + if re.match( + r'"(?:[a-zA-Z]|(?:%[ \t\n\r]*(?:(?:[-+]?\d+[ \t\n\r]+)*(?:[-+]?\d+))*[ \t\n\r]*%)|[0-9]|[\!\#\$\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]|[ \t\n\r])*"', + self.token, + ): return True return False - -if __name__ == "__main__": - # filename = r"C:\Users\keller\workplace\SpyDrNet\data\large_edif\osfbm.edf" - import cProfile - def run(): - filename = r"C:\Users\akeller9\workspace\SpyDrNet\data\large_edif\osfbm.edf" - tokenizer = EdifTokenizer.from_filename(filename) - count = 0 - for token in tokenizer.generator: - if count < 100: - print(token) - count += 1 - print(count) - cProfile.run("run()") \ No newline at end of file diff --git a/spydrnet/support_files/EDIF_netlists/toggle.edf.zip b/spydrnet/support_files/EDIF_netlists/toggle.edf.zip new file mode 100644 index 00000000..39a23cb7 Binary files /dev/null and b/spydrnet/support_files/EDIF_netlists/toggle.edf.zip differ