Parse UDP primitives all the way to pform.

This commit is contained in:
steve 1998-11-25 02:35:53 +00:00
parent af8d6fbf01
commit 91aad30e1f
7 changed files with 462 additions and 29 deletions

80
PUdp.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef __PUdp_H
#define __PUdp_H
/*
* Copyright (c) 1998 Stephen Williams (steve@picturel.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PUdp.h,v 1.1 1998/11/25 02:35:53 steve Exp $"
#endif
# include <vector>
# include "verinum.h"
/*
* This class represents a parsed UDP. This is a much simpler object
* then a module or macromodule.
*
* - all ports are scaler,
* - pin 0 (the first port) is always output,
* and the remaining pins are input.
*
* Thus, the ports can be represented as an ordered list of pin names.
* If the output port is declared as a register in the Verilog source,
* then this is a sequential UDP and the sequential flag is set to true.
*
* STATE TABLE
* Each entry in the state table is given as a string with the same
* number of characters as inputs. If the UDP is sequential, a
* character is also included at the end of the string to represent
* the current output.
*
* If the UDP is sequential, the "initial" member is taken to be the
* intial value assigned in the source, or 'x' if none is given.
*/
class PUdp {
public:
explicit PUdp(const string&n, unsigned nports)
: ports(nports), sequential(false), initial(verinum::Vx), name_(n) { }
vector<string>ports;
bool sequential;
vector<string>tinput;
vector<char> tcurrent;
vector<char> toutput;
verinum::V initial;
void dump(ostream&out) const;
private:
const string name_;
private: // Not implemented
PUdp(const PUdp&);
PUdp& operator= (const PUdp&);
};
/*
* $Log: PUdp.h,v $
* Revision 1.1 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
*/
#endif

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.4 1998/11/23 00:20:23 steve Exp $"
#ident "$Id: lexor.lex,v 1.5 1998/11/25 02:35:53 steve Exp $"
#endif
//# define YYSTYPE lexval
@ -55,7 +55,7 @@ static verinum*make_sized_hex(const char*txt);
[ \t\b\f\r] { ; }
\n { yylloc.first_line += 1; }
"//".* { ; }
<*>"//".* { ; }
"/*" { BEGIN(CCOMMENT); }
<CCOMMENT>. { yymore(); }
@ -82,7 +82,14 @@ static verinum*make_sized_hex(const char*txt);
return STRING; }
<CSTRING>. { yymore(); }
<UDPTABLE>[xXbB01\?] { return yytext[0]; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>[bB] { return 'b'; }
<UDPTABLE>[fF] { return 'f'; }
<UDPTABLE>[rR] { return 'r'; }
<UDPTABLE>[xX] { return 'x'; }
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
[a-zA-Z_][a-zA-Z0-9$_]* {
int rc = check_identifier(yytext);
@ -103,13 +110,13 @@ static verinum*make_sized_hex(const char*txt);
yylval.text = new string(yytext);
return SYSTEM_IDENTIFIER; }
([0-9][0-9_])?\'d[0-9][0-9_]* { yylval.number = 0;
[0-9][0-9_]*\'d[0-9][0-9_]* { yylval.number = 0;
return NUMBER; }
([0-9][0-9_])?\'[bB][0-1xz_]+ { yylval.number = make_sized_binary(yytext);
[0-9][0-9_]*\'[bB][0-1xz_]+ { yylval.number = make_sized_binary(yytext);
return NUMBER; }
([0-9][0-9_])?\'[oO][0-7xz_]+ { yylval.number = make_sized_octal(yytext);
[0-9][0-9_]*\'[oO][0-7xz_]+ { yylval.number = make_sized_octal(yytext);
return NUMBER; }
([0-9][0-9_])?\'[hH][0-9a-fA-Fxz_]+ { yylval.number = make_sized_hex(yytext);
[0-9][0-9_]*\'[hH][0-9a-fA-Fxz_]+ { yylval.number = make_sized_hex(yytext);
return NUMBER; }
[0-9][0-9_]* {
@ -275,7 +282,7 @@ static verinum*make_sized_binary(const char*txt)
verinum::V*bits = new verinum::V[size];
unsigned idx = size;
unsigned idx = 0;
char*eptr = ptr + strlen(ptr) - 1;
while ((eptr > ptr) && (idx < size)) {
@ -306,7 +313,7 @@ static verinum*make_sized_binary(const char*txt)
// Zero-extend binary number, except that z or x is extended
// if it is the highest supplied digit.
while (idx > 0) {
while (idx < size) {
switch (ptr[1]) {
case '0':
case '1':
@ -336,7 +343,7 @@ static verinum*make_sized_octal(const char*txt)
verinum::V*bits = new verinum::V[size];
unsigned idx = size;
unsigned idx = 0;
char*eptr = ptr + strlen(ptr);
while ((eptr > ptr) && (idx < (size-3))) {
@ -363,7 +370,7 @@ static verinum*make_sized_octal(const char*txt)
}
// zero extend octal numbers
while (idx > 0) switch (ptr[1]) {
while (idx < size) switch (ptr[1]) {
case 'x':
bits[idx++] = verinum::Vx;
break;
@ -387,7 +394,7 @@ static verinum*make_sized_hex(const char*txt)
verinum::V*bits = new verinum::V[size];
unsigned idx = size;
unsigned idx = 0;
char*eptr = ptr + strlen(ptr);
while ((eptr > ptr) && (idx < (size-4))) {
@ -428,7 +435,7 @@ static verinum*make_sized_hex(const char*txt)
}
// zero extend octal numbers
while (idx > 0) switch (ptr[1]) {
while (idx < size) switch (ptr[1]) {
case 'x':
bits[idx++] = verinum::Vx;
break;

16
main.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.5 1998/11/18 04:25:22 steve Exp $"
#ident "$Id: main.cc,v 1.6 1998/11/25 02:35:53 steve Exp $"
#endif
# include <stdio.h>
@ -155,7 +155,8 @@ int main(int argc, char*argv[])
/* Parse the input. Make the pform. */
list<Module*>modules;
int rc = pform_parse(input, modules);
map<string,PUdp*>primitives;
int rc = pform_parse(input, modules, primitives);
if (rc) {
return rc;
@ -163,12 +164,18 @@ int main(int argc, char*argv[])
if (dump_flag) {
ofstream out ("a.pf");
out << "PFORM DUMP:" << endl;
out << "PFORM DUMP MODULES:" << endl;
for (list<Module*>::iterator mod = modules.begin()
; mod != modules.end()
; mod ++ ) {
pform_dump(out, *mod);
}
out << "PFORM DUMP PRIMITIVES:" << endl;
for (map<string,PUdp*>::iterator idx = primitives.begin()
; idx != primitives.end()
; idx ++ ) {
(*idx).second->dump(out);
}
}
@ -219,6 +226,9 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.6 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.5 1998/11/18 04:25:22 steve
* Add -f flags for generic flag key/values.
*

140
parse.y
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.6 1998/11/23 00:20:23 steve Exp $"
#ident "$Id: parse.y,v 1.7 1998/11/25 02:35:53 steve Exp $"
#endif
# include "parse_misc.h"
@ -30,6 +30,7 @@ extern void lex_end_table();
%}
%union {
char letter;
string*text;
list<string>*strings;
@ -74,6 +75,13 @@ extern void lex_end_table();
%token KK_attribute
%type <letter> udp_input_sym udp_output_sym
%type <text> udp_input_list udp_sequ_entry udp_comb_entry
%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 <text> identifier lvalue register_variable
%type <strings> list_of_register_variables
%type <strings> list_of_variables
@ -622,46 +630,162 @@ statement_opt
udp_body
: K_table { lex_start_table(); }
udp_comb_entry_list
K_endtable { lex_end_table(); }
udp_entry_list
K_endtable { lex_end_table(); $$ = $3; }
;
udp_entry_list
: udp_comb_entry_list
| udp_sequ_entry_list
;
udp_comb_entry
: udp_input_list ':' udp_output_sym ';'
{ string*tmp = $1;
*tmp += ':';
*tmp += $3;
$$ = tmp;
}
;
udp_comb_entry_list
: udp_comb_entry
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_comb_entry_list udp_comb_entry
{ list<string>*tmp = $1;
tmp->push_back(*$2);
delete $2;
$$ = tmp;
}
;
udp_sequ_entry_list
: udp_sequ_entry
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_sequ_entry_list udp_sequ_entry
{ list<string>*tmp = $1;
tmp->push_back(*$2);
delete $2;
$$ = tmp;
}
;
udp_sequ_entry
: udp_input_list ':' udp_input_sym ':' udp_output_sym ';'
{ string*tmp = $1;
*tmp += ':';
*tmp += $3;
*tmp += ':';
*tmp += $5;
$$ = tmp;
}
;
udp_initial
: K_initial IDENTIFIER '=' NUMBER ';'
{ PExpr*etmp = new PENumber($4);
PAssign*atmp = new PAssign(*$2, etmp);
delete $2;
$$ = atmp;
}
;
udp_init_opt
: udp_initial { $$ = $1; }
| { $$ = 0; }
;
udp_input_list
: udp_input_sym
{ string*tmp = new string;
*tmp += $1;
$$ = tmp;
}
| udp_input_list udp_input_sym
{ string*tmp = $1;
*tmp += $2;
$$ = tmp;
}
;
udp_input_sym : '0' | '1' | 'x' | 'X' | '?' | 'b' | 'B' ;
udp_output_sym : '0' | '1' | 'x' | 'X' ;
udp_input_sym
: '0' { $$ = '0'; }
| '1' { $$ = '1'; }
| 'x' { $$ = 'x'; }
| '?' { $$ = '?'; }
| 'b' { $$ = 'b'; }
| '*' { $$ = '*'; }
| 'f' { $$ = 'f'; }
| 'r' { $$ = 'f'; }
;
udp_output_sym
: '0' { $$ = '0'; }
| '1' { $$ = '1'; }
| 'x' { $$ = 'x'; }
| '-' { $$ = '-'; }
;
udp_port_decl
: K_input list_of_variables ';'
{ $$ = pform_make_udp_input_ports($2); }
| K_output IDENTIFIER ';'
{ PWire*pp = new PWire(*$2);
pp->port_type = NetNet::POUTPUT;
list<PWire*>*tmp = new list<PWire*>;
tmp->push_back(pp);
delete $2;
$$ = tmp;
}
| K_reg IDENTIFIER ';'
{ PWire*pp = new PWire(*$2, NetNet::REG);
pp->port_type = NetNet::PIMPLICIT;
list<PWire*>*tmp = new list<PWire*>;
tmp->push_back(pp);
delete $2;
$$ = tmp;
}
;
udp_port_decls
: udp_port_decl
{ $$ = $1; }
| udp_port_decls udp_port_decl
{ list<PWire*>*tmp = $1;
tmp->merge(*$2);
delete $2;
$$ = tmp;
}
;
udp_port_list
: IDENTIFIER { ; }
| udp_port_list ',' IDENTIFIER { ; }
: IDENTIFIER
{ list<string>*tmp = new list<string>;
tmp->push_back(*$1);
delete $1;
$$ = tmp;
}
| udp_port_list ',' IDENTIFIER
{ list<string>*tmp = $1;
tmp->push_back(*$3);
delete $3;
$$ = tmp;
}
;
udp_primitive
: K_primitive IDENTIFIER '(' udp_port_list ')' ';'
udp_port_decls
udp_init_opt
udp_body
K_endprimitive
{ yyerror(@1, "Sorry, UDP primitives not supported."); }
{ pform_make_udp($2, $4, $7, $9, $8); }
;

173
pform.cc
View File

@ -17,12 +17,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.4 1998/11/23 00:20:23 steve Exp $"
#ident "$Id: pform.cc,v 1.5 1998/11/25 02:35:53 steve Exp $"
#endif
# include "pform.h"
# include "parse_misc.h"
# include "PUdp.h"
# include <list>
# include <map>
# include <assert.h>
# include <typeinfo>
@ -31,6 +33,7 @@ extern int VLparse();
static Module*cur_module = 0;
static list<Module*>*vl_modules = 0;
static map<string,PUdp*> vl_primitives;
/*
* This function evaluates delay expressions. The result should be a
@ -74,6 +77,151 @@ void pform_endmodule(const string&name)
cur_module = 0;
}
void pform_make_udp(string*name, list<string>*parms,
list<PWire*>*decl, list<string>*table,
Statement*init_expr)
{
assert(parms->size() > 0);
/* Put the declarations into a map, so that I can check them
off with the parameters in the list. I will rebuild a list
of parameters for the PUdp object. */
map<string,PWire*> defs;
for (list<PWire*>::iterator cur = decl->begin()
; cur != decl->end()
; cur ++ )
if (defs[(*cur)->name] == 0) {
defs[(*cur)->name] = *cur;
} else switch ((*cur)->port_type) {
case NetNet::PIMPLICIT:
case NetNet::POUTPUT:
assert(defs[(*cur)->name]->port_type != NetNet::PINPUT);
// OK, merge the output definitions.
defs[(*cur)->name]->port_type = NetNet::POUTPUT;
if ((*cur)->type == NetNet::REG)
defs[(*cur)->name]->type = NetNet::REG;
break;
case NetNet::PINPUT:
// Allow duplicate input declarations.
assert(defs[(*cur)->name]->port_type == NetNet::PINPUT);
delete *cur;
break;
default:
assert(0);
}
/* Put the parameters into a vector of wire descriptions. Look
in the map for the definitions of the name. */
vector<PWire*> pins (parms->size());
{ list<string>::iterator cur;
unsigned idx;
for (cur = parms->begin(), idx = 0
; cur != parms->end()
; idx++, cur++) {
pins[idx] = defs[*cur];
}
}
/* Check that the output is an output and the inputs are
inputs. I can also make sure that only the single output is
declared a register, if anything. */
assert(pins.size() > 0);
assert(pins[0]);
assert(pins[0]->port_type == NetNet::POUTPUT);
for (unsigned idx = 1 ; idx < pins.size() ; idx += 1) {
assert(pins[idx]);
assert(pins[idx]->port_type == NetNet::PINPUT);
assert(pins[idx]->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. */
vector<string> input (table->size());
vector<char> current (table->size());
vector<char> output (table->size());
{ unsigned idx = 0;
for (list<string>::iterator cur = table->begin()
; cur != table->end()
; cur ++, idx += 1) {
string tmp = *cur;
assert(tmp.find(':') == (pins.size() - 1));
input[idx] = tmp.substr(0, pins.size()-1);
tmp = tmp.substr(pins.size()-1);
if (pins[0]->type == NetNet::REG) {
assert(tmp[0] == ':');
assert(tmp.size() == 4);
current[idx] = tmp[1];
tmp = tmp.substr(2);
}
assert(tmp[0] == ':');
assert(tmp.size() == 2);
output[idx] = tmp[1];
}
}
/* Verify the "initial" statement, if present, to be sure that
it only assignes 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]->type == NetNet::REG);
PAssign*pa = dynamic_cast<PAssign*>(init_expr);
assert(pa);
// XXXX
assert(pa->lval() == pins[0]->name);
const PENumber*np = dynamic_cast<const PENumber*>(pa->get_expr());
assert(np);
init = np->value()[0];
}
// Put the primitive into the primitives table
if (vl_primitives[*name]) {
VLerror("UDP primitive already exists.");
} else {
PUdp*udp = new PUdp(*name, parms->size());
// Detect sequential udp.
if (pins[0]->type == NetNet::REG)
udp->sequential = true;
// Make the port list for the UDP
for (unsigned idx = 0 ; idx < pins.size() ; idx += 1)
udp->ports[idx] = pins[idx]->name;
udp->tinput = input;
udp->tcurrent = current;
udp->toutput = output;
udp->initial = init;
vl_primitives[*name] = udp;
}
/* Delete the excess tables and lists from the parser. */
delete name;
delete parms;
delete decl;
delete table;
delete init_expr;
}
void pform_makegate(PGBuiltin::Type type,
const string&name,
const vector<PExpr*>&wires,
@ -249,6 +397,22 @@ void pform_set_net_range(list<string>*names, list<PExpr*>*range)
}
}
list<PWire*>* pform_make_udp_input_ports(list<string>*names)
{
list<PWire*>*out = new list<PWire*>;
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
PWire*pp = new PWire(*cur);
pp->port_type = NetNet::PINPUT;
out->push_back(pp);
}
delete names;
return out;
}
void pform_make_behavior(PProcess::Type type, Statement*st)
{
PProcess*pp = new PProcess(type, st);
@ -284,7 +448,7 @@ Statement* pform_make_calltask(string*name, list<PExpr*>*parms)
}
FILE*vl_input = 0;
int pform_parse(FILE*input, list<Module*>&modules)
int pform_parse(FILE*input, list<Module*>&modules, map<string,PUdp*>&prim)
{
vl_input = input;
vl_modules = &modules;
@ -294,12 +458,17 @@ int pform_parse(FILE*input, list<Module*>&modules)
if (rc) {
cerr << "I give up." << endl;
}
prim = vl_primitives;
return error_count;
}
/*
* $Log: pform.cc,v $
* Revision 1.5 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.4 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,

14
pform.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.h,v 1.2 1998/11/23 00:20:23 steve Exp $"
#ident "$Id: pform.h,v 1.3 1998/11/25 02:35:53 steve Exp $"
#endif
# include "netlist.h"
@ -27,6 +27,7 @@
# include "Statement.h"
# include "PGate.h"
# include "PExpr.h"
# include "PUdp.h"
# include "PWire.h"
# include "verinum.h"
# include <iostream.h>
@ -77,6 +78,10 @@ struct lgate {
extern void pform_startmodule(const string&, list<PWire*>*ports);
extern void pform_endmodule(const string&);
extern void pform_make_udp(string*name, list<string>*parms,
list<PWire*>*decl, list<string>*table,
Statement*init);
/*
* The makewire functions announce to the pform code new wires. These
* go into a module that is currently opened.
@ -92,6 +97,8 @@ extern Statement* pform_make_block(PBlock::BL_TYPE, list<Statement*>*);
extern Statement* pform_make_assignment(string*t, PExpr*e);
extern Statement* pform_make_calltask(string*t, list<PExpr*>* =0);
extern list<PWire*>* pform_make_udp_input_ports(list<string>*);
/*
* The makegate function creates a new gate (which need not have a
* name) and connects it to the specified wires.
@ -117,11 +124,14 @@ extern void pform_make_pgassign(const string&lval, PExpr*sel, PExpr*rval);
* parses the source file and places all the modules it finds into the
* mod list. The dump function dumps a module to the output stream.
*/
extern int pform_parse(FILE*, list<Module*>&mod);
extern int pform_parse(FILE*, list<Module*>&mod, map<string,PUdp*>&prim);
extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.3 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.2 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform_dump.cc,v 1.5 1998/11/23 00:20:23 steve Exp $"
#ident "$Id: pform_dump.cc,v 1.6 1998/11/25 02:35:54 steve Exp $"
#endif
/*
@ -332,9 +332,42 @@ void pform_dump(ostream&out, Module*mod)
out << "endmodule" << endl;
}
void PUdp::dump(ostream&out) const
{
out << "primitive " << name_ << "(" << ports[0];
for (unsigned idx = 1 ; idx < ports.size() ; idx += 1)
out << ", " << ports[idx];
out << ");" << endl;
if (sequential)
out << " reg " << ports[0] << ";" << endl;
out << " table" << endl;
for (unsigned idx = 0 ; idx < tinput.size() ; idx += 1) {
out << " ";
for (unsigned chr = 0 ; chr < tinput[idx].length() ; chr += 1)
out << " " << tinput[idx][chr];
if (sequential)
out << " : " << tcurrent[idx];
out << " : " << toutput[idx] << " ;" << endl;
}
out << " endtable" << endl;
if (sequential)
out << " initial " << ports[0] << " = 1'b" << initial
<< ";" << endl;
out << "endprimitive" << endl;
}
/*
* $Log: pform_dump.cc,v $
* Revision 1.6 1998/11/25 02:35:54 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.5 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,