Generator Parameters¶
Although it is perfectly fine to create different modules given different
generator parameters, sometimes it’s much cleaner to create a “verilog”
parameter. Using this kind of parameter reduces the number of modules
being generated and make the code more readable. An example for this usage
is configuration registers, where the register enable is on if the address
matches with a fixed value. We can of course pass the fixed value, i
into the system and make the generator name into config_ref_{i}
.
The problem comes when you have multiple configuration registers. With
kratos’ parameter feature, you can specify the fixed value as a parameter,
just as in verilog.
Examples¶
Kratos allows you to either parameterize constant values or variable widths. Although it’s more restricted than what SystemVerilog offers, it should cover the majority of use cases. You can also directly use Python’s meta-programming to parameterize your generators.
Here is the function definition for parameter
def parameter(self, name: str, width: int, default_value=0,
is_signed: bool = False)
# param is an alias of parameter
def param(self, name: str, width: int, default_value=0,
is_signed: bool = False)
Parameterize constant values¶
We can create a module that add value
to the input and then output the
sum. Here is the python code that defines a module called add_value
. Here
we created a parameter called value
.
class ParameterModule(kratos.Generator):
def __init__(self, width):
super().__init__("add_value")
in_ = self.port("in", width, kratos.PortDirection.In)
out_ = self.port("out", width, kratos.PortDirection.Out)
self.value_param = self.param("value", width, default_value=0)
self.add_stmt(out_.assign(in_ + self.value_param))
Here is the generated verilog:
module add_value (
input logic [15:0] in,
output logic [15:0] out
);
parameter value = 16'h0;
assign out = in + value;
endmodule // add_value
To use the parameter in a parent generator, you can simply set the parameter
value on that generator instance. In the following example, we set the
parameter to 42
.
class ParentModule(kratos.Generator):
def __init__(self):
super().__init__("parent")
width = 16
self.port("in", width, kratos.PortDirection.In)
self.port("out", width, kratos.PortDirection.Out)
adder = ParameterModule(width)
adder.value_param.value = 42
self.add_child("adder", adder)
self.wire(adder.ports["in"], self.ports["in"])
self.wire(self.ports["out"], adder.ports["out"])
Here is the generated verilog for the parent module:
module parent (
input logic [15:0] in,
output logic [15:0] out
);
add_value #(
.value(16'h2A)) adder (
.out(out),
.in(in)
);
endmodule // parent
Parameterize variable width¶
When you create a port or a variable from the generator, you can pass in a
parameter as width
.
Here is an example on how to use it:
mod = Generator("mod")
param = mod.param("P", 4, 4)
in_ = mod.input("in", param)
out = mod.output("out", param)
var = mod.var("v", param)
mod.wire(var, in_)
mod.wire(out, var * 2)
Here is generated SystemVerilog:
module mod #(parameter P = 4'h4)
(
input logic [P-1:0] in,
output logic [P-1:0] out
);
logic [P-1:0] v;
assign v = in;
assign out = v * 4'h2;
endmodule // mod