Verilog2001 new style port declartions for primitives.

This commit is contained in:
steve 2004-03-08 00:10:29 +00:00
parent 9531920685
commit 413932e406
4 changed files with 241 additions and 69 deletions

View File

@ -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<perm_string,PUdp*>::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(list<perm_string>roots)
/*
* $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.
*

51
parse.y
View File

@ -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<char*>*texts;
list<perm_string>*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> number
%type <flag> signed_opt
%type <flag> signed_opt udp_reg_opt
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
%type <perm_strings> udp_input_declaration_list
%type <strings> udp_entry_list udp_comb_entry_list udp_sequ_entry_list
%type <strings> udp_body udp_port_list
%type <wires> udp_port_decl udp_port_decls
%type <statement> udp_initial udp_init_opt
%type <expr> udp_initial_expr_opt
%type <hier> identifier
%type <text> 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<perm_string>*tmp = new list<perm_string>;
tmp->push_back(lex_strings.make($2));
$$ = tmp;
delete[]$2;
}
| udp_input_declaration_list ',' K_input IDENTIFIER
{ list<perm_string>*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;
}
;

217
pform.cc
View File

@ -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<string>*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<string> input (table->size());
svector<char> current (table->size());
svector<char> output (table->size());
{ unsigned idx = 0;
for (list<string>::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<<":"<<lineno << ": error: "
<< "Invalid table format for"
<< " sequential primitive." << endl;
error_count += 1;
break;
}
assert(tmp.size() == 4);
current[idx] = tmp[1];
tmp = tmp.substr(2);
} else if (tmp.size() != 2) {
cerr << file<<":"<<lineno << ": error: "
<< "Invalid table format for"
<< " combinational primitive." << endl;
error_count += 1;
break;
}
/* Finally, extract the desired output. */
assert(tmp.size() == 2);
output[idx] = tmp[1];
}
}
udp->tinput = input;
udp->tcurrent = current;
udp->toutput = output;
}
void pform_make_udp(perm_string name, list<string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init_expr,
@ -462,66 +529,6 @@ void pform_make_udp(perm_string name, list<string>*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<string> input (table->size());
svector<char> current (table->size());
svector<char> output (table->size());
{ unsigned idx = 0;
for (list<string>::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<<":"<<lineno << ": error: "
<< "Invalid table format for"
<< " sequential primitive." << endl;
error_count += 1;
local_errors += 1;
break;
}
assert(tmp.size() == 4);
current[idx] = tmp[1];
tmp = tmp.substr(2);
} else if (tmp.size() != 2) {
cerr << file<<":"<<lineno << ": error: "
<< "Invalid table format for"
<< " combinational primitive." << endl;
error_count += 1;
local_errors += 1;
break;
}
/* Finally, extract the desired output. */
assert(tmp.size() == 2);
output[idx] = tmp[1];
}
}
/* Verify the "initial" statement, if present, to be sure that
it only assigns to the output and the output is
@ -561,9 +568,7 @@ void pform_make_udp(perm_string name, list<string>*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<string>*parms,
delete init_expr;
}
void pform_make_udp(perm_string name, bool synchronous_flag,
perm_string out_name, PExpr*init_expr,
list<perm_string>*parms, list<string>*table,
const char*file, unsigned lineno)
{
svector<PWire*> 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<perm_string>::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<PAssign*>(init_expr);
assert(pa);
const PEIdent*id = dynamic_cast<const PEIdent*>(pa->lval());
assert(id);
// XXXX
//assert(id->name() == pins[0]->name());
const PENumber*np = dynamic_cast<const PENumber*>(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.
*

12
pform.h
View File

@ -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<string>*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<perm_string>*parms,
list<string>*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.
*