diff --git a/elab_expr.cc b/elab_expr.cc index 5f09558a6..6d5a81a68 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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 * 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; } - 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); } /* diff --git a/eval_tree.cc b/eval_tree.cc index 7a7eb2775..39ba506e9 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1591,6 +1591,39 @@ NetEConst* NetEUReduce::eval_arguments_(const NetExpr*ex) const return tmp; } +NetExpr* NetECast::eval_arguments_(const NetExpr*ex) const +{ + NetExpr*res = 0; + switch (op_) { + case 'r': + if (const NetEConst*val = dynamic_cast(ex)) { + verireal res_val = verireal(val->value().as_double()); + res = new NetECReal(res_val); + } + break; + case '2': + if (const NetEConst*val = dynamic_cast(ex)) { + verinum res_val(val->value()); + res_val.cast_to_int2(); + res = new NetEConst(res_val); + } + case 'v': + if (const NetECReal*val = dynamic_cast(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 { const NetEConst*tmpi = dynamic_cast(arg_); diff --git a/expr_synth.cc b/expr_synth.cc index 9f5cc0e3f..6a69d256e 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -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 * 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()) { 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; case 'r': isig = cast_to_real(des, scope, isig); diff --git a/netlist.h b/netlist.h index 655648738..0ae436754 100644 --- a/netlist.h +++ b/netlist.h @@ -4187,6 +4187,9 @@ class NetECast : public NetEUnary { virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetECast* dup_expr() const; virtual ivl_variable_type_t expr_type() const; + + private: + virtual NetExpr* eval_arguments_(const NetExpr*ex) const; }; /* diff --git a/netmisc.cc b/netmisc.cc index cbd31f4c3..4e0344bb0 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -139,7 +139,7 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) 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) return expr; @@ -153,11 +153,45 @@ NetExpr* cast_to_int2(NetExpr*expr) 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) { if (expr->expr_type() == IVL_VT_REAL) return expr; + if (debug_elaborate) + cerr << expr->get_fileline() << ": debug: " + << "Cast expression to real." << endl; + NetECast*cast = new NetECast('r', expr, 1, true); cast->set_line(*expr); 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, - 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; 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); 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); if (NetEConst*ce = dynamic_cast(tmp)) { diff --git a/netmisc.h b/netmisc.h index f095e1b05..6cb6d25d6 100644 --- a/netmisc.h +++ b/netmisc.h @@ -1,7 +1,7 @@ #ifndef __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 * 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_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_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 * treated as standard self-determined if the gn_strict_expr_width flag * 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; extern NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width, 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 diff --git a/verinum.cc b/verinum.cc index 685ffb4a7..4a87aec2f 100644 --- a/verinum.cc +++ b/verinum.cc @@ -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 * 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(); } +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) { if (that.len() >= width) diff --git a/verinum.h b/verinum.h index f8c5bcc46..a459e03f6 100644 --- a/verinum.h +++ b/verinum.h @@ -1,7 +1,7 @@ #ifndef __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 * 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. 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 // methods. V get(unsigned idx) const; diff --git a/vvp/arith.cc b/vvp/arith.cc index e348fefa7..30c5e2597 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -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 * 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_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