diff --git a/Module.cc b/Module.cc index e608a6401e..774dfdbf76 100644 --- a/Module.cc +++ b/Module.cc @@ -30,6 +30,7 @@ Module::Module(perm_string n) { library_flag = false; is_cell = false; + uc_drive = UCD_NONE; default_nettype = NetNet::NONE; timescale_warn_done = false; } diff --git a/Module.h b/Module.h index a2960bc747..80d43031ac 100644 --- a/Module.h +++ b/Module.h @@ -76,6 +76,9 @@ class Module : public PScope, public LineInfo { bool is_cell; + enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; + UCDriveType uc_drive; + NetNet::Type default_nettype; /* specparams are simpler then other params, in that they have diff --git a/elaborate.cc b/elaborate.cc index e5674c4740..3dec83463f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -978,6 +978,28 @@ static bool need_bufz_for_input_port(const vector&prts) 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 * 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. if (pins[idx] == 0) { + // We need this information to support the + // unconnected_drive directive and for a + // unconnected input warning when asked for. + vector 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); + + if (tmp->port_type() == NetNet::PINPUT) { + // 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; + } - // While we're here, look to see if this - // unconnected (from the outside) port is an - // input. If so, consider printing a port binding - // warning. - if (warn_portbinding) { - vector 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); - - if (tmp->port_type() == NetNet::PINPUT) { + // Print a waring for an unconnected input. + if (warn_portbinding) { cerr << get_fileline() << ": warning: " << "Instantiating module " << rmod->mod_name() - << " with dangling input port " - << rmod->ports[idx]->name - << "." << endl; + << " with dangling input port '" + << rmod->ports[idx]->name; + 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; + } } } diff --git a/lexor.lex b/lexor.lex index 1d991563eb..6f3aa21761 100644 --- a/lexor.lex +++ b/lexor.lex @@ -80,6 +80,7 @@ static verinum*make_unsized_hex(const char*txt); static int dec_buf_div2(char *buf); static void process_timescale(const char*txt); +static void process_ucdrive(const char*txt); static list keyword_mask_stack; @@ -87,6 +88,7 @@ static int comment_enter; static bool in_module = false; static bool in_UDP = false; bool in_celldefine = false; +UCDriveType uc_drive = UCD_NONE; %} %x CCOMMENT @@ -95,6 +97,7 @@ bool in_celldefine = false; %x CSTRING %s UDPTABLE %x PPTIMESCALE +%x PPUCDRIVE %x PPDEFAULT_NETTYPE %x PPBEGIN_KEYWORDS %s EDGES @@ -392,16 +395,36 @@ S [afpnumkKMGT] pform_set_default_nettype(NetNet::WIRE, yylloc.text, yylloc.first_line); in_celldefine = false; + uc_drive = UCD_NONE; 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); } +.* { process_ucdrive(yytext); } +\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 should handle these, not an external preprocessor. */ /* From 1364-2005 Chapter 19. */ -^{W}?`nounconnected_drive{W}?.* { } ^{W}?`pragme{W}?.* { } -^{W}?`unconnected_drive{W}?.* { } /* From 1364-2005 Annex D. */ ^{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: * " xs / xs" diff --git a/parse.y b/parse.y index e24d67bbc6..ce7f66a706 100644 --- a/parse.y +++ b/parse.y @@ -1923,7 +1923,20 @@ module : attribute_list_opt module_start IDENTIFIER { pform_module_set_ports($6); } module_item_list_opt 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; } diff --git a/parse_misc.h b/parse_misc.h index 6aa623a139..0a33c6999f 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -66,5 +66,7 @@ extern unsigned error_count, warn_count; extern unsigned long based_size; extern bool in_celldefine; +enum UCDriveType { UCD_NONE, UCD_PULL0, UCD_PULL1 }; +extern UCDriveType uc_drive; #endif diff --git a/pform.cc b/pform.cc index 52dfed03cb..69ca9de365 100644 --- a/pform.cc +++ b/pform.cc @@ -467,12 +467,14 @@ void pform_module_set_ports(vector*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); perm_string mod_name = pform_cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); pform_cur_module->is_cell = in_celldefine; + pform_cur_module->uc_drive = uc_drive; map::const_iterator test = pform_modules.find(mod_name); diff --git a/pform.h b/pform.h index 92166d41bf..53e56f38e1 100644 --- a/pform.h +++ b/pform.h @@ -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, const char*file, 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*parms, svector*decl, list*table,