Fix implicit casts in assignments (part 1).

This patch adds support for implicit casts to the elaborate_rval_expr()
function. This will handle the majority of cases where an implicit cast
can occur.
This commit is contained in:
Martin Whitaker 2013-02-25 20:32:56 +00:00 committed by Stephen Williams
parent 03ebd2f98d
commit 22769afd20
9 changed files with 123 additions and 12 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -111,7 +111,8 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
break; break;
} }
return elab_and_eval(des, scope, expr, context_wid, need_const); return elab_and_eval(des, scope, expr, context_wid, need_const,
false, lv_type);
} }
/* /*

View File

@ -1591,6 +1591,39 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const
return tmp; return tmp;
} }
NetExpr* NetECast::eval_arguments_(const NetExpr*ex) const
{
NetExpr*res = 0;
switch (op_) {
case 'r':
if (const NetEConst*val = dynamic_cast<const NetEConst*>(ex)) {
verireal res_val = verireal(val->value().as_double());
res = new NetECReal(res_val);
}
break;
case '2':
if (const NetEConst*val = dynamic_cast<const NetEConst*>(ex)) {
verinum res_val(val->value());
res_val.cast_to_int2();
res = new NetEConst(res_val);
}
case 'v':
if (const NetECReal*val = dynamic_cast<const NetECReal*>(ex)) {
verinum res_val = verinum(val->value().as_double(), false);
res = new NetEConst(res_val);
}
break;
default:
ivl_assert(*this, 0);
return 0;
}
if (res == 0) return 0;
ivl_assert(*this, res);
eval_debug(this, res, op_ == 'r');
return res;
}
NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const NetEConst* NetESFunc::evaluate_clog2_(const NetExpr*arg_) const
{ {
const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_); const NetEConst*tmpi = dynamic_cast<const NetEConst*>(arg_);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -980,7 +980,10 @@ NetNet* NetECast::synthesize(Design*des, NetScope*scope, NetExpr*root)
switch (op()) { switch (op()) {
case 'v': case 'v':
isig = cast_to_int4(des, scope, isig, isig->vector_width()); isig = cast_to_int4(des, scope, isig, expr_width());
break;
case '2':
isig = cast_to_int2(des, scope, isig, expr_width());
break; break;
case 'r': case 'r':
isig = cast_to_real(des, scope, isig); isig = cast_to_real(des, scope, isig);

View File

@ -4187,6 +4187,9 @@ class NetECast : public NetEUnary {
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
virtual NetECast* dup_expr() const; virtual NetECast* dup_expr() const;
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
private:
virtual NetExpr* eval_arguments_(const NetExpr*ex) const;
}; };
/* /*

View File

@ -139,7 +139,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
NetExpr* cast_to_int2(NetExpr*expr) NetExpr* cast_to_int2(NetExpr*expr)
{ {
// Special case: The expression is alreadt BOOL // Special case: The expression is already BOOL
if (expr->expr_type() == IVL_VT_BOOL) if (expr->expr_type() == IVL_VT_BOOL)
return expr; return expr;
@ -153,11 +153,45 @@ NetExpr* cast_to_int2(NetExpr*expr)
return cast; return cast;
} }
NetExpr* cast_to_int2(NetExpr*expr, unsigned width)
{
// Special case: The expression is already BOOL
if (expr->expr_type() == IVL_VT_BOOL)
return expr;
if (debug_elaborate)
cerr << expr->get_fileline() << ": debug: "
<< "Cast expression to int2, width=" << width << "." << endl;
NetECast*cast = new NetECast('2', expr, width, expr->has_sign());
cast->set_line(*expr);
return cast;
}
NetExpr* cast_to_int4(NetExpr*expr, unsigned width)
{
// Special case: The expression is already LOGIC or BOOL
if (expr->expr_type() != IVL_VT_REAL)
return expr;
if (debug_elaborate)
cerr << expr->get_fileline() << ": debug: "
<< "Cast expression to int4, width=" << width << "." << endl;
NetECast*cast = new NetECast('v', expr, width, expr->has_sign());
cast->set_line(*expr);
return cast;
}
NetExpr* cast_to_real(NetExpr*expr) NetExpr* cast_to_real(NetExpr*expr)
{ {
if (expr->expr_type() == IVL_VT_REAL) if (expr->expr_type() == IVL_VT_REAL)
return expr; return expr;
if (debug_elaborate)
cerr << expr->get_fileline() << ": debug: "
<< "Cast expression to real." << endl;
NetECast*cast = new NetECast('r', expr, 1, true); NetECast*cast = new NetECast('r', expr, 1, true);
cast->set_line(*expr); cast->set_line(*expr);
return cast; return cast;
@ -728,7 +762,8 @@ static const char*width_mode_name(PExpr::width_mode_t mode)
} }
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
int context_width, bool need_const, bool annotatable) int context_width, bool need_const, bool annotatable,
ivl_variable_type_t cast_type)
{ {
PExpr::width_mode_t mode = PExpr::SIZED; PExpr::width_mode_t mode = PExpr::SIZED;
if ((context_width == -2) && !gn_strict_expr_width_flag) if ((context_width == -2) && !gn_strict_expr_width_flag)
@ -777,6 +812,22 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags); NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, flags);
if (tmp == 0) return 0; if (tmp == 0) return 0;
if ((cast_type != IVL_VT_NO_TYPE) && (cast_type != tmp->expr_type())) {
switch (cast_type) {
case IVL_VT_REAL:
tmp = cast_to_real(tmp);
break;
case IVL_VT_BOOL:
tmp = cast_to_int2(tmp, context_width);
break;
case IVL_VT_LOGIC:
tmp = cast_to_int4(tmp, context_width);
break;
default:
break;
}
}
eval_expr(tmp, context_width); eval_expr(tmp, context_width);
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) { if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {

View File

@ -1,7 +1,7 @@
#ifndef __netmisc_H #ifndef __netmisc_H
#define __netmisc_H #define __netmisc_H
/* /*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -78,6 +78,8 @@ extern NetNet*cast_to_int4(Design*des, NetScope*scope, NetNet*src, unsigned wid)
extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid); extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid);
extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src); extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src);
extern NetExpr*cast_to_int4(NetExpr*expr, unsigned width);
extern NetExpr*cast_to_int2(NetExpr*expr, unsigned width);
extern NetExpr*cast_to_int2(NetExpr*expr); extern NetExpr*cast_to_int2(NetExpr*expr);
extern NetExpr*cast_to_real(NetExpr*expr); extern NetExpr*cast_to_real(NetExpr*expr);
@ -222,13 +224,20 @@ extern unsigned count_lval_width(const class NetAssign_*first);
* if the expression is lossless self-determined (this last option is * if the expression is lossless self-determined (this last option is
* treated as standard self-determined if the gn_strict_expr_width flag * treated as standard self-determined if the gn_strict_expr_width flag
* is set). * is set).
*
* cast_type allows the expression to be cast to a different type
* (before it is evaluated). If cast to a vector type, the vector
* width will be set to the context_width. The default value of
* IVL_VT_NO_TYPE causes the expression to retain its self-determined
* type.
*/ */
class PExpr; class PExpr;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope, extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
PExpr*pe, int context_width, PExpr*pe, int context_width,
bool need_const =false, bool need_const =false,
bool annotatable =false); bool annotatable =false,
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
/* /*
* This function is a variant of elab_and_eval that elaborates and * This function is a variant of elab_and_eval that elaborates and

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -568,6 +568,14 @@ bool verinum::is_negative() const
return (bits_[nbits_-1] == V1) && has_sign(); return (bits_[nbits_-1] == V1) && has_sign();
} }
void verinum::cast_to_int2()
{
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
if (bits_[idx] == Vx || bits_[idx] == Vz)
bits_[idx] = V0;
}
}
verinum pad_to_width(const verinum&that, unsigned width) verinum pad_to_width(const verinum&that, unsigned width)
{ {
if (that.len() >= width) if (that.len() >= width)

View File

@ -1,7 +1,7 @@
#ifndef __verinum_H #ifndef __verinum_H
#define __verinum_H #define __verinum_H
/* /*
* Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -86,6 +86,9 @@ class verinum {
// Comparison for use in sorting algorithms. // Comparison for use in sorting algorithms.
bool is_before(const verinum&that) const; bool is_before(const verinum&that) const;
// Convert 4-state to 2-state
void cast_to_int2();
// Individual bits can be accessed with the get and set // Individual bits can be accessed with the get and set
// methods. // methods.
V get(unsigned idx) const; V get(unsigned idx) const;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -140,7 +140,7 @@ void vvp_arith_cast_vec2::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t) vvp_context_t)
{ {
vvp_vector2_t tmp = bit; vvp_vector2_t tmp = bit;
ptr.ptr()->send_vec4(vector2_to_vector4(tmp,tmp.size()), 0); ptr.ptr()->send_vec4(vector2_to_vector4(tmp,wid_), 0);
} }
// Division // Division