Merge branch 'x-mil13'

This commit is contained in:
Stephen Williams 2014-04-07 11:06:54 -07:00
commit 97e1151388
23 changed files with 622 additions and 224 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2014 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
@ -22,22 +22,26 @@
# include <iostream>
# include <cstring>
# include <cstdlib>
# include <climits>
using namespace std;
hname_t::hname_t()
{
number_ = INT_MIN;
}
hname_t::hname_t(perm_string text)
: name_(text)
{
number_ = INT_MIN;
}
hname_t::hname_t(perm_string text, int num)
: name_(text), number_(num)
: name_(text), number_(1)
{
number_[0] = num;
}
hname_t::hname_t(perm_string text, vector<int>&nums)
: name_(text), number_(nums)
{
}
@ -53,24 +57,50 @@ hname_t& hname_t::operator = (const hname_t&that)
return *this;
}
bool operator < (const hname_t&l, const hname_t&r)
bool hname_t::operator < (const hname_t&r) const
{
int cmp = strcmp(l.peek_name(), r.peek_name());
int cmp = strcmp(name_, r.name_);
if (cmp < 0) return true;
if (cmp > 0) return false;
if (l.has_number() && r.has_number())
return l.peek_number() < r.peek_number();
else
return false;
// The text parts are equal, so compare then number
// parts. Finish as soon as we find one to be less or more
// than the other.
size_t idx = 0;
while (number_.size() > idx || r.number_.size() > idx) {
// Ran out of l numbers, so less.
if (number_.size() <= idx)
return true;
// Ran out of r numbers, so greater.
if (r.number_.size() <= idx)
return false;
if (number_[idx] < r.number_[idx])
return true;
if (number_[idx] > r.number_[idx])
return false;
idx += 1;
}
// Fall-through means that we are equal, including all the
// number parts, so not less.
return false;
}
bool operator == (const hname_t&l, const hname_t&r)
bool hname_t::operator == (const hname_t&r) const
{
if (l.peek_name() == r.peek_name()) {
if (l.has_number() && r.has_number())
return l.peek_number() == r.peek_number();
else
return true;
if (name_ == r.name_) {
if (number_.size() != r.number_.size())
return false;
for (size_t idx = 0 ; idx < number_.size() ; idx += 1)
if (number_[idx] != r.number_[idx]) return false;
return true;
}
return false;
@ -84,8 +114,8 @@ ostream& operator<< (ostream&out, const hname_t&that)
}
out << that.peek_name();
if (that.has_number())
out << "[" << that.peek_number() << "]";
for (size_t idx = 0 ; idx < that.number_.size() ; idx += 1)
out << "[" << that.number_[idx] << "]";
return out;
}

34
HName.h
View File

@ -1,7 +1,7 @@
#ifndef __HName_H
#define __HName_H
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2014 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
@ -21,13 +21,10 @@
# include <iostream>
# include <list>
# include <vector>
# include "StringHeap.h"
# include <climits>
#ifdef __GNUC__
#if __GNUC__ > 2
using namespace std;
#endif
#endif
# include <cassert>
/*
* This class represents a component of a Verilog hierarchical name. A
@ -39,27 +36,33 @@ using namespace std;
class hname_t {
friend ostream& operator<< (ostream&out, const hname_t&that);
public:
hname_t ();
explicit hname_t (perm_string text);
explicit hname_t (perm_string text, int num);
explicit hname_t (perm_string text, std::vector<int>&nums);
hname_t (const hname_t&that);
~hname_t();
hname_t& operator= (const hname_t&);
bool operator == (const hname_t&that) const;
bool operator < (const hname_t&that) const;
// Return the string part of the hname_t.
perm_string peek_name(void) const;
bool has_number() const;
int peek_number() const;
size_t has_numbers() const;
int peek_number(size_t idx) const;
private:
perm_string name_;
// If the number is anything other than INT_MIN, then this is
// the numeric part of the name. Otherwise, it is not part of
// the name at all.
int number_;
std::vector<int> number_;
private: // not implemented
};
@ -73,18 +76,17 @@ inline perm_string hname_t::peek_name(void) const
return name_;
}
inline int hname_t::peek_number() const
inline int hname_t::peek_number(size_t idx) const
{
return number_;
assert(number_.size() > idx);
return number_[idx];
}
inline bool hname_t::has_number() const
inline size_t hname_t::has_numbers() const
{
return number_ != INT_MIN;
return number_.size();
}
extern bool operator < (const hname_t&, const hname_t&);
extern bool operator == (const hname_t&, const hname_t&);
extern ostream& operator<< (ostream&, const hname_t&);
inline bool operator != (const hname_t&l, const hname_t&r)

View File

@ -366,6 +366,11 @@ class PEIdent : public PExpr {
// only applies to Ident expressions.
NetNet* elaborate_subport(Design*des, NetScope*sc) const;
// Elaborate the identifier allowing for unpacked arrays. This
// method only applies to Ident expressions because only Ident
// expressions can can be unpacked arrays.
NetNet* elaborate_unpacked_net(Design*des, NetScope*sc) const;
verinum* eval_const(Design*des, NetScope*sc) const;
virtual bool is_collapsible_net(Design*des, NetScope*scope) const;

View File

@ -124,6 +124,7 @@ class PGAssign : public PGate {
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
void elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const;
};

View File

@ -145,6 +145,35 @@ ostream& operator << (ostream&o, ivl_switch_type_t val)
return o;
}
ostream& operator << (ostream&fd, PortType::Enum val)
{
switch (val) {
case PortType::NOT_A_PORT:
fd << "NOT_A_PORT";
break;
case PortType::PIMPLICIT:
fd << "PIMPLICIT";
break;
case PortType::PINPUT:
fd << "PINPUT";
break;
case PortType::POUTPUT:
fd << "POUTPUT";
break;
case PortType::PINOUT:
fd << "PINOUT";
break;
case PortType::PREF:
fd << "PREF";
break;
default:
fd << "PortType::Enum::?";
break;
}
return fd;
}
ostream& ivl_type_s::debug_dump(ostream&o) const
{
o << typeid(*this).name();
@ -171,9 +200,7 @@ static inline void dump_scope_path(ostream&o, const NetScope*scope)
o << ".";
}
const hname_t name = scope->fullname();
o << name.peek_name();
if (name.has_number())
o << "[" << name.peek_number() << "]";
o << name;
}
ostream& operator <<(ostream&o, struct __ScopePathManip marg)

View File

@ -1790,6 +1790,11 @@ bool calculate_part(const LineInfo*li, Design*des, NetScope*scope,
}
return true;
case index_component_t::SEL_IDX_UP:
wid = lsb;
off = msb;
break;
default:
ivl_assert(*li, 0);
break;
@ -2585,6 +2590,7 @@ bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
{
list<index_component_t> index;
index = path_.back().index;
ivl_assert(*this, index.size() >= net->unpacked_dimensions());
for (size_t idx = 0 ; idx < net->unpacked_dimensions() ; idx += 1)
index.pop_front();
@ -2826,7 +2832,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb);
}
use_width = 1;
// If we have a net in hand, then we can predict what
// the slice width will be. If not, then just guess.
if (net == 0)
use_width = 1;
break;
default:
ivl_assert(*this, 0);
@ -2858,15 +2867,35 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// The width of a signal expression is the width of the signal.
if (net != 0) {
size_t use_depth = name_tail.index.size();
// Account for unpacked dimensions by assuming that the
// unpacked dimensions are consumed first, so subtract
// the unpacked dimensions from the dimension depth
// useable for making the slice.
if (use_depth >= net->unpacked_dimensions()) {
use_depth -= net->unpacked_dimensions();
} else {
// In this case, we have a slice of an unpacked
// array. This likely handled as an array instead
// of a slice. Hmm...
use_depth = 0;
}
expr_type_ = net->data_type();
expr_width_ = net->vector_width();
expr_width_ = net->slice_width(use_depth);
min_width_ = expr_width_;
signed_flag_ = net->get_signed();
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::test_width: "
<< net->name() << " is a net, "
<< "type=" << expr_type_
<< ", width=" << expr_width_ << endl;
<< ", width=" << expr_width_
<< ", signed_=" << (signed_flag_?"true":"false")
<< ", use_depth=" << use_depth
<< ", packed_dimensions=" << net->packed_dimensions()
<< ", unpacked_dimensions=" << net->unpacked_dimensions()
<< endl;
}
return expr_width_;
}
@ -3222,6 +3251,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
if (!tmp) return 0;
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
<< "Expression as net. expr_wid=" << expr_wid
<< ", tmp->expr_width()=" << tmp->expr_width()
<< ", tmp=" << *tmp << endl;
}
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
@ -3969,7 +4005,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
if (name_tail.index.empty()) {
cerr << get_fileline() << ": error: Array " << path()
<< " Needs an array index here." << endl;
<< " needs an array index here." << endl;
des->errors += 1;
return 0;
}
@ -4439,6 +4475,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
// making a mux part in the netlist.
if (NetEConst*msc = dynamic_cast<NetEConst*> (mux)) {
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: "
<< "mux is constant=" << *msc
<< ", packed_dims()=" << net->sig()->packed_dims()
<< ", packed_dims().size()=" << net->sig()->packed_dims().size()
<< ", prefix_indices.size()=" << prefix_indices.size()
<< endl;
}
// Special case: The bit select expression is constant
// x/z. The result of the expression is 1'bx.
if (! msc->value().is_defined()) {
@ -4456,6 +4501,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
<< endl;
}
// FIXME: Should I be using slice_width() here?
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
delete mux;
@ -4547,6 +4593,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
if (net->vector_width() == 1)
return net;
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_expr_net_bit_: "
<< "Make bit select idx=" << idx
<< endl;
}
// Make an expression out of the index
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);

View File

@ -501,6 +501,10 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first.
long widx = 0;
// Set this to true if we calculate the word index. This is
// used to distinguish between unpacked array assignment and
// array word assignment.
bool widx_flag = false;
list<long> unpacked_indices_const;
@ -555,8 +559,9 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
packed_base = collapse_array_indices(des, scope, sig, tmp_index);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "packed_base expression = " << *packed_base << endl;
cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: "
<< "packed_base=" << *packed_base
<< ", member_off=" << member_off << endl;
}
}
@ -590,13 +595,31 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
midx = lidx + tmp_wid - 1;
}
} else if (gn_system_verilog() && sig->unpacked_dimensions() > 0 && path_tail.index.size() == 0) {
// In this case, we are doing a continuous assignment to
// an unpacked array. The NetNet representation is a
// NetNet with a pin for each array element, so there is
// nothing more needed here.
//
// This can come up from code like this:
// logic [...] data [0:3];
// assign data = ...;
// In this case, "sig" is "data", and sig->pin_count()
// is 4 to account for the unpacked size.
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: "
<< "Net assign to unpacked array \"" << sig->name()
<< "\" with " << sig->pin_count() << " elements." << endl;
}
} else if (sig->unpacked_dimensions() > 0) {
// Make sure there are enough indices to address an array element.
if (path_tail.index.size() < sig->unpacked_dimensions()) {
cerr << get_fileline() << ": error: Array " << path()
<< " needs " << sig->unpacked_dimensions() << " indices,"
<< " but got only " << path_tail.index.size() << "." << endl;
<< " but got only " << path_tail.index.size() << ". (net)" << endl;
des->errors += 1;
return 0;
}
@ -627,6 +650,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
<< sig->name() << as_indices(unpacked_indices)
<< "." << endl;
widx = -1;
widx_flag = true;
} else {
NetExpr*canon_index = 0;
@ -639,12 +663,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
<< sig->name() << as_indices(unpacked_indices_const)
<< "." << endl;
widx = -1;
widx_flag = true;
} else {
NetEConst*canon_const = dynamic_cast<NetEConst*>(canon_index);
ivl_assert(*this, canon_const);
widx = canon_const->value().as_long();
widx_flag = true;
delete canon_index;
}
}
@ -682,6 +708,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
}
} else if (!path_tail.index.empty()) {
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_lnet_common_: "
<< "path_tail.index.size()=" << path_tail.index.size()
<< endl;
}
// There are index expressions on the name, so this is a
// bit/slice select of the name. Calculate a canonical
// part select.
if (sig->get_scalar()) {
cerr << get_fileline() << ": error: "
<< "can not select part of ";
@ -710,14 +746,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned subnet_wid = midx-lidx+1;
/* Check if the l-value bits are double-driven. */
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx)) {
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx, widx_flag? widx : 0)) {
cerr << get_fileline() << ": error: Unresolved net/uwire "
<< sig->name() << " cannot have multiple drivers." << endl;
if (debug_elaborate) {
cerr << get_fileline() << ": : Overlap in "
<< "[" << midx << ":" << lidx << "] (canonical)"
<< ", widx=" << (widx_flag? widx : 0)
<< ", vector width=" << sig->vector_width()
<< endl;
}
des->errors += 1;
return 0;
}
if (sig->pin_count() > 1) {
if (sig->pin_count() > 1 && widx_flag) {
if (widx < 0 || widx >= (long) sig->pin_count())
return 0;
@ -729,6 +772,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
tmp->local_flag(true);
connect(sig->pin(widx), tmp->pin(0));
sig = tmp;
} else if (sig->pin_count() > 1) {
// If this turns out to be an l-value unpacked array,
// then let the caller handle it. It will probably be
// converted into an array of assignments.
return sig;
}
/* If the desired l-value vector is narrower than the
@ -851,6 +901,33 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const
long midx;
long lidx;
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_subport: "
<< "path_ = \"" << path_
<< "\", unpacked_dimensions=" << sig->unpacked_dimensions()
<< ", port_type()=" << sig->port_type() << endl;
}
if (sig->unpacked_dimensions() && !gn_system_verilog()) {
cerr << get_fileline() << ": error: "
<< "Ports cannot be unpacked arrays. Try enabling SystemVerilog support." << endl;
des->errors += 1;
return 0;
}
// There cannot be parts to an unpacked array, so process this
// simply as an unpacked array.
if (sig->unpacked_dimensions()) {
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_subport: "
<< "path_=\"" << path_
<< "\" is an unpacked array with " << sig->pin_count()
<< " elements." << endl;
}
scope->add_module_port_net(sig);
return sig;
}
/* Evaluate the part/bit select expressions, to get the part
select of the signal that attaches to the port. Also handle
range and direction checking here. */
@ -912,6 +989,20 @@ NetNet* PEIdent::elaborate_subport(Design*des, NetScope*scope) const
return sig;
}
NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const
{
NetNet* sig = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
perm_string method_name;
symbol_search(this, des, scope, path_, sig, par, eve);
ivl_assert(*this, sig);
return sig;
}
bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const
{
assert(scope);

View File

@ -883,8 +883,10 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// Check the generate block name.
// A generate "loop" can not have the same name as another scope object.
const NetScope *child = container->child(hname_t(scope_name));
// A generate "loop" can not have the same name as another
// scope object. Find any scope with this name, not just an
// exact match scope.
const NetScope *child = container->child_byname(scope_name);
if (child) {
cerr << get_fileline() << ": error: generate \"loop\" and ";
child->print_type(cerr);

View File

@ -949,7 +949,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
des->errors += error_cnt_;
// A signal can not have the same name as a scope object.
const NetScope *child = scope->child(hname_t(name_));
const NetScope *child = scope->child_byname(name_);
if (child) {
cerr << get_fileline() << ": error: signal and ";
child->print_type(cerr);

View File

@ -77,11 +77,19 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return;
}
// If this turns out to be an assignment to an unpacked array,
// then handle that special case elsewhere.
if (lval->pin_count() > 1) {
elaborate_unpacked_array_(des, scope, lval);
return;
}
ivl_assert(*this, lval->pin_count() == 1);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
<< " width=" << lval->vector_width() << endl;
cerr << get_fileline() << ": PGAssign::elaborate: elaborated l-value"
<< " width=" << lval->vector_width()
<< ", pin_count=" << lval->pin_count() << endl;
}
NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(),
@ -211,6 +219,18 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
}
void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const
{
PEIdent*rval_pident = dynamic_cast<PEIdent*> (pin(1));
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == lval->pin_count());
assign_unpacked_with_bufz(des, scope, this, lval, rval_net);
}
unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
long&high, long&low) const
{
@ -1350,18 +1370,22 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
unsigned int prt_vector_width = 0;
PortType::Enum ptype = PortType::PIMPLICIT;
// Scan the module sub-ports for this instance...
// (Sub-ports are concatenated ports that form the
// single port for the instance. This is not a
// commonly used feature.)
for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) {
unsigned lbase = inst * mport.size();
PEIdent*pport = mport[ldx];
assert(pport);
ivl_assert(*this, pport);
NetNet *netnet = pport->elaborate_subport(des, inst_scope);
prts[lbase + ldx] = netnet;
if (netnet == 0)
continue;
assert(netnet);
prts_vector_width += netnet->vector_width();
prt_vector_width += netnet->vector_width();
ivl_assert(*this, netnet);
unsigned port_width = netnet->vector_width() * netnet->pin_count();
prts_vector_width += port_width;
prt_vector_width += port_width;
ptype = PortType::merged(netnet->port_type(), ptype);
}
inst_scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width );
@ -1392,9 +1416,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// module[s] port. sig is the thing outside the module
// that connects to the port.
NetNet*sig;
NetNet*sig = 0;
if (prts.empty() || (prts[0]->port_type() == NetNet::PINPUT)) {
// Special case: If the input port is an unpacked
// array, then there should be no sub-ports and
// the r-value expression is processed
// differently.
if (prts.size() >= 1 && prts[0]->pin_count()>1) {
ivl_assert(*this, prts.size()==1);
PEIdent*rval_pident = dynamic_cast<PEIdent*> (pins[idx]);
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count());
assign_unpacked_with_bufz(des, scope, this, prts[0], rval_net);
continue;
}
/* Input to module. elaborate the expression to
the desired width. If this in an instance
array, then let the net determine its own
@ -1471,6 +1511,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
} else if (prts[0]->port_type() == NetNet::PINOUT) {
// For now, do not support unpacked array outputs.
ivl_assert(*this, prts[0]->unpacked_dimensions()==0);
/* Inout to/from module. This is a more
complicated case, where the expression must be
an lnet, but also an r-value net.
@ -1530,6 +1573,28 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
/* Port type must be OUTPUT here. */
ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT);
// Special case: If the output port is an unpacked
// array, then there should be no sub-ports and
// the passed pexxpression is processed
// differently. Note that we are calling it the
// "r-value" expression, but since this is an
// output port, we assign to it from the internal object.
if (prts[0]->pin_count() > 1) {
ivl_assert(*this, prts.size()==1);
PEIdent*rval_pident = dynamic_cast<PEIdent*>(pins[idx]);
ivl_assert(*this, rval_pident);
NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope);
ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count());
assign_unpacked_with_bufz(des, scope, this, rval_net, prts[0]);
continue;
}
// At this point, arrays are handled.
ivl_assert(*this, prts[0]->unpacked_dimensions()==0);
/* Output from module. Elaborate the port
expression as the l-value of a continuous
assignment, as the port will continuous assign
@ -5812,7 +5877,9 @@ Design* elaborate(list<perm_string>roots)
// stuff to the design that should be cleaned later.
NetNet *netnet = mport[pin]->elaborate_subport(des, scope);
if (netnet != 0) {
// Elaboration may actually fail with erroneous input source
// Elaboration may actually fail with
// erroneous input source
ivl_assert(*mport[pin], netnet->pin_count()==1);
prt_vector_width += netnet->vector_width();
ptype = PortType::merged(netnet->port_type(), ptype);
}

View File

@ -325,8 +325,8 @@ TU [munpf]
if (in_package_scope) {
if (rc == IDENTIFIER) {
if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) {
delete[]yylval.text;
yylval.data_type = type;
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
rc = TYPE_IDENTIFIER;
}
}
@ -361,8 +361,8 @@ TU [munpf]
return this as a TYPE_IDENTIFIER instead. */
if (rc == IDENTIFIER && gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
delete[]yylval.text;
yylval.data_type = type;
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
rc = TYPE_IDENTIFIER;
}
}
@ -382,8 +382,8 @@ TU [munpf]
}
if (gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
delete[]yylval.text;
yylval.data_type = type;
yylval.type_identifier.text = yylval.text;
yylval.type_identifier.type = type;
return TYPE_IDENTIFIER;
}
}

View File

@ -668,6 +668,21 @@ const NetScope* NetScope::child(const hname_t&name) const
return cur->second;
}
const NetScope* NetScope::child_byname(perm_string name) const
{
hname_t hname (name);
map<hname_t,NetScope*>::const_iterator cur = children_.lower_bound(hname);
if (cur == children_.end())
return 0;
if (cur->first.peek_name() == name)
return cur->second;
return 0;
}
perm_string NetScope::local_symbol()
{
ostringstream res;

View File

@ -762,6 +762,9 @@ const netclass_t* NetNet::class_type(void) const
* In this case, slice_width(2) == 1 (slice_width(N) where N is the
* number of dimensions will always be 1.) and represents
* $bits(foo[a][b]). Then, slice_width(1)==4 ($bits(foo[a]) and slice_width(0)==24.
*
* NOTE: The caller should already have accounted for unpacked
* dimensions. The "depth" is only for the packed dimensions.
*/
unsigned long NetNet::slice_width(size_t depth) const
{
@ -868,17 +871,25 @@ unsigned NetNet::peek_eref() const
* Test each of the bits in the range, and set them. If any bits are
* already set then return true.
*/
bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb)
bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb, int widx)
{
if (lref_mask_.empty())
lref_mask_.resize(vector_width());
lref_mask_.resize(vector_width() * pin_count());
// If indexing a word that doesn't exist, then pretend this is
// never driven.
if (widx < 0)
return false;
if (widx >= (int)pin_count())
return false;
bool rc = false;
unsigned word_base = vector_width() * widx;
for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) {
if (lref_mask_[idx])
if (lref_mask_[idx+word_base])
rc = true;
else
lref_mask_[idx] = true;
lref_mask_[idx+word_base] = true;
}
return rc;

View File

@ -610,6 +610,7 @@ public:
static Enum merged( Enum lhs, Enum rhs );
};
extern std::ostream& operator << (std::ostream&, PortType::Enum);
/*
* Information on actual ports (rather than port-connected signals) of
@ -749,8 +750,10 @@ class NetNet : public NetObj, public PortType {
// Treating this node as a uwire, this function tests whether
// any bits in the canonical part are already driven. This is
// only useful for UNRESOLVED_WIRE objects.
bool test_and_set_part_driver(unsigned msb, unsigned lsb);
// only useful for UNRESOLVED_WIRE objects. The msb and lsb
// are the part select of the signal, and the widx is the word
// index if this is an unpacked array.
bool test_and_set_part_driver(unsigned msb, unsigned lsb, int widx =0);
unsigned get_refs() const;
@ -963,6 +966,12 @@ class NetScope : public Definitions, public Attrib {
const NetScope* parent() const { return up_; }
const NetScope* child(const hname_t&name) const;
// Look for a child scope by name. This ignores the number
// part of the child scope name, so there may be multiple
// matches. Only return one. This function is only really
// useful for some elaboration error checking.
const NetScope* child_byname(perm_string name) const;
// Nested modules have slightly different scope search rules.
inline bool nested_module() const { return nested_module_; }
// Program blocks have elaboration constraints.

View File

@ -309,7 +309,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
if (min_wid < base->expr_width()) min_wid = base->expr_width();
/* Now that we have the minimum needed width increase it by
* one to make room for the normalization calculation. */
min_wid += 1;
min_wid += 2;
/* Pad the base expression to the correct width. */
base = pad_to_width(base, min_wid, *base);
/* If the base expression is unsigned and either the lsb
@ -344,7 +344,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb,
if (min_wid < base->expr_width()) min_wid = base->expr_width();
/* Now that we have the minimum needed width increase it by
* one to make room for the normalization calculation. */
min_wid += 1;
min_wid += 2;
/* Pad the base expression to the correct width. */
base = pad_to_width(base, min_wid, *base);
/* If the offset is greater than zero then we need to do
@ -950,50 +950,48 @@ hname_t eval_path_component(Design*des, NetScope*scope,
if (comp.index.empty())
return hname_t(comp.name);
// The parser will assure that path components will have only
// one index. For example, foo[N] is one index, foo[n][m] is two.
assert(comp.index.size() == 1);
vector<int> index_values;
const index_component_t&index = comp.index.front();
for (list<index_component_t>::const_iterator cur = comp.index.begin()
; cur != comp.index.end() ; ++cur) {
const index_component_t&index = *cur;
if (index.sel != index_component_t::SEL_BIT) {
cerr << index.msb->get_fileline() << ": error: "
<< "Part select is not valid for this kind of object." << endl;
des->errors += 1;
return hname_t(comp.name, 0);
}
if (index.sel != index_component_t::SEL_BIT) {
cerr << index.msb->get_fileline() << ": error: "
<< "Part select is not valid for this kind of object." << endl;
des->errors += 1;
return hname_t(comp.name, 0);
}
// The parser will assure that path components will have only
// bit select index expressions. For example, "foo[n]" is OK,
// but "foo[n:m]" is not.
assert(index.sel == index_component_t::SEL_BIT);
// The parser will assure that path components will have only
// bit select index expressions. For example, "foo[n]" is OK,
// but "foo[n:m]" is not.
assert(index.sel == index_component_t::SEL_BIT);
// Evaluate the bit select to get a number.
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
ivl_assert(*index.msb, tmp);
// Now we should have a constant value for the bit select
// expression, and we can use it to make the final hname_t
// value, for example "foo[5]".
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
hname_t res(comp.name, ctmp->value().as_long());
delete ctmp;
return res;
}
// Evaluate the bit select to get a number.
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
ivl_assert(*index.msb, tmp);
if (NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp)) {
index_values.push_back(ctmp->value().as_long());
delete ctmp;
continue;
}
#if 1
// Darn, the expression doesn't evaluate to a constant. That's
// an error to be reported. And make up a fake index value to
// return to the caller.
cerr << index.msb->get_fileline() << ": error: "
<< "Scope index expression is not constant: "
<< *index.msb << endl;
des->errors += 1;
// Darn, the expression doesn't evaluate to a constant. That's
// an error to be reported. And make up a fake index value to
// return to the caller.
cerr << index.msb->get_fileline() << ": error: "
<< "Scope index expression is not constant: "
<< *index.msb << endl;
des->errors += 1;
#endif
error_flag = true;
error_flag = true;
delete tmp;
return hname_t (comp.name, 0);
delete tmp;
}
return hname_t(comp.name, index_values);
}
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
@ -1338,3 +1336,21 @@ NetExpr*collapse_array_indices(Design*des, NetScope*scope, NetNet*net,
eval_expr(res, -1);
return res;
}
void assign_unpacked_with_bufz(Design*des, NetScope*scope,
const LineInfo*loc,
NetNet*lval, NetNet*rval)
{
ivl_assert(*loc, lval->pin_count()==rval->pin_count());
for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1) {
NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(),
lval->vector_width(), false);
driver->set_line(*loc);
des->add_node(driver);
connect(lval->pin(idx), driver->pin(0));
connect(driver->pin(1), rval->pin(idx));
}
}

View File

@ -349,4 +349,8 @@ extern NetExpr*collapse_array_exprs(Design*des, NetScope*scope,
const LineInfo*loc, NetNet*net,
const list<index_component_t>&indices);
extern void assign_unpacked_with_bufz(Design*des, NetScope*scope,
const LineInfo*loc,
NetNet*lval, NetNet*rval);
#endif

View File

@ -49,7 +49,7 @@ vector<netrange_t> netparray_t::slice_dimensions() const
vector<netrange_t> res (packed_dims_.size() + elem_dims.size());
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1)
res[idx] = packed_dims_[0];
res[idx] = packed_dims_[idx];
for (size_t idx = 0 ; idx < elem_dims.size() ; idx += 1)
res[idx+packed_dims_.size()] = elem_dims[idx];

View File

@ -18,6 +18,7 @@
*/
# include "nettypes.h"
# include <iostream>
# include <cassert>
using namespace std;
@ -101,6 +102,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
{
assert(prefix.size() < dims.size());
// Figure out the width of the slice, given the number of
// prefix numbers there are. We don't need to look at the
// actual values yet, but we do need to know how many there
// are compared to the actual dimensions of the target. So do
// this by multiplying the widths of the dims that are NOT
// accounted for by the prefix or sb indices.
size_t acc_wid = 1;
vector<netrange_t>::const_iterator pcur = dims.end();
for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) {
@ -108,8 +115,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
acc_wid *= pcur->width();
}
lwid = acc_wid;
lwid = acc_wid; // lwid is now the final slice width.
// pcur is pointing to the dimension AFTER the dimension that
// we have an index for, so step back one, then this will be
// used with the sb index. Start accumulating in the acc_off
// the offset into the n-dimensional vector.
-- pcur;
if (sb < pcur->get_msb() && sb < pcur->get_lsb())
return false;
@ -122,16 +133,18 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
else
acc_off += (pcur->get_lsb() - sb) * acc_wid;
// If there are no more prefix items, we are done.
if (prefix.empty()) {
loff = acc_off;
return true;
}
lwid *= pcur->width();
// Now similarly go through the prefix numbers, working
// through the dimensions until we run out. Accumulate a
// growing slice width (acc_wid) that is used to caculate the
// growing offset (acc_off).
list<long>::const_iterator icur = prefix.end();
do {
-- pcur;
-- icur;
acc_wid *= pcur->width();
if (pcur->get_msb() >= pcur->get_lsb())
@ -139,8 +152,11 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
else
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
-- pcur;
} while (icur != prefix.begin());
// Got our final offset.
loff = acc_off;
return true;

189
parse.y
View File

@ -46,12 +46,8 @@ static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
static struct {
NetNet::Type port_net_type;
NetNet::PortType port_type;
ivl_variable_type_t var_type;
bool sign_flag;
data_type_t* data_type;
list<pform_range_t>* range;
} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT,
IVL_VT_NO_TYPE, false, 0, 0};
} port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, 0};
/* The task and function rules need to briefly hold the pointer to the
task/function that is currently in progress. */
@ -417,6 +413,11 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
property_qualifier_t property_qualifier;
PPackage*package;
struct {
char*text;
data_type_t*type;
} type_identifier;
struct {
data_type_t*type;
list<PExpr*>*exprs;
@ -431,7 +432,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
%token <data_type> TYPE_IDENTIFIER
%token <type_identifier> TYPE_IDENTIFIER
%token <package> PACKAGE_IDENTIFIER
%token <discipline> DISCIPLINE_IDENTIFIER
%token <text> PATHPULSE_IDENTIFIER
@ -730,10 +731,11 @@ class_identifier
$$ = tmp;
}
| TYPE_IDENTIFIER
{ class_type_t*tmp = dynamic_cast<class_type_t*>($1);
{ class_type_t*tmp = dynamic_cast<class_type_t*>($1.type);
if (tmp == 0) {
yyerror(@1, "Type name is not a predeclared class name.");
yyerror(@1, "Type name \"%s\"is not a predeclared class name.", $1.text);
}
delete[]$1.text;
$$ = tmp;
}
;
@ -743,13 +745,14 @@ class_identifier
does indeed match a name. */
class_declaration_endlabel_opt
: ':' TYPE_IDENTIFIER
{ class_type_t*tmp = dynamic_cast<class_type_t*> ($2);
{ class_type_t*tmp = dynamic_cast<class_type_t*> ($2.type);
if (tmp == 0) {
yyerror(@2, "error: class declaration endlabel is not a class name\n");
yyerror(@2, "error: class declaration endlabel \"%s\" is not a class name\n", $2.text);
$$ = 0;
} else {
$$ = strdupnew(tmp->name.str());
}
delete[]$2.text;
}
| ':' IDENTIFIER
{ $$ = $2; }
@ -767,12 +770,14 @@ class_declaration_endlabel_opt
class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */
: K_extends TYPE_IDENTIFIER
{ $$.type = $2;
{ $$.type = $2.type;
$$.exprs= 0;
delete[]$2.text;
}
| K_extends TYPE_IDENTIFIER '(' expression_list_with_nuls ')'
{ $$.type = $2;
{ $$.type = $2.type;
$$.exprs = $4;
delete[]$2.text;
}
|
{ $$.type = 0; $$.exprs = 0; }
@ -1013,14 +1018,16 @@ data_type /* IEEE1800-2005: A.2.2.1 */
$$ = tmp;
}
| TYPE_IDENTIFIER dimensions_opt
{ if ($2) $$ = new parray_type_t($1, $2);
else $$ = $1;
{ if ($2) $$ = new parray_type_t($1.type, $2);
else $$ = $1.type;
delete[]$1.text;
}
| PACKAGE_IDENTIFIER K_SCOPE_RES
{ lex_in_package_scope($1); }
TYPE_IDENTIFIER
{ lex_in_package_scope(0);
$$ = $4;
$$ = $4.type;
delete[]$4.text;
}
| K_string
{ string_type_t*tmp = new string_type_t;
@ -1307,10 +1314,42 @@ loop_statement /* IEEE1800-2005: A.6.8 */
$$ = tmp;
}
// Handle for_variable_declaration syntax by wrapping the for(...)
// statement in a synthetic named block. We can name the block
// after the variable that we are creating, that identifier is
// safe in the controlling scope.
| K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')'
{ static unsigned for_counter = 0;
char for_block_name [64];
snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter);
for_counter += 1;
PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
FILE_NAME(tmp, @1);
current_block_stack.push(tmp);
list<decl_assignment_t*>assign_list;
decl_assignment_t*tmp_assign = new decl_assignment_t;
tmp_assign->name = lex_strings.make($4);
assign_list.push_back(tmp_assign);
pform_makewire(@4, 0, str_strength, &assign_list, NetNet::REG, $3);
}
statement_or_null
{ $$ = 0;
yyerror(@3, "sorry: for_variable_declaration not supported");
{ pform_name_t tmp_hident;
tmp_hident.push_back(name_component_t(lex_strings.make($4)));
PEIdent*tmp_ident = pform_new_ident(tmp_hident);
FILE_NAME(tmp_ident, @4);
PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13);
FILE_NAME(tmp_for, @1);
pform_pop_scope();
vector<Statement*>tmp_for_list (1);
tmp_for_list[0] = tmp_for;
PBlock*tmp_blk = current_block_stack.top();
tmp_blk->set_statement(tmp_for_list);
$$ = tmp_blk;
delete[]$4;
}
| K_forever statement_or_null
@ -1857,27 +1896,16 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
if ($4 != 0) {
yyerror(@4, "internal error: How can there be an unpacked range here?\n");
}
if (port_declaration_context.var_type == IVL_VT_NO_TYPE) {
tmp = pform_make_task_ports(@3, use_port_type,
port_declaration_context.data_type,
ilist);
} else {
tmp = pform_make_task_ports(@3, use_port_type,
port_declaration_context.var_type,
port_declaration_context.sign_flag,
copy_range(port_declaration_context.range),
ilist);
}
tmp = pform_make_task_ports(@3, use_port_type,
port_declaration_context.data_type,
ilist);
} else {
// Otherwise, the decorations for this identifier
// indicate the type. Save the type for any right
// context thta may come later.
port_declaration_context.port_type = use_port_type;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
if ($2 == 0) {
$2 = new vector_type_t(IVL_VT_LOGIC, false, 0);
FILE_NAME($2, @3);
@ -2143,6 +2171,20 @@ type_declaration
delete[]$3;
}
/* If the IDENTIFIER already is a typedef, it is possible for this
code to override the definition, but only if the typedef is
inherited from a different scope. */
| K_typedef data_type TYPE_IDENTIFIER ';'
{ perm_string name = lex_strings.make($3.text);
if (pform_test_type_identifier_local(name)) {
yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text);
} else {
pform_set_typedef(name, $2);
}
delete[]$3.text;
}
/* These are forward declarations... */
| K_typedef K_class IDENTIFIER ';'
@ -2170,9 +2212,6 @@ type_declaration
delete[]$2;
}
| K_typedef data_type TYPE_IDENTIFIER ';'
{ yyerror(@3, "error: Typedef identifier is already a type name."); }
| K_typedef error ';'
{ yyerror(@2, "error: Syntax error in typedef clause.");
yyerrok;
@ -3108,9 +3147,10 @@ expr_primary
/* There are a few special cases (notably $bits argument) where the
expression may be a type name. Let the elaborator sort this out. */
| TYPE_IDENTIFIER
{ PETypename*tmp = new PETypename($1);
{ PETypename*tmp = new PETypename($1.type);
FILE_NAME(tmp,@1);
$$ = tmp;
delete[]$1.text;
}
/* The hierarchy_identifier rule matches simple identifiers as well as
@ -3762,10 +3802,7 @@ list_of_port_declarations
pform_module_define_port(@3, name,
port_declaration_context.port_type,
port_declaration_context.port_net_type,
port_declaration_context.var_type,
port_declaration_context.sign_flag,
port_declaration_context.data_type,
port_declaration_context.range, 0);
port_declaration_context.data_type, 0);
delete[]$3;
$$ = tmp;
}
@ -3785,21 +3822,14 @@ port_declaration
: attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
{ Module::port_t*ptmp;
perm_string name = lex_strings.make($5);
data_type_t*use_type = $4;
if ($6) use_type = new uarray_type_t(use_type, $6);
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, IVL_VT_NO_TYPE,
false, $4, 0, $1);
pform_module_define_port(@2, name, NetNet::PINPUT, $3, use_type, $1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = $3;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = $4;
delete[]$5;
if ($6) {
yyerror(@6, "sorry: Input ports with unpacked dimensions not supported.");
delete $6;
}
$$ = ptmp;
}
| attribute_list_opt
@ -3808,15 +3838,13 @@ port_declaration
perm_string name = lex_strings.make($4);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
pform_module_define_port(@2, name, NetNet::PINPUT,
NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1);
real_type_t*real_type = new real_type_t(real_type_t::REAL);
FILE_NAME(real_type, @3);
pform_module_define_port(@2, name, NetNet::PINPUT,
NetNet::WIRE, real_type, $1);
port_declaration_context.port_type = NetNet::PINPUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = 0;
port_declaration_context.data_type = real_type;
delete[]$4;
$$ = ptmp;
}
@ -3824,14 +3852,9 @@ port_declaration
{ Module::port_t*ptmp;
perm_string name = lex_strings.make($5);
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
pform_module_define_port(@2, name, NetNet::PINOUT, $3, IVL_VT_NO_TYPE,
false, $4, 0, $1);
pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, $1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = $3;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = $4;
delete[]$5;
if ($6) {
@ -3846,21 +3869,21 @@ port_declaration
perm_string name = lex_strings.make($4);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
real_type_t*real_type = new real_type_t(real_type_t::REAL);
FILE_NAME(real_type, @3);
pform_module_define_port(@2, name, NetNet::PINOUT,
NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1);
NetNet::WIRE, real_type, $1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = 0;
port_declaration_context.data_type = real_type;
delete[]$4;
$$ = ptmp;
}
| attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
{ Module::port_t*ptmp;
perm_string name = lex_strings.make($5);
data_type_t*use_dtype = $4;
if ($6) use_dtype = new uarray_type_t(use_dtype, $6);
NetNet::Type use_type = $3;
if (use_type == NetNet::IMPLICIT) {
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($4)) {
@ -3882,20 +3905,11 @@ port_declaration
}
}
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE,
false, $4, 0, $1);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, use_dtype, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = use_type;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = $4;
delete[]$5;
if ($6) {
yyerror(@6, "sorry: Output ports with unpacked dimensions not supported.");
delete $6;
}
$$ = ptmp;
}
| attribute_list_opt
@ -3904,15 +3918,13 @@ port_declaration
perm_string name = lex_strings.make($4);
ptmp = pform_module_port_reference(name, @2.text,
@2.first_line);
real_type_t*real_type = new real_type_t(real_type_t::REAL);
FILE_NAME(real_type, @3);
pform_module_define_port(@2, name, NetNet::POUTPUT,
NetNet::WIRE, IVL_VT_REAL, true, 0, 0, $1);
NetNet::WIRE, real_type, $1);
port_declaration_context.port_type = NetNet::POUTPUT;
port_declaration_context.port_net_type = NetNet::WIRE;
port_declaration_context.var_type = IVL_VT_REAL;
port_declaration_context.sign_flag = true;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = 0;
port_declaration_context.data_type = real_type;
delete[]$4;
$$ = ptmp;
}
@ -3931,14 +3943,9 @@ port_declaration
}
}
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, IVL_VT_NO_TYPE,
false, $4, 0, $1);
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $1);
port_declaration_context.port_type = NetNet::PINOUT;
port_declaration_context.port_net_type = use_type;
port_declaration_context.var_type = IVL_VT_NO_TYPE;
port_declaration_context.sign_flag = false;
delete port_declaration_context.range;
port_declaration_context.range = 0;
port_declaration_context.data_type = $4;
pform_make_reginit(@5, name, $7);

View File

@ -96,6 +96,8 @@ extern void lex_in_package_scope(PPackage*pkg);
extern data_type_t* pform_test_type_identifier(const char*txt);
extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt);
extern bool pform_test_type_identifier_local(perm_string txt);
/*
* Test if this identifier is a package name. The pform needs to help
* the lexor here because the parser detects packages and saves them.

View File

@ -584,6 +584,31 @@ data_type_t* pform_test_type_identifier(const char*txt)
return 0;
}
/*
* The parser uses this function to test if the name is a typedef in
* the current scope. We use this to know if we can override the
* definition because it shadows a containing scope.
*/
bool pform_test_type_identifier_local(perm_string name)
{
if (lexical_scope == 0) {
if (test_type_identifier_in_root(name))
return true;
else
return false;
}
LexicalScope*cur_scope = lexical_scope;
map<perm_string,data_type_t*>::iterator cur;
cur = cur_scope->typedefs.find(name);
if (cur != cur_scope->typedefs.end())
return true;
return false;
}
PECallFunction* pform_make_call_function(const struct vlltype&loc,
const pform_name_t&name,
const list<PExpr*>&parms)
@ -2129,15 +2154,14 @@ void pform_make_reginit(const struct vlltype&li,
*/
void pform_module_define_port(const struct vlltype&li,
perm_string name,
NetNet::PortType port_type,
NetNet::PortType port_kind,
NetNet::Type type,
ivl_variable_type_t data_type,
bool signed_flag,
data_type_t*vtype,
list<pform_range_t>*range,
list<named_pexpr_t>*attr)
{
struct_type_t*struct_type = 0;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
bool signed_flag = false;
PWire*cur = pform_get_wire_in_scope(name);
if (cur) {
@ -2149,27 +2173,34 @@ void pform_module_define_port(const struct vlltype&li,
return;
}
if (vtype) {
ivl_assert(li, data_type == IVL_VT_NO_TYPE);
ivl_assert(li, range == 0);
// Packed ranges
list<pform_range_t>*prange = 0;
// Unpacked dimensions
list<pform_range_t>*urange = 0;
// If this is an unpacked array, then split out the parts that
// we can send to the PWire object that we create.
if (uarray_type_t*uarr_type = dynamic_cast<uarray_type_t*> (vtype)) {
urange = uarr_type->dims.get();
vtype = uarr_type->base_type;
}
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
data_type = vec_type->base_type;
signed_flag = vec_type->signed_flag;
range = vec_type->pdims.get();
prange = vec_type->pdims.get();
if (vec_type->reg_flag)
type = NetNet::REG;
} else if (atom2_type_t*atype = dynamic_cast<atom2_type_t*>(vtype)) {
data_type = IVL_VT_BOOL;
signed_flag = atype->signed_flag;
range = make_range_from_width(atype->type_code);
prange = make_range_from_width(atype->type_code);
} else if (real_type_t*rtype = dynamic_cast<real_type_t*>(vtype)) {
data_type = IVL_VT_REAL;
signed_flag = true;
range = 0;
prange = 0;
if (rtype->type_code != real_type_t::REAL) {
VLerror(li, "sorry: Only real (not shortreal) supported here (%s:%d).",
@ -2179,7 +2210,7 @@ void pform_module_define_port(const struct vlltype&li,
} else if ((struct_type = dynamic_cast<struct_type_t*>(vtype))) {
data_type = struct_type->figure_packed_base_type();
signed_flag = false;
range = 0;
prange = 0;
} else if (vtype) {
VLerror(li, "sorry: Given type %s not supported here (%s:%d).",
@ -2191,7 +2222,7 @@ void pform_module_define_port(const struct vlltype&li,
if (data_type == IVL_VT_NO_TYPE)
data_type = IVL_VT_LOGIC;
cur = new PWire(name, type, port_type, data_type);
cur = new PWire(name, type, port_kind, data_type);
FILE_NAME(cur, li);
cur->set_signed(signed_flag);
@ -2199,11 +2230,15 @@ void pform_module_define_port(const struct vlltype&li,
if (struct_type) {
cur->set_data_type(struct_type);
} else if (range == 0) {
} else if (prange == 0) {
cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
} else {
cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
cur->set_range(*prange, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH);
}
if (urange) {
cur->set_unpacked_idx(*urange);
}
pform_bind_attributes(cur->attributes, attr);

View File

@ -168,10 +168,7 @@ extern void pform_module_define_port(const struct vlltype&li,
perm_string name,
NetNet::PortType,
NetNet::Type type,
ivl_variable_type_t data_type,
bool signed_flag,
data_type_t*vtype,
list<pform_range_t>*range,
list<named_pexpr_t>*attr);
extern Module::port_t* pform_module_port_reference(perm_string name,

View File

@ -160,12 +160,21 @@ inline static const char *basename(ivl_scope_t scope, const char *inst)
static perm_string make_scope_name(const hname_t&name)
{
if (! name.has_number())
if (! name.has_numbers())
return name.peek_name();
char buf[1024];
snprintf(buf, sizeof buf, "%s[%d]",
name.peek_name().str(), name.peek_number());
snprintf(buf, sizeof buf, "%s", name.peek_name().str());
char*cp = buf + strlen(buf);
size_t ncp = sizeof buf - (cp-buf);
for (size_t idx = 0 ; idx < name.has_numbers() ; idx += 1) {
int len = snprintf(cp, ncp, "[%d]", name.peek_number(idx));
cp += len;
ncp -= len;
}
return lex_strings.make(buf);
}