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
, andunique 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.
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
.
You can check the documentation at Read the Docs.
Here are some examples to showcase the ability of kratos.
Python code that parametrizes based on the width
. Notice that we
specify the sensitivity of the always_ff
block when defining
seq_code_block
.
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
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
This is another example to showcase the kratos' ability to produce high-quality SystemVerilog. In practice we would not write it this way.
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.
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
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).
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!