slvcodec


Nameslvcodec JSON
Version 0.4.14 PyPI version JSON
download
home_pagehttps://github.com/benreynwar/slvcodec
SummaryUtilities for generating VHDL to convert to and from std_logic_vector, as well as utilties to create testbenches described by python.
upload_time2021-02-24 19:42:27
maintainer
docs_urlNone
authorBen Reynwar
requires_python
licenseMIT
keywords vhdl hdl rtl fpga asic xilinx altera
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
slvcodec
========

slvcodec is a tool that analyzes VHDL and generates:

  * Functions to convert arbitrary VHDL types to and from std_logic_vector.

  * Generate testbenches for entities that read inputs from a file, and
    write outputs to a file.

  * Utilities so that unit tests for VHDL code can easily to be written
    in python.


Generation of functions to convert to and from std_logic_vector
---------------------------------------------------------------

Here's an example VHDL package.

.. code:: vhdl

    library ieee;
    use ieee.numeric_std.all;

    package complex is

      constant FIXED_WIDTH: natural := 8;
      subtype fixed_t is unsigned(FIXED_WIDTH-1 downto 0);

      type complex_t is record
        real: fixed_t;
        imag: fixed_t;
      end record;

      type array_of_complex is array(natural range <>) of complex_t;

    end package;

The following python script is used to generate a helper package that contains
functions to convert the types to and from std_logic_vector.

.. code:: python

    import os

    from slvcodec import filetestbench_generator


    thisdir = os.path.dirname(__file__)


    def make_slvcodec_package():
        complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')
        directory = os.path.join(thisdir, 'generated')
        os.mkdir(directory)
        filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])


    if __name__ == '__main__':
        make_slvcodec_package()

Here is what the generated VHDL looks like.

.. code:: vhdl

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    use work.complex.all;
    use work.slvcodec.all;

    package complex_slvcodec is


      function to_slvcodec (constant data: array_of_complex) return std_logic_vector;
      function from_slvcodec (constant slv: std_logic_vector) return array_of_complex;
      constant fixed_t_slvcodecwidth: natural := fixed_width;
      constant complex_t_slvcodecwidth: natural := 2*fixed_width;
      function to_slvcodec (constant data: complex_t) return std_logic_vector;
      function from_slvcodec (constant slv: std_logic_vector) return complex_t;

    end package;

    package body complex_slvcodec is

      function to_slvcodec (constant data: array_of_complex) return std_logic_vector is
        constant W: natural := complex_t_slvcodecwidth;
        constant N: natural := data'length;
        variable slv: std_logic_vector(N*W-1 downto 0);
      begin
        for ii in 0 to N-1 loop
          slv((ii+1)*W-1 downto ii*W) := to_slvcodec(data(ii));
        end loop;
        return slv; 
      end function;

      function from_slvcodec (constant slv: std_logic_vector) return array_of_complex is
        constant W: natural := complex_t_slvcodecwidth;
        constant N: natural := slv'length/W;
        variable mapped: std_logic_vector(slv'length-1 downto 0);
        variable output: array_of_complex(N-1 downto 0);
      begin
        mapped := slv;
        for ii in 0 to N-1 loop
          output(ii) := from_slvcodec(mapped((ii+1)*W-1 downto ii*W));
        end loop;
        return output; 
      end function;

      function to_slvcodec (constant data: complex_t) return std_logic_vector is
        constant W0: natural := 0;
        constant W1: natural := W0 + fixed_width;
        constant W2: natural := W1 + fixed_width;
        variable slv: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);
      begin
        slv(W1-1 downto W0) := to_slvcodec(data.real);
        slv(W2-1 downto W1) := to_slvcodec(data.imag);
        return slv; 
      end function;

      function from_slvcodec (constant slv: std_logic_vector) return complex_t is
        constant W0: natural := 0;
        constant W1: natural := W0 + fixed_width;
        constant W2: natural := W1 + fixed_width;
        variable data: complex_t;
        variable mapped: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);
      begin
        mapped := slv;
        data.real := from_slvcodec(mapped(W1-1 downto W0)); 
        data.imag := from_slvcodec(mapped(W2-1 downto W1)); 
        return data; 
      end function;

    end package body;


Generation of file-based testbenches
------------------------------------

Here's an example entity that just returns the magnitude squared of a complex data type
that we defined earlier.

.. code:: vhdl

    library ieee;
    use ieee.numeric_std.all;
    use work.complex.all;

    entity complex_mag2 is
      port (
        i: in complex_t;
        o: out unsigned(FIXED_WIDTH+1-1 downto 0)
        );
    end entity;

    architecture arch of complex_mag2 is

      signal real2: signed(FIXED_WIDTH*2-1 downto 0);
      signal imag2: signed(FIXED_WIDTH*2-1 downto 0);
      signal mag2: unsigned(FIXED_WIDTH*2-1 downto 0);
      signal scaled_mag2: unsigned(FIXED_WIDTH+1-1 downto 0);

    begin

      real2 <= i.real * i.real;
      imag2 <= i.imag * i.imag;
      mag2 <= unsigned(real2) + unsigned(imag2);

      scaled_mag2 <= mag2(FIXED_WIDTH*2-1-1 downto FIXED_WIDTH-2);

      o <= scaled_mag2;

    end architecture;

We can use slvcodec to generate a testbench that reads input data from a file,
and writes output data to another file.

.. code:: python

    import os

    from slvcodec import filetestbench_generator


    thisdir = os.path.dirname(__file__)


    def make_slvcodec_package():
        complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')
        directory = os.path.join(thisdir, 'generated')
        os.mkdir(directory)
        slvcodec_files = filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])
        return slvcodec_files


    def make_complex_mag2_testbench():
        base_filenames = [
            os.path.join(thisdir, 'complex_pkg.vhd'),
            os.path.join(thisdir, 'complex_mag2.vhd'),
            ]
        slvcodec_fns = make_slvcodec_package()
        with_slvcodec_fns = base_filenames + slvcodec_fns
        directory = os.path.join(thisdir, 'generated')
        generated_fns, generated_wrapper_fns, resolved = filetestbench_generator.prepare_files(
            directory=directory, filenames=with_slvcodec_fns,
            top_entity='complex_mag2')
        return generated_fns


    if __name__ == '__main__':
        make_complex_mag2_testbench()


This will generate the following VHDL testbench.

.. code:: vhdl

    library ieee;
    use ieee.std_logic_1164.all;
    use work.slvcodec.all;
    use ieee.numeric_std.all;
    use work.complex.all;
    use work.complex_slvcodec.all;

    entity complex_mag2_tb is
      generic (

        CLOCK_PERIOD: time := 10 ns;
        RUNNER_CFG: string;
        OUTPUT_PATH: string
      );
    end entity;

    architecture arch of complex_mag2_tb is
      type t_input is
    record
        i: complex_t;
    end record;
    type t_output is
    record
        o: unsigned((1+fixed_width)-1 downto 0);
    end record;
      constant t_input_slvcodecwidth: natural := 2*fixed_width;
      function to_slvcodec (constant data: t_input) return std_logic_vector;
      function from_slvcodec (constant slv: std_logic_vector) return t_input;
      function to_slvcodec (constant data: t_input) return std_logic_vector is
        constant W0: natural := 0;
        constant W1: natural := W0 + 2*fixed_width;
        variable slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
      begin
        slv(W1-1 downto W0) := to_slvcodec(data.i);
        return slv; 
      end function;

      function from_slvcodec (constant slv: std_logic_vector) return t_input is
        constant W0: natural := 0;
        constant W1: natural := W0 + 2*fixed_width;
        variable data: t_input;
        variable mapped: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
      begin
        mapped := slv;
        data.i := from_slvcodec(mapped(W1-1 downto W0)); 
        return data; 
      end function;
      constant t_output_slvcodecwidth: natural := (1+fixed_width);
      function to_slvcodec (constant data: t_output) return std_logic_vector;
      function from_slvcodec (constant slv: std_logic_vector) return t_output;
      function to_slvcodec (constant data: t_output) return std_logic_vector is
        constant W0: natural := 0;
        constant W1: natural := W0 + (1+fixed_width);
        variable slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
      begin
        slv(W1-1 downto W0) := to_slvcodec(data.o);
        return slv; 
      end function;

      function from_slvcodec (constant slv: std_logic_vector) return t_output is
        constant W0: natural := 0;
        constant W1: natural := W0 + (1+fixed_width);
        variable data: t_output;
        variable mapped: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
      begin
        mapped := slv;
        data.o := from_slvcodec(mapped(W1-1 downto W0)); 
        return data; 
      end function;
      signal input_data: t_input;
      signal output_data: t_output;
      signal input_slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);
      signal output_slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);
      signal clk: std_logic;
      signal read_clk: std_logic;
      signal write_clk: std_logic;
    begin

      input_data <= from_slvcodec(input_slv);
      output_slv <= to_slvcodec(output_data);

      file_reader: entity work.ReadFile
        generic map(FILENAME => OUTPUT_PATH & "/indata.dat",
                    PASSED_RUNNER_CFG => RUNNER_CFG,
                    WIDTH => t_input_slvcodecwidth)
        port map(clk => read_clk,
                 out_data => input_slv);

      file_writer: entity work.WriteFile
        generic map(FILENAME => OUTPUT_PATH & "/outdata.dat",
                    WIDTH => t_output_slvcodecwidth)
        port map(clk => write_clk,
                 in_data => output_slv);

      clock_generator: entity work.ClockGenerator
        generic map(CLOCK_PERIOD => CLOCK_PERIOD,
                    CLOCK_OFFSET => 0 ns
                    )
        port map(clk => clk);

      read_clock_generator: entity work.ClockGenerator
        generic map(CLOCK_PERIOD => CLOCK_PERIOD,
                    CLOCK_OFFSET => CLOCK_PERIOD/10
                    )
        port map(clk => read_clk);

      write_clock_generator: entity work.ClockGenerator
        generic map(CLOCK_PERIOD => CLOCK_PERIOD,
                    CLOCK_OFFSET => 4*CLOCK_PERIOD/10
                    )
        port map(clk => write_clk);

      dut: entity work.complex_mag2
        port map(
                 i => input_data.i,
    o => output_data.o
                 );

    end architecture;


But generating a test bench that just reads and writes the input and output data
to and from files isn't particularly useful unless we have a way of generating the
input data, and checking the output data.  Slvcodec include tools to do this
with python.

Python-based testing
--------------------

We define a python class with a ``make_input_data`` method that returns an iterable of
dictionaries specifying the input data, and a ``check_output_data`` method that receives
a list of input_data dictionaries and a list of output data dictionaries, that raises an
exeception is the output data is incorrect.

.. code:: python

    class ComplexMag2Test:

        def __init__(self, resolved, generics, top_params):
            # Here we're taking advantage of the fact that when the test is intialized it
            # has access to the parsed VHDL.  We use that to get the value of the constant
            # FIXED_WIDTH that is defined in complex_pkg.vhd.
            self.fixed_width = resolved['packages']['complex'].constants['fixed_width'].value()
            self.max_fixed = pow(2, self.fixed_width-1)-1
            self.min_fixed = -pow(2, self.fixed_width-1)
            self.n_data = 100

        def fixed_to_float(self, f):
            r = f / pow(2, self.fixed_width-2)
            return r

        def make_input_data(self, seed=None, n_data=3000):
            input_data = [{
                'i': {'real': random.randint(self.min_fixed, self.max_fixed),
                      'imag': random.randint(self.min_fixed, self.max_fixed)},
            } for i in range(self.n_data)]

            return input_data

        def check_output_data(self, input_data, output_data):
            inputs = [self.fixed_to_float(d['i']['real']) + self.fixed_to_float(d['i']['imag']) * 1j
                      for d in input_data]
            input_float_mag2s = [abs(v)*abs(v) for v in inputs] 
            outputs = [self.fixed_to_float(d['o']) for d in output_data]
            differences = [abs(expected - actual) for expected, actual in zip(input_float_mag2s, outputs)]
            allowed_error = 1/pow(2, self.fixed_width-2)
            assert all([d < allowed_error for d in differences])


We then use ``slvcodec.test_utils.register_test_with_vunit`` to generate an appropriate testbench and input
data file, and register the produced test with vunit.  VUnit can then be run as normal.


.. code:: python

    from slvcodec import test_utils, config
    import os

    if __name__ == '__main__':
        random.seed(0)
        # Initialize vunit with command line parameters.
        vu = config.setup_vunit()
        # Set up logging.
        config.setup_logging(vu.log_level)
        # Get filenames for test
        this_dir = os.path.dirname(os.path.realpath(__file__))
        filenames = [
            os.path.join(this_dir, 'complex_pkg.vhd'),
            os.path.join(this_dir, 'complex_mag2.vhd'),
            ]
        # Register the test with VUnit.
        test_output_directory = os.path.join(this_dir, 'generated')
        test_utils.register_test_with_vunit(
            vu=vu,
            directory=test_output_directory,
            filenames=filenames,
            top_entity='complex_mag2',
            all_generics=[{}],
            test_class=ComplexMag2Test,
            top_params={},
            )
        # Run the tests with VUnit
        vu.set_sim_option('disable_ieee_warnings', True)
        vu.main()



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/benreynwar/slvcodec",
    "name": "slvcodec",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "VHDL,hdl,rtl,FPGA,ASIC,Xilinx,Altera",
    "author": "Ben Reynwar",
    "author_email": "ben@reynwar.net",
    "download_url": "https://files.pythonhosted.org/packages/3e/10/24f11daaa52722db80a9a6d4860dd39d966b4644b478d1603fcbda0c3ea0/slvcodec-0.4.14.tar.gz",
    "platform": "",
    "description": "\nslvcodec\n========\n\nslvcodec is a tool that analyzes VHDL and generates:\n\n  * Functions to convert arbitrary VHDL types to and from std_logic_vector.\n\n  * Generate testbenches for entities that read inputs from a file, and\n    write outputs to a file.\n\n  * Utilities so that unit tests for VHDL code can easily to be written\n    in python.\n\n\nGeneration of functions to convert to and from std_logic_vector\n---------------------------------------------------------------\n\nHere's an example VHDL package.\n\n.. code:: vhdl\n\n    library ieee;\n    use ieee.numeric_std.all;\n\n    package complex is\n\n      constant FIXED_WIDTH: natural := 8;\n      subtype fixed_t is unsigned(FIXED_WIDTH-1 downto 0);\n\n      type complex_t is record\n        real: fixed_t;\n        imag: fixed_t;\n      end record;\n\n      type array_of_complex is array(natural range <>) of complex_t;\n\n    end package;\n\nThe following python script is used to generate a helper package that contains\nfunctions to convert the types to and from std_logic_vector.\n\n.. code:: python\n\n    import os\n\n    from slvcodec import filetestbench_generator\n\n\n    thisdir = os.path.dirname(__file__)\n\n\n    def make_slvcodec_package():\n        complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')\n        directory = os.path.join(thisdir, 'generated')\n        os.mkdir(directory)\n        filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])\n\n\n    if __name__ == '__main__':\n        make_slvcodec_package()\n\nHere is what the generated VHDL looks like.\n\n.. code:: vhdl\n\n    library ieee;\n    use ieee.std_logic_1164.all;\n    use ieee.numeric_std.all;\n    use work.complex.all;\n    use work.slvcodec.all;\n\n    package complex_slvcodec is\n\n\n      function to_slvcodec (constant data: array_of_complex) return std_logic_vector;\n      function from_slvcodec (constant slv: std_logic_vector) return array_of_complex;\n      constant fixed_t_slvcodecwidth: natural := fixed_width;\n      constant complex_t_slvcodecwidth: natural := 2*fixed_width;\n      function to_slvcodec (constant data: complex_t) return std_logic_vector;\n      function from_slvcodec (constant slv: std_logic_vector) return complex_t;\n\n    end package;\n\n    package body complex_slvcodec is\n\n      function to_slvcodec (constant data: array_of_complex) return std_logic_vector is\n        constant W: natural := complex_t_slvcodecwidth;\n        constant N: natural := data'length;\n        variable slv: std_logic_vector(N*W-1 downto 0);\n      begin\n        for ii in 0 to N-1 loop\n          slv((ii+1)*W-1 downto ii*W) := to_slvcodec(data(ii));\n        end loop;\n        return slv; \n      end function;\n\n      function from_slvcodec (constant slv: std_logic_vector) return array_of_complex is\n        constant W: natural := complex_t_slvcodecwidth;\n        constant N: natural := slv'length/W;\n        variable mapped: std_logic_vector(slv'length-1 downto 0);\n        variable output: array_of_complex(N-1 downto 0);\n      begin\n        mapped := slv;\n        for ii in 0 to N-1 loop\n          output(ii) := from_slvcodec(mapped((ii+1)*W-1 downto ii*W));\n        end loop;\n        return output; \n      end function;\n\n      function to_slvcodec (constant data: complex_t) return std_logic_vector is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + fixed_width;\n        constant W2: natural := W1 + fixed_width;\n        variable slv: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);\n      begin\n        slv(W1-1 downto W0) := to_slvcodec(data.real);\n        slv(W2-1 downto W1) := to_slvcodec(data.imag);\n        return slv; \n      end function;\n\n      function from_slvcodec (constant slv: std_logic_vector) return complex_t is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + fixed_width;\n        constant W2: natural := W1 + fixed_width;\n        variable data: complex_t;\n        variable mapped: std_logic_vector(complex_t_slvcodecwidth-1 downto 0);\n      begin\n        mapped := slv;\n        data.real := from_slvcodec(mapped(W1-1 downto W0)); \n        data.imag := from_slvcodec(mapped(W2-1 downto W1)); \n        return data; \n      end function;\n\n    end package body;\n\n\nGeneration of file-based testbenches\n------------------------------------\n\nHere's an example entity that just returns the magnitude squared of a complex data type\nthat we defined earlier.\n\n.. code:: vhdl\n\n    library ieee;\n    use ieee.numeric_std.all;\n    use work.complex.all;\n\n    entity complex_mag2 is\n      port (\n        i: in complex_t;\n        o: out unsigned(FIXED_WIDTH+1-1 downto 0)\n        );\n    end entity;\n\n    architecture arch of complex_mag2 is\n\n      signal real2: signed(FIXED_WIDTH*2-1 downto 0);\n      signal imag2: signed(FIXED_WIDTH*2-1 downto 0);\n      signal mag2: unsigned(FIXED_WIDTH*2-1 downto 0);\n      signal scaled_mag2: unsigned(FIXED_WIDTH+1-1 downto 0);\n\n    begin\n\n      real2 <= i.real * i.real;\n      imag2 <= i.imag * i.imag;\n      mag2 <= unsigned(real2) + unsigned(imag2);\n\n      scaled_mag2 <= mag2(FIXED_WIDTH*2-1-1 downto FIXED_WIDTH-2);\n\n      o <= scaled_mag2;\n\n    end architecture;\n\nWe can use slvcodec to generate a testbench that reads input data from a file,\nand writes output data to another file.\n\n.. code:: python\n\n    import os\n\n    from slvcodec import filetestbench_generator\n\n\n    thisdir = os.path.dirname(__file__)\n\n\n    def make_slvcodec_package():\n        complex_pkg_fn = os.path.join(thisdir, 'complex_pkg.vhd')\n        directory = os.path.join(thisdir, 'generated')\n        os.mkdir(directory)\n        slvcodec_files = filetestbench_generator.add_slvcodec_files(directory, [complex_pkg_fn])\n        return slvcodec_files\n\n\n    def make_complex_mag2_testbench():\n        base_filenames = [\n            os.path.join(thisdir, 'complex_pkg.vhd'),\n            os.path.join(thisdir, 'complex_mag2.vhd'),\n            ]\n        slvcodec_fns = make_slvcodec_package()\n        with_slvcodec_fns = base_filenames + slvcodec_fns\n        directory = os.path.join(thisdir, 'generated')\n        generated_fns, generated_wrapper_fns, resolved = filetestbench_generator.prepare_files(\n            directory=directory, filenames=with_slvcodec_fns,\n            top_entity='complex_mag2')\n        return generated_fns\n\n\n    if __name__ == '__main__':\n        make_complex_mag2_testbench()\n\n\nThis will generate the following VHDL testbench.\n\n.. code:: vhdl\n\n    library ieee;\n    use ieee.std_logic_1164.all;\n    use work.slvcodec.all;\n    use ieee.numeric_std.all;\n    use work.complex.all;\n    use work.complex_slvcodec.all;\n\n    entity complex_mag2_tb is\n      generic (\n\n        CLOCK_PERIOD: time := 10 ns;\n        RUNNER_CFG: string;\n        OUTPUT_PATH: string\n      );\n    end entity;\n\n    architecture arch of complex_mag2_tb is\n      type t_input is\n    record\n        i: complex_t;\n    end record;\n    type t_output is\n    record\n        o: unsigned((1+fixed_width)-1 downto 0);\n    end record;\n      constant t_input_slvcodecwidth: natural := 2*fixed_width;\n      function to_slvcodec (constant data: t_input) return std_logic_vector;\n      function from_slvcodec (constant slv: std_logic_vector) return t_input;\n      function to_slvcodec (constant data: t_input) return std_logic_vector is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + 2*fixed_width;\n        variable slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);\n      begin\n        slv(W1-1 downto W0) := to_slvcodec(data.i);\n        return slv; \n      end function;\n\n      function from_slvcodec (constant slv: std_logic_vector) return t_input is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + 2*fixed_width;\n        variable data: t_input;\n        variable mapped: std_logic_vector(t_input_slvcodecwidth-1 downto 0);\n      begin\n        mapped := slv;\n        data.i := from_slvcodec(mapped(W1-1 downto W0)); \n        return data; \n      end function;\n      constant t_output_slvcodecwidth: natural := (1+fixed_width);\n      function to_slvcodec (constant data: t_output) return std_logic_vector;\n      function from_slvcodec (constant slv: std_logic_vector) return t_output;\n      function to_slvcodec (constant data: t_output) return std_logic_vector is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + (1+fixed_width);\n        variable slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);\n      begin\n        slv(W1-1 downto W0) := to_slvcodec(data.o);\n        return slv; \n      end function;\n\n      function from_slvcodec (constant slv: std_logic_vector) return t_output is\n        constant W0: natural := 0;\n        constant W1: natural := W0 + (1+fixed_width);\n        variable data: t_output;\n        variable mapped: std_logic_vector(t_output_slvcodecwidth-1 downto 0);\n      begin\n        mapped := slv;\n        data.o := from_slvcodec(mapped(W1-1 downto W0)); \n        return data; \n      end function;\n      signal input_data: t_input;\n      signal output_data: t_output;\n      signal input_slv: std_logic_vector(t_input_slvcodecwidth-1 downto 0);\n      signal output_slv: std_logic_vector(t_output_slvcodecwidth-1 downto 0);\n      signal clk: std_logic;\n      signal read_clk: std_logic;\n      signal write_clk: std_logic;\n    begin\n\n      input_data <= from_slvcodec(input_slv);\n      output_slv <= to_slvcodec(output_data);\n\n      file_reader: entity work.ReadFile\n        generic map(FILENAME => OUTPUT_PATH & \"/indata.dat\",\n                    PASSED_RUNNER_CFG => RUNNER_CFG,\n                    WIDTH => t_input_slvcodecwidth)\n        port map(clk => read_clk,\n                 out_data => input_slv);\n\n      file_writer: entity work.WriteFile\n        generic map(FILENAME => OUTPUT_PATH & \"/outdata.dat\",\n                    WIDTH => t_output_slvcodecwidth)\n        port map(clk => write_clk,\n                 in_data => output_slv);\n\n      clock_generator: entity work.ClockGenerator\n        generic map(CLOCK_PERIOD => CLOCK_PERIOD,\n                    CLOCK_OFFSET => 0 ns\n                    )\n        port map(clk => clk);\n\n      read_clock_generator: entity work.ClockGenerator\n        generic map(CLOCK_PERIOD => CLOCK_PERIOD,\n                    CLOCK_OFFSET => CLOCK_PERIOD/10\n                    )\n        port map(clk => read_clk);\n\n      write_clock_generator: entity work.ClockGenerator\n        generic map(CLOCK_PERIOD => CLOCK_PERIOD,\n                    CLOCK_OFFSET => 4*CLOCK_PERIOD/10\n                    )\n        port map(clk => write_clk);\n\n      dut: entity work.complex_mag2\n        port map(\n                 i => input_data.i,\n    o => output_data.o\n                 );\n\n    end architecture;\n\n\nBut generating a test bench that just reads and writes the input and output data\nto and from files isn't particularly useful unless we have a way of generating the\ninput data, and checking the output data.  Slvcodec include tools to do this\nwith python.\n\nPython-based testing\n--------------------\n\nWe define a python class with a ``make_input_data`` method that returns an iterable of\ndictionaries specifying the input data, and a ``check_output_data`` method that receives\na list of input_data dictionaries and a list of output data dictionaries, that raises an\nexeception is the output data is incorrect.\n\n.. code:: python\n\n    class ComplexMag2Test:\n\n        def __init__(self, resolved, generics, top_params):\n            # Here we're taking advantage of the fact that when the test is intialized it\n            # has access to the parsed VHDL.  We use that to get the value of the constant\n            # FIXED_WIDTH that is defined in complex_pkg.vhd.\n            self.fixed_width = resolved['packages']['complex'].constants['fixed_width'].value()\n            self.max_fixed = pow(2, self.fixed_width-1)-1\n            self.min_fixed = -pow(2, self.fixed_width-1)\n            self.n_data = 100\n\n        def fixed_to_float(self, f):\n            r = f / pow(2, self.fixed_width-2)\n            return r\n\n        def make_input_data(self, seed=None, n_data=3000):\n            input_data = [{\n                'i': {'real': random.randint(self.min_fixed, self.max_fixed),\n                      'imag': random.randint(self.min_fixed, self.max_fixed)},\n            } for i in range(self.n_data)]\n\n            return input_data\n\n        def check_output_data(self, input_data, output_data):\n            inputs = [self.fixed_to_float(d['i']['real']) + self.fixed_to_float(d['i']['imag']) * 1j\n                      for d in input_data]\n            input_float_mag2s = [abs(v)*abs(v) for v in inputs] \n            outputs = [self.fixed_to_float(d['o']) for d in output_data]\n            differences = [abs(expected - actual) for expected, actual in zip(input_float_mag2s, outputs)]\n            allowed_error = 1/pow(2, self.fixed_width-2)\n            assert all([d < allowed_error for d in differences])\n\n\nWe then use ``slvcodec.test_utils.register_test_with_vunit`` to generate an appropriate testbench and input\ndata file, and register the produced test with vunit.  VUnit can then be run as normal.\n\n\n.. code:: python\n\n    from slvcodec import test_utils, config\n    import os\n\n    if __name__ == '__main__':\n        random.seed(0)\n        # Initialize vunit with command line parameters.\n        vu = config.setup_vunit()\n        # Set up logging.\n        config.setup_logging(vu.log_level)\n        # Get filenames for test\n        this_dir = os.path.dirname(os.path.realpath(__file__))\n        filenames = [\n            os.path.join(this_dir, 'complex_pkg.vhd'),\n            os.path.join(this_dir, 'complex_mag2.vhd'),\n            ]\n        # Register the test with VUnit.\n        test_output_directory = os.path.join(this_dir, 'generated')\n        test_utils.register_test_with_vunit(\n            vu=vu,\n            directory=test_output_directory,\n            filenames=filenames,\n            top_entity='complex_mag2',\n            all_generics=[{}],\n            test_class=ComplexMag2Test,\n            top_params={},\n            )\n        # Run the tests with VUnit\n        vu.set_sim_option('disable_ieee_warnings', True)\n        vu.main()\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Utilities for generating VHDL to convert to and from std_logic_vector, as well as utilties to create testbenches described by python.",
    "version": "0.4.14",
    "split_keywords": [
        "vhdl",
        "hdl",
        "rtl",
        "fpga",
        "asic",
        "xilinx",
        "altera"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "9b0845c3eccdb741b4f548359c8d6970",
                "sha256": "d4228830decf1540f95192e6567c68d27ba3ca1294a51a2fd601fcc6bd884d18"
            },
            "downloads": -1,
            "filename": "slvcodec-0.4.14-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9b0845c3eccdb741b4f548359c8d6970",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 81809,
            "upload_time": "2021-02-24T19:42:24",
            "upload_time_iso_8601": "2021-02-24T19:42:24.890841Z",
            "url": "https://files.pythonhosted.org/packages/85/10/9ae6f94f1e46af8a5989a808d38783ec2cba78dfb7719d5ae640e568c09f/slvcodec-0.4.14-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "e2cb4b42b2b718cbd16e28614b2e3174",
                "sha256": "2f5a1ca2d85aca16d188b8a1cbd86d7a6a9ad275a4f2ec410c98e5db6fe986f4"
            },
            "downloads": -1,
            "filename": "slvcodec-0.4.14.tar.gz",
            "has_sig": false,
            "md5_digest": "e2cb4b42b2b718cbd16e28614b2e3174",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 75491,
            "upload_time": "2021-02-24T19:42:27",
            "upload_time_iso_8601": "2021-02-24T19:42:27.732188Z",
            "url": "https://files.pythonhosted.org/packages/3e/10/24f11daaa52722db80a9a6d4860dd39d966b4644b478d1603fcbda0c3ea0/slvcodec-0.4.14.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-02-24 19:42:27",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": null,
    "github_project": "benreynwar",
    "error": "Could not fetch GitHub repository",
    "lcname": "slvcodec"
}
        
Elapsed time: 0.24568s