Hi there,
I have a question regarding how to read from an modport that is defined in a module definition. For example, when declaring a hw.module
like this:
module {
sv.interface @interface_def{
sv.interface.signal @sig: i1
sv.interface.modport @modport_def(input @sig)
}
hw.module @MY_MODULE(%if: !sv.modport<@interface_def::@modport_def>) ...
}
I assumed that it should be possible to read the sig
signal from the modport, similar to the following Verilog code snippet:
interface interface_def;
logic sig;
modport modport_def(input sig);
endinterface
module MY_MODULE (
interface_def.modport_def if
);
logic w;
assign w = if.sig; // like this
endmodule
I think the CIRCT equivalent to read from an interface signal is the ReadInterfaceSignalOp
, which takes as inputs an InterfaceType
and a FlatSymbolRefAttr
. However, %if
is a ModportType
which is not a valid constructor parameter to the ReadInterfaceSignalOp
constructor. Am I missing something or is it not possible to write the above Verilog example in CIRCT?
Thanks in advance.
Best,
Patrick
I think the status of interface support in CIRCT is currently not complete. We added it about three years ago, for a very narrow use case, and have not added support for other reasonable use cases, like what you have in mind.
There are some tests showing what is currently supported: https://github.com/llvm/circt/blob/e1183587788ffe1d54d00825b4f87cd10d23d48a/test/Dialect/SV/interfaces.mlir#L48-L57
You can declare an interface, take a modport out of the declared interface, and pass it to an instance of an external module. So something like this:
module {
sv.interface @interface_def{
sv.interface.signal @sig: i1
sv.interface.modport @modport_def(input @sig)
}
hw.module.extern @MY_MODULE(in %if: !sv.modport<@interface_def::@modport_def>)
hw.module @TOP() {
%iface = sv.interface.instance : !sv.interface<@interface_def>
%modport = sv.modport.get %iface @modport_def : !sv.interface<@interface_def> -> !sv.modport<@interface_def::@modport_def>
hw.instance "my_module" @MY_MODULE(if: %modport : !sv.modport<@interface_def::@modport_def>) -> ()
}
}
Will produce something like this:
interface interface_def;
logic sig;
modport modport_def(input sig);
endinterface
// external module MY_MODULE
module TOP(); // iface.mlir:9:3
interface_def iface(); // iface.mlir:10:14
MY_MODULE my_module ( // iface.mlir:12:5
.if (iface.modport_def) // iface.mlir:11:16
);
endmodule
However, it seems we simply cannot express what you’re trying to do. Looks like two things are missing:
- Ability to pass an interface’s modport as the type of a
hw.module
port. We support a modport as the type of a hw.module.extern
port, but you will see an error if you change this to hw.module
. The difference is hw.module.extern
doesn’t print the types of the ports in the final verilog, but when we go to get the types of an hw.module
ports, you encounter the error since modport is not supported.
- Ability to read a signal from a modport. We have the ability to express reading a signal from an interface, but not the modport of an interface.
I also tried rewriting your example to pass the entire interface_def
as the type of your MY_MODULE’s port, which is partially supported, but reading the signal out of it within the module also triggers a crash.
Like many things in MLIR, we have added support for just what was needed by someone, and apparently no one has needed what you’re looking for. It should be relatively easy to add this support; I don’t think there is anything fundamental preventing it. To track this, I would open an issue on GitHub - llvm/circt: Circuit IR Compilers and Tools.