From 413932e406642f71349d3a6962c7e23d0fd44888 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 8 Mar 2004 00:10:29 +0000 Subject: [PATCH] Verilog2001 new style port declartions for primitives. --- elaborate.cc | 30 ++++++- parse.y | 51 +++++++++++- pform.cc | 217 ++++++++++++++++++++++++++++++++++++--------------- pform.h | 12 ++- 4 files changed, 241 insertions(+), 69 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index d5eb40ca8..6c92c16b3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elaborate.cc,v 1.298 2004/03/07 20:04:10 steve Exp $" +#ident "$Id: elaborate.cc,v 1.299 2004/03/08 00:10:29 steve Exp $" #endif # include "config.h" @@ -792,6 +792,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const } + assert(udp); NetUDP*net = new NetUDP(scope, my_name, udp->ports.count(), udp); net->rise_time(rise_time); net->fall_time(fall_time); @@ -807,10 +808,31 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const delete[]attrib_list; + /* Handle the output port of the primitive special. It is an + output port (the only output port) so must be passed an + l-value net. */ + if (pin(0) == 0) { + cerr << get_line() << ": warning: output port unconnected." + << endl; + + } else { + NetNet*sig = pin(0)->elaborate_lnet(des, scope, true); + if (sig == 0) { + cerr << get_line() << ": error: " + << "Output port expression is not valid." << endl; + cerr << get_line() << ": : Output " + << "port of " << udp->name_ + << " is " << udp->ports[0] << "." << endl; + des->errors += 1; + } else { + connect(sig->pin(0), net->pin(0)); + } + } + /* Run through the pins, making netlists for the pin expressions and connecting them to the pin in question. All of this is independent of the nature of the UDP. */ - for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { + for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) { if (pin(idx) == 0) continue; @@ -856,6 +878,7 @@ void PGModule::elaborate(Design*des, NetScope*scope) const // Try a primitive type map::const_iterator udp = pform_primitives.find(type_); if (udp != pform_primitives.end()) { + assert((*udp).second); elaborate_udp_(des, (*udp).second, scope); return; } @@ -2584,6 +2607,9 @@ Design* elaborate(listroots) /* * $Log: elaborate.cc,v $ + * Revision 1.299 2004/03/08 00:10:29 steve + * Verilog2001 new style port declartions for primitives. + * * Revision 1.298 2004/03/07 20:04:10 steve * MOre thorough use of elab_and_eval function. * diff --git a/parse.y b/parse.y index 474b96f76..38f95ef9d 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.192 2004/02/20 18:53:35 steve Exp $" +#ident "$Id: parse.y,v 1.193 2004/03/08 00:10:29 steve Exp $" #endif # include "config.h" @@ -78,6 +78,7 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; strdup. They can be put into lists with the texts type. */ char*text; list*texts; + list*perm_strings; hname_t*hier; @@ -155,14 +156,16 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; %token KK_attribute %type number -%type signed_opt +%type signed_opt udp_reg_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry +%type udp_input_declaration_list %type udp_entry_list udp_comb_entry_list udp_sequ_entry_list %type udp_body udp_port_list %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt +%type udp_initial_expr_opt %type identifier %type register_variable @@ -3015,15 +3018,59 @@ udp_port_list } ; +udp_reg_opt: K_reg { $$ = true; } | { $$ = false; }; + +udp_initial_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + +udp_input_declaration_list + : K_input IDENTIFIER + { list*tmp = new list; + tmp->push_back(lex_strings.make($2)); + $$ = tmp; + delete[]$2; + } + | udp_input_declaration_list ',' K_input IDENTIFIER + { list*tmp = $1; + tmp->push_back(lex_strings.make($4)); + $$ = tmp; + delete[]$4; + } + ; + udp_primitive + /* This is the syntax for primitives that uses the IEEE1364-1995 + format. The ports are simply names in the port list, and the + declarations are in the body. */ + : K_primitive IDENTIFIER '(' udp_port_list ')' ';' udp_port_decls udp_init_opt udp_body K_endprimitive + { perm_string tmp2 = lex_strings.make($2); pform_make_udp(tmp2, $4, $7, $9, $8, @2.text, @2.first_line); delete[]$2; } + + /* This is the syntax for IEEE1364-2001 format definitions. The port + names and declarations are all in the parameter list. */ + + | K_primitive IDENTIFIER + '(' K_output udp_reg_opt IDENTIFIER udp_initial_expr_opt ',' + udp_input_declaration_list ')' ';' + udp_body + K_endprimitive + + { perm_string tmp2 = lex_strings.make($2); + perm_string tmp6 = lex_strings.make($6); + pform_make_udp(tmp2, $5, tmp6, $7, $9, $12, + @2.text, @2.first_line); + delete[]$2; + delete[]$6; + } ; diff --git a/pform.cc b/pform.cc index e91abc4dc..e5b6e57a1 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.cc,v 1.123 2004/02/20 18:53:35 steve Exp $" +#ident "$Id: pform.cc,v 1.124 2004/03/08 00:10:30 steve Exp $" #endif # include "config.h" @@ -323,6 +323,73 @@ PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max) return res; } +static void process_udp_table(PUdp*udp, list*table, + const char*file, unsigned lineno) +{ + const bool synchronous_flag = udp->sequential; + + /* Interpret and check the table entry strings, to make sure + they correspond to the inputs, output and output type. Make + up vectors for the fully interpreted result that can be + placed in the PUdp object. + + The table strings are made up by the parser to be two or + three substrings seperated by ';', i.e.: + + 0101:1:1 (synchronous device entry) + 0101:0 (combinational device entry) + + The parser doesn't check that we got the right kind here, + so this loop must watch out. */ + svector input (table->size()); + svector current (table->size()); + svector output (table->size()); + { unsigned idx = 0; + for (list::iterator cur = table->begin() + ; cur != table->end() + ; cur ++, idx += 1) { + string tmp = *cur; + + /* Pull the input values from the string. */ + assert(tmp.find(':') == (udp->ports.count() - 1)); + input[idx] = tmp.substr(0, udp->ports.count()-1); + tmp = tmp.substr(udp->ports.count()-1); + + assert(tmp[0] == ':'); + + /* If this is a synchronous device, get the current + output string. */ + if (synchronous_flag) { + if (tmp.size() != 4) { + cerr << file<<":"<tinput = input; + udp->tcurrent = current; + udp->toutput = output; +} + void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init_expr, @@ -462,66 +529,6 @@ void pform_make_udp(perm_string name, list*parms, return; } - bool synchronous_flag = pins[0]->get_wire_type() == NetNet::REG; - - /* Interpret and check the table entry strings, to make sure - they correspond to the inputs, output and output type. Make - up vectors for the fully interpreted result that can be - placed in the PUdp object. - - The table strings are made up by the parser to be two or - three substrings seperated by ';', i.e.: - - 0101:1:1 (synchronous device entry) - 0101:0 (combinational device entry) - - The parser doesn't check that we got the right kind here, - so this loop must watch out. */ - svector input (table->size()); - svector current (table->size()); - svector output (table->size()); - { unsigned idx = 0; - for (list::iterator cur = table->begin() - ; cur != table->end() - ; cur ++, idx += 1) { - string tmp = *cur; - - /* Pull the input values from the string. */ - assert(tmp.find(':') == (pins.count() - 1)); - input[idx] = tmp.substr(0, pins.count()-1); - tmp = tmp.substr(pins.count()-1); - - assert(tmp[0] == ':'); - - /* If this is a synchronous device, get the current - output string. */ - if (synchronous_flag) { - if (tmp.size() != 4) { - cerr << file<<":"<*parms, for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) udp->ports[idx] = pins[idx]->path().peek_name(0); - udp->tinput = input; - udp->tcurrent = current; - udp->toutput = output; + process_udp_table(udp, table, file, lineno); udp->initial = init; pform_primitives[name] = udp; @@ -577,6 +582,87 @@ void pform_make_udp(perm_string name, list*parms, delete init_expr; } +void pform_make_udp(perm_string name, bool synchronous_flag, + perm_string out_name, PExpr*init_expr, + list*parms, list*table, + const char*file, unsigned lineno) +{ + + svector pins(parms->size() + 1); + + /* Make the PWire for the output port. */ + pins[0] = new PWire(hier_name(out_name), + synchronous_flag? NetNet::REG : NetNet::WIRE, + NetNet::POUTPUT); + pins[0]->set_file(file); + pins[0]->set_lineno(lineno); + + /* Make the PWire objects for the input ports. */ + { list::iterator cur; + unsigned idx; + for (cur = parms->begin(), idx = 1 + ; cur != parms->end() + ; idx += 1, cur++) { + assert(idx < pins.count()); + pins[idx] = new PWire(hier_name(*cur), + NetNet::WIRE, + NetNet::PINPUT); + pins[idx]->set_file(file); + pins[idx]->set_lineno(lineno); + } + assert(idx == pins.count()); + } + + /* Verify the initial expression, if present, to be sure that + it only assigns to the output and the output is + registered. Then save the initial value that I get. */ + verinum::V init = verinum::Vx; + if (init_expr) { + // XXXX + assert(pins[0]->get_wire_type() == NetNet::REG); + + PAssign*pa = dynamic_cast(init_expr); + assert(pa); + + const PEIdent*id = dynamic_cast(pa->lval()); + assert(id); + + // XXXX + //assert(id->name() == pins[0]->name()); + + const PENumber*np = dynamic_cast(pa->rval()); + assert(np); + + init = np->value()[0]; + } + + // Put the primitive into the primitives table + if (pform_primitives[name]) { + VLerror("UDP primitive already exists."); + + } else { + PUdp*udp = new PUdp(name, pins.count()); + + // Detect sequential udp. + udp->sequential = synchronous_flag; + + // Make the port list for the UDP + for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) + udp->ports[idx] = pins[idx]->path().peek_name(0); + + assert(udp); + assert(table); + process_udp_table(udp, table, file, lineno); + udp->initial = init; + + pform_primitives[name] = udp; + } + + delete parms; + delete table; + delete init_expr; +} + /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, @@ -1519,6 +1605,9 @@ int pform_parse(const char*path, FILE*file) /* * $Log: pform.cc,v $ + * Revision 1.124 2004/03/08 00:10:30 steve + * Verilog2001 new style port declartions for primitives. + * * Revision 1.123 2004/02/20 18:53:35 steve * Addtrbute keys are perm_strings. * diff --git a/pform.h b/pform.h index 1fc3afa37..5399cd7e8 100644 --- a/pform.h +++ b/pform.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.h,v 1.76 2004/02/20 18:53:35 steve Exp $" +#ident "$Id: pform.h,v 1.77 2004/03/08 00:10:30 steve Exp $" #endif # include "netlist.h" @@ -142,6 +142,13 @@ extern void pform_make_udp(perm_string name, list*parms, Statement*init, const char*file, unsigned lineno); +extern void pform_make_udp(perm_string name, + bool sync_flag, perm_string out_name, + PExpr*sync_init, + list*parms, + list*table, + const char*file, unsigned lineno); + /* * Enter/exit name scopes. The push_scope function pushes the scope * name string onto the scope hierarchy. The pop pulls it off and @@ -283,6 +290,9 @@ extern void pform_dump(ostream&out, Module*mod); /* * $Log: pform.h,v $ + * Revision 1.77 2004/03/08 00:10:30 steve + * Verilog2001 new style port declartions for primitives. + * * Revision 1.76 2004/02/20 18:53:35 steve * Addtrbute keys are perm_strings. *