iverilog/pform.cc

712 lines
19 KiB
C++
Raw Normal View History

1998-11-04 00:28:49 +01:00
/*
1999-02-15 03:06:15 +01:00
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
1998-11-04 00:28:49 +01:00
*
* 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)
1999-06-15 05:44:53 +02:00
#ident "$Id: pform.cc,v 1.27 1999/06/15 03:44:53 steve Exp $"
1998-11-04 00:28:49 +01:00
#endif
# include "compiler.h"
1998-11-04 00:28:49 +01:00
# include "pform.h"
# include "parse_misc.h"
# include "PUdp.h"
1998-11-04 00:28:49 +01:00
# include <list>
# include <map>
1998-11-04 00:28:49 +01:00
# include <assert.h>
# include <typeinfo>
# include <strstream>
1998-11-04 00:28:49 +01:00
1998-12-09 05:02:47 +01:00
/*
* The lexor accesses the vl_* variables.
*/
string vl_file = "";
1998-11-04 00:28:49 +01:00
extern int VLparse();
static Module*cur_module = 0;
static map<string,Module*> vl_modules;
static map<string,PUdp*> vl_primitives;
1998-11-04 00:28:49 +01:00
/*
* This function evaluates delay expressions. The result should be a
* simple constant that I can interpret as an unsigned number.
*/
static unsigned long evaluate_delay(PExpr*delay)
{
PENumber*pp = dynamic_cast<PENumber*>(delay);
if (pp == 0) {
VLerror("Sorry, delay expression is too complicated.");
return 0;
}
return pp->value().as_ulong();
}
1999-06-12 22:35:27 +02:00
void pform_startmodule(const string&name, svector<PWire*>*ports)
1998-11-04 00:28:49 +01:00
{
assert( cur_module == 0 );
1999-06-12 22:35:27 +02:00
cur_module = new Module(name, ports? ports->count() : 0);
1998-11-04 00:28:49 +01:00
if (ports) {
1999-06-12 22:35:27 +02:00
for (unsigned idx = 0 ; idx < ports->count() ; idx += 1) {
cur_module->add_wire((*ports)[idx]);
cur_module->ports[idx] = (*ports)[idx];
1998-11-04 00:28:49 +01:00
}
delete ports;
}
}
void pform_endmodule(const string&name)
{
assert(cur_module);
assert(name == cur_module->get_name());
vl_modules[name] = cur_module;
1998-11-04 00:28:49 +01:00
cur_module = 0;
}
bool pform_expression_is_constant(const PExpr*ex)
{
return ex->is_constant(cur_module);
}
void pform_make_udp(string*name, list<string>*parms,
1999-06-12 22:35:27 +02:00
svector<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;
1999-06-12 22:35:27 +02:00
for (unsigned idx = 0 ; idx < decl->count() ; idx += 1)
1999-06-12 22:35:27 +02:00
if (defs[(*decl)[idx]->name] == 0) {
defs[(*decl)[idx]->name] = (*decl)[idx];
1999-06-12 22:35:27 +02:00
} else switch ((*decl)[idx]->port_type) {
case NetNet::PIMPLICIT:
case NetNet::POUTPUT:
1999-06-12 22:35:27 +02:00
assert(defs[(*decl)[idx]->name]->port_type != NetNet::PINPUT);
// OK, merge the output definitions.
1999-06-12 22:35:27 +02:00
defs[(*decl)[idx]->name]->port_type = NetNet::POUTPUT;
if ((*decl)[idx]->type == NetNet::REG)
defs[(*decl)[idx]->name]->type = NetNet::REG;
break;
case NetNet::PINPUT:
// Allow duplicate input declarations.
1999-06-12 22:35:27 +02:00
assert(defs[(*decl)[idx]->name]->port_type == NetNet::PINPUT);
delete (*decl)[idx];
break;
default:
assert(0);
}
/* Put the parameters into a vector of wire descriptions. Look
in the map for the definitions of the name. */
1999-06-15 05:44:53 +02:00
svector<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. */
1999-06-15 05:44:53 +02:00
assert(pins.count() > 0);
assert(pins[0]);
assert(pins[0]->port_type == NetNet::POUTPUT);
1999-06-15 05:44:53 +02:00
for (unsigned idx = 1 ; idx < pins.count() ; 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. */
1999-06-15 05:44:53 +02:00
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;
1999-06-15 05:44:53 +02:00
assert(tmp.find(':') == (pins.count() - 1));
1999-06-15 05:44:53 +02:00
input[idx] = tmp.substr(0, pins.count()-1);
tmp = tmp.substr(pins.count()-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);
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 (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
1999-06-15 05:44:53 +02:00
for (unsigned idx = 0 ; idx < pins.count() ; 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;
}
1999-02-15 03:06:15 +01:00
/*
* pform_makegates is called when a list of gates (with the same type)
* are ready to be instantiated. The function runs through the list of
1999-05-29 04:36:17 +02:00
* gates and calls the pform_makegate function to make the individual gate.
1999-02-15 03:06:15 +01:00
*/
1998-11-04 00:28:49 +01:00
void pform_makegate(PGBuiltin::Type type,
1999-02-15 03:06:15 +01:00
unsigned long delay_val,
const lgate&info)
1998-11-04 00:28:49 +01:00
{
1999-05-29 04:36:17 +02:00
if (info.parms_by_name) {
cerr << info.file << ":" << info.lineno << ": Gates do not "
"have port names." << endl;
error_count += 1;
return;
}
PGBuiltin*cur = new PGBuiltin(type, info.name, info.parms, delay_val);
1999-02-15 03:06:15 +01:00
if (info.range[0])
cur->set_range(info.range[0], info.range[1]);
cur->set_file(info.file);
cur->set_lineno(info.lineno);
1998-11-04 00:28:49 +01:00
cur_module->add_gate(cur);
}
void pform_makegates(PGBuiltin::Type type,
1999-05-06 06:37:17 +02:00
PExpr*delay, svector<lgate>*gates)
1998-11-04 00:28:49 +01:00
{
1999-02-15 03:06:15 +01:00
unsigned long delay_val = delay? evaluate_delay(delay) : 0;
1998-11-04 00:28:49 +01:00
delete delay;
1999-05-31 17:45:59 +02:00
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
1999-05-06 06:37:17 +02:00
pform_makegate(type, delay_val, (*gates)[idx]);
1998-11-04 00:28:49 +01:00
}
delete gates;
}
1999-05-29 04:36:17 +02:00
/*
* A module is different from a gate in that there are different
* constraints, and sometimes different syntax.
*/
static void pform_make_modgate(const string&type,
const string&name,
1999-05-29 04:36:17 +02:00
svector<PExpr*>*wires,
const string&fn, unsigned ln)
1998-11-04 00:28:49 +01:00
{
1999-05-03 01:25:32 +02:00
if (name == "") {
cerr << fn << ":" << ln << ": Instantiation of " << type
<< " module requires an instance name." << endl;
error_count += 1;
return;
}
1998-11-04 00:28:49 +01:00
PGate*cur = new PGModule(type, name, wires);
cur->set_file(fn);
cur->set_lineno(ln);
1998-11-04 00:28:49 +01:00
cur_module->add_gate(cur);
}
1999-05-29 04:36:17 +02:00
static void pform_make_modgate(const string&type,
const string&name,
svector<portname_t*>*bind,
const string&fn, unsigned ln)
{
if (name == "") {
cerr << fn << ":" << ln << ": Instantiation of " << type
<< " module requires an instance name." << endl;
error_count += 1;
return;
}
unsigned npins = bind->count();
PGModule::bind_t*pins = new PGModule::bind_t[npins];
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
portname_t*curp = (*bind)[idx];
pins[idx].name = curp->name;
pins[idx].parm = curp->parm;
}
PGate*cur = new PGModule(type, name, pins, npins);
cur->set_file(fn);
cur->set_lineno(ln);
cur_module->add_gate(cur);
}
1999-05-06 06:37:17 +02:00
void pform_make_modgates(const string&type, svector<lgate>*gates)
1998-11-04 00:28:49 +01:00
{
1999-05-06 06:37:17 +02:00
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
lgate cur = (*gates)[idx];
1998-11-04 00:28:49 +01:00
1999-05-29 04:36:17 +02:00
if (cur.parms_by_name) {
pform_make_modgate(type, cur.name, cur.parms_by_name,
cur.file, cur.lineno);
} else if (cur.parms) {
pform_make_modgate(type, cur.name, cur.parms, cur.file,
cur.lineno);
} else {
1999-05-29 04:36:17 +02:00
svector<PExpr*>*wires = new svector<PExpr*>(0);
pform_make_modgate(type, cur.name, wires, cur.file,
cur.lineno);
1998-11-04 00:28:49 +01:00
}
}
delete gates;
}
PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval)
1998-11-04 00:28:49 +01:00
{
1999-05-29 04:36:17 +02:00
svector<PExpr*>*wires = new svector<PExpr*>(2);
(*wires)[0] = lval;
(*wires)[1] = rval;
1998-11-04 00:28:49 +01:00
PGAssign*cur = new PGAssign(wires);
cur_module->add_gate(cur);
return cur;
1998-11-04 00:28:49 +01:00
}
1999-06-02 17:38:46 +02:00
void pform_makewire(const vlltype&li, const string&name,
NetNet::Type type)
1998-11-04 00:28:49 +01:00
{
PWire*cur = cur_module->get_wire(name);
if (cur) {
if (cur->type != NetNet::IMPLICIT) {
strstream msg;
1999-06-02 17:38:46 +02:00
msg << name << " previously defined at " <<
cur->get_line() << ".";
VLerror(msg.str());
}
1998-11-04 00:28:49 +01:00
cur->type = type;
return;
}
cur = new PWire(name, type);
1999-06-02 17:38:46 +02:00
cur->set_file(li.text);
cur->set_lineno(li.first_line);
1998-11-04 00:28:49 +01:00
cur_module->add_wire(cur);
}
1999-06-02 17:38:46 +02:00
void pform_makewire(const vlltype&li, const list<string>*names,
NetNet::Type type)
1998-11-04 00:28:49 +01:00
{
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ )
1999-06-02 17:38:46 +02:00
pform_makewire(li, *cur, type);
1998-11-04 00:28:49 +01:00
}
void pform_set_port_type(const string&name, NetNet::PortType pt)
{
PWire*cur = cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a port.");
return;
}
if (cur->port_type != NetNet::PIMPLICIT) {
VLerror("error setting port direction.");
return;
}
cur->port_type = pt;
}
void pform_set_attrib(const string&name, const string&key, const string&value)
{
PWire*cur = cur_module->get_wire(name);
assert(cur);
cur->attributes[key] = value;
}
/*
* Set the attribute of a TYPE. This is different from an object in
* that this applies to every instantiation of the given type.
*/
void pform_set_type_attrib(const string&name, const string&key,
const string&value)
{
map<string,PUdp*>::const_iterator udp = vl_primitives.find(name);
if (udp == vl_primitives.end()) {
VLerror("type name is not (yet) defined.");
return;
}
(*udp).second ->attributes[key] = value;
}
void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
{
PWire*cur = cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a valid net.");
return;
}
assert(cur->lidx == 0);
assert(cur->ridx == 0);
cur->lidx = l;
cur->ridx = r;
}
static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
1998-11-04 00:28:49 +01:00
{
1999-06-12 05:42:17 +02:00
assert(range);
assert(range->count() == 2);
1998-11-04 00:28:49 +01:00
PWire*cur = cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a valid net.");
return;
}
if ((cur->msb == 0) && (cur->lsb == 0)){
cur->msb = (*range)[0];
cur->lsb = (*range)[1];
1998-11-04 00:28:49 +01:00
} else {
1999-06-12 22:35:27 +02:00
if (cur->msb == 0) {
VLerror(yylloc, "missing msb of range.");
return;
}
if (cur->lsb == 0) {
VLerror(yylloc, "missing lsb of range.");
return;
}
PExpr*msb = (*range)[0];
PExpr*lsb = (*range)[1];
1999-06-12 05:42:17 +02:00
assert(msb);
assert(lsb);
1999-05-06 06:09:28 +02:00
if (msb == 0) {
VLerror(yylloc, "failed to parse msb of range.");
} else if (lsb == 0) {
VLerror(yylloc, "failed to parse lsb of range.");
} else if (! (cur->msb->is_the_same(msb) &&
cur->lsb->is_the_same(lsb))) {
1999-06-12 05:42:17 +02:00
cerr << msb->get_line() << ": bit range mismatch"
" for " << name << ": [" << *msb << ":" <<
*lsb << "] != [" << *cur->msb << ":" <<
*cur->lsb << "]" << endl;
error_count += 1;
1999-05-06 06:09:28 +02:00
}
1998-11-04 00:28:49 +01:00
}
}
void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
{
assert(range->count() == 2);
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_net_range(*cur, range);
}
}
1999-02-21 18:01:57 +01:00
void pform_set_parameter(const string&name, PExpr*expr)
{
cur_module->parameters[name] = expr;
}
1998-11-04 00:28:49 +01:00
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
{
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_port_type(*cur, pt);
}
}
static void pform_set_reg_integer(const string&name)
1998-11-04 00:28:49 +01:00
{
PWire*cur = cur_module->get_wire(name);
assert(cur);
assert(cur->type == NetNet::REG);
cur->type = NetNet::INTEGER;
1998-11-04 00:28:49 +01:00
cur->msb = new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH));
cur->lsb = new PENumber(new verinum(0UL, INTEGER_WIDTH));
}
void pform_set_reg_integer(list<string>*names)
{
1998-11-04 00:28:49 +01:00
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
pform_set_reg_integer(*cur);
1998-11-04 00:28:49 +01:00
}
}
1999-06-12 22:35:27 +02:00
svector<PWire*>* pform_make_udp_input_ports(list<string>*names)
{
1999-06-12 22:35:27 +02:00
svector<PWire*>*out = new svector<PWire*>(names->size());
1999-06-12 22:35:27 +02:00
unsigned idx = 0;
for (list<string>::const_iterator cur = names->begin()
; cur != names->end()
; cur ++ ) {
PWire*pp = new PWire(*cur);
pp->port_type = NetNet::PINPUT;
1999-06-12 22:35:27 +02:00
(*out)[idx] = pp;
}
delete names;
return out;
}
PProcess* pform_make_behavior(PProcess::Type type, Statement*st)
1998-11-04 00:28:49 +01:00
{
PProcess*pp = new PProcess(type, st);
cur_module->add_behavior(pp);
return pp;
1998-11-04 00:28:49 +01:00
}
Statement* pform_make_block(PBlock::BL_TYPE type, list<Statement*>*sl)
{
if (sl == 0)
sl = new list<Statement*>;
PBlock*bl = new PBlock(type, *sl);
delete sl;
return bl;
}
Statement* pform_make_calltask(string*name, svector<PExpr*>*parms)
1998-11-04 00:28:49 +01:00
{
if (parms == 0)
parms = new svector<PExpr*>(0);
1998-11-04 00:28:49 +01:00
PCallTask*ct = new PCallTask(*name, *parms);
delete name;
delete parms;
return ct;
}
FILE*vl_input = 0;
1998-12-09 05:02:47 +01:00
int pform_parse(const char*path, map<string,Module*>&modules,
map<string,PUdp*>&prim)
1998-11-04 00:28:49 +01:00
{
1998-12-09 05:02:47 +01:00
vl_file = path;
vl_input = fopen(path, "r");
if (vl_input == 0) {
cerr << "Unable to open " <<vl_file << "." << endl;
return 11;
}
error_count = 0;
warn_count = 0;
1998-11-04 00:28:49 +01:00
int rc = VLparse();
if (rc) {
cerr << "I give up." << endl;
}
modules = vl_modules;
prim = vl_primitives;
return error_count;
1998-11-04 00:28:49 +01:00
}
/*
* $Log: pform.cc,v $
1999-06-15 05:44:53 +02:00
* Revision 1.27 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
* Revision 1.26 1999/06/13 23:51:16 steve
* l-value part select for procedural assignments.
*
1999-06-12 22:35:27 +02:00
* Revision 1.25 1999/06/12 20:35:27 steve
* parse more verilog.
*
1999-06-12 05:42:17 +02:00
* Revision 1.24 1999/06/12 03:42:17 steve
* Assert state of bit range expressions.
*
* Revision 1.23 1999/06/06 20:45:39 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
1999-06-02 17:38:46 +02:00
* Revision 1.22 1999/06/02 15:38:46 steve
* Line information with nets.
*
1999-05-31 17:45:59 +02:00
* Revision 1.21 1999/05/31 15:45:59 steve
* makegates infinite loop fixed.
*
1999-05-29 04:36:17 +02:00
* Revision 1.20 1999/05/29 02:36:17 steve
* module parameter bind by name.
*
* Revision 1.19 1999/05/20 04:31:45 steve
* Much expression parsing work,
* mark continuous assigns with source line info,
* replace some assertion failures with Sorry messages.
*
* Revision 1.18 1999/05/16 05:08:42 steve
* Redo constant expression detection to happen
* after parsing.
*
* Parse more operators and expressions.
*
* Revision 1.17 1999/05/10 00:16:58 steve
* Parse and elaborate the concatenate operator
* in structural contexts, Replace vector<PExpr*>
* and list<PExpr*> with svector<PExpr*>, evaluate
* constant expressions with parameters, handle
* memories as lvalues.
*
* Parse task declarations, integer types.
*
1999-05-08 22:19:20 +02:00
* Revision 1.16 1999/05/08 20:19:20 steve
* Parse more things.
*
* Revision 1.15 1999/05/07 04:26:49 steve
* Parse more complex continuous assign lvalues.
*
1999-05-06 06:37:17 +02:00
* Revision 1.14 1999/05/06 04:37:17 steve
* Get rid of list<lgate> types.
*
1999-05-06 06:09:28 +02:00
* Revision 1.13 1999/05/06 04:09:28 steve
* Parse more constant expressions.
*
1999-05-03 01:25:32 +02:00
* Revision 1.12 1999/05/02 23:25:32 steve
* Enforce module instance names.
*
* Revision 1.11 1999/04/19 01:59:37 steve
* Add memories to the parse and elaboration phases.
*
1999-02-21 18:01:57 +01:00
* Revision 1.10 1999/02/21 17:01:57 steve
* Add support for module parameters.
*
1999-02-15 03:06:15 +01:00
* Revision 1.9 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
* Revision 1.8 1999/01/25 05:45:56 steve
* Add the LineInfo class to carry the source file
* location of things. PGate, Statement and PProcess.
*
* elaborate handles module parameter mismatches,
* missing or incorrect lvalues for procedural
* assignment, and errors are propogated to the
* top of the elaboration call tree.
*
* Attach line numbers to processes, gates and
* assignment statements.
*
1998-12-09 05:02:47 +01:00
* Revision 1.7 1998/12/09 04:02:47 steve
* Support the include directive.
*
* Revision 1.6 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* 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,
* Wire attributes added,
* Ability to parse UDP descriptions added,
* XNF generates EXT records for signals with
* the PAD attribute.
*
1998-11-11 01:01:51 +01:00
* Revision 1.3 1998/11/11 00:01:51 steve
* Check net ranges in declarations.
*
* Revision 1.2 1998/11/07 17:05:06 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
1998-11-04 00:28:49 +01:00
* Revision 1.1 1998/11/03 23:29:03 steve
* Introduce verilog to CVS.
*
*/