Support for 'modports' for System Verilog interfaces
authorRuben Undheim <ruben.undheim@gmail.com>
Fri, 12 Oct 2018 18:58:37 +0000 (20:58 +0200)
committerRuben Undheim <ruben.undheim@gmail.com>
Fri, 12 Oct 2018 19:11:48 +0000 (21:11 +0200)
frontends/ast/ast.cc
frontends/ast/ast.h
frontends/ast/genrtlil.cc
frontends/verilog/verilog_parser.y
kernel/rtlil.cc
kernel/rtlil.h
passes/hierarchy/hierarchy.cc
tests/simple/svinterface1.sv

index 256c08776b0c2970dddbf5bfc6b3caf063f59785..10fd5277a4b802d7cc0fee85b764a1f4fb051699 100644 (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
-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;
        std::string modname = derive_common(design, parameters, &new_ast, mayfail);
@@ -1143,14 +1143,46 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
                for(auto &intf : interfaces) {
                        RTLIL::Module * intfmodule = intf.second;
                        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_){
                                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 newname = intfname + "." + origname;
                                wire->str = newname;
-                               wire->is_input = true;
-                               wire->is_output = true;
-                               new_ast->children.push_back(wire);
+                               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_output = true;
+                                       new_ast->children.push_back(wire);
+                               }
                        }
                }
 
index 6b93832b42e74e9bba7cc71e674fdc7f2185e489..8187b1ac6b98a9bf61c0473828122d07a4092ea9 100644 (file)
@@ -145,6 +145,8 @@ namespace AST
                AST_INTERFACE,
                AST_INTERFACEPORT,
                AST_INTERFACEPORTTYPE,
+               AST_MODPORT,
+               AST_MODPORTMEMBER,
                AST_PACKAGE
        };
 
@@ -287,7 +289,7 @@ namespace AST
                bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
                ~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, 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);
                void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;
                RTLIL::Module *clone() const YS_OVERRIDE;
index 1dd1a913090fc686601c96812c50e795b9b33e05..d87163dc2e48d48f98bbd1fa9a454d7113a93822 100644 (file)
@@ -853,6 +853,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
        case AST_GENIF:
        case AST_GENCASE:
        case AST_PACKAGE:
+       case AST_MODPORT:
+       case AST_MODPORTMEMBER:
                break;
        case AST_INTERFACEPORT: {
                // 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_output = true;
                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;
                }
                break;
index 0ff5d576e0d1b3286f677a2fad092000291ca98a..a6f37008a2e2268ca0720f820c921b30a01f4416 100644 (file)
@@ -61,6 +61,7 @@ namespace VERILOG_FRONTEND {
        bool noassert_mode, noassume_mode, norestrict_mode;
        bool assume_asserts_mode, assert_assumes_mode;
        bool current_wire_rand, current_wire_const;
+       bool current_modport_input, current_modport_output;
        std::istream *lexin;
 }
 YOSYS_NAMESPACE_END
@@ -1325,7 +1326,16 @@ opt_stmt_label:
        TOK_ID ':' | /* empty */;
 
 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 optional_comma ')';
@@ -1334,11 +1344,19 @@ modport_args:
     modport_arg | modport_args ',' 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
+    /* FIXME for TOK_ID without 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:
        opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
index fadac087228d317ca164d4b4cdd0a073b756d4eb..07dd4bfa0145186b49dd856c476858b75b0d2ed7 100644 (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)
                return RTLIL::IdString();
index 8a2b0a4f3e7660df00009d633410c9c93d610bb9..276540aa174731fb7cb75251dff6371db5626586 100644 (file)
@@ -907,7 +907,7 @@ public:
        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, 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 void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces);
 
index dd43411272811d37307555442b4f7983112cc807..f2f0d6e5b210798c8beb2eca3498cb076b78d92b 100644 (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);
                }
                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)
                {
@@ -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:
                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
+                               //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")) {
                                        std::string interface_name_str = conn.second.bits()[0].wire->name.str();
                                        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);
                                                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;
                                        }
@@ -322,7 +334,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
                        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();
                did_something = true;
 
index 779d50c145c760c4337e88ac105c06b6f859b186..64383a06c5c2a4c84d2f6121dfcae71ec8423865 100644 (file)
@@ -19,7 +19,7 @@ module TopModule(
 
 
   assign MyInterfaceInstance.setting = 1;
-  assign MyInterfaceInstance.other_setting[2:0] = 3'b101;
+//  assign MyInterfaceInstance.other_setting[2:0] = 3'b101;
 
 endmodule
 
@@ -32,13 +32,25 @@ interface MyInterface #(
 
   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
 
 
 module SubModule1(
     input logic clk,
     input logic rst,
-    MyInterface u_MyInterface,
+    MyInterface.submodule1 u_MyInterface,
     input logic [1:0] sig
 
   );
@@ -68,9 +80,11 @@ module SubModule2(
 
     input logic clk,
     input logic rst,
-    MyInterface u_MyInterfaceInSub2,
+    MyInterface.submodule2 u_MyInterfaceInSub2,
     input logic [1:0] sig
 
   );
 
+   assign u_MyInterfaceInSub2.other_setting[2:0] = 9;
+
 endmodule