diff --git a/Module.cc b/Module.cc index a7e5183bc..e2a4f807f 100644 --- a/Module.cc +++ b/Module.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -104,6 +104,11 @@ perm_string Module::get_port_name(unsigned idx) const return ports[idx]->name; } +PExpr* Module::get_port_default_value(unsigned idx) const +{ + assert(idx < ports.size()); + return ports[idx] ? ports[idx]->default_value : 0; +} PGate* Module::get_gate(perm_string name) diff --git a/Module.h b/Module.h index 993a8c0df..e80b555fc 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef IVL_Module_H #define IVL_Module_H /* - * Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -60,11 +60,13 @@ class Module : public PScopeExtra, public PNamedItem { objects. Each port has a name and an ordered list of wires. The name is the means that the outside uses to access the port, the wires are the internal connections to - the port. */ + the port. In SystemVerilog, input ports may also have a + default value. */ public: struct port_t { perm_string name; vector expr; + PExpr*default_value; }; public: @@ -148,6 +150,8 @@ class Module : public PScopeExtra, public PNamedItem { // Return port name ("" for undeclared port) perm_string get_port_name(unsigned idx) const; + PExpr* get_port_default_value(unsigned idx) const; + PGate* get_gate(perm_string name); const list& get_gates() const; diff --git a/elaborate.cc b/elaborate.cc index 481092413..15ef6fce6 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1323,9 +1323,15 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const perm_string port_name = rmod->get_port_name(idx); - // Skip unconnected module ports. This happens when a - // null parameter is passed in. + // If the port is unconnected, substitute the default + // value. The parser ensures that a default value only + // exists for input ports. + if (pins[idx] == 0) + pins[idx] = rmod->get_port_default_value(idx); + // Skip unconnected module ports. This happens when a + // null parameter is passed in and there is no default + // value. if (pins[idx] == 0) { if (pins_fromwc[idx]) { diff --git a/parse.y b/parse.y index 7eaf1d20c..21d0e090d 100644 --- a/parse.y +++ b/parse.y @@ -4634,6 +4634,22 @@ port_declaration delete[]$4; $$ = ptmp; } + | attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER '=' expression + { if (!gn_system_verilog()) { + yyerror("error: Default port values require SystemVerilog."); + } + Module::port_t*ptmp; + perm_string name = lex_strings.make($5); + data_type_t*use_type = $4; + ptmp = pform_module_port_reference(name, @2.text, @2.first_line); + ptmp->default_value = $7; + pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1); + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.data_type = $4; + delete[]$5; + $$ = ptmp; + } | attribute_list_opt K_inout net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt { Module::port_t*ptmp; perm_string name = lex_strings.make($5); @@ -5972,6 +5988,7 @@ port_reference Module::port_t*ptmp = new Module::port_t; ptmp->name = perm_string(); ptmp->expr.push_back(wtmp); + ptmp->default_value = 0; delete[]$1; $$ = ptmp; @@ -5995,6 +6012,7 @@ port_reference Module::port_t*ptmp = new Module::port_t; ptmp->name = perm_string(); ptmp->expr.push_back(tmp); + ptmp->default_value = 0; delete[]$1; $$ = ptmp; } @@ -6006,6 +6024,7 @@ port_reference FILE_NAME(wtmp, @1); ptmp->name = lex_strings.make($1); ptmp->expr.push_back(wtmp); + ptmp->default_value = 0; delete[]$1; $$ = ptmp; } diff --git a/pform.cc b/pform.cc index f5ec4ff2c..dc0b84582 100644 --- a/pform.cc +++ b/pform.cc @@ -1394,6 +1394,7 @@ Module::port_t* pform_module_port_reference(perm_string name, FILE_NAME(tmp, file, lineno); ptmp->name = name; ptmp->expr.push_back(tmp); + ptmp->default_value = 0; return ptmp; }