kratos 0.1.3
Kratos is a fast hardware design language embedded in Python
Requires Python: >=3.6

Kratos
======

|Build Status| |Appveyor Build status| |PyPI - Version|
|Coverage| |Documentation Status|

Kratos is a hardware design language written in C++/Python. It
differentiates itself from other DSL with the following design
philosophy:

- Fully debuggable: debug hardware just like debugging Python code!
  Thanks to `hgdb`_.
- Highly efficient: Python frontend powered by
  Modern C++ binding. Designed with multi-processing in mind.
- Human-readable verilog: we know how difficult it is to read machine
  generated verilog. kratos has multiple passes to produce nice-looking
  verilog.
- Generator of generators: every python object is a generator
  that can be modified at any time, even after instantiation. This allows
  complex passes on the generators without ripping old structure apart.
- Keep the good parts of SystemVerilog, such as ``always_ff``,
  ``always_comb``, ``interface``, and ``unique case``. Users control
  how and when to generate these semantics.
- Single source of truth: kratos encourages users to infuse generator
  information inside generator itself. This makes debugging and
  verification much easier.
- Static elaboration: kratos allows user to write parametrized code,
  even in the ``always`` block, all in Python.
- Type checking: kratos check the variable types
  for each assignment to make sure there is no implicit conversion.

Install
-------

::

   pip install kratos

Pre-built wheels support all Python 3.6+ on Linux, Windows, and
OSX. To build it from scratch, you need a ``C++17`` compatible
compiler, such as ``g++-8`` or ``clang-8``.

Documentation and Examples
--------------------------

You can check the documentation at `Read the
Docs <https://kratos-doc.readthedocs.io/en/latest/>`__.

Here are some examples to showcase the ability of kratos.

Async Reset Register
~~~~~~~~~~~~~~~~~~~~

Python code that parametrizes based on the ``width``. Notice that we
specify the sensitivity of the ``always_ff`` block when defining
``seq_code_block``.

.. code:: python

   class AsyncReg(Generator):
       def __init__(self, width):
           super().__init__("register")

           # define inputs and outputs
           self._in = self.input("in", width)
           self._out = self.output("out", width)
           self._clk = self.clock("clk")
           self._rst = self.reset("rst")

           # add combination and sequential blocks
           self.add_code(self.seq_code_block)

       @always_ff((posedge, "clk"), (posedge, "rst"))
       def seq_code_block(self):
           if self._rst:
               self._out = 0
           else:
               self._out = self._in

Here is the generated SystemVerilog

.. code:: SystemVerilog

   module register (
     input logic clk,
     input logic [15:0] in,
     output logic [15:0] out,
     input logic rst
   );


   always_ff @(posedge clk, posedge rst) begin
     if (rst) begin
       out <= 16'h0;
     end
     else out <= in;
   end
   endmodule   // register


Fanout module
~~~~~~~~~~~~~

This is another example to showcase the kratos' ability to produce high-quality
SystemVerilog. In practice we would not write it this way.

.. code:: python

   class PassThrough(Generator):
       def __init__(self, num_loop):
           super().__init__("PassThrough")
           self.in_ = self.input("in", 1)
           self.out_ = self.output("out", num_loop)
           self.num_loop = num_loop

           self.add_code(self.code)

       @always_comb
       def code(self):
           if self.in_:
               for i in range(self.num_loop):
                   self.out_[i] = 1
           else:
               for i in range(self.num_loop):
                   self.out_[i] = 0

Here is generated SystemVerilog. Notice that the iteration variable ``i``
has been properly checked and resized to avoid index out of range.

.. code:: SystemVerilog

  module PassThrough (
    input logic in,
    output logic [3:0] out
  );

  always_comb begin
    if (in) begin
      for (int unsigned i = 0; i < 4; i += 1) begin
          out[2'(i)] = 1'h1;
        end
    end
    else begin
      for (int unsigned i = 0; i < 4; i += 1) begin
          out[2'(i)] = 1'h0;
        end
    end
  end
  endmodule   // PassThrough


How to debug
------------

Because Python is quite slow, By default the debug option is off. You
can turn on debugging for individual modules. See
``tests/test_generator.py`` for more details).


Use an IDE Debugger
-------------------

.. image:: https://cdn.jsdelivr.net/gh/Kuree/kratos-vscode@master/images/demo.gif
     :alt: demo

Thanks to the native support of `hgdb`_, you can debug the generated RTL with a
professional debugger as if you are debugging Python code. ``gdb``-like console version
is also available. Check out `hgdb`_ to see how it works!



.. |Build Status| image:: https://github.com/Kuree/kratos/workflows/Linux%20Wheel%20Test/badge.svg
   :target: https://github.com/Kuree/kratos/actions
.. |Appveyor Build status| image:: https://ci.appveyor.com/api/projects/status/en1u36q9tdqbaoh9/branch/master?svg=true
   :target: https://ci.appveyor.com/project/Kuree/kratos/branch/master
.. |PyPI - Version| image:: https://badge.fury.io/py/kratos.svg
   :target: https://pypi.org/project/kratos/
.. |Coverage| image:: https://codecov.io/gh/Kuree/kratos/branch/master/graph/badge.svg
  :target: https://codecov.io/gh/Kuree/kratos
.. |Documentation Status| image:: https://readthedocs.org/projects/kratos-doc/badge/?version=latest
   :target: https://kratos-doc.readthedocs.io/en/latest/?badge=latest
.. _hgdb: https://github.com/Kuree/hgdb