Handle array assignment patters through pform.

This gets us to elaboration. In the process also fix up ivl_type_t
type comparisons to do deep type comparison.
This commit is contained in:
Stephen Williams 2013-09-29 14:48:42 -07:00
parent 2355e1ed8e
commit 18c338ad09
14 changed files with 251 additions and 22 deletions

View File

@ -94,6 +94,25 @@ const char* PExpr::width_mode_name(width_mode_t mode)
}
}
PEAssignPattern::PEAssignPattern()
{
}
PEAssignPattern::PEAssignPattern(const list<PExpr*>&p)
: parms_(p.size())
{
size_t idx = 0;
for (list<PExpr*>::const_iterator cur = p.begin()
; cur != p.end() ; ++cur) {
parms_[idx] = *cur;
idx += 1;
}
}
PEAssignPattern::~PEAssignPattern()
{
}
PEBinary::PEBinary(char op, PExpr*l, PExpr*r)
: op_(op), left_(l), right_(r)
{

20
PExpr.h
View File

@ -194,6 +194,26 @@ class PExpr : public LineInfo {
ostream& operator << (ostream&, const PExpr&);
class PEAssignPattern : public PExpr {
public:
explicit PEAssignPattern();
explicit PEAssignPattern(const std::list<PExpr*>&p);
~PEAssignPattern();
void dump(std::ostream&) const;
virtual unsigned test_width(Design*des, NetScope*scope, width_mode_t&mode);
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
ivl_type_t type, unsigned flags) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid,
unsigned flags) const;
private:
std::vector<PExpr*>parms_;
};
class PEConcat : public PExpr {
public:

View File

@ -86,15 +86,34 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd)
return 0;
}
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, unsigned lv_width,
PExpr*expr, bool need_const)
{
if (debug_elaborate) {
cerr << expr->get_fileline() << ": elaborate_rval_expr: "
<< "expr=" << *expr;
if (lv_net_type)
cerr << ", lv_net_type=" << *lv_net_type;
else
cerr << ", lv_net_type=<nil>";
cerr << ", lv_type=" << lv_type
<< ", lv_width=" << lv_width
<< endl;
}
int context_wid = -1;
switch (lv_type) {
case IVL_VT_DARRAY:
// For these types, use a different elab_and_eval that
// uses the lv_net_type. We should eventually transition
// all the types to this new form.
if (lv_net_type)
return elab_and_eval(des, scope, expr, lv_net_type, need_const);
break;
case IVL_VT_REAL:
case IVL_VT_STRING:
case IVL_VT_DARRAY:
break;
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
@ -163,6 +182,42 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const
return 0;
}
/*
* For now, assuse that assignment patterns are for dynamic
* objects. This is not really true as this expression type, fully
* supported, can assign to packed arrays and structs, unpacked arrays
* and dynamic arrays.
*/
unsigned PEAssignPattern::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{
expr_type_ = IVL_VT_DARRAY;
expr_width_ = 1;
min_width_ = 1;
signed_flag_= false;
return 1;
}
NetExpr*PEAssignPattern::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned flags) const
{
cerr << get_fileline() << ": sorry: I don't know how to elaborate "
<< "assignment_pattern expressions yet." << endl;
cerr << get_fileline() << ": : Expression is: " << *this
<< endl;
des->errors += 1;
return 0;
}
NetExpr* PEAssignPattern::elaborate_expr(Design*des, NetScope*, unsigned, unsigned) const
{
cerr << get_fileline() << ": sorry: I do not know how to"
<< " elaborate assignment patterns using old method." << endl;
cerr << get_fileline() << ": : Expression is: " << *this
<< endl;
des->errors += 1;
ivl_assert(*this, 0);
return 0;
}
unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{
@ -1524,7 +1579,8 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
// Process the method argument if it is available.
NetExpr* count = 0;
if (args != 0 && parg) {
count = elaborate_rval_expr(des, scope, IVL_VT_BOOL, 32, parg);
count = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
IVL_VT_BOOL, 32, parg);
if (count == 0) {
cerr << li->get_fileline() << ": error: unable to elaborate "
"enumeration method argument " << use_path << "."
@ -1978,7 +2034,7 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
if (debug_elaborate) {
cerr << get_fileline() << ": PECallFunction::elaborate_base_: "
<< "Expecting " << parms_count
<< " for function " << scope_path(dscope) << "." << endl;
<< " argument for function " << scope_path(dscope) << "." << endl;
}
/* Elaborate the input expressions for the function. This is
@ -2061,6 +2117,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
PExpr*tmp = parms_[idx];
if (tmp) {
parms[pidx] = elaborate_rval_expr(des, scope,
def->port(pidx)->net_type(),
def->port(pidx)->data_type(),
(unsigned)def->port(pidx)->vector_width(),
tmp, need_const);
@ -2153,12 +2210,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
ivl_assert(*this, parms_.size() == 2);
NetExpr*tmp;
tmp = elaborate_rval_expr(des, scope, IVL_VT_BOOL,
32, parms_[0], false);
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
IVL_VT_BOOL, 32, parms_[0], false);
sys_expr->parm(1, tmp);
tmp = elaborate_rval_expr(des, scope, IVL_VT_BOOL,
32, parms_[1], false);
tmp = elaborate_rval_expr(des, scope, &netvector_t::atom2u32,
IVL_VT_BOOL, 32, parms_[1], false);
sys_expr->parm(2, tmp);
return sys_expr;
@ -2902,7 +2959,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
if (net->net_type() != ntype) {
if (! ntype->type_compatible(net->net_type())) {
cerr << get_fileline() << ": internal_error: "
<< "net type doesn't match context type." << endl;
@ -2920,7 +2977,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
ntype->debug_dump(cerr);
cerr << endl;
}
ivl_assert(*this, net->net_type() == ntype);
ivl_assert(*this, ntype->type_compatible(net->net_type()));
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
@ -4619,7 +4676,8 @@ NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
// While there are default arguments, check them.
if (idx <= parms_.size() && parms_[idx-1]) {
PExpr*tmp = parms_[idx-1];
parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->data_type(),
parms[idx] = elaborate_rval_expr(des, scope, def->port(idx)->net_type(),
def->port(idx)->data_type(),
def->port(idx)->vector_width(),
tmp, false);
if (parms[idx] == 0)

View File

@ -84,7 +84,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
<< " width=" << lval->vector_width() << endl;
}
NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->data_type(),
NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->net_type(),
lval->data_type(),
lval->vector_width(), pin(1));
if (rval_expr == 0) {
@ -2249,7 +2250,11 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
{
ivl_assert(*this, rval_);
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(),
// Don't have a good value for the lv_net_type argument to
// elaborate_rval_expr, so punt and pass nil. In the future we
// should look into fixing calls to this method to pass a
// net_type instead of the separate lv_width/lv_type values.
NetExpr*rv = elaborate_rval_expr(des, scope, 0, lv_type, lv_width, rval(),
is_constant_);
if (!is_constant_ || !rv) return rv;
@ -3463,7 +3468,8 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
NetExpr*rv = 0;
if (parms_idx<parms_.size() && parms_[parms_idx]) {
rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [parms_idx]);
rv = elaborate_rval_expr(des, scope, port->net_type(),
lv_type, wid, parms_ [parms_idx]);
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
cerr << evt->get_fileline() << ": error: An event '"
<< evt->event()->name() << "' can not be a user "
@ -3617,7 +3623,11 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
unsigned lwid = count_lval_width(lval);
ivl_variable_type_t ltype = lval->expr_type();
NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_);
// Need to figure out a better thing to do about the
// lv_net_type argument to elaborate_rval_expr here. This
// would entail getting the NetAssign_ to give us an
// ivl_type_t as needed.
NetExpr*rexp = elaborate_rval_expr(des, scope, 0, ltype, lwid, expr_);
if (rexp == 0)
return 0;
@ -4295,7 +4305,11 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
unsigned lwid = count_lval_width(lval);
ivl_variable_type_t ltype = lval->expr_type();
NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_);
// Like a variety of other assigns, we need to figure out a
// better way to get a reasonable lv_net_type value, and that
// probably will involve NetAssign_ having a method for
// synthesizing one as needed.
NetExpr*rexp = elaborate_rval_expr(des, scope, 0, ltype, lwid, expr_);
if (rexp == 0)
return 0;
@ -4351,7 +4365,8 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
/* Make the r-value of the initial assignment, and size it
properly. Then use it to build the assignment statement. */
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
etmp = elaborate_rval_expr(des, scope, sig->net_type(),
lv->expr_type(), lv->lwidth(),
expr1_);
if (debug_elaborate) {
@ -4566,7 +4581,8 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
unsigned long wid = res->vector_width();
NetAssign_*lv = new NetAssign_(res);
NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_);
NetExpr*val = elaborate_rval_expr(des, scope, res->net_type(),
lv_type, wid, expr_);
NetBlock*proc = new NetBlock(NetBlock::SEQU, 0);
proc->set_line( *this );

View File

@ -18,6 +18,7 @@
*/
# include "netdarray.h"
# include <iostream>
using namespace std;
@ -34,3 +35,12 @@ ivl_variable_type_t netdarray_t::base_type(void) const
{
return IVL_VT_DARRAY;
}
bool netdarray_t::test_compatibility(ivl_type_t that) const
{
const netdarray_t*that_da = dynamic_cast<const netdarray_t*>(that);
if (that_da == 0)
return false;
return element_type()->type_compatible(that_da->element_type());
}

View File

@ -45,6 +45,7 @@ class netdarray_t : public netarray_t {
std::ostream& debug_dump(std::ostream&) const;
private:
bool test_compatibility(ivl_type_t that) const;
};
#endif

View File

@ -809,6 +809,26 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
return tmp;
}
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
ivl_type_t lv_net_type, bool need_const)
{
if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: "
<< "pe=" << *pe
<< ", lv_net_type=" << *lv_net_type << endl;
}
// Elaborate the expression using the more general
// elaborate_expr method.
unsigned flags = PExpr::NO_FLAGS;
if (need_const)
flags |= PExpr::NEED_CONST;
NetExpr*tmp = pe->elaborate_expr(des, scope, lv_net_type, flags);
return tmp;
}
NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
unsigned arg_idx, PExpr*pe, bool need_const)
{

View File

@ -244,6 +244,15 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
bool annotatable =false,
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
/*
* This form of elab_and_eval uses the ivl_type_t to carry type
* information instead of the piecemeal form. We should transition to
* this form as we reasonably can.
*/
extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
PExpr*expr, ivl_type_t lv_net_type,
bool need_const);
/*
* This function is a variant of elab_and_eval that elaborates and
* evaluates the arguments of a system task.
@ -256,8 +265,14 @@ extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope,
* of an assignment, The lv_type and lv_width are the type and width
* of the l-value, and the expr is the expression to elaborate. The
* result is the NetExpr elaborated and evaluated. (See elab_expr.cc)
*
* I would rather that all calls to elaborate_rval_expr use the
* lv_net_type argument to express the l-value type, but, for now,
* that it not possible. Those cases will be indicated by the
* lv_net_type being set to nil.
*/
extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width, PExpr*expr,
bool need_const =false);

View File

@ -46,6 +46,19 @@ bool ivl_type_s::get_signed() const
return false;
}
bool ivl_type_s::type_compatible(ivl_type_t that) const
{
if (this == that)
return true;
return test_compatibility(that);
}
bool ivl_type_s::test_compatibility(const ivl_type_s*that) const
{
return false;
}
netarray_t::~netarray_t()
{
}

View File

@ -44,7 +44,17 @@ class ivl_type_s {
virtual ivl_variable_type_t base_type() const;
virtual bool get_signed() const;
// Return true if "that" type is compatible with this
// type. Compatibile means the types are essentially the same.
bool type_compatible(ivl_type_t that) const;
virtual std::ostream& debug_dump(std::ostream&) const;
private:
// The "type_compatibile" method uses this virtual method to
// invoke type-specific tests of compatibility. This should
// only be called by the type_compatible method above.
virtual bool test_compatibility(ivl_type_t that) const;
};
/*
@ -100,6 +110,18 @@ class netrange_t {
inline long get_msb() const { assert(defined()); return msb_; }
inline long get_lsb() const { assert(defined()); return lsb_; }
inline bool operator == (const netrange_t&that) const
{ if (msb_ != that.msb_) return false;
if (lsb_ != that.lsb_) return false;
return true;
}
inline bool operator != (const netrange_t&that) const
{ if (msb_ != that.msb_) return true;
if (lsb_ != that.lsb_) return true;
return false;
}
private:
long msb_;
long lsb_;

View File

@ -18,6 +18,7 @@
*/
# include "netvector.h"
# include <iostream>
using namespace std;
@ -62,3 +63,22 @@ vector<netrange_t> netvector_t::slice_dimensions() const
{
return packed_dims_;
}
bool netvector_t::test_compatibility(ivl_type_t that) const
{
const netvector_t*that_st = dynamic_cast<const netvector_t*>(that);
if (that_st == 0)
return false;
if (type_ != that_st->type_)
return false;
if (packed_dims_.size() != that_st->packed_dims_.size())
return false;
for (size_t idx = 0 ; idx < packed_dims_.size() ; idx += 1) {
if (packed_dims_[idx] != that_st->packed_dims_[idx])
return false;
}
return true;
}

View File

@ -78,6 +78,9 @@ class netvector_t : public ivl_type_s {
static netvector_t scalar_bool;
static netvector_t scalar_logic;
private:
bool test_compatibility(ivl_type_t that) const;
private:
std::vector<netrange_t> packed_dims_;
ivl_variable_type_t type_;

View File

@ -669,15 +669,14 @@ source_text : description_list | ;
assignment_pattern /* IEEE1800-2005: A.6.7.1 */
: K_LP expression_list_proper '}'
{ PEVoid*tmp = new PEVoid;
{ PEAssignPattern*tmp = new PEAssignPattern(*$2);
FILE_NAME(tmp, @1);
yyerror(@1, "sorry: Assignment patterns (array literals) not supported.");
delete $2;
$$ = tmp;
}
| K_LP '}'
{ PEVoid*tmp = new PEVoid;
{ PEAssignPattern*tmp = new PEAssignPattern;
FILE_NAME(tmp, @1);
yyerror(@1, "sorry: Assignment patterns (empty array literals) not supported.");
$$ = tmp;
}
;

View File

@ -230,6 +230,19 @@ void PExpr::dump(ostream&out) const
out << typeid(*this).name();
}
void PEAssignPattern::dump(ostream&out) const
{
out << "'{";
if (parms_.size() > 0) {
parms_[0]->dump(out);
for (size_t idx = 1 ; idx < parms_.size() ; idx += 1) {
out << ", ";
parms_[idx]->dump(out);
}
}
out << "}";
}
void PEConcat::dump(ostream&out) const
{
if (repeat_)