Add support for module input port default values (issue #489).

This commit is contained in:
Martin Whitaker 2021-03-10 08:21:42 +00:00
parent 60a77b08d2
commit c7eaa06a2b
5 changed files with 40 additions and 5 deletions

View File

@ -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)

View File

@ -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<PEIdent*> 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<PGate*>& get_gates() const;

View File

@ -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]) {

19
parse.y
View File

@ -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;
}

View File

@ -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;
}