Add support for unconnected_drive.

Icarus has recognized this directive, but it did not do anything
with the information. This patch adds the functionality for most
common cases. It adds this by changing the input net type from
wire/tri to tri1 or tri0 depending on the pull. The issue is that
if the input net is not a wire or tri this is not safe and should
really be done as an external pull gate connected to the input.
We will need to handle this is it ever comes up. For now a sorry
message is printed.
This commit is contained in:
Cary R 2009-05-27 13:41:54 -07:00 committed by Stephen Williams
parent d345fb7654
commit bbf11b830b
8 changed files with 155 additions and 21 deletions

View File

@ -30,6 +30,7 @@ Module::Module(perm_string n)
{ {
library_flag = false; library_flag = false;
is_cell = false; is_cell = false;
uc_drive = UCD_NONE;
default_nettype = NetNet::NONE; default_nettype = NetNet::NONE;
timescale_warn_done = false; timescale_warn_done = false;
} }

View File

@ -76,6 +76,9 @@ class Module : public PScope, public LineInfo {
bool is_cell; bool is_cell;
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
UCDriveType uc_drive;
NetNet::Type default_nettype; NetNet::Type default_nettype;
/* specparams are simpler then other params, in that they have /* specparams are simpler then other params, in that they have

View File

@ -978,6 +978,28 @@ static bool need_bufz_for_input_port(const vector<NetNet*>&prts)
return false; return false;
} }
/*
* Convert a wire or tri to a tri0 or tri1 as needed to make
* an unconnected drive pull for floating inputs.
*/
static void convert_net(Design*des, const LineInfo *line,
NetNet *net, NetNet::Type type)
{
// If the types already match just return.
if (net->type() == type) return;
// We can only covert a wire or tri to have a default pull.
if (net->type() == NetNet::WIRE || net->type() == NetNet::TRI) {
net->type(type);
return;
}
// We may have to support this at some point in time!
cerr << line->get_fileline() << ": sorry: Can not pull floating "
"input type '" << net->type() << "'." << endl;
des->errors += 1;
}
/* /*
* Instantiate a module by recursively elaborating it. Set the path of * Instantiate a module by recursively elaborating it. Set the path of
* the recursive elaboration so that signal names get properly * the recursive elaboration so that signal names get properly
@ -1105,28 +1127,50 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// null parameter is passed in. // null parameter is passed in.
if (pins[idx] == 0) { if (pins[idx] == 0) {
// We need this information to support the
// unconnected_drive directive and for a
// unconnected input warning when asked for.
vector<PEIdent*> mport = rmod->get_port(idx);
if (mport.size() == 0) continue;
// While we're here, look to see if this perm_string pname = peek_tail_name(mport[0]->path());
// unconnected (from the outside) port is an
// input. If so, consider printing a port binding
// warning.
if (warn_portbinding) {
vector<PEIdent*> mport = rmod->get_port(idx);
if (mport.size() == 0)
continue;
perm_string pname = peek_tail_name(mport[0]->path()); NetNet*tmp = instance[0]->find_signal(pname);
assert(tmp);
NetNet*tmp = instance[0]->find_signal(pname); if (tmp->port_type() == NetNet::PINPUT) {
assert(tmp); // If we have an unconnected input convert it
// as needed if an unconnected_drive directive
// was given. This only works for tri or wire!
switch (rmod->uc_drive) {
case Module::UCD_PULL0:
convert_net(des, this, tmp, NetNet::TRI0);
break;
case Module::UCD_PULL1:
convert_net(des, this, tmp, NetNet::TRI1);
break;
case Module::UCD_NONE:
break;
}
if (tmp->port_type() == NetNet::PINPUT) { // Print a waring for an unconnected input.
if (warn_portbinding) {
cerr << get_fileline() << ": warning: " cerr << get_fileline() << ": warning: "
<< "Instantiating module " << "Instantiating module "
<< rmod->mod_name() << rmod->mod_name()
<< " with dangling input port " << " with dangling input port '"
<< rmod->ports[idx]->name << rmod->ports[idx]->name;
<< "." << endl; switch (rmod->uc_drive) {
case Module::UCD_PULL0:
cerr << "' (pulled low)." << endl;
break;
case Module::UCD_PULL1:
cerr << "' (pulled high)." << endl;
break;
case Module::UCD_NONE:
cerr << "' (floating)." << endl;
break;
}
} }
} }

View File

@ -80,6 +80,7 @@ static verinum*make_unsized_hex(const char*txt);
static int dec_buf_div2(char *buf); static int dec_buf_div2(char *buf);
static void process_timescale(const char*txt); static void process_timescale(const char*txt);
static void process_ucdrive(const char*txt);
static list<int> keyword_mask_stack; static list<int> keyword_mask_stack;
@ -87,6 +88,7 @@ static int comment_enter;
static bool in_module = false; static bool in_module = false;
static bool in_UDP = false; static bool in_UDP = false;
bool in_celldefine = false; bool in_celldefine = false;
UCDriveType uc_drive = UCD_NONE;
%} %}
%x CCOMMENT %x CCOMMENT
@ -95,6 +97,7 @@ bool in_celldefine = false;
%x CSTRING %x CSTRING
%s UDPTABLE %s UDPTABLE
%x PPTIMESCALE %x PPTIMESCALE
%x PPUCDRIVE
%x PPDEFAULT_NETTYPE %x PPDEFAULT_NETTYPE
%x PPBEGIN_KEYWORDS %x PPBEGIN_KEYWORDS
%s EDGES %s EDGES
@ -392,16 +395,36 @@ S [afpnumkKMGT]
pform_set_default_nettype(NetNet::WIRE, yylloc.text, pform_set_default_nettype(NetNet::WIRE, yylloc.text,
yylloc.first_line); yylloc.first_line);
in_celldefine = false; in_celldefine = false;
uc_drive = UCD_NONE;
pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); pform_set_timescale(def_ts_units, def_ts_prec, 0, 0);
/* Add `nounconnected_drive when implemented. */
} } } }
/* Notice and handle the `unconnected_drive directive. */
^{W}?`unconnected_drive { BEGIN(PPUCDRIVE); }
<PPUCDRIVE>.* { process_ucdrive(yytext); }
<PPUCDRIVE>\n {
if (in_module) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`unconnected_drive directive can not be inside a "
"module definition." << endl;
error_count += 1;
}
yylloc.first_line += 1;
BEGIN(0); }
^{W}?`nounconnected_drive{W}? {
if (in_module) {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`nounconnected_drive directive can not be inside a "
"module definition." << endl;
error_count += 1;
}
uc_drive = UCD_NONE; }
/* These are directives that I do not yet support. I think that IVL /* These are directives that I do not yet support. I think that IVL
should handle these, not an external preprocessor. */ should handle these, not an external preprocessor. */
/* From 1364-2005 Chapter 19. */ /* From 1364-2005 Chapter 19. */
^{W}?`nounconnected_drive{W}?.* { }
^{W}?`pragme{W}?.* { } ^{W}?`pragme{W}?.* { }
^{W}?`unconnected_drive{W}?.* { }
/* From 1364-2005 Annex D. */ /* From 1364-2005 Annex D. */
^{W}?`default_decay_time{W}?.* { } ^{W}?`default_decay_time{W}?.* { }
@ -1082,6 +1105,51 @@ static bool get_timescale_const(const char *&cp, int &res, bool is_unit)
} }
/*
* process either a pull0 or a pull1.
*/
static void process_ucdrive(const char*txt)
{
UCDriveType ucd = UCD_NONE;
const char*cp = txt + strspn(txt, " \t");
/* Skip the space after the `unconnected_drive directive. */
if (cp == txt) {
VLerror(yylloc, "Space required after `unconnected_drive "
"directive.");
return;
}
/* Check for the pull keyword. */
if (strncmp("pull", cp, 4) != 0) {
VLerror(yylloc, "pull required for `unconnected_drive "
"directive.");
return;
}
cp += 4;
if (*cp == '0') ucd = UCD_PULL0;
else if (*cp == '1') ucd = UCD_PULL1;
else {
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
"`unconnected_drive does not support 'pull" << *cp
<< "'." << endl;
error_count += 1;
return;
}
cp += 1;
/* Verify that only space and/or a single line comment is left. */
cp += strspn(cp, " \t");
if (strncmp(cp, "//", 2) != 0 &&
(size_t)(cp-yytext) != strlen(yytext)) {
VLerror(yylloc, "Invalid `unconnected_dirve directive (extra "
"garbage after precision).");
return;
}
uc_drive = ucd;
}
/* /*
* The timescale parameter has the form: * The timescale parameter has the form:
* " <num> xs / <num> xs" * " <num> xs / <num> xs"

15
parse.y
View File

@ -1923,7 +1923,20 @@ module : attribute_list_opt module_start IDENTIFIER
{ pform_module_set_ports($6); } { pform_module_set_ports($6); }
module_item_list_opt module_item_list_opt
K_endmodule K_endmodule
{ pform_endmodule($3, in_celldefine); { Module::UCDriveType ucd;
switch (uc_drive) {
case UCD_NONE:
default:
ucd = Module::UCD_NONE;
break;
case UCD_PULL0:
ucd = Module::UCD_PULL0;
break;
case UCD_PULL1:
ucd = Module::UCD_PULL1;
break;
}
pform_endmodule($3, in_celldefine, ucd);
delete[]$3; delete[]$3;
} }

View File

@ -66,5 +66,7 @@ extern unsigned error_count, warn_count;
extern unsigned long based_size; extern unsigned long based_size;
extern bool in_celldefine; extern bool in_celldefine;
enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 };
extern UCDriveType uc_drive;
#endif #endif

View File

@ -467,12 +467,14 @@ void pform_module_set_ports(vector<Module::port_t*>*ports)
} }
} }
void pform_endmodule(const char*name, bool in_celldefine) void pform_endmodule(const char*name, bool in_celldefine,
Module::UCDriveType uc_drive)
{ {
assert(pform_cur_module); assert(pform_cur_module);
perm_string mod_name = pform_cur_module->mod_name(); perm_string mod_name = pform_cur_module->mod_name();
assert(strcmp(name, mod_name) == 0); assert(strcmp(name, mod_name) == 0);
pform_cur_module->is_cell = in_celldefine; pform_cur_module->is_cell = in_celldefine;
pform_cur_module->uc_drive = uc_drive;
map<perm_string,Module*>::const_iterator test = map<perm_string,Module*>::const_iterator test =
pform_modules.find(mod_name); pform_modules.find(mod_name);

View File

@ -159,7 +159,8 @@ extern void pform_module_define_port(const struct vlltype&li,
extern Module::port_t* pform_module_port_reference(perm_string name, extern Module::port_t* pform_module_port_reference(perm_string name,
const char*file, const char*file,
unsigned lineno); unsigned lineno);
extern void pform_endmodule(const char*, bool in_celldefine); extern void pform_endmodule(const char*, bool in_celldefine,
Module::UCDriveType uc_drive);
extern void pform_make_udp(perm_string name, list<perm_string>*parms, extern void pform_make_udp(perm_string name, list<perm_string>*parms,
svector<PWire*>*decl, list<string>*table, svector<PWire*>*decl, list<string>*table,