Packed Struct and Bundles¶
Packed Struct¶
kratos allows to use packed struct in a limited ways. For now you can only use it in ports declaration.
To create a packed struct, simply do by calling kratos.PackedStruct
constructor. For instance, if you want to create a struct called
“config_data” which has two members (16-bit wide and unsigned), you
can do
struct = PackedStruct("config_data", [("read", 16, False),
("data", 16, False)])
To use it in your generator, you can pass the definition into the
normal call [gen].input()
or [gen].output
. You can then use the name
to directly refer the members. For instance, to use the config_data
we defined above, we can do something like below, where we create
a module to slice the "data"
from the input port.
class Mod(Generator):
def __init__(self):
super().__init__("mod")
self.input("in", struct)
self.output("out", 16)
self.wire(self.ports["out"], self.ports["in"]["data"])
To generate the packed struct information, you can pass in
extract_struct=True
in the verilog
function call.
mod = Mod()
mod_src, struct_def = verilog(mod, extra_struct=True)
Port Bundles¶
Similar to pymtl and Chisel, kratos allows you to create arbitrary port
bundles with arbitrary direction within it. To create a bundle definition,
you need to subclass the PortBundle
class like the following:
class Test(PortBundle):
def __init__(self):
super().__init__()
self.input("a", 1)
self.output("b", 1)
The input()
and ouput()
interfaces are the same as that of
Generator
. To add a port bundle to the generator, you can do
self.port_bundle("in_port", Test())
where "in_port"
is the bundle port name. Notice that we need to instantiate
the object. You can also call flip
to flip the port direction in place.
For instance, you can do something like this:
p = self.port_bundle("out_port", Test().flip())
The wiring process is the same as as the packed struct. To access a
port bundle member, you can either access via []
, .
(such as p.a
), or through [gen].ports.p.a
When to use packed sturct and when to use port bundles¶
Keep in mind that in SystemVerilog there is no correspondence of a port
bundle. That means the port bundle will be flattened into normal ports
(the Python front-end does the job for you). As a result, the generated
SystemVerilog code may not be that readable. The naming scheme is
{bundle_name}_{member_name}
.
The rule of thumb is that if you want to have a mixture of input and output in your struct, use port bundle, otherwise use packed struct.
If you want better generated SystemVerilog while using port bundles, it
is highly recommended to use interface
instead. It will be compiled to
SystemVerilog interface
instead, which offers better functionality
than port bundles. You can check out more details, see Interfacce.
Note
There is a pass called change_port_bundle_struct
that can convert
port bundles into a packed struct. The only condition is that all the
ports in the bundle have to be the same direction.