Support for 'modports' for System Verilog interfaces

This commit is contained in:
Ruben Undheim 2018-10-12 20:58:37 +02:00
parent 75009ada3c
commit 458a94059e
8 changed files with 121 additions and 14 deletions

View File

@ -1118,7 +1118,7 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT
} }
// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces // create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail) RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail)
{ {
AstNode *new_ast = NULL; AstNode *new_ast = NULL;
std::string modname = derive_common(design, parameters, &new_ast, mayfail); std::string modname = derive_common(design, parameters, &new_ast, mayfail);
@ -1143,16 +1143,48 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
for(auto &intf : interfaces) { for(auto &intf : interfaces) {
RTLIL::Module * intfmodule = intf.second; RTLIL::Module * intfmodule = intf.second;
std::string intfname = intf.first.str(); std::string intfname = intf.first.str();
AstNode *modport = NULL;
if (modports.count(intfname) > 0) {
std::string interface_modport = modports.at(intfname).str();
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
AstNode *ast_node_of_interface = ast_module_of_interface->ast;
for (auto &ch : ast_node_of_interface->children) {
if (ch->type == AST_MODPORT) {
if (ch->str == interface_modport) {
modport = ch;
}
}
}
}
for (auto &wire_it : intfmodule->wires_){ for (auto &wire_it : intfmodule->wires_){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
std::string origname = log_id(wire_it.first); std::string origname = log_id(wire_it.first);
std::string newname = intfname + "." + origname; std::string newname = intfname + "." + origname;
wire->str = newname; wire->str = newname;
if (modport != NULL) {
bool found_in_modport = false;
for (auto &ch : modport->children) {
if (ch->type == AST_MODPORTMEMBER) {
std::string compare_name = "\\" + origname;
if (ch->str == compare_name) {
found_in_modport = true;
wire->is_input = ch->is_input;
wire->is_output = ch->is_output;
break;
}
}
}
if (found_in_modport) { // If not found in modport, do not create port
new_ast->children.push_back(wire);
}
}
else { // If no modport, set inout
wire->is_input = true; wire->is_input = true;
wire->is_output = true; wire->is_output = true;
new_ast->children.push_back(wire); new_ast->children.push_back(wire);
} }
} }
}
design->add(process_module(new_ast, false)); design->add(process_module(new_ast, false));
design->module(modname)->check(); design->module(modname)->check();

View File

@ -145,6 +145,8 @@ namespace AST
AST_INTERFACE, AST_INTERFACE,
AST_INTERFACEPORT, AST_INTERFACEPORT,
AST_INTERFACEPORTTYPE, AST_INTERFACEPORTTYPE,
AST_MODPORT,
AST_MODPORTMEMBER,
AST_PACKAGE AST_PACKAGE
}; };
@ -287,7 +289,7 @@ namespace AST
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire; bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
~AstModule() YS_OVERRIDE; ~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;
std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail); std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail);
void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE; void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
RTLIL::Module *clone() const YS_OVERRIDE; RTLIL::Module *clone() const YS_OVERRIDE;

View File

@ -853,6 +853,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENIF: case AST_GENIF:
case AST_GENCASE: case AST_GENCASE:
case AST_PACKAGE: case AST_PACKAGE:
case AST_MODPORT:
case AST_MODPORTMEMBER:
break; break;
case AST_INTERFACEPORT: { case AST_INTERFACEPORT: {
// If a port in a module with unknown type is found, mark it as "is_interface=true" // If a port in a module with unknown type is found, mark it as "is_interface=true"
@ -865,6 +867,33 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->port_input = true; wire->port_input = true;
wire->port_output = true; wire->port_output = true;
wire->set_bool_attribute("\\is_interface"); wire->set_bool_attribute("\\is_interface");
if (children.size() > 0) {
for(size_t i=0; i<children.size();i++) {
if(children[i]->type == AST_INTERFACEPORTTYPE) {
std::string name_type = children[i]->str;
size_t ndots = std::count(name_type.begin(), name_type.end(), '.');
if (ndots == 0) {
wire->attributes["\\interface_type"] = name_type;
}
else {
std::stringstream name_type_stream(name_type);
std::string segment;
std::vector<std::string> seglist;
while(std::getline(name_type_stream, segment, '.')) {
seglist.push_back(segment);
}
if (ndots == 1) {
wire->attributes["\\interface_type"] = seglist[0];
wire->attributes["\\interface_modport"] = seglist[1];
}
else {
log_error("More than two '.' in signal port type (%s)\n", name_type.c_str());
}
}
break;
}
}
}
wire->upto = 0; wire->upto = 0;
} }
break; break;

View File

@ -61,6 +61,7 @@ namespace VERILOG_FRONTEND {
bool noassert_mode, noassume_mode, norestrict_mode; bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode; bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const; bool current_wire_rand, current_wire_const;
bool current_modport_input, current_modport_output;
std::istream *lexin; std::istream *lexin;
} }
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
@ -1325,7 +1326,16 @@ opt_stmt_label:
TOK_ID ':' | /* empty */; TOK_ID ':' | /* empty */;
modport_stmt: modport_stmt:
TOK_MODPORT TOK_ID modport_args_opt ';' TOK_MODPORT TOK_ID {
AstNode *modport = new AstNode(AST_MODPORT);
ast_stack.back()->children.push_back(modport);
ast_stack.push_back(modport);
modport->str = *$2;
delete $2;
} modport_args_opt {
ast_stack.pop_back();
log_assert(ast_stack.size() == 2);
} ';'
modport_args_opt: modport_args_opt:
'(' ')' | '(' modport_args optional_comma ')'; '(' ')' | '(' modport_args optional_comma ')';
@ -1334,11 +1344,19 @@ modport_args:
modport_arg | modport_args ',' modport_arg; modport_arg | modport_args ',' modport_arg;
modport_arg: modport_arg:
modport_type_token TOK_ID | modport_type_token TOK_ID {
AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
ast_stack.back()->children.push_back(modport_member);
modport_member->str = *$2;
modport_member->is_input = current_modport_input;
modport_member->is_output = current_modport_output;
delete $2;
} |
TOK_ID TOK_ID
/* FIXME for TOK_ID without modport_type_token */
modport_type_token: modport_type_token:
TOK_INPUT | TOK_OUTPUT TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
assert: assert:
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {

View File

@ -654,7 +654,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI
} }
RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*> , bool mayfail) RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail)
{ {
if (mayfail) if (mayfail)
return RTLIL::IdString(); return RTLIL::IdString();

View File

@ -907,7 +907,7 @@ public:
Module(); Module();
virtual ~Module(); virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false);
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id); virtual size_t count_id(RTLIL::IdString id);
virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces); virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);

View File

@ -174,6 +174,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
cell->type = cell->type.str().substr(pos_type + 1); cell->type = cell->type.str().substr(pos_type + 1);
} }
dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule; dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule;
dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule;
if (design->modules_.count(cell->type) == 0) if (design->modules_.count(cell->type) == 0)
{ {
@ -224,6 +225,14 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
// some lists, so that they can be replaced further down: // some lists, so that they can be replaced further down:
for (auto &conn : cell->connections()) { for (auto &conn : cell->connections()) {
if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list
//const pool<string> &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type");
//for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module
//}
const pool<string> &interface_modport_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_modport");
std::string interface_modport = "";
for (auto &d : interface_modport_pool) {
interface_modport = "\\" + d;
}
if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) {
std::string interface_name_str = conn.second.bits()[0].wire->name.str(); std::string interface_name_str = conn.second.bits()[0].wire->name.str();
interface_name_str.replace(0,23,""); interface_name_str.replace(0,23,"");
@ -247,6 +256,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
} }
connections_to_remove.push_back(conn.first); connections_to_remove.push_back(conn.first);
interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name); interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name);
if (interface_modport != "") {
modports_used_in_submodule[conn.first] = interface_modport;
}
} }
else will_do_step = true; else will_do_step = true;
} }
@ -322,7 +334,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
continue; continue;
} }
cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule); cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule, modports_used_in_submodule);
cell->parameters.clear(); cell->parameters.clear();
did_something = true; did_something = true;

View File

@ -19,7 +19,7 @@ module TopModule(
assign MyInterfaceInstance.setting = 1; assign MyInterfaceInstance.setting = 1;
assign MyInterfaceInstance.other_setting[2:0] = 3'b101; // assign MyInterfaceInstance.other_setting[2:0] = 3'b101;
endmodule endmodule
@ -32,13 +32,25 @@ interface MyInterface #(
logic [1:0] mysig_out; logic [1:0] mysig_out;
modport submodule1 (
input setting,
output other_setting,
output mysig_out
);
modport submodule2 (
input setting,
output other_setting,
input mysig_out
);
endinterface endinterface
module SubModule1( module SubModule1(
input logic clk, input logic clk,
input logic rst, input logic rst,
MyInterface u_MyInterface, MyInterface.submodule1 u_MyInterface,
input logic [1:0] sig input logic [1:0] sig
); );
@ -68,9 +80,11 @@ module SubModule2(
input logic clk, input logic clk,
input logic rst, input logic rst,
MyInterface u_MyInterfaceInSub2, MyInterface.submodule2 u_MyInterfaceInSub2,
input logic [1:0] sig input logic [1:0] sig
); );
assign u_MyInterfaceInSub2.other_setting[2:0] = 9;
endmodule endmodule