Hdlparse

Hdlparse is a simple package implementing a rudimentary parser for VHDL and Verilog. It is not capable of fully parsing the entire language. Rather, it is meant to extract enough key information from a source file to create generated documentation.

This library is used by the Symbolator diagram generator.

For VHDL this library can extract component, subprogram, type, subtype, and constant declarations from a package. For Verilog it can extract module declarations (both 1995 and 2001 syntax).

Requirements

Hdlparse requires either Python 2.7 or Python 3.x and no additional libraries.

The installation script depends on setuptools. The source is written in Python 2.7 syntax but will convert cleanly to Python 3 when the installer passes it through 2to3.

Licensing

Opbasm and the included VHDL source is licensed for free commercial and non-commercial use under the terms of the MIT license.

Download

You can access the Hdlparse Git repository from Github. You can install direct from PyPI with the pip command if you have it available.

Installation

Hdlparse is a Python library. You must have Python installed first to use it. Most modern Linux distributions and OS/X have it available by default. There are a number of options available for Windows. If you don’t already have a favorite, I recommend getting one of the “full-stack” Python distros that are geared toward scientific computing such as Anaconda or Python(x,y).

You need to have the Python setuptools installed first. If your OS has a package manager, it may be preferable to install setuptools through that tool. Otherwise you can use Pip:

> pip install setuptools

The easiest way to install Hdlparse is from PyPI.

> pip install --upgrade hdlparse

This will download and install the latest release, upgrading if you already have it installed. If you don’t have pip you may have the easy_install command available which can be used to install pip on your system:

> easy_install pip

You can also use pip to get the latest development code from Github:

> pip install --upgrade https://github.com/kevinpt/hdlparse/tarball/master

If you manually downloaded a source package or created a clone with Git you can install with the following command run from the base Hdlparse directory:

> python setup.py install

On Linux systems you may need to install with root privileges using the sudo command.

After a successful install the Hdlparse library will be available.

Using Hdlparse

The Hdlparse library has two main modules vhdl_parser and verilog_parser. You import one or both of them as needed.

import hdlparse.vhdl_parser as vhdl
import hdlparse.verilog_parser as vlog

Within each module are extractor classes VhdlExtractor and VerilogExtractor that are the central mechanisms for using Hdlparse.

vhdl_ex = vhdl.VhdlExtractor()
vlog_ex = vlog.VerilogExtractor()

VHDL

The VHDL parser can extract a variety of different objects from sourec code. It can be used to access package definitions and component declarations,type and subtype definitions, functions, and procedures found within a package. It will not process entity declarations or nested subprograms and types.

Extraction proceeds as follows:

with io.open(fname, 'rt', encoding='latin-1') as fh:
  code = fh.read()
vhdl_objs = vhdl_ex.extract_objects_from_source(code)

vhdl_objs = vhdl_ex.extract_objects(fname)

These will extract a list of all supported object types. The result is a list of objects subclassed from VhdlObject. You can pass an optional subclass of VhdlObject to filter the results for just that type. Repeated calls are more efficient when using extract_objects() which maintains a cache of all previously parsed objects in the extractor.

package example is
  component demo is
    generic (
      GENERIC1: boolean := false;
      GENERIC2: integer := 100
    );
    port (
      a, b : in std_ulogic := '1';
      c, d : out std_ulogic_vector(7 downto 0);
      e, f : inout unsigned(7 downto 0)
    );
  end component;
end package;

Each port and generic is an instance of VhdlParameter containing the name, mode (input, output, inout), and type.

import hdlparse.vhdl_parser as vhdl
from hdlparse.vhdl_parser import VhdlComponent

vhdl_ex = vhdl.VhdlExtractor()
vhdl_comps = vhdl_ex.extract_objects('example.vhdl', VhdlComponent)

for c in vhdl_comps:
  print('Component "{}":'.format(c.name))

  print('  Generics:')
  for p in c.generics:
    print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type))

  print('  Ports:')
  for p in c.ports:
    print('\t{:20}{:8} {}'.format(p.name, p.mode, p.data_type ))

When run against the example code produces the following:

VHDL arrays

It can be useful to know which data types are an array. The VhdlExtractor class will keep track of all visited array type definitions it sees. The is_array() method lets you query the internal list to check if a type is for an array. All IEEE standard array types are supported by default. Any subtypes derived from an array type will also be considered as arrays.

import hdlparse.vhdl_parser as vhdl

vhdl_ex = vhdl.VhdlExtractor()

code = '''
package foobar is
  type custom_array is array(integer range <>) of boolean;
  subtype custom_subtype is custom_array(1 to 10);
end package;
'''
vhdl_comps = vhdl_ex.extract_objects(code)

# These all return true:
print(vhdl_ex.is_array('unsigned'))
print(vhdl_ex.is_array('custom_array'))
print(vhdl_ex.is_array('custom_subtype'))

Parsed array data can be saved to a file with save_array_types() and restored with load_array_types(). This lets you parse one set of files for type definitions and use the saved info for parsing other code at a different time.

Verilog

The Verilog parser is only able to extract module definitions with a port and optional parameter list. Verilog modules are extracted using the extract_objects() and extract_objects_from_source() methods. The latter is used when you have the code in a string. The former when you want to read the Veirlog source from a file. When parsing a file, a cache of objects is maintained so you can repeatedly call extract_objects() without reparsing the file.

with open(fname, 'rt') as fh:
  code = fh.read()
vlog_mods = vlog_ex.extract_objects_from_source(code)

vlog_mods = vlog_ex.extract_objects(fname)

The result is a list of extracted VerilogModule objects. Each instance of this class has name, generics, and ports attributes. The name attribute is the name of the module. The generics attribute is a list of extracted parameters and ports is a list of the ports on the module.

module newstyle // This is a new style module def
#(parameter real foo = 8, bar=1, baz=2,
parameter signed [7:0] zip = 100)
(
  input x, x2, inout y, y2_long_output,
  output wire [4:1] z, z2
);
endmodule

Each port and generic is an instance of VerilogParameter containing the name, mode (input, output, inout), and type.

import hdlparse.verilog_parser as vlog

vlog_ex = vlog.VerilogExtractor()
vlog_mods = vlog_ex.extract_objects_from_source('example.v')

for m in vlog_mods:
  print('Module "{}":'.format(m.name))

  print('  Parameters:')
  for p in m.generics:
    print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type))

  print('  Ports:')
  for p in m.ports:
    print('\t{:20}{:8}{}'.format(p.name, p.mode, p.data_type))

When run against the example code produces the following:

Module "newstyle":
  Parameters:
        foo                 in      real
        bar                 in      real
        baz                 in      real
        zip                 in      signed [7:0]
  Ports:
        x                   input
        x2                  input
        y                   inout
        y2_long_output      inout
        z                   output  wire [4:1]
        z2                  output  wire [4:1]

Indices and tables