Merge branch 'x-mil11'

This commit is contained in:
Stephen Williams 2013-10-21 08:55:13 -07:00
commit 61fbfb562e
38 changed files with 864 additions and 83 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)
{
@ -417,12 +436,12 @@ bool PEIdent::has_aa_term(Design*des, NetScope*scope) const
return false;
}
PENew::PENew(PExpr*size_expr)
: size_(size_expr)
PENewArray::PENewArray(PExpr*size_expr, PExpr*init_expr)
: size_(size_expr), init_(init_expr)
{
}
PENew::~PENew()
PENewArray::~PENewArray()
{
delete size_;
}

37
PExpr.h
View File

@ -194,6 +194,29 @@ 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:
NetExpr* elaborate_expr_darray_(Design*des, NetScope*scope,
ivl_type_t type, unsigned flags) const;
private:
std::vector<PExpr*>parms_;
};
class PEConcat : public PExpr {
public:
@ -279,6 +302,8 @@ class PEFNumber : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode);
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
ivl_type_t type, unsigned flags) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid,
unsigned flags) const;
@ -479,11 +504,11 @@ class PEIdent : public PExpr {
long&midx, long&lidx) const;
};
class PENew : public PExpr {
class PENewArray : public PExpr {
public:
explicit PENew (PExpr*s);
~PENew();
explicit PENewArray (PExpr*s, PExpr*i);
~PENewArray();
virtual void dump(ostream&) const;
virtual unsigned test_width(Design*des, NetScope*scope,
@ -496,6 +521,7 @@ class PENew : public PExpr {
private:
PExpr*size_;
PExpr*init_;
};
class PENewClass : public PExpr {
@ -570,7 +596,7 @@ class PENumber : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode);
virtual NetEConst*elaborate_expr(Design*des, NetScope*scope,
virtual NetExpr *elaborate_expr(Design*des, NetScope*scope,
ivl_type_t type, unsigned flags) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned) const;
@ -606,6 +632,9 @@ class PEString : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
width_mode_t&mode);
virtual NetEConst*elaborate_expr(Design*des, NetScope*scope,
ivl_type_t type, unsigned flags) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
unsigned expr_wid, unsigned) const;
verinum* eval_const(Design*, NetScope*) const;

View File

@ -105,8 +105,9 @@ class PAssign_ : public Statement {
protected:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width,
ivl_variable_type_t type) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const;
NetExpr* elaborate_rval_obj_(Design*, NetScope*,

View File

@ -1410,6 +1410,19 @@ void NetEAccess::dump(ostream&o) const
o << ")";
}
void NetEArrayPattern::dump(ostream&fd) const
{
fd << "'{";
if (items_.size() >= 1) {
if (items_[0]) fd << *items_[0];
}
for (size_t idx = 1 ; idx < items_.size() ; idx += 1) {
fd << ", ";
if (items_[idx]) fd << *items_[idx];
}
fd << "}";
}
void NetEBinary::dump(ostream&o) const
{
if (op_ == 'm' || op_ == 'M') {
@ -1549,7 +1562,14 @@ void NetENetenum::dump(ostream&o) const
void NetENew::dump(ostream&o) const
{
o << "new <type>";
o << "new <type> [";
if (size_) size_->dump(o);
o << "]";
if (init_val_) {
o << "(";
init_val_->dump(o);
o << ")";
}
}
void NetENull::dump(ostream&o) const

View File

@ -32,6 +32,17 @@ NetEAccess* NetEAccess::dup_expr() const
return tmp;
}
NetEArrayPattern*NetEArrayPattern::dup_expr() const
{
vector<NetExpr*>tmp (items_.size());
for (size_t idx = 0 ; idx < tmp.size() ; idx += 1)
tmp[idx] = items_[idx]->dup_expr();
NetEArrayPattern*res = new NetEArrayPattern(net_type(), tmp);
res->set_line(*this);
return res;
}
NetEBinary* NetEBinary::dup_expr() const
{
ivl_assert(*this, 0);

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,76 @@ 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
{
// Special case: If this is an empty pattern (i.e. '{}) and
// the expected type is a DARRAY, then convert this to a null
// handle. Internally, Icarus Verilog uses this to represent
// nil dynamic arrays.
if (parms_.size() == 0 && ntype->base_type()==IVL_VT_DARRAY) {
NetENull*tmp = new NetENull;
tmp->set_line(*this);
return tmp;
}
if (ntype->base_type()==IVL_VT_DARRAY)
return elaborate_expr_darray_(des, scope, ntype, flags);
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_darray_(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned flags) const
{
const netdarray_t*array_type = dynamic_cast<const netdarray_t*> (ntype);
ivl_assert(*this, array_type);
// This is an array pattern, so run through the elements of
// the expression and elaborate each as if they are
// element_type expressions.
ivl_type_t elem_type = array_type->element_type();
vector<NetExpr*> elem_exprs (parms_.size());
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
NetExpr*tmp = parms_[idx]->elaborate_expr(des, scope, elem_type, flags);
elem_exprs[idx] = tmp;
}
NetEArrayPattern*res = new NetEArrayPattern(array_type, elem_exprs);
res->set_line(*this);
return res;
}
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 +1613,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 +2068,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 +2151,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 +2244,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;
@ -2446,6 +2537,13 @@ unsigned PEFNumber::test_width(Design*, NetScope*, width_mode_t&)
return expr_width_;
}
NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, ivl_type_t type, unsigned) const
{
NetECReal*tmp = new NetECReal(*value_);
tmp->set_line(*this);
return tmp;
}
NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
{
NetECReal*tmp = new NetECReal(*value_);
@ -2902,7 +3000,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 +3018,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);
@ -4515,7 +4613,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
return node;
}
unsigned PENew::test_width(Design*, NetScope*, width_mode_t&)
unsigned PENewArray::test_width(Design*, NetScope*, width_mode_t&)
{
expr_type_ = IVL_VT_DARRAY;
expr_width_ = 1;
@ -4524,23 +4622,41 @@ unsigned PENew::test_width(Design*, NetScope*, width_mode_t&)
return 1;
}
NetExpr* PENew::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned flags) const
NetExpr* PENewArray::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned flags) const
{
// Elaborate the size expression.
width_mode_t mode = LOSSLESS;
unsigned use_wid = size_->test_width(des, scope, mode);
NetExpr*size = size_->elaborate_expr(des, scope, use_wid, flags);
NetExpr*init_val = 0;
NetENew*tmp = new NetENew(ntype, size);
if (dynamic_cast<PEAssignPattern*> (init_)) {
// Special case: the initial value expression is an
// array_pattern. Elaborate the expresion like the
// r-value to an assignment to array.
init_val = init_->elaborate_expr(des, scope, ntype, flags);
} else if (init_) {
// Regular case: The initial value is an
// expression. Elaborate the expression as an element
// type. The run-time will assign this value to each element.
const netarray_t*array_type = dynamic_cast<const netarray_t*> (ntype);
ivl_type_t elem_type = array_type->element_type();
init_val = init_->elaborate_expr(des, scope, elem_type, flags);
}
NetENew*tmp = new NetENew(ntype, size, init_val);
tmp->set_line(*this);
return tmp;
}
/*
* This method should never actually be called.
*/
NetExpr* PENew::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
NetExpr* PENewArray::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
{
ivl_assert(*this, 0);
return 0;
@ -4623,7 +4739,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)
@ -4734,7 +4851,7 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
return expr_width_;
}
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, ivl_type_t ntype, unsigned) const
NetExpr* PENumber::elaborate_expr(Design*des, NetScope*, ivl_type_t ntype, unsigned) const
{
const netvector_t*use_type = dynamic_cast<const netvector_t*> (ntype);
if (use_type == 0) {
@ -4745,6 +4862,15 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, ivl_type_t ntype, uns
return 0;
}
// Special case: If the context type is REAL, then cast the
// vector value to a real and rethrn a NetECReal.
if (ntype->base_type() == IVL_VT_REAL) {
verireal val (value_->as_long());
NetECReal*tmp = new NetECReal(val);
tmp->set_line(*this);
return tmp;
}
verinum use_val = value();
use_val .has_sign( use_type->get_signed() );
use_val = cast_to_width(use_val, use_type->packed_width());
@ -4780,6 +4906,16 @@ unsigned PEString::test_width(Design*, NetScope*, width_mode_t&)
return expr_width_;
}
NetEConst* PEString::elaborate_expr(Design*, NetScope*, ivl_type_t type, unsigned)const
{
verinum val(value());
NetEConst*tmp = new NetEConst(val);
tmp->cast_signed(signed_flag_);
tmp->set_line(*this);
return tmp;
}
NetEConst* PEString::elaborate_expr(Design*, NetScope*,
unsigned expr_wid, unsigned) const
{

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) {
@ -2244,13 +2245,18 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
}
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
unsigned lv_width,
ivl_variable_type_t lv_type) const
ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width) const
{
ivl_assert(*this, rval_);
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(),
is_constant_);
// 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, lv_net_type, lv_type, lv_width,
rval(), is_constant_);
if (!is_constant_ || !rv) return rv;
@ -2368,7 +2374,7 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0;
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv));
if (rv == 0) return 0;
NetAssign*cur = new NetAssign(lv, op_, rv);
@ -2456,7 +2462,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
} else {
/* Elaborate the r-value expression, then try to evaluate it. */
rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
rv = elaborate_rval_(des, scope, lv_net_type, lv->expr_type(), count_lval_width(lv));
}
if (rv == 0) return 0;
@ -2648,7 +2654,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
// because it would necessarily trigger other errors.
}
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv));
if (rv == 0) return 0;
NetExpr*delay = 0;
@ -3463,7 +3469,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 +3624,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 +4306,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 +4366,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 +4582,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

@ -546,6 +546,11 @@ void NetEAccess::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_access_func(this);
}
void NetEArrayPattern::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_array_pattern(this);
}
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_binary(this);

View File

@ -228,6 +228,7 @@ typedef enum ivl_expr_type_e {
IVL_EX_NEW = 23,
IVL_EX_NULL = 22,
IVL_EX_NUMBER = 5,
IVL_EX_ARRAY_PATTERN = 26,
IVL_EX_PROPERTY = 24,
IVL_EX_REALNUM = 16,
IVL_EX_SCOPE = 6,
@ -827,6 +828,16 @@ extern unsigned ivl_event_lineno(ivl_event_t net);
* table. That number can be passed to ivl_type_prop_*() functions to
* get details about the property.
*
* - IVL_EX_NEW
* This expression takes one or two operands. The first operand,
* returned by ivl_expr_oper1() is the number of elements to create
* for the dynamic array. The second operand, if present, is returned
* by the ivl_expr_oper2() function. If this returns a non-nil
* expression, it is the initial value to be written to the elements
* of the array. If the expression is an IVL_EX_ARRAY_PATTERN, then
* this is the very special case of a list of values to be written to
* array elements.
*
* - IVL_EX_SELECT
* This expression takes two operands, oper1 is the expression to
* select from, and oper2 is the selection base. The ivl_expr_width
@ -895,17 +906,17 @@ extern const char* ivl_expr_name(ivl_expr_t net);
extern ivl_nature_t ivl_expr_nature(ivl_expr_t net);
/* IVL_EX_BINARY IVL_EX_UNARY */
extern char ivl_expr_opcode(ivl_expr_t net);
/* IVL_EX_BINARY IVL_EX_UNARY, IVL_EX_MEMORY IVL_EX_TERNARY */
/* IVL_EX_BINARY IVL_EX_UNARY, IVL_EX_MEMORY IVL_EX_NEW IVL_EX_TERNARY */
extern ivl_expr_t ivl_expr_oper1(ivl_expr_t net);
/* IVL_EX_BINARY IVL_EX_TERNARY */
/* IVL_EX_BINARY IVL_EX_NEW IVL_EX_TERNARY */
extern ivl_expr_t ivl_expr_oper2(ivl_expr_t net);
/* IVL_EX_TERNARY */
extern ivl_expr_t ivl_expr_oper3(ivl_expr_t net);
/* and expression */
extern ivl_parameter_t ivl_expr_parameter(ivl_expr_t net);
/* IVL_EX_CONCAT IVL_EX_UFUNC */
/* IVL_EX_ARRAY_PATTERN IVL_EX_CONCAT IVL_EX_UFUNC */
extern ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx);
/* IVL_EX_CONCAT IVL_EX_SFUNC IVL_EX_UFUNC */
/* IVL_EX_ARRAY_PATTERN IVL_EX_CONCAT IVL_EX_SFUNC IVL_EX_UFUNC */
extern unsigned ivl_expr_parms(ivl_expr_t net);
/* IVL_EX_CONCAT */
extern unsigned ivl_expr_repeat(ivl_expr_t net);

View File

@ -61,7 +61,10 @@ bool NetExpr::has_width() const
*/
ivl_variable_type_t NetExpr::expr_type() const
{
return IVL_VT_LOGIC;
if (net_type_)
return net_type_->base_type();
else
return IVL_VT_LOGIC;
}
const netenum_t*NetExpr::enumeration() const
@ -69,6 +72,17 @@ const netenum_t*NetExpr::enumeration() const
return 0;
}
NetEArrayPattern::NetEArrayPattern(ivl_type_t lv_type, vector<NetExpr*>&items)
: NetExpr(lv_type), items_(items)
{
}
NetEArrayPattern::~NetEArrayPattern()
{
for (size_t idx = 0 ; idx < items_.size() ; idx += 1)
delete items_[idx];
}
/*
* Create an add/sub node from the two operands.
*/
@ -322,12 +336,12 @@ const netenum_t* NetENetenum::netenum() const
}
NetENew::NetENew(ivl_type_t t)
: obj_type_(t), size_(0)
: obj_type_(t), size_(0), init_val_(0)
{
}
NetENew::NetENew(ivl_type_t t, NetExpr*size)
: obj_type_(t), size_(size)
NetENew::NetENew(ivl_type_t t, NetExpr*size, NetExpr*init_val)
: obj_type_(t), size_(size), init_val_(init_val)
{
}

View File

@ -43,6 +43,21 @@ NexusSet* NetProc::nex_input(bool)
return 0;
}
NexusSet* NetEArrayPattern::nex_input(bool rem_out)
{
NexusSet*result = new NexusSet;
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
if (items_[idx]==0) continue;
NexusSet*tmp = items_[idx]->nex_input(rem_out);
if (tmp == 0) continue;
result->add(*tmp);
delete tmp;
}
return result;
}
NexusSet* NetEBinary::nex_input(bool rem_out)
{
NexusSet*result = left_->nex_input(rem_out);

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

@ -759,18 +759,14 @@ void NetNet::set_module_port_index(unsigned idx)
ivl_variable_type_t NetNet::data_type() const
{
if (net_type_==0)
return IVL_VT_LOGIC;
else
return net_type_->base_type();
ivl_assert(*this, net_type_);
return net_type_->base_type();
}
bool NetNet::get_signed() const
{
if (net_type_==0)
return false;
else
return net_type_->get_signed();
ivl_assert(*this, net_type_);
return net_type_->get_signed();
}
bool NetNet::get_isint() const

View File

@ -627,7 +627,7 @@ class NetNet : public NetObj, public PortType {
// now, the unpacked type is not burried into an ivl_type_s object.
explicit NetNet(NetScope*s, perm_string n, Type t,
const std::list<netrange_t>&unpacked,
ivl_type_t type =0);
ivl_type_t type);
// This form builds a NetNet from its record/enum/darray
// definition. They should probably be replaced with a single
@ -1914,6 +1914,25 @@ class NetExpr : public LineInfo {
NetExpr& operator=(const NetExpr&);
};
class NetEArrayPattern : public NetExpr {
public:
NetEArrayPattern(ivl_type_t lv_type, std::vector<NetExpr*>&items);
~NetEArrayPattern();
inline size_t item_size() const { return items_.size(); }
const NetExpr* item(size_t idx) const { return items_[idx]; }
void expr_scan(struct expr_scan_t*) const;
void dump(ostream&) const;
NetEArrayPattern* dup_expr() const;
NexusSet* nex_input(bool rem_out =true);
private:
std::vector<NetExpr*> items_;
};
/*
* The expression constant is slightly special, and is sometimes
* returned from other classes that can be evaluated at compile
@ -4011,11 +4030,12 @@ class NetENew : public NetExpr {
// Make class object
explicit NetENew(ivl_type_t);
// dynamic array of objects.
explicit NetENew(ivl_type_t, NetExpr*);
explicit NetENew(ivl_type_t, NetExpr*size, NetExpr* init_val=0);
~NetENew();
inline ivl_type_t get_type() const { return obj_type_; }
inline const NetExpr*size_expr() const { return size_; }
inline const NetExpr*init_expr() const { return init_val_; }
virtual ivl_variable_type_t expr_type() const;
@ -4028,6 +4048,7 @@ class NetENew : public NetExpr {
private:
ivl_type_t obj_type_;
NetExpr*size_;
NetExpr*init_val_;
};
/*

View File

@ -751,13 +751,15 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
expr_width = context_width;
if (debug_elaborate) {
cerr << pe->get_fileline() << ": debug: test_width of "
cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
<< *pe << endl;
cerr << pe->get_fileline() << ": "
cerr << pe->get_fileline() << ": : "
<< "returns type=" << pe->expr_type()
<< ", width=" << expr_width
<< ", signed=" << pe->has_sign()
<< ", mode=" << PExpr::width_mode_name(mode) << endl;
cerr << pe->get_fileline() << ": : "
<< "cast_type=" << cast_type << endl;
}
// If we can get the same result using a smaller expression
@ -807,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

@ -38,11 +38,23 @@ class ivl_type_s {
virtual long packed_width(void) const;
virtual std::vector<netrange_t> slice_dimensions() const;
// Some types have a base variable type.
// Some types have a base variable type. This is the bit type
// for packed data types, or IVL_VT_DARRAY or IVL_VT_CLASS for
// those specific types.
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;
};
/*
@ -98,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_;

34
parse.y
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 (array literals) not supported.");
$$ = tmp;
}
;
@ -1070,13 +1069,11 @@ endnew_opt : ':' K_new | ;
dynamic_array_new /* IEEE1800-2005: A.2.4 */
: K_new '[' expression ']'
{ $$ = new PENew($3);
{ $$ = new PENewArray($3, 0);
FILE_NAME($$, @1);
}
| K_new '[' expression ']' '(' expression ')'
{ yyerror(@1, "sorry: Dynamic array new expression with initializer not supported.");
delete $6;
$$ = new PENew($3);
{ $$ = new PENewArray($3, $6);
FILE_NAME($$, @1);
}
;
@ -1795,12 +1792,16 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
: port_direction_opt data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt
{ vector<pform_tf_port_t>*tmp;
NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1;
perm_string name = lex_strings.make($3);
list<perm_string>* ilist = list_from_identifier($3);
if (($2 == 0) && ($1==NetNet::PIMPLICIT)) {
// Detect special case this is an undecorated
// identifier and we need to get the declaration from
// left context.
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,
@ -1829,11 +1830,11 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
port_declaration_context.data_type = $2;
tmp = pform_make_task_ports(@3, use_port_type, $2, ilist);
}
$$ = tmp;
if ($4) {
yyerror(@4, "sorry: Port variable dimensions not supported yet.");
delete $4;
if ($4 != 0) {
pform_set_reg_idx(name, $4);
}
$$ = tmp;
if ($5) {
assert(tmp->size()==1);
tmp->front().defe = $5;
@ -5072,11 +5073,12 @@ register_variable
pform_set_reg_idx(name, $2);
$$ = $1;
}
| IDENTIFIER '=' expression
{ perm_string ident_name = lex_strings.make($1);
pform_makewire(@1, ident_name, NetNet::REG,
| IDENTIFIER dimensions_opt '=' expression
{ perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
pform_make_reginit(@1, ident_name, $3);
pform_set_reg_idx(name, $2);
pform_make_reginit(@1, name, $4);
$$ = $1;
}
;

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_)
@ -299,9 +312,11 @@ void PEFNumber::dump(ostream &out) const
out << value();
}
void PENew::dump(ostream&out) const
void PENewArray::dump(ostream&out) const
{
out << "new [" << *size_ << "]";
if (init_)
out << "(" << *init_ << ")";
}
void PENewClass::dump(ostream&out) const

View File

@ -520,6 +520,9 @@ extern "C" ivl_expr_t ivl_expr_oper2(ivl_expr_t net)
case IVL_EX_BINARY:
return net->u_.binary_.rig_;
case IVL_EX_NEW:
return net->u_.new_.init_val;
case IVL_EX_SELECT:
return net->u_.select_.base_;
@ -570,6 +573,10 @@ extern "C" ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx)
assert(net);
switch (net->type_) {
case IVL_EX_ARRAY_PATTERN:
assert(idx < net->u_.array_pattern_.parms);
return net->u_.array_pattern_.parm[idx];
case IVL_EX_CONCAT:
assert(idx < net->u_.concat_.parms);
return net->u_.concat_.parm[idx];
@ -593,6 +600,9 @@ extern "C" unsigned ivl_expr_parms(ivl_expr_t net)
assert(net);
switch (net->type_) {
case IVL_EX_ARRAY_PATTERN:
return net->u_.array_pattern_.parms;
case IVL_EX_CONCAT:
return net->u_.concat_.parms;

View File

@ -175,6 +175,31 @@ void dll_target::expr_access_func(const NetEAccess*net)
expr_->u_.branch_.nature = net->get_nature();
}
void dll_target::expr_array_pattern(const NetEArrayPattern*net)
{
assert(expr_ == 0);
ivl_expr_t expr_tmp = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
expr_tmp->type_ = IVL_EX_ARRAY_PATTERN;
expr_tmp->value_= net->expr_type();
expr_tmp->net_type = net->net_type();
expr_tmp->width_ = 1;
expr_tmp->signed_ = 0;
expr_tmp->sized_ = 0;
FILE_NAME(expr_tmp, net);
expr_tmp->u_.array_pattern_.parms = net->item_size();
expr_tmp->u_.array_pattern_.parm = new ivl_expr_t [net->item_size()];
for (size_t idx = 0 ; idx < net->item_size() ; idx += 1) {
const NetExpr*tmp = net->item(idx);
tmp->expr_scan(this);
expr_tmp->u_.array_pattern_.parm[idx] = expr_;
expr_ = 0;
}
expr_ = expr_tmp;
}
void dll_target::expr_binary(const NetEBinary*net)
{
assert(expr_ == 0);
@ -321,12 +346,20 @@ void dll_target::expr_creal(const NetECReal*net)
void dll_target::expr_new(const NetENew*net)
{
ivl_expr_t size = 0;
ivl_expr_t init_val = 0;
if (net->size_expr()) {
net->size_expr()->expr_scan(this);
size = expr_;
expr_ = 0;
}
if (net->init_expr()) {
net->init_expr()->expr_scan(this);
init_val = expr_;
expr_ = 0;
}
assert(expr_ == 0);
expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
expr_->width_ = net->expr_width();
@ -337,6 +370,7 @@ void dll_target::expr_new(const NetENew*net)
expr_->value_ = net->expr_type(); // May be IVL_VT_DARRAY or _CLASS
expr_->net_type= net->get_type();
expr_->u_.new_.size = size;
expr_->u_.new_.init_val = init_val;
}
void dll_target::expr_null(const NetENull*net)

View File

@ -135,6 +135,7 @@ struct dll_target : public target_t, public expr_scan_t {
struct ivl_expr_s*expr_;
void expr_access_func(const NetEAccess*);
void expr_array_pattern(const NetEArrayPattern*);
void expr_binary(const NetEBinary*);
void expr_concat(const NetEConcat*);
void expr_const(const NetEConst*);
@ -239,6 +240,11 @@ struct ivl_expr_s {
ivl_expr_t rig_;
} binary_;
struct {
size_t parms;
ivl_expr_t*parm;
} array_pattern_;
struct {
ivl_select_type_t sel_type_;
ivl_expr_t expr_;
@ -331,6 +337,7 @@ struct ivl_expr_s {
struct {
ivl_expr_t size;
ivl_expr_t init_val;
} new_;
struct {

View File

@ -452,6 +452,12 @@ void expr_scan_t::expr_access_func(const NetEAccess*)
"unhandled expr_access_func." << endl;
}
void expr_scan_t::expr_array_pattern(const NetEArrayPattern*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled expr_array_pattern." << endl;
}
void expr_scan_t::expr_const(const NetEConst*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "

View File

@ -152,6 +152,7 @@ struct target_t {
struct expr_scan_t {
virtual ~expr_scan_t();
virtual void expr_access_func(const NetEAccess*);
virtual void expr_array_pattern(const NetEArrayPattern*);
virtual void expr_const(const NetEConst*);
virtual void expr_new(const NetENew*);
virtual void expr_null(const NetENull*);

View File

@ -40,6 +40,16 @@ static void show_array_expression(ivl_expr_t net, unsigned ind)
ivl_signal_dimensions(sig), width, vt);
}
static void show_array_pattern_expression(ivl_expr_t net, unsigned ind)
{
size_t idx;
fprintf(out, "%*sArrayPattern (%s): %u expressions\n",
ind, "", vt_type_string(net), ivl_expr_parms(net));
for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) {
show_expression(ivl_expr_parm(net,idx), ind+4);
}
}
static void show_branch_access_expression(ivl_expr_t net, unsigned ind)
{
ivl_branch_t bra = ivl_expr_branch(net);
@ -176,6 +186,12 @@ static void show_new_expression(ivl_expr_t net, unsigned ind)
show_expression(ivl_expr_oper1(net), ind+3);
stub_errors += 1;
}
if (ivl_expr_oper2(net)){
fprintf(out, "%*sERROR: class_new with array element initializer!\n",
ind+3, "");
show_expression(ivl_expr_oper2(net), ind+3);
stub_errors += 1;
}
break;
case IVL_VT_DARRAY:
fprintf(out, "%*snew [] <type>\n", ind, "");
@ -185,6 +201,12 @@ static void show_new_expression(ivl_expr_t net, unsigned ind)
fprintf(out, "%*sERROR: darray_new missing size expression\n",
ind+3, "");
stub_errors += 1;
}
/* The IVL_EX_NEW expression may include an element
initializer. This may be an array pattern or simple
expression. */
if (ivl_expr_oper2(net)) {
show_expression(ivl_expr_oper2(net), ind+3);
}
break;
default:
@ -408,6 +430,10 @@ void show_expression(ivl_expr_t net, unsigned ind)
show_array_expression(net, ind);
break;
case IVL_EX_ARRAY_PATTERN:
show_array_pattern_expression(net, ind);
break;
case IVL_EX_BACCESS:
show_branch_access_expression(net, ind);
break;

View File

@ -65,6 +65,12 @@ static void function_argument_class(ivl_signal_t port, ivl_expr_t expr)
fprintf(vvp_out, " %%store/obj v%p_0;\n", port);
}
static void function_argument_darray(ivl_signal_t port, ivl_expr_t expr)
{
draw_eval_object(expr);
fprintf(vvp_out, " %%store/obj v%p_0;\n", port);
}
static void function_argument_string(ivl_signal_t port, ivl_expr_t expr)
{
draw_eval_string(expr);
@ -90,6 +96,9 @@ static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr)
case IVL_VT_STRING:
function_argument_string(port, expr);
break;
case IVL_VT_DARRAY:
function_argument_darray(port, expr);
break;
default:
fprintf(stderr, "XXXX function argument %s type=%d?!\n",
ivl_signal_basename(port), dtype);
@ -205,7 +214,23 @@ void draw_ufunc_real(ivl_expr_t expr)
fprintf(vvp_out, " %%load/real v%p_0;\n", retval);
draw_ufunc_epilogue(expr);
}
void draw_ufunc_string(ivl_expr_t expr)
{
ivl_scope_t def = ivl_expr_def(expr);
ivl_signal_t retval = ivl_scope_port(def, 0);
/* Take in arguments to function and call the function code. */
draw_ufunc_preamble(expr);
/* Return value signal cannot be an array. */
assert(ivl_signal_dimensions(retval) == 0);
/* Load the result into a word. */
fprintf(vvp_out, " %%load/str v%p_0;\n", retval);
draw_ufunc_epilogue(expr);
}
void draw_ufunc_object(ivl_expr_t expr)

View File

@ -23,8 +23,10 @@
static int eval_darray_new(ivl_expr_t ex)
{
int errors = 0;
unsigned size_reg = allocate_word();
ivl_expr_t size_expr = ivl_expr_oper1(ex);
ivl_expr_t init_expr = ivl_expr_oper2(ex);
draw_eval_expr_into_integer(size_expr, size_reg);
clr_word(size_reg);
@ -64,7 +66,91 @@ static int eval_darray_new(ivl_expr_t ex)
break;
}
return 0;
if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) {
int idx;
struct vector_info rvec;
unsigned wid;
switch (ivl_type_base(element_type)) {
case IVL_VT_BOOL:
wid = width_of_packed_type(element_type);
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
rvec = draw_eval_expr_wid(ivl_expr_parm(init_expr,idx),
wid, STUFF_OK_XZ);
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
rvec.base, rvec.wid);
if (rvec.base >= 4) clr_vector(rvec);
}
break;
case IVL_VT_REAL:
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
draw_eval_real(ivl_expr_parm(init_expr,idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/real 3;\n");
fprintf(vvp_out, " %%pop/real 1;\n");
}
break;
case IVL_VT_STRING:
for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
draw_eval_string(ivl_expr_parm(init_expr,idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/str 3;\n");
fprintf(vvp_out, " %%pop/str 1;\n");
}
break;
default:
fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n");
errors += 1;
break;
}
} else if (init_expr && number_is_immediate(size_expr,32,0)) {
/* In this case, there is an init expression, the
expression is NOT an array_pattern, and the size
expression used to calculate the size of the array is
a constant. Generate an unrolled set of assignments. */
long idx;
long cnt = get_number_immediate(size_expr);
struct vector_info rvec;
unsigned wid;
switch (ivl_type_base(element_type)) {
case IVL_VT_BOOL:
wid = width_of_packed_type(element_type);
rvec = draw_eval_expr_wid(init_expr, wid, STUFF_OK_XZ);
for (idx = 0 ; idx < cnt ; idx += 1) {
fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj 3, %u, %u;\n",
rvec.base, rvec.wid);
}
if (rvec.base >= 4) clr_vector(rvec);
break;
case IVL_VT_REAL:
draw_eval_real(init_expr);
for (idx = 0 ; idx < cnt ; idx += 1) {
fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/real 3;\n");
}
fprintf(vvp_out, " %%pop/real 1;\n");
break;
case IVL_VT_STRING:
draw_eval_string(init_expr);
for (idx = 0 ; idx < cnt ; idx += 1) {
fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx);
fprintf(vvp_out, " %%set/dar/obj/str 3;\n");
}
fprintf(vvp_out, " %%pop/str 1;\n");
break;
default:
fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n");
errors += 1;
break;
}
} else if (init_expr) {
fprintf(vvp_out, "; ERROR: Sorry, I don't know how to work with this size expr.\n");
errors += 1;
}
return errors;
}
static int eval_class_new(ivl_expr_t ex)

View File

@ -180,6 +180,10 @@ void draw_eval_string(ivl_expr_t expr)
fallback_eval(expr);
break;
case IVL_EX_UFUNC:
draw_ufunc_string(expr);
break;
default:
fallback_eval(expr);
break;

View File

@ -687,7 +687,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
}
/*
* This function assigns a value to a real .variable. This is destined
* This function assigns a value to a real variable. This is destined
* for /dev/null when typed ivl_signal_t takes over all the real
* variable support.
*/
@ -795,6 +795,81 @@ static int show_stmt_assign_sig_string(ivl_statement_t net)
return 0;
}
unsigned width_of_packed_type(ivl_type_t net)
{
unsigned idx;
unsigned width = 1;
for (idx = 0 ; idx < ivl_type_packed_dimensions(net) ; idx += 1) {
int lsb = ivl_type_packed_lsb(net,idx);
int msb = ivl_type_packed_msb(net,idx);
if (lsb <= msb)
width *= msb - lsb + 1;
else
width *= lsb - msb + 1;
}
return width;
}
/*
* This function handles the special case that we assign an array
* pattern to a dynamic array. Handle this by assigning each
* element. The array pattern will have a fixed size.
*/
static int show_stmt_assign_darray_pattern(ivl_statement_t net)
{
int errors = 0;
ivl_lval_t lval = ivl_stmt_lval(net, 0);
ivl_expr_t rval = ivl_stmt_rval(net);
ivl_signal_t var= ivl_lval_sig(lval);
ivl_type_t var_type= ivl_signal_net_type(var);
assert(ivl_type_base(var_type) == IVL_VT_DARRAY);
ivl_type_t element_type = ivl_type_element(var_type);
unsigned idx;
struct vector_info rvec;
unsigned element_width = 1;
if (ivl_type_base(element_type) == IVL_VT_BOOL)
element_width = width_of_packed_type(element_type);
else if (ivl_type_base(element_type) == IVL_VT_LOGIC)
element_width = width_of_packed_type(element_type);
assert(ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN);
for (idx = 0 ; idx < ivl_expr_parms(rval) ; idx += 1) {
switch (ivl_type_base(element_type)) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
rvec = draw_eval_expr_wid(ivl_expr_parm(rval,idx),
element_width, STUFF_OK_XZ);
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n",
var, rvec.base, rvec.wid);
if (rvec.base >= 4) clr_vector(rvec);
break;
case IVL_VT_REAL:
draw_eval_real(ivl_expr_parm(rval,idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var);
break;
case IVL_VT_STRING:
draw_eval_string(ivl_expr_parm(rval,idx));
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var);
break;
default:
fprintf(vvp_out, "; ERROR: show_stmt_assign_darray_pattern: type_base=%d not implemented\n", ivl_type_base(element_type));
errors += 1;
break;
}
}
return errors;
}
static int show_stmt_assign_sig_darray(ivl_statement_t net)
{
int errors = 0;
@ -845,6 +920,12 @@ static int show_stmt_assign_sig_darray(ivl_statement_t net)
if (rvec.base >= 4) clr_vector(rvec);
} else if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) {
/* There is no l-value mux, but the r-value is an array
pattern. This is a special case of an assignment to
elements of the l-value. */
errors += show_stmt_assign_darray_pattern(net);
} else {
/* There is no l-value mux, so this must be an
assignment to the array as a whole. Evaluate the

View File

@ -83,6 +83,11 @@ extern const char* vvp_signal_label(ivl_signal_t sig);
extern unsigned width_of_nexus(ivl_nexus_t nex);
extern ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex);
/*
* Calculate the width (in bits) of a packed type.
*/
extern unsigned width_of_packed_type(ivl_type_t net);
extern int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr);
/*
@ -101,6 +106,7 @@ extern void draw_lpm_mux(ivl_lpm_t net);
extern struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid);
extern void draw_ufunc_real(ivl_expr_t expr);
extern void draw_ufunc_string(ivl_expr_t expr);
extern void draw_ufunc_object(ivl_expr_t expr);
extern void pad_expr_in_place(ivl_expr_t expr, struct vector_info res,

View File

@ -181,6 +181,9 @@ extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
extern bool of_SCOPY(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0_X(vthread_t thr, vvp_code_t code);

View File

@ -229,6 +229,9 @@ static const struct opcode_table_s opcode_table[] = {
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/dar",of_SET_DAR,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/dar/obj", of_SET_DAR_OBJ, 3,{OA_NUMBER,OA_BIT1,OA_BIT2} },
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },

View File

@ -952,10 +952,26 @@ statement. The <type> is 0 for nets and 1 for registers. See the other
%release commands above.
* %set/dar <var-label>, <bit>, <wid>
* %set/dar/obj <index>, <bit>, <wid>
This sets a vector to a word of the dynamic array. Index register 3
contains the word address within the dynamic array, and <bit>,<wid>
specifies the thread vector to be written.
The "%set/dar" opcode sets a vector to a word of the dynamic
array. Index register 3 contains the word address within the dynamic
array, and <bit>,<wid> specifies the thread vector to be written.
The "%set/dar/obj" opcode is similar, except that it sets elements of
a dynamic array that is in the top of the object stack. Instead of
using a fixed index register, use the register addressed by <index>.
* %set/dar/obj/real <index>
* %set/dar/obj/str <index>
The "%set/dar/obj/real" opcode sets the top value from the real-value
stack to the index. This does NOT pop the real value off the
stack. The intent is that this value may be written to a bunch of
values.
The "%set/dar/obj/str" opcode does the same but for string values and
uses the string stack.
* %set/v <var-label>, <bit>, <wid>

View File

@ -4921,6 +4921,59 @@ bool of_SET_DAR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %set/dar/obj <index>, <bit>, <wid>
*/
bool of_SET_DAR_OBJ(vthread_t thr, vvp_code_t cp)
{
unsigned adr = thr->words[cp->number].w_int;
unsigned bit = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
vvp_vector4_t value = vthread_bits_to_vector(thr, bit, wid);
vvp_object_t&top = thr->peek_object();
vvp_darray*darray = top.peek<vvp_darray>();
assert(darray);
darray->set_word(adr, value);
return true;
}
/*
* %set/dar/obj/real <index>
*/
bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t cp)
{
unsigned adr = thr->words[cp->number].w_int;
double value = thr->peek_real(0);
vvp_object_t&top = thr->peek_object();
vvp_darray*darray = top.peek<vvp_darray>();
assert(darray);
darray->set_word(adr, value);
return true;
}
/*
* %set/dar/obj/str <index>
*/
bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t cp)
{
unsigned adr = thr->words[cp->number].w_int;
string value = thr->peek_str(0);
vvp_object_t&top = thr->peek_object();
vvp_darray*darray = top.peek<vvp_darray>();
assert(darray);
darray->set_word(adr, value);
return true;
}
/*
* This implements the "%set/v <label>, <bit>, <wid>" instruction.
*