789 lines
23 KiB
C++
789 lines
23 KiB
C++
/*
|
|
* Copyright (c) 2000-2007 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
|
|
*/
|
|
|
|
# include "config.h"
|
|
|
|
# include <cstdlib>
|
|
# include <iostream>
|
|
|
|
# include "Module.h"
|
|
# include "PExpr.h"
|
|
# include "PGate.h"
|
|
# include "PGenerate.h"
|
|
# include "PTask.h"
|
|
# include "PWire.h"
|
|
# include "compiler.h"
|
|
# include "netlist.h"
|
|
# include "netmisc.h"
|
|
# include "util.h"
|
|
# include "ivl_assert.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,
|
|
NetNet*sig)
|
|
{
|
|
perm_string name = sig->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.
|
|
|
|
// Note that module ports should not have any hierarchy
|
|
// in their names: they are in the root of the module
|
|
// scope by definition.
|
|
|
|
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
|
|
perm_string pname = peek_tail_name(pp->expr[cc]->path());
|
|
assert(pp->expr[cc]);
|
|
if (pname == name)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
|
{
|
|
bool flag = true;
|
|
|
|
// 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<pform_name_t,PWire*>::const_iterator wt;
|
|
for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) {
|
|
pform_name_t port_path (pp->expr[cc]->path());
|
|
wt = wires_.find(port_path);
|
|
|
|
if (wt == wires_.end()) {
|
|
cerr << get_fileline() << ": 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_fileline() << ": error: "
|
|
<< "Port " << pp->expr[cc]->path() << " ("
|
|
<< (idx+1) << ") of module " << name_
|
|
<< " has no direction declaration."
|
|
<< endl;
|
|
des->errors += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (map<pform_name_t,PWire*>::const_iterator wt = wires_.begin()
|
|
; wt != wires_.end() ; wt ++ ) {
|
|
|
|
PWire*cur = (*wt).second;
|
|
NetNet*sig = cur->elaborate_sig(des, scope);
|
|
|
|
// 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)) {
|
|
|
|
if (! signal_is_in_port(ports, sig)) {
|
|
|
|
cerr << cur->get_fileline() << ": error: Signal "
|
|
<< sig->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_fileline() << ": 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_fileline() << ": error: "
|
|
<< cur->path() << " in module "
|
|
<< scope->module_name()
|
|
<< " declared as inout and as a reg type." << endl;
|
|
des->errors += 1;
|
|
}
|
|
|
|
}
|
|
|
|
// Run through all the generate schemes to elaborate the
|
|
// signals that they hold. Note that the generate schemes hold
|
|
// the scopes that they instantiated, so we don't pass any
|
|
// scope in.
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
|
for (generate_it_t cur = generate_schemes.begin()
|
|
; cur != generate_schemes.end() ; cur ++ ) {
|
|
(*cur) -> elaborate_sig(des, scope);
|
|
}
|
|
|
|
// 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 ++) {
|
|
|
|
hname_t use_name ( (*cur).first );
|
|
NetScope*fscope = scope->child(use_name);
|
|
if (scope == 0) {
|
|
cerr << (*cur).second->get_fileline() << ": internal error: "
|
|
<< "Child scope for function " << (*cur).first
|
|
<< " missing in " << scope_path(scope) << "." << 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( hname_t((*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_fileline() << ": internal error: "
|
|
<< "Instance " << scope_path(my_scope)
|
|
<< " is in parent " << scope_path(my_scope->parent())
|
|
<< " instead of " << scope_path(scope)
|
|
<< endl;
|
|
}
|
|
assert(my_scope->parent() == scope);
|
|
|
|
if (! rmod->elaborate_sig(des, my_scope))
|
|
flag = false;
|
|
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
bool PGenerate::elaborate_sig(Design*des, NetScope*container) const
|
|
{
|
|
bool flag = true;
|
|
|
|
typedef list<NetScope*>::const_iterator scope_list_it_t;
|
|
for (scope_list_it_t cur = scope_list_.begin()
|
|
; cur != scope_list_.end() ; cur ++ ) {
|
|
|
|
NetScope*scope = *cur;
|
|
|
|
if (scope->parent() != container)
|
|
continue;
|
|
|
|
if (debug_elaborate)
|
|
cerr << get_fileline() << ": debug: Elaborate nets in "
|
|
<< "scope " << scope_path(*cur)
|
|
<< " in generate " << id_number << endl;
|
|
flag = elaborate_sig_(des, *cur) & flag;
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const
|
|
{
|
|
// Scan the declared PWires to elaborate the obvious signals
|
|
// in the current scope.
|
|
typedef map<pform_name_t,PWire*>::const_iterator wires_it_t;
|
|
for (wires_it_t wt = wires.begin()
|
|
; wt != wires.end() ; wt ++ ) {
|
|
|
|
PWire*cur = (*wt).second;
|
|
|
|
if (debug_elaborate)
|
|
cerr << get_fileline() << ": debug: Elaborate PWire "
|
|
<< cur->path() << " in scope " << scope_path(scope) << endl;
|
|
|
|
cur->elaborate_sig(des, scope);
|
|
}
|
|
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
|
for (generate_it_t cur = generates.begin()
|
|
; cur != generates.end() ; cur ++ ) {
|
|
(*cur) -> elaborate_sig(des, scope);
|
|
}
|
|
|
|
typedef list<PGate*>::const_iterator pgate_list_it_t;
|
|
for (pgate_list_it_t cur = gates.begin()
|
|
; cur != gates.end() ; cur ++) {
|
|
(*cur) ->elaborate_sig(des, scope);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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_fileline() << ": error: Function " << fname
|
|
<< " has no ports." << endl;
|
|
cerr << get_fileline() << ": : Functions must have"
|
|
<< " at least one input port." << endl;
|
|
des->errors += 1;
|
|
}
|
|
|
|
NetNet*ret_sig = 0;
|
|
|
|
/* Create the signals/variables of the return value and write
|
|
them into the function scope. */
|
|
switch (return_type_.type) {
|
|
|
|
case PTF_REG:
|
|
case PTF_REG_S:
|
|
if (return_type_.range) {
|
|
NetExpr*me = elab_and_eval(des, scope,
|
|
(*return_type_.range)[0], -1);
|
|
assert(me);
|
|
NetExpr*le = elab_and_eval(des, scope,
|
|
(*return_type_.range)[1], -1);
|
|
assert(le);
|
|
|
|
long mnum = 0, lnum = 0;
|
|
if (NetEConst*tmp = dynamic_cast<NetEConst*>(me)) {
|
|
mnum = tmp->value().as_long();
|
|
} else {
|
|
cerr << me->get_fileline() << ": 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_fileline() << ": 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->set_signed(return_type_.type == PTF_REG_S);
|
|
ret_sig->port_type(NetNet::POUTPUT);
|
|
ret_sig->data_type(IVL_VT_LOGIC);
|
|
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);
|
|
ret_sig->data_type(IVL_VT_LOGIC);
|
|
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);
|
|
ret_sig->data_type(IVL_VT_LOGIC);
|
|
break;
|
|
|
|
case PTF_REAL:
|
|
case PTF_REALTIME:
|
|
ret_sig = new NetNet(scope, fname, NetNet::REG, 1);
|
|
ret_sig->set_line(*this);
|
|
ret_sig->set_signed(true);
|
|
ret_sig->set_isint(false);
|
|
ret_sig->port_type(NetNet::POUTPUT);
|
|
ret_sig->data_type(IVL_VT_REAL);
|
|
break;
|
|
|
|
default:
|
|
cerr << get_fileline() << ": 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>. */
|
|
|
|
pform_name_t path = (*ports_)[idx]->path();
|
|
ivl_assert(*this, path.size() == 2);
|
|
|
|
perm_string pname = peek_tail_name(path);
|
|
perm_string ppath = peek_head_name(path);
|
|
|
|
if (ppath != scope->basename()) {
|
|
cerr << get_fileline() << ": internal error: function "
|
|
<< "port " << (*ports_)[idx]->path()
|
|
<< " has wrong name for function "
|
|
<< scope_path(scope) << "." << endl;
|
|
des->errors += 1;
|
|
}
|
|
|
|
NetNet*tmp = scope->find_signal(pname);
|
|
if (tmp == 0) {
|
|
cerr << get_fileline() << ": internal error: function "
|
|
<< scope_path(scope) << " is missing port "
|
|
<< pname << "." << endl;
|
|
scope->dump(cerr);
|
|
cerr << get_fileline() << ": Continuing..." << endl;
|
|
des->errors += 1;
|
|
}
|
|
|
|
ports[idx] = tmp;
|
|
}
|
|
|
|
|
|
NetFuncDef*def = 0;
|
|
if (ret_sig) def = new NetFuncDef(scope, ret_sig, 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>. */
|
|
|
|
pform_name_t path = (*ports_)[idx]->path();
|
|
ivl_assert(*this, path.size() == 2);
|
|
|
|
perm_string scope_name = peek_head_name(path);
|
|
perm_string port_name = peek_tail_name(path);
|
|
|
|
/* 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. */
|
|
ivl_assert(*this, scope->basename() == scope_name);
|
|
|
|
/* 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(port_name);
|
|
|
|
if (tmp == 0) {
|
|
cerr << get_fileline() << ": internal error: "
|
|
<< "Could not find port " << port_name
|
|
<< " in scope " << scope_path(scope) << endl;
|
|
scope->dump(cerr);
|
|
}
|
|
|
|
ports[idx] = tmp;
|
|
}
|
|
|
|
NetTaskDef*def = new NetTaskDef(scope, 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.
|
|
*/
|
|
NetNet* 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. */
|
|
{ pform_name_t tmp_path = hname_;
|
|
tmp_path.pop_back();
|
|
while (! tmp_path.empty()) {
|
|
name_component_t cur = tmp_path.front();
|
|
tmp_path.pop_front();
|
|
|
|
scope = scope->child( hname_t(cur.name) );
|
|
|
|
if (scope == 0) {
|
|
cerr << get_fileline() << ": 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;
|
|
|
|
des->errors += error_cnt_;
|
|
|
|
if (port_set_ || net_set_) {
|
|
long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0;
|
|
/* If they exist get the port definition MSB and LSB */
|
|
if (port_set_ && port_msb_ != 0) {
|
|
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1);
|
|
|
|
if (! eval_as_long(pmsb, texpr)) {
|
|
cerr << port_msb_->get_fileline() << ": error: "
|
|
"Unable to evaluate MSB constant expression ``"
|
|
<< *port_msb_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
delete texpr;
|
|
|
|
texpr = elab_and_eval(des, scope, port_lsb_, -1);
|
|
|
|
if (! eval_as_long(plsb, texpr)) {
|
|
cerr << port_lsb_->get_fileline() << ": error: "
|
|
"Unable to evaluate LSB constant expression ``"
|
|
<< *port_lsb_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
delete texpr;
|
|
nmsb = pmsb;
|
|
nlsb = plsb;
|
|
}
|
|
if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0);
|
|
if (port_msb_ == 0) assert(port_lsb_ == 0);
|
|
if (port_lsb_ == 0) assert(port_msb_ == 0);
|
|
|
|
/* If they exist get the net/etc. definition MSB and LSB */
|
|
if (net_set_ && net_msb_ != 0) {
|
|
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1);
|
|
|
|
if (! eval_as_long(nmsb, texpr)) {
|
|
cerr << net_msb_->get_fileline() << ": error: "
|
|
"Unable to evaluate MSB constant expression ``"
|
|
<< *net_msb_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
delete texpr;
|
|
|
|
texpr = elab_and_eval(des, scope, net_lsb_, -1);
|
|
|
|
if (! eval_as_long(nlsb, texpr)) {
|
|
cerr << net_lsb_->get_fileline() << ": error: "
|
|
"Unable to evaluate LSB constant expression ``"
|
|
<< *net_lsb_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
delete texpr;
|
|
}
|
|
if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0);
|
|
if (net_msb_ == 0) assert(net_lsb_ == 0);
|
|
if (net_lsb_ == 0) assert(net_msb_ == 0);
|
|
|
|
/* We have a port size error */
|
|
if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) {
|
|
|
|
/* Scalar port with a vector net/etc. definition */
|
|
if (port_msb_ == 0) {
|
|
if (!gn_io_range_error_flag) {
|
|
cerr << get_fileline()
|
|
<< ": warning: Scalar port ``" << hname_
|
|
<< "'' has a vectored net declaration ["
|
|
<< nmsb << ":" << nlsb << "]." << endl;
|
|
} else {
|
|
cerr << get_fileline()
|
|
<< ": error: Scalar port ``" << hname_
|
|
<< "'' has a vectored net declaration ["
|
|
<< nmsb << ":" << nlsb << "]." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Vectored port with a scalar net/etc. definition */
|
|
if (net_msb_ == 0) {
|
|
cerr << port_msb_->get_fileline()
|
|
<< ": error: Vectored port ``"
|
|
<< hname_ << "'' [" << pmsb << ":" << plsb
|
|
<< "] has a scalar net declaration at "
|
|
<< get_fileline() << "." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
/* Both vectored, but they have different ranges. */
|
|
if (port_msb_ != 0 && net_msb_ != 0) {
|
|
cerr << port_msb_->get_fileline()
|
|
<< ": error: Vectored port ``"
|
|
<< hname_ << "'' [" << pmsb << ":" << plsb
|
|
<< "] has a net declaration [" << nmsb << ":"
|
|
<< nlsb << "] at " << net_msb_->get_fileline()
|
|
<< " that does not match." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
lsb = nlsb;
|
|
msb = nmsb;
|
|
if (nmsb > nlsb)
|
|
wid = nmsb - nlsb + 1;
|
|
else
|
|
wid = nlsb - nmsb + 1;
|
|
|
|
|
|
}
|
|
|
|
unsigned nattrib = 0;
|
|
attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib,
|
|
des, scope);
|
|
|
|
long array_s0 = 0;
|
|
long array_e0 = 0;
|
|
unsigned array_dimensions = 0;
|
|
|
|
/* 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_, -1);
|
|
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1);
|
|
|
|
if ((lexp == 0) || (rexp == 0)) {
|
|
cerr << get_fileline() << ": internal error: There is "
|
|
<< "a problem evaluating indices for ``"
|
|
<< hname_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
NetEConst*lcon = dynamic_cast<NetEConst*> (lexp);
|
|
NetEConst*rcon = dynamic_cast<NetEConst*> (rexp);
|
|
|
|
if ((lcon == 0) || (rcon == 0)) {
|
|
cerr << get_fileline() << ": internal error: The indices "
|
|
<< "are not constant for array ``"
|
|
<< hname_ << "''." << endl;
|
|
des->errors += 1;
|
|
return 0;
|
|
}
|
|
|
|
verinum lval = lcon->value();
|
|
verinum rval = rcon->value();
|
|
|
|
delete lexp;
|
|
delete rexp;
|
|
|
|
array_dimensions = 1;
|
|
array_s0 = lval.as_long();
|
|
array_e0 = rval.as_long();
|
|
}
|
|
|
|
/* If the net type is supply0 or supply1, replace it
|
|
with a simple wire with a pulldown/pullup with supply
|
|
strength. In other words, transform:
|
|
|
|
supply0 foo;
|
|
|
|
to:
|
|
|
|
wire foo;
|
|
pulldown #(supply0) (foo);
|
|
|
|
This reduces the backend burden, and behaves exactly
|
|
the same. */
|
|
|
|
NetLogic*pull = 0;
|
|
if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) {
|
|
NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1)
|
|
? NetLogic::PULLUP
|
|
: NetLogic::PULLDOWN;
|
|
pull = new NetLogic(scope, scope->local_symbol(),
|
|
1, pull_type, wid);
|
|
pull->set_line(*this);
|
|
pull->pin(0).drive0(Link::SUPPLY);
|
|
pull->pin(0).drive1(Link::SUPPLY);
|
|
des->add_node(pull);
|
|
wtype = NetNet::WIRE;
|
|
|
|
if (debug_elaborate) {
|
|
cerr << get_fileline() << ": debug: "
|
|
<< "Generate a SUPPLY pulldown for the "
|
|
<< "supply0 net." << endl;
|
|
}
|
|
}
|
|
|
|
perm_string name = peek_tail_name(hname_);
|
|
if (debug_elaborate) {
|
|
cerr << get_fileline() << ": debug: Create signal "
|
|
<< wtype << " ["<<msb<<":"<<lsb<<"] " << name
|
|
<< " in scope " << scope_path(scope) << endl;
|
|
}
|
|
|
|
|
|
NetNet*sig = array_dimensions > 0
|
|
? new NetNet(scope, name, wtype, msb, lsb, array_s0, array_e0)
|
|
: new NetNet(scope, name, wtype, msb, lsb);
|
|
|
|
ivl_variable_type_t use_data_type = data_type_;
|
|
if (use_data_type == IVL_VT_NO_TYPE) {
|
|
use_data_type = IVL_VT_LOGIC;
|
|
if (debug_elaborate) {
|
|
cerr << get_fileline() << ": debug: "
|
|
<< "Signal " << name
|
|
<< " in scope " << scope_path(scope)
|
|
<< " defaults to data type " << use_data_type << endl;
|
|
}
|
|
}
|
|
|
|
sig->data_type(use_data_type);
|
|
sig->set_line(*this);
|
|
sig->port_type(port_type_);
|
|
sig->set_signed(get_signed());
|
|
sig->set_isint(get_isint());
|
|
|
|
if (pull)
|
|
connect(sig->pin(0), pull->pin(0));
|
|
|
|
for (unsigned idx = 0 ; idx < nattrib ; idx += 1)
|
|
sig->attribute(attrib_list[idx].key, attrib_list[idx].val);
|
|
|
|
return sig;
|
|
}
|
|
|