Verilog2001 new style port declartions for primitives.
This commit is contained in:
parent
9531920685
commit
413932e406
30
elaborate.cc
30
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<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
51
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<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
217
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<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
12
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<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.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue