diff --git a/elab_net.cc b/elab_net.cc index d16add4f6..27656c299 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -638,6 +638,7 @@ NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const */ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const { + assert(scope->type() == NetScope::MODULE); NetNet*sig = des->find_signal(scope, path_); if (sig == 0) { cerr << get_fileline() << ": error: no wire/reg " << path_ @@ -690,8 +691,10 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const /* If this is a part select of the entire signal (or no part select at all) then we're done. */ - if ((lidx == 0) && (midx == (long)sig->vector_width()-1)) + if ((lidx == 0) && (midx == (long)sig->vector_width()-1)) { + scope->add_module_port(sig); return sig; + } unsigned swid = abs(midx - lidx) + 1; ivl_assert(*this, swid > 0 && swid < sig->vector_width()); @@ -701,6 +704,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const tmp->port_type(sig->port_type()); tmp->data_type(sig->data_type()); tmp->set_line(*this); + tmp->local_flag(true); NetNode*ps = 0; switch (sig->port_type()) { @@ -732,5 +736,6 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const ps->set_line(*this); des->add_node(ps); + scope->add_module_port(sig); return sig; } diff --git a/emit.cc b/emit.cc index 8148dc1dd..8411489a8 100644 --- a/emit.cc +++ b/emit.cc @@ -409,6 +409,7 @@ void NetScope::emit_scope(struct target_t*tgt) const tgt->signal_paths(cur->second); } + if (type_ == MODULE) tgt->convert_module_ports(this); } bool NetScope::emit_defs(struct target_t*tgt) const diff --git a/ivl.def b/ivl.def index 2eceb62dd..d44386270 100644 --- a/ivl.def +++ b/ivl.def @@ -189,6 +189,7 @@ ivl_scope_logs ivl_scope_log ivl_scope_lpms ivl_scope_lpm +ivl_scope_mod_port ivl_scope_name ivl_scope_param ivl_scope_params diff --git a/ivl_target.h b/ivl_target.h index 41cf61d9c..cba9aa05a 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1712,6 +1712,7 @@ extern ivl_parameter_t ivl_scope_param(ivl_scope_t net, unsigned idx); extern ivl_scope_t ivl_scope_parent(ivl_scope_t net); extern unsigned ivl_scope_ports(ivl_scope_t net); extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx); +extern ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_sigs(ivl_scope_t net); extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_switches(ivl_scope_t net); diff --git a/net_scope.cc b/net_scope.cc index f040b038a..50f2d646f 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2011 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 @@ -359,6 +359,25 @@ perm_string NetScope::module_name() const return module_name_; } +void NetScope::add_module_port(NetNet*port) +{ + assert(type_ == MODULE); + ports_.push_back(port); +} + +unsigned NetScope::module_ports() const +{ + assert(type_ == MODULE); + return ports_.size(); +} + +NetNet* NetScope::module_port(unsigned idx) const +{ + assert(type_ == MODULE); + assert(idx < ports_.size()); + return ports_[idx]; +} + void NetScope::time_unit(int val) { time_unit_ = val; diff --git a/netlist.h b/netlist.h index 623d023c0..4de029512 100644 --- a/netlist.h +++ b/netlist.h @@ -804,6 +804,11 @@ class NetScope : public Attrib { /* If the scope represents a module instance, the module_name is the name of the module itself. */ perm_string module_name() const; + /* If the scope is a module then it may have ports that we need + * to keep track of. */ + void add_module_port(NetNet*port); + unsigned module_ports() const; + NetNet*module_port(unsigned idx) const; /* Scopes have their own time units and time precision. The unit and precision are given as power of 10, i.e., -3 is @@ -944,6 +949,7 @@ class NetScope : public Attrib { typedef std::map::const_iterator signals_map_iter_t; std::map signals_map_; perm_string module_name_; + vectorports_; union { NetTaskDef*task_; NetFuncDef*func_; diff --git a/t-dll-api.cc b/t-dll-api.cc index ad0efc8ba..c04be3e66 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1928,7 +1928,8 @@ extern "C" ivl_scope_t ivl_scope_parent(ivl_scope_t net) extern "C" unsigned ivl_scope_ports(ivl_scope_t net) { assert(net); - if (net->type_ == IVL_SCT_FUNCTION || + if (net->type_ == IVL_SCT_MODULE || + net->type_ == IVL_SCT_FUNCTION || net->type_ == IVL_SCT_TASK) return net->ports; return 0; } @@ -1939,7 +1940,15 @@ extern "C" ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx) assert(net->type_ == IVL_SCT_FUNCTION || net->type_ == IVL_SCT_TASK); assert(idx < net->ports); - return net->port[idx]; + return net->u_.port[idx]; +} + +extern "C" ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx) +{ + assert(net); + assert(net->type_ == IVL_SCT_MODULE); + assert(idx < net->ports); + return net->u_.nex[idx]; } extern "C" unsigned ivl_scope_sigs(ivl_scope_t net) diff --git a/t-dll-proc.cc b/t-dll-proc.cc index bb75c982f..783ce6618 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -88,9 +88,9 @@ void dll_target::task_def(const NetScope*net) scop->ports = def->port_count(); if (scop->ports > 0) { - scop->port = new ivl_signal_t[scop->ports]; + scop->u_.port = new ivl_signal_t[scop->ports]; for (unsigned idx = 0 ; idx < scop->ports ; idx += 1) - scop->port[idx] = find_signal(des_, def->port(idx)); + scop->u_.port[idx] = find_signal(des_, def->port(idx)); } } @@ -110,9 +110,9 @@ bool dll_target::func_def(const NetScope*net) scop->ports = def->port_count() + 1; if (scop->ports > 0) { - scop->port = new ivl_signal_t[scop->ports]; + scop->u_.port = new ivl_signal_t[scop->ports]; for (unsigned idx = 1 ; idx < scop->ports ; idx += 1) - scop->port[idx] = find_signal(des_, def->port(idx-1)); + scop->u_.port[idx] = find_signal(des_, def->port(idx-1)); } /* FIXME: the ivl_target API expects port-0 to be the output @@ -121,7 +121,7 @@ bool dll_target::func_def(const NetScope*net) this, but that will break code generators that use this result. */ if (const NetNet*ret_sig = def->return_sig()) { - scop->port[0] = find_signal(des_, ret_sig); + scop->u_.port[0] = find_signal(des_, ret_sig); return true; } diff --git a/t-dll.cc b/t-dll.cc index 2ae7b0c93..1378539c8 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -563,6 +563,13 @@ void dll_target::add_root(ivl_design_s &des__, const NetScope *s) root_->attr = fill_in_attributes(s); root_->is_auto = 0; root_->is_cell = s->is_cell(); + root_->ports = s->module_ports(); + if (root_->ports > 0) { + root_->u_.net = new NetNet*[root_->ports]; + for (unsigned idx = 0; idx < root_->ports; idx += 1) { + root_->u_.net[idx] = s->module_port(idx); + } + } des__.nroots_++; if (des__.roots_) @@ -2273,6 +2280,7 @@ void dll_target::scope(const NetScope*net) FILE_NAME(scop, net); scop->parent = find_scope(des_, net->parent()); assert(scop->parent); + scop->parent->children[net->fullname()] = scop; scop->nsigs_ = 0; scop->sigs_ = 0; scop->nlog_ = 0; @@ -2294,6 +2302,13 @@ void dll_target::scope(const NetScope*net) case NetScope::MODULE: scop->type_ = IVL_SCT_MODULE; scop->tname_ = net->module_name(); + scop->ports = net->module_ports(); + if (scop->ports > 0) { + scop->u_.net = new NetNet*[scop->ports]; + for (unsigned idx = 0; idx < scop->ports; idx += 1) { + scop->u_.net[idx] = net->module_port(idx); + } + } break; case NetScope::TASK: { const NetTaskDef*def = net->task_def(); @@ -2324,10 +2339,20 @@ void dll_target::scope(const NetScope*net) scop->tname_ = scop->name_; break; } + } +} - assert(scop->parent != 0); - - scop->parent->children[net->fullname()] = scop; +void dll_target::convert_module_ports(const NetScope*net) +{ + ivl_scope_t scop = find_scope(des_, net); + if (scop->ports > 0) { + NetNet**nets = scop->u_.net; + scop->u_.nex = new ivl_nexus_t[scop->ports]; + for (unsigned idx = 0; idx < scop->ports; idx += 1) { + ivl_signal_t sig = find_signal(des_, nets[idx]); + scop->u_.nex[idx] = nexus_sig_make(sig, 0); + } + delete nets; } } diff --git a/t-dll.h b/t-dll.h index db0828627..00ae3a820 100644 --- a/t-dll.h +++ b/t-dll.h @@ -93,6 +93,7 @@ struct dll_target : public target_t, public expr_scan_t { bool process(const NetProcTop*); bool process(const NetAnalogTop*); void scope(const NetScope*); + void convert_module_ports(const NetScope*); void signal(const NetNet*); bool signal_paths(const NetNet*); ivl_dll_t dll_; @@ -646,7 +647,11 @@ struct ivl_scope_s { unsigned is_cell; unsigned ports; - ivl_signal_t*port; + union { + ivl_signal_t*port; + ivl_nexus_t*nex; + NetNet**net; + } u_; std::vectorswitches; diff --git a/target.cc b/target.cc index 3df7a9c1b..7c744dd87 100644 --- a/target.cc +++ b/target.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010 Stephen Williams + * Copyright (c) 1998-2011 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -32,6 +32,10 @@ void target_t::scope(const NetScope*) { } +void target_t::convert_module_ports(const NetScope*) +{ +} + bool target_t::branch(const NetBranch*obj) { cerr << obj->get_fileline() << ": error: target (" << typeid(*this).name() diff --git a/target.h b/target.h index 87d338c24..1ff7fc522 100644 --- a/target.h +++ b/target.h @@ -1,7 +1,7 @@ #ifndef __target_H #define __target_H /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2011 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 @@ -56,6 +56,10 @@ struct target_t { anything else is called. */ virtual void scope(const NetScope*); + /* This is called to convert module ports from a NetNet* to an + * ivl_signal_t object. */ + virtual void convert_module_ports(const NetScope*); + /* Output an event object. Called for each named event in the scope. */ virtual void event(const NetEvent*); diff --git a/vvp/parse.y b/vvp/parse.y index 1f3e4c2cb..23bab0337 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -560,7 +560,7 @@ statement requirements so are handled by their own rules. */ | label_opt K_file_line T_NUMBER T_NUMBER T_STRING ';' { compile_file_line($1, $3, $4, $5); } - + | label_opt K_file_line T_NUMBER T_NUMBER T_NUMBER ';' { assert($5 == 0); compile_file_line($1, $3, $4, 0); }