/* * Copyright (c) 1998 Stephen Williams (steve@icarus.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: pform.cc,v 1.6 1998/12/01 00:42:14 steve Exp $" #endif # include "pform.h" # include "parse_misc.h" # include "PUdp.h" # include # include # include # include extern int VLparse(); static Module*cur_module = 0; static map vl_modules; static map vl_primitives; /* * 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(delay); if (pp == 0) { VLerror("Sorry, delay expression is too complicated."); return 0; } return pp->value().as_ulong(); } void pform_startmodule(const string&name, list*ports) { assert( cur_module == 0 ); cur_module = new Module(name, ports? ports->size() : 0); if (ports) { unsigned idx = 0; for (list::iterator cur = ports->begin() ; cur != ports->end() ; cur ++ ) { cur_module->add_wire(*cur); cur_module->ports[idx++] = *cur; } delete ports; } } void pform_endmodule(const string&name) { assert(cur_module); assert(name == cur_module->get_name()); vl_modules[name] = cur_module; cur_module = 0; } void pform_make_udp(string*name, list*parms, list*decl, list*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 defs; for (list::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 pins (parms->size()); { list::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 input (table->size()); vector current (table->size()); vector output (table->size()); { unsigned idx = 0; for (list::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(init_expr); assert(pa); // XXXX assert(pa->lval() == pins[0]->name); const PENumber*np = dynamic_cast(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&wires, unsigned long delay_val) { PGate*cur = new PGBuiltin(type, name, wires, delay_val); cur_module->add_gate(cur); } void pform_makegates(PGBuiltin::Type type, PExpr*delay, list*gates) { unsigned long delay_val = evaluate_delay(delay); delete delay; while (! gates->empty()) { lgate cur = gates->front(); gates->pop_front(); vectorwires (cur.parms->size()); for (unsigned idx = 0 ; idx < wires.size() ; idx += 1) { PExpr*ep = cur.parms->front(); cur.parms->pop_front(); wires[idx] = ep; } pform_makegate(type, cur.name, wires, delay_val); } delete gates; } void pform_make_modgate(const string&type, const string&name, const vector&wires) { PGate*cur = new PGModule(type, name, wires); cur_module->add_gate(cur); } void pform_make_modgates(const string&type, list*gates) { while (! gates->empty()) { lgate cur = gates->front(); gates->pop_front(); vectorwires (cur.parms->size()); for (unsigned idx = 0 ; idx < wires.size() ; idx += 1) { PExpr*ep = cur.parms->front(); cur.parms->pop_front(); wires[idx] = ep; } pform_make_modgate(type, cur.name, wires); } delete gates; } void pform_make_pgassign(const string&lval, PExpr*rval) { vector wires (2); wires[0] = new PEIdent(lval); wires[1] = rval; PGAssign*cur = new PGAssign(wires); cur_module->add_gate(cur); } void pform_make_pgassign(const string&lval, PExpr*sel, PExpr*rval) { vector wires (2); PEIdent*tmp = new PEIdent(lval); tmp->msb_ = sel; wires[0] = tmp; wires[1] = rval; PGAssign*cur = new PGAssign(wires); cur_module->add_gate(cur); } void pform_makewire(const string&name, NetNet::Type type) { PWire*cur = cur_module->get_wire(name); if (cur) { if (cur->type != NetNet::IMPLICIT) VLerror("Extra definition of wire."); cur->type = type; return; } cur = new PWire(name, type); cur_module->add_wire(cur); } void pform_makewire(const list*names, NetNet::Type type) { for (list::const_iterator cur = names->begin() ; cur != names->end() ; cur ++ ) pform_makewire(*cur, type); } 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::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; } static void pform_set_net_range(const string&name, list*range) { assert(range->size() == 2); 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)){ list::const_iterator idx = range->begin(); cur->msb = *idx; idx ++; cur->lsb = *idx; } else { list::const_iterator idx = range->begin(); PExpr*msb = *idx; idx ++; PExpr*lsb = *idx; if (! (cur->msb->is_the_same(msb) && cur->lsb->is_the_same(lsb))) VLerror(yylloc, "net ranges are not identical."); delete msb; delete lsb; } } void pform_set_port_type(list*names, NetNet::PortType pt) { for (list::const_iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { pform_set_port_type(*cur, pt); } } void pform_set_net_range(list*names, list*range) { assert(range->size() == 2); for (list::const_iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { pform_set_net_range(*cur, range); } } list* pform_make_udp_input_ports(list*names) { list*out = new list; for (list::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); cur_module->add_behavior(pp); } Statement* pform_make_block(PBlock::BL_TYPE type, list*sl) { if (sl == 0) sl = new list; PBlock*bl = new PBlock(type, *sl); delete sl; return bl; } Statement* pform_make_assignment(string*text, PExpr*ex) { PAssign*st = new PAssign (*text, ex); delete text; return st; } Statement* pform_make_calltask(string*name, list*parms) { if (parms == 0) parms = new list; PCallTask*ct = new PCallTask(*name, *parms); delete name; delete parms; return ct; } FILE*vl_input = 0; int pform_parse(FILE*input, map&modules, map&prim) { vl_input = input; error_count = 0; warn_count = 0; int rc = VLparse(); if (rc) { cerr << "I give up." << endl; } modules = vl_modules; prim = vl_primitives; return error_count; } /* * $Log: pform.cc,v $ * 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. * * 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. * * Revision 1.1 1998/11/03 23:29:03 steve * Introduce verilog to CVS. * */