/*
 * Copyright (c) 2000-2004 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
 */
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_sig.cc,v 1.37 2004/12/11 02:31:25 steve Exp $"
#endif

# include "config.h"

# include  <iostream>

# include  "Module.h"
# include  "PExpr.h"
# include  "PGate.h"
# include  "PTask.h"
# include  "PWire.h"
# include  "compiler.h"
# include  "netlist.h"
# include  "netmisc.h"
# include  "util.h"

/*
 * This local function checks if a named signal is connected to a
 * port. It looks in the array of ports passed, for NetEIdent objects
 * within the port_t that have a matching name.
 */
static bool signal_is_in_port(const svector<Module::port_t*>&ports,
			      const hname_t&name)
{
      for (unsigned idx = 0 ;  idx < ports.count() ;  idx += 1) {

	    Module::port_t*pp = ports[idx];
	      // Skip internally unconnected ports.
	    if (pp == 0)
		  continue;

	      // This port has an internal connection. In this case,
	      // the port has 0 or more NetEIdent objects concatenated
	      // together that form the port.
	    for (unsigned cc = 0 ;  cc < pp->expr.count() ;  cc += 1) {
		  assert(pp->expr[cc]);
		  if (pp->expr[cc]->path() == name)
			return true;
	    }
      }

      return false;
}

bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
      bool flag = true;

	// Get all the explicitly declared wires of the module and
	// start the signals list with them.
      const map<hname_t,PWire*>&wl = get_wires();

	// Scan all the ports of the module, and make sure that each
	// is connected to wires that have port declarations.
      for (unsigned idx = 0 ;  idx < ports.count() ;  idx += 1) {
	    Module::port_t*pp = ports[idx];
	    if (pp == 0)
		  continue;

	    map<hname_t,PWire*>::const_iterator wt;
	    for (unsigned cc = 0 ;  cc < pp->expr.count() ;  cc += 1) {
		  hname_t port_path (pp->expr[cc]->path());
		  wt = wl.find(port_path);

		  if (wt == wl.end()) {
			cerr << get_line() << ": error: "
			     << "Port " << pp->expr[cc]->path() << " ("
			     << (idx+1) << ") of module " << name_
			     << " is not declared within module." << endl;
			des->errors += 1;
			continue;
		  }

		  if ((*wt).second->get_port_type() == NetNet::NOT_A_PORT) {
			cerr << get_line() << ": error: "
			     << "Port " << pp->expr[cc]->path() << " ("
			     << (idx+1) << ") of module " << name_
			     << " has no direction declaration."
			     << endl;
			des->errors += 1;
		  }
	    }
      }

      for (map<hname_t,PWire*>::const_iterator wt = wl.begin()
		 ; wt != wl.end()
		 ; wt ++ ) {

	    PWire*cur = (*wt).second;
	    cur->elaborate_sig(des, scope);

	    NetNet*sig = scope->find_signal_in_child(cur->path());

	      // If this wire is a signal of the module (as opposed to
	      // a port of a function) and is a port, then check that
	      // the module knows about it. We know that the signal is
	      // the name of a signal within a subscope of a module
	      // (a task, a function, etc.) if the name for the PWire
	      // has hierarchy.

	    if (sig && (sig->scope() == scope)
		&& (cur->get_port_type() != NetNet::NOT_A_PORT)) {

		  hname_t name = (*wt).first;

		  if (! signal_is_in_port(ports, name)) {

			cerr << cur->get_line() << ": error: Signal "
			     << name << " has a declared direction "
			     << "but is not a port." << endl;
			des->errors += 1;
		  }
	    }


	      /* If the signal is an input and is also declared as a
		 reg, then report an error. */

	    if (sig && (sig->scope() == scope)
		&& (sig->port_type() == NetNet::PINPUT)
		&& (sig->type() == NetNet::REG)) {

		  cerr << cur->get_line() << ": error: "
		       << cur->path() << " in module "
		       << scope->module_name()
		       << " declared as input and as a reg type." << endl;
		  des->errors += 1;
	    }

	    if (sig && (sig->scope() == scope)
		&& (sig->port_type() == NetNet::PINOUT)
		&& (sig->type() == NetNet::REG)) {

		  cerr << cur->get_line() << ": error: "
		       << cur->path() << " in  module "
		       << scope->module_name()
		       << " declared as inout and as a reg type." << endl;
		  des->errors += 1;
	    }

      }

	// Get all the gates of the module and elaborate them by
	// connecting them to the signals. The gate may be simple or
	// complex. What we are looking for is gates that are modules
	// that can create scopes and signals.

      const list<PGate*>&gl = get_gates();

      for (list<PGate*>::const_iterator gt = gl.begin()
		 ; gt != gl.end()
		 ; gt ++ ) {

	    flag &= (*gt)->elaborate_sig(des, scope);
      }


      typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;

      for (mfunc_it_t cur = funcs_.begin()
		 ; cur != funcs_.end() ;  cur ++) {
	    NetScope*fscope = scope->child((*cur).first);
	    if (scope == 0) {
		  cerr << (*cur).second->get_line() << ": internal error: "
		       << "Child scope for function " << (*cur).first
		       << " missing in " << scope->name() << "." << endl;
		  des->errors += 1;
		  continue;
	    }

	    (*cur).second->elaborate_sig(des, fscope);
      }


	// After all the wires are elaborated, we are free to
	// elaborate the ports of the tasks defined within this
	// module. Run through them now.

      typedef map<perm_string,PTask*>::const_iterator mtask_it_t;

      for (mtask_it_t cur = tasks_.begin()
		 ; cur != tasks_.end() ;  cur ++) {
	    NetScope*tscope = scope->child((*cur).first);
	    assert(tscope);
	    (*cur).second->elaborate_sig(des, tscope);
      }

      return flag;
}

bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
				  Module*rmod) const
{
      bool flag = true;

      NetScope::scope_vec_t instance = scope->instance_arrays[get_name()];

      for (unsigned idx = 0 ;  idx < instance.count() ;  idx += 1) {
	      // I know a priori that the elaborate_scope created the scope
	      // already, so just look it up as a child of the current scope.
	    NetScope*my_scope = instance[idx];
	    assert(my_scope);

	    if (my_scope->parent() != scope) {
		  cerr << get_line() << ": internal error: "
		       << "Instance " << my_scope->name()
		       << " is in parent " << my_scope->parent()->name()
		       << " instead of " << scope->name()
		       << endl;
	    }
	    assert(my_scope->parent() == scope);

	    if (! rmod->elaborate_sig(des, my_scope))
		  flag = false;

      }

      return flag;
}

/*
 * A function definition exists within an elaborated module. This
 * matters when elaborating signals, as the ports of the function are
 * created as signals/variables for each instance of the
 * function. That is why PFunction has an elaborate_sig method.
 */
void PFunction::elaborate_sig(Design*des, NetScope*scope) const
{
      perm_string fname = scope->basename();
      assert(scope->type() == NetScope::FUNC);

	/* Make sure the function has at least one input port. If it
	   fails this test, print an error message. Keep going so we
	   can find more errors. */
      if (ports_ == 0) {
	    cerr << get_line() << ": error: Function " << fname
		 << " has no ports." << endl;
	    cerr << get_line() << ":      : Functions must have"
		 << " at least one input port." << endl;
	    des->errors += 1;
      }

      NetNet*ret_sig = 0;
      NetVariable*ret_real = 0;

	/* Create the signals/variables of the return value and write
	   them into the function scope. */
      switch (return_type_.type) {

	  case PTF_REG:
	    if (return_type_.range) {
		  NetExpr*me = elab_and_eval(des, scope,
					     (*return_type_.range)[0]);
		  assert(me);
		  NetExpr*le = elab_and_eval(des, scope,
					     (*return_type_.range)[1]);
		  assert(le);

		  long mnum = 0, lnum = 0;
		  if (NetEConst*tmp = dynamic_cast<NetEConst*>(me)) {
			mnum = tmp->value().as_long();
		  } else {
			cerr << me->get_line() << ": error: "
			      "Unable to evaluate constant expression "
			     << *me << "." << endl;
			des->errors += 1;
		  }

		  if (NetEConst*tmp = dynamic_cast<NetEConst*>(le)) {
			lnum = tmp->value().as_long();
		  } else {
			cerr << le->get_line() << ": error: "
			      "Unable to evaluate constant expression "
			     << *le << "." << endl;
			des->errors += 1;
		  }

		  ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum);

	    } else {
		  ret_sig = new NetNet(scope, fname, NetNet::REG);
	    }
	    ret_sig->set_line(*this);
	    ret_sig->port_type(NetNet::POUTPUT);
	    break;

	  case PTF_INTEGER:
	    ret_sig = new NetNet(scope, fname, NetNet::REG, INTEGER_WIDTH);
	    ret_sig->set_line(*this);
	    ret_sig->set_signed(true);
	    ret_sig->set_isint(true);
	    ret_sig->port_type(NetNet::POUTPUT);
	    break;

	  case PTF_TIME:
	    ret_sig = new NetNet(scope, fname, NetNet::REG, 64);
	    ret_sig->set_line(*this);
	    ret_sig->set_signed(false);
	    ret_sig->set_isint(false);
	    ret_sig->port_type(NetNet::POUTPUT);
	    break;

	  case PTF_REAL:
	  case PTF_REALTIME:
	    ret_real = new NetVariable(fname);
	    ret_real->set_line(*this);
	    scope->add_variable(ret_real);
	    break;

	  default:
	    cerr << get_line() << ": internal error: I don't know how "
		 << "to deal with return type of function "
		 << scope->basename() << "." << endl;
      }

      svector<NetNet*>ports (ports_? ports_->count() : 0);

      if (ports_)
	    for (unsigned idx = 0 ;  idx < ports_->count() ;  idx += 1) {

		    /* Parse the port name into the task name and the reg
		       name. We know by design that the port name is given
		       as two components: <func>.<port>. */

		  hname_t path = (*ports_)[idx]->path();
		  perm_string pname = lex_strings.make(path.peek_name(1));
		  perm_string ppath = lex_strings.make(path.peek_name(0));

		  if (ppath != scope->basename()) {
			cerr << get_line() << ": internal error: function "
			     << "port " << (*ports_)[idx]->path()
			     << " has wrong name for function "
			     << scope->name() << "." << endl;
			des->errors += 1;
		  }

		  NetNet*tmp = scope->find_signal(pname);
		  if (tmp == 0) {
			cerr << get_line() << ": internal error: function "
			     << scope->name() << " is missing port "
			     << pname << "." << endl;
			scope->dump(cerr);
			cerr << get_line() << ": Continuing..." << endl;
			des->errors += 1;
		  }

		  ports[idx] = tmp;
	    }


      NetFuncDef*def = 0;
      if (ret_sig)  def = new NetFuncDef(scope, ret_sig, ports);
      if (ret_real) def = new NetFuncDef(scope, ret_real, ports);

      assert(def);
      scope->set_func_def(def);
}

/*
 * A task definition is a scope within an elaborated module. When we
 * are elaborating signals, the scopes have already been created, as
 * have the reg objects that are the parameters of this task. The
 * elaborate_sig method of PTask is therefore left to connect the
 * signals to the ports of the NetTaskDef definition. We know for
 * certain that signals exist (They are in my scope!) so the port
 * binding is sure to work.
 */
void PTask::elaborate_sig(Design*des, NetScope*scope) const
{
      assert(scope->type() == NetScope::TASK);

      svector<NetNet*>ports (ports_? ports_->count() : 0);
      for (unsigned idx = 0 ;  idx < ports.count() ;  idx += 1) {

	      /* Parse the port name into the task name and the reg
		 name. We know by design that the port name is given
		 as two components: <task>.<port>. */

	    hname_t path = (*ports_)[idx]->path();
	    assert(path.peek_name(0) && path.peek_name(1));

	      /* check that the current scope really does have the
		 name of the first component of the task port name. Do
		 this by looking up the task scope in the parent of
		 the current scope. */
	    if (scope->parent()->child(path.peek_name(0)) != scope) {
		  cerr << "internal error: task scope " << path
		       << " not the same as scope " << scope->name()
		       << "?!" << endl;
		  return;
	    }

	      /* Find the signal for the port. We know by definition
		 that it is in the scope of the task, so look only in
		 the scope. */
	    NetNet*tmp = scope->find_signal(path.peek_name(1));

	    if (tmp == 0) {
		  cerr << get_line() << ": internal error: "
		       << "Could not find port " << path.peek_name(1)
		       << " in scope " << scope->name() << endl;
		  scope->dump(cerr);
	    }

	    ports[idx] = tmp;
      }

      NetTaskDef*def = new NetTaskDef(scope->name(), ports);
      scope->set_task_def(def);
}

bool PGate::elaborate_sig(Design*des, NetScope*scope) const
{
      return true;
}

/*
 * Elaborate a source wire. The "wire" is the declaration of wires,
 * registers, ports and memories. The parser has already merged the
 * multiple properties of a wire (i.e., "input wire") so come the
 * elaboration this creates an object in the design that represent the
 * defined item.
 */
void PWire::elaborate_sig(Design*des, NetScope*scope) const
{

	/* The parser may produce hierarchical names for wires. I here
	   follow the scopes down to the base where I actually want to
	   elaborate the NetNet object. */
      { hname_t tmp_path = hname_;
        free(tmp_path.remove_tail_name());
	for (unsigned idx = 0 ;  tmp_path.peek_name(idx) ;  idx += 1) {
	      scope = scope->child(tmp_path.peek_name(idx));

	      if (scope == 0) {
		    cerr << get_line() << ": internal error: "
			 << "Bad scope component for name "
			 << hname_ << endl;
		    assert(scope);
	      }
	}
      }

      NetNet::Type wtype = type_;
      if (wtype == NetNet::IMPLICIT)
	    wtype = NetNet::WIRE;
      if (wtype == NetNet::IMPLICIT_REG)
	    wtype = NetNet::REG;

      unsigned wid = 1;
      long lsb = 0, msb = 0;

      assert(msb_.count() == lsb_.count());
      if (msb_.count()) {
	    svector<long>mnum (msb_.count());
	    svector<long>lnum (msb_.count());
	      /* There may be places where the signal is declared as a
		 scalar. Count those here, for consistency check
		 later. */
	    unsigned count_scalars = 0;

	      /* There may be multiple declarations of ranges, because
		 the symbol may have its range declared in e.g., input
		 and reg declarations. Calculate *all* the numbers
		 here. I will resolve the values later. */

	    for (unsigned idx = 0 ;  idx < msb_.count() ;  idx += 1) {

		  if (msb_[idx] == 0) {
			count_scalars += 1;
			assert(lsb_[idx] == 0);
			mnum[idx] = 0;
			lnum[idx] = 0;
			continue;
		  }

		  NetEConst*tmp;
		  NetExpr*texpr = elab_and_eval(des, scope, msb_[idx]);

		  tmp = dynamic_cast<NetEConst*>(texpr);
		  if (tmp == 0) {
			cerr << msb_[idx]->get_line() << ": error: "
			      "Unable to evaluate constant expression ``" <<
			      *msb_[idx] << "''." << endl;
			des->errors += 1;
			return;
		  }

		  mnum[idx] = tmp->value().as_long();
		  delete texpr;

		  texpr = elab_and_eval(des, scope, lsb_[idx]);
		  tmp = dynamic_cast<NetEConst*>(texpr);
		  if (tmp == 0) {
			cerr << msb_[idx]->get_line() << ": error: "
			      "Unable to evaluate constant expression ``" <<
			      *lsb_[idx] << "''." << endl;
			des->errors += 1;
			return;
		  }

		  lnum[idx] = tmp->value().as_long();
		  delete texpr;

	    }

	      /* Check that the declarations were all scalar or all
		 vector. It is an error to mix them. Use the
		 count_scalars to know. */
	    if ((count_scalars > 0) && (count_scalars != msb_.count())) {
		  cerr << get_line() << ": error: Signal ``" << hname_
		       << "'' declared both as a vector and a scalar."
		       << endl;
		  des->errors += 1;
		  return;
	    }


	      /* Make sure all the values for msb and lsb match by
		 value. If not, report an error. */
	    for (unsigned idx = 1 ;  idx < msb_.count() ;  idx += 1) {
		  if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) {
			cerr << get_line() << ": error: Inconsistent width, "
			      "[" << mnum[idx] << ":" << lnum[idx] << "]"
			      " vs. [" << mnum[0] << ":" << lnum[0] << "]"
			      " for signal ``" << hname_ << "''" << endl;
			des->errors += 1;
			return;
		  }
	    }

	    lsb = lnum[0];
	    msb = mnum[0];
	    if (mnum[0] > lnum[0])
		  wid = mnum[0] - lnum[0] + 1;
	    else
		  wid = lnum[0] - mnum[0] + 1;


      }

      unsigned nattrib = 0;
      attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
						      des, scope);

	/* If the ident has idx expressions, then this is a
	   memory. It can only have the idx registers after the msb
	   and lsb expressions are filled. And, if it has one index,
	   it has both. */
      if (lidx_ || ridx_) {
	    assert(lidx_ && ridx_);

	    NetExpr*lexp = elab_and_eval(des, scope, lidx_);
	    NetExpr*rexp = elab_and_eval(des, scope, ridx_);

	    if ((lexp == 0) || (rexp == 0)) {
		  cerr << get_line() << ": internal error: There is "
		       << "a problem evaluating indices for ``"
		       << hname_.peek_tail_name() << "''." << endl;
		  des->errors += 1;
		  return;
	    }

	    NetEConst*lcon = dynamic_cast<NetEConst*> (lexp);
	    NetEConst*rcon = dynamic_cast<NetEConst*> (rexp);

	    if ((lcon == 0) || (rcon == 0)) {
		  cerr << get_line() << ": internal error: The indices "
		       << "are not constant for memory ``"
		       << hname_.peek_tail_name() << "''." << endl;
		  des->errors += 1;
		  return;
	    }

	    verinum lval = lcon->value();
	    verinum rval = rcon->value();

	    delete lexp;
	    delete rexp;

	    perm_string name = lex_strings.make(hname_.peek_tail_name());

	    long lnum = lval.as_long();
	    long rnum = rval.as_long();

	    new NetMemory(scope, name, wid, lnum, rnum);
	      // The constructor automatically adds the memory object
	      // to the scope. Do I need to set line number information?

      } else {

	    perm_string name = lex_strings.make(hname_.peek_tail_name());
	    if (debug_elaborate) {
		  cerr << get_line() << ": debug: Create signal "
		       << name << "["<<msb<<":"<<lsb<<"]"
		       << " in scope " << scope->name() << endl;
	    }

	    NetNet*sig = new NetNet(scope, name, wtype, msb, lsb);
	    sig->set_line(*this);
	    sig->port_type(port_type_);
	    sig->set_signed(get_signed());
	    sig->set_isint(get_isint());

	    for (unsigned idx = 0 ;  idx < nattrib ;  idx += 1)
		  sig->attribute(attrib_list[idx].key, attrib_list[idx].val);
      }
}

/*
 * $Log: elab_sig.cc,v $
 * Revision 1.37  2004/12/11 02:31:25  steve
 *  Rework of internals to carry vectors through nexus instead
 *  of single bits. Make the ivl, tgt-vvp and vvp initial changes
 *  down this path.
 *
 * Revision 1.36  2004/09/27 22:34:10  steve
 *  Cleanup and factoring of autoconf.
 *
 * Revision 1.35  2004/09/05 17:44:41  steve
 *  Add support for module instance arrays.
 *
 * Revision 1.34  2004/05/31 23:34:37  steve
 *  Rewire/generalize parsing an elaboration of
 *  function return values to allow for better
 *  speed and more type support.
 *
 * Revision 1.33  2004/02/18 17:11:55  steve
 *  Use perm_strings for named langiage items.
 *
 * Revision 1.32  2003/09/20 05:24:00  steve
 *  Evaluate memory index constants using elab_and_eval.
 *
 * Revision 1.31  2003/07/15 03:49:22  steve
 *  Spelling fixes.
 *
 * Revision 1.30  2003/06/24 01:38:02  steve
 *  Various warnings fixed.
 *
 * Revision 1.29  2003/06/21 01:21:43  steve
 *  Harmless fixup of warnings.
 *
 * Revision 1.28  2003/03/06 00:28:41  steve
 *  All NetObj objects have lex_string base names.
 *
 * Revision 1.27  2003/01/30 16:23:07  steve
 *  Spelling fixes.
 *
 * Revision 1.26  2003/01/27 05:09:17  steve
 *  Spelling fixes.
 *
 * Revision 1.25  2002/08/12 01:34:59  steve
 *  conditional ident string using autoconfig.
 *
 * Revision 1.24  2002/08/05 04:18:45  steve
 *  Store only the base name of memories.
 *
 * Revision 1.23  2002/06/21 04:59:35  steve
 *  Carry integerness throughout the compilation.
 *
 * Revision 1.22  2002/05/23 03:08:51  steve
 *  Add language support for Verilog-2001 attribute
 *  syntax. Hook this support into existing $attribute
 *  handling, and add number and void value types.
 *
 *  Add to the ivl_target API new functions for access
 *  of complex attributes attached to gates.
 *
 * Revision 1.21  2002/05/19 23:37:28  steve
 *  Parse port_declaration_lists from the 2001 Standard.
 *
 * Revision 1.20  2002/01/26 05:28:28  steve
 *  Detect scalar/vector declarion mismatch.
 *
 * Revision 1.19  2002/01/23 03:35:17  steve
 *  Detect incorrect function ports.
 *
 * Revision 1.18  2001/12/03 04:47:14  steve
 *  Parser and pform use hierarchical names as hname_t
 *  objects instead of encoded strings.
 *
 * Revision 1.17  2001/11/07 04:01:59  steve
 *  eval_const uses scope instead of a string path.
 *
 * Revision 1.16  2001/11/01 05:21:26  steve
 *  Catch ports that have no direction.
 *
 * Revision 1.15  2001/10/31 03:11:15  steve
 *  detect module ports not declared within the module.
 *
 * Revision 1.14  2001/07/25 03:10:49  steve
 *  Create a config.h.in file to hold all the config
 *  junk, and support gcc 3.0. (Stephan Boettcher)
 *
 * Revision 1.13  2001/05/25 02:21:34  steve
 *  Detect input and input ports declared as reg.
 *
 * Revision 1.12  2001/02/17 05:15:33  steve
 *  Allow task ports to be given real types.
 *
 * Revision 1.11  2001/02/10 20:29:39  steve
 *  In the context of range declarations, use elab_and_eval instead
 *  of the less robust eval_const methods.
 */

