Merge branch 'x-mil13'
This commit is contained in:
commit
97e1151388
68
HName.cc
68
HName.cc
|
|
@ -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
34
HName.h
|
|
@ -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)
|
||||
|
|
|
|||
5
PExpr.h
5
PExpr.h
|
|
@ -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;
|
||||
|
|
|
|||
1
PGate.h
1
PGate.h
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
60
elab_expr.cc
60
elab_expr.cc
|
|
@ -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);
|
||||
|
|
|
|||
101
elab_net.cc
101
elab_net.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
83
elaborate.cc
83
elaborate.cc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
12
lexor.lex
12
lexor.lex
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
net_scope.cc
15
net_scope.cc
|
|
@ -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;
|
||||
|
|
|
|||
19
netlist.cc
19
netlist.cc
|
|
@ -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;
|
||||
|
|
|
|||
13
netlist.h
13
netlist.h
|
|
@ -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.
|
||||
|
|
|
|||
92
netmisc.cc
92
netmisc.cc
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
24
nettypes.cc
24
nettypes.cc
|
|
@ -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
189
parse.y
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
63
pform.cc
63
pform.cc
|
|
@ -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);
|
||||
|
|
|
|||
3
pform.h
3
pform.h
|
|
@ -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,
|
||||
|
|
|
|||
15
t-dll.cc
15
t-dll.cc
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue