.. _basics:

First steps
###########

This sections demonstrates the basic features of PyStim. Before getting
started, make sure that development environment is set up to compile the
included set of examples.


Compiling examples
====================

Linux
-----------

In below examples, we will compile the example located in the :file:`examples/math_factorial` directory.
To compile we will use the Questa Sim simulator. You can use any other HDL simulator or Verilator by
running the appropriate ``./run.sh`` script followed by simulator name.


After installing the prerequisites, go to examples directory and run the following command 
inside one of the example directories:

.. code-block:: bash

    $ source ../../scripts/environment
    $ ./run.sh questa


The last line will both compile and run the example under Questa Sim.


Import and initialization conventions
=====================================

For brevity, all code examples assume that the following lines are present:

.. code-block:: systemverilog

    import pystim_pkg::*;

    typedef pystim_pkg::pystim py;

    py::initialize_interpreter();
    ...
    py::finalize_interpreter();

The :func:`pystim_pkg::initialize_interpreter` method should be invoked only once during
the simulation. It starts up the Python interpreter and sets up the environment. 
The import statement is used to bring all the PyStim classes and functions into
the current namespace. 

Some features may require additional method invocation, but those will be
specified as needed.

.. _simple_example:

Creating bindings for a simple function
=======================================

Let's start by creating Python bindings for an extremely simple function, which
returns factorial of a number. The underlying Python ``factorial`` function is part of the
``math`` module. 

.. code-block:: systemverilog

    function int factorial(int x); 
        automatic py_object result_obj;
        result_obj = py_module::import_("math").attr("factorial").call(py::int_(x));
        return result_obj.cast_int().get_value();
    endfunction


For simplicity [#f1]_, we'll put both this function and the initialization code into
a file named :file:`math_factorial.sv` with the following contents:

.. code-block:: systemverilog

    import pystim_pkg::*;

    module math_factorial();
        typedef pystim_pkg::pystim py;

        initial begin
            py::initialize_interpreter();
            $display("Result: factorial(4)  = %0d", factorial(4));
            py::finalize_interpreter();
        end

        function int factorial(int x); 
            automatic py_object result_obj;
            result_obj = py_module::import_("math").attr("factorial").call(py::int_(x));
            return result_obj.cast_int().get_value();
        endfunction
    endmodule

.. [#f1] In practice, implementation and initialization code will generally be located
         in separate files.

The :func:`py_module::import_` imports the Python module named :class:``math``.
The :func:`attr` function used to reference attribute waiting the module or class. The :func:`call` 
method invokes referenced method with the argument of type :class:`py_int`. :class:`py_int` is a SystemVerilog wrapper
for Python integer type. The :class:`py_object` :func:`cast_int` method is used to convert the return value to an :class:`py_int`
object. :class:`py_int` is a SystemVerilog wrapper for Python integer type. :func:`get_value` returns 
coresponding :class:`int` represented by :class:`py_int`. In the example above, the method  calls the function
:func:``factorial`` from the :class:``math`` module with the arguments ``x``. The :func:`py::int_` method is
used to create an SystemVerilog wrapper for Python integer type.

.. note::

    Notice how little code was needed to expose Python methods: all
    details regarding the function's parameters and return value were
    automatically inferred using template metaprogramming. This overall
    approach and the used syntax are borrowed from pybind11, though the
    underlying implementation is very different.

PyStim is a SystemVerilog package and shared library, hence it is not necessary to compile against
any special libraries and there are no intermediate (magic) translation steps.
On Linux, the above example can be compiled under Questa Sim using the following command:

.. code-block:: bash

    $ source $PY_STIM_INSTALL_DIR/scripts/environment
    $ vlog -O0 +acc  -f $PY_STIM_INSTALL_DIR/system_verilog/list/py_stim.f math_factorial.sv
    $ vsim -c -lib work math_factorial -do "run -all; quit" -l run.log -sv_lib $PY_STIM_INSTALL_DIR/lib/libpystim -gblso $PY_STIM_INSTALL_DIR/lib/libpystim.so

    # or using the run.sh script in examples/math_factorial directory

For more details on the required compiler flags on Linux for different HDL simulators, see
:ref:`compiling`. 


Building and running the above code will produce listed below output:

.. code-block:: bash
    
    Result: factorial(4)  = 24

.. _supported_types:

Supported data types
====================

A large number of data types are supported out of the box and can be used
seamlessly as functions arguments and return values.
For a full overview, see the :doc:`advanced/cast/index` section.
