Expression width rework.

This patch is a major rework of expression elaboration and
evaluation in the compiler, aimed at better compliance with
the IEEE standard.
This commit is contained in:
Martin Whitaker 2011-02-26 22:59:52 +00:00 committed by Stephen Williams
parent 2df6850824
commit 312b4da46f
25 changed files with 1500 additions and 2686 deletions

View File

@ -106,7 +106,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \
net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_types.o set_width.o \ pform_disciplines.o pform_dump.o pform_types.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \ Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2011 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,11 +78,7 @@ unsigned PDelays::delay_count() const
static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr) static NetExpr*calculate_val(Design*des, NetScope*scope, PExpr*expr)
{ {
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE; NetExpr*dex = elab_and_eval(des, scope, expr, -1);
bool tmp_flag = false;
expr->test_width(des, scope, 0, 0, tmp_type, tmp_flag);
NetExpr*dex = expr->elaborate_expr(des, scope, -1, false);
eval_expr(dex);
/* Print a warning if we find default and `timescale based /* Print a warning if we find default and `timescale based
* delays in the design, since this is likely an error. */ * delays in the design, since this is likely an error. */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com> * Copyright (c) 1998-2011 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
@ -31,8 +31,10 @@
PExpr::PExpr() PExpr::PExpr()
{ {
expr_width_ = 0;
expr_type_ = IVL_VT_NO_TYPE; expr_type_ = IVL_VT_NO_TYPE;
expr_width_ = 0;
min_width_ = 0;
signed_flag_ = false;
} }
PExpr::~PExpr() PExpr::~PExpr()
@ -94,8 +96,8 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
PEBComp::PEBComp(char op, PExpr*l, PExpr*r) PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r) : PEBinary(op, l, r)
{ {
left_width_ = 0; l_width_ = 0;
right_width_ = 0; r_width_ = 0;
} }
PEBComp::~PEBComp() PEBComp::~PEBComp()
@ -204,13 +206,16 @@ bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
} }
PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r) PEConcat::PEConcat(const list<PExpr*>&p, PExpr*r)
: parms_(p.size()), tested_widths_(p.size()), repeat_(r) : parms_(p.size()), width_modes_(p.size()), repeat_(r)
{ {
int tmp_idx = 0; int tmp_idx = 0;
assert(parms_.size() == p.size()); assert(parms_.size() == p.size());
for (list<PExpr*>::const_iterator idx = p.begin() for (list<PExpr*>::const_iterator idx = p.begin()
; idx != p.end() ; ++idx) ; idx != p.end() ; ++idx)
parms_[tmp_idx++] = *idx; parms_[tmp_idx++] = *idx;
tested_scope_ = 0;
repeat_count_ = 1;
} }
PEConcat::~PEConcat() PEConcat::~PEConcat()
@ -437,3 +442,11 @@ bool PEUnary::has_aa_term(Design*des, NetScope*scope) const
assert(expr_); assert(expr_);
return expr_->has_aa_term(des, scope); return expr_->has_aa_term(des, scope);
} }
PEVoid::PEVoid()
{
}
PEVoid::~PEVoid()
{
}

236
PExpr.h
View File

@ -1,7 +1,7 @@
#ifndef __PExpr_H #ifndef __PExpr_H
#define __PExpr_H #define __PExpr_H
/* /*
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com> * Copyright (c) 1998-2011 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
@ -43,6 +43,8 @@ class NetScope;
class PExpr : public LineInfo { class PExpr : public LineInfo {
public: public:
enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED };
PExpr(); PExpr();
virtual ~PExpr(); virtual ~PExpr();
@ -62,53 +64,65 @@ class PExpr : public LineInfo {
// references to automatically allocated variables. // references to automatically allocated variables.
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
// This method tests the width that the expression wants to // This method tests the type and width that the expression wants
// be. It is used by elaboration of assignments to figure out // to be. It should be called before elaborating an expression to
// the width of the expression. // figure out the type and width of the expression. It also figures
// out the minimum width that can be used to evaluate the expression
// without changing the result. This allows the expression width to
// be pruned when not all bits of the result are used.
// //
// The "min" is the width of the local context, so is the // Normally mode should be initialised to SIZED before starting to
// minimum width that this function should return. Initially // test the width of an expression. In SIZED mode the expression
// this is the same as the lval width. // width will be calculated strictly according to the IEEE standard
// rules for expression width.
// If the expression contains an unsized literal, mode will be
// changed to LOSSLESS. In LOSSLESS mode the expression width will
// be calculated as the minimum width necessary to avoid arithmetic
// overflow or underflow.
// If the expression both contains an unsized literal and contains
// an operation that coerces a vector operand to a different type
// (signed <-> unsigned), mode is changed to UNSIZED. UNSIZED mode
// is the same as LOSSLESS, except that the final expression width
// will be forced to be at least integer_width. This is necessary
// to ensure compatibility with the IEEE standard, which requires
// unsized literals to be treated as having the same width as an
// integer. The lossless width calculation is inadequate in this
// case because coercing an operand to a different type means that
// the expression no longer obeys the normal rules of arithmetic.
// //
// The "lval" is the width of the destination where this // If mode is initialised to EXPAND instead of SIZED, the expression
// result is going to go. This can be used to constrain the // width will be calculated as the minimum width necessary to avoid
// amount that an expression can reasonably expand. For // arithmetic overflow or underflow, even if it contains no unsized
// example, there is no point expanding an addition to beyond // literals. mode will be changed LOSSLESS or UNSIZED as described
// the lval. This extra bit of information allows the // above. This supports a non-standard mode of expression width
// expression to optimize itself a bit. If the lval==0, then // calculation.
// the subexpression should not make l-value related
// optimizations.
// //
// The expr_type is an output argument that gives the // When the final value of mode is UNSIZED, the width returned by
// calculated type for the expression. // this method is the calculated lossless width, but the width
// // returned by a subsequent call to the expr_width method will be
// The unsized_flag is set to true if the expression is // the final expression width.
// unsized and therefore expandable. This happens if a
// sub-expression is an unsized literal. Some expressions make
// special use of that.
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
// After the test_width method is complete, these methods // After the test_width method is complete, these methods
// return valid results. // return valid results.
ivl_variable_type_t expr_type() const { return expr_type_; } ivl_variable_type_t expr_type() const { return expr_type_; }
unsigned expr_width() const { return expr_width_; } unsigned expr_width() const { return expr_width_; }
unsigned min_width() const { return min_width_; }
bool has_sign() const { return signed_flag_; }
// This method allows the expression type (signed/unsigned)
// to be propagated down to any context-dependant operands.
void cast_signed(bool flag) { signed_flag_ = flag; }
// Procedural elaboration of the expression. The expr_width is // Procedural elaboration of the expression. The expr_width is
// the width of the context of the expression (i.e. the // the required width of the expression.
// l-value width of an assignment),
//
// ... or -1 if the expression is self-determined. or
// ... or -2 if the expression is losslessly
// self-determined. This can happen in situations where the
// result is going to a pseudo-infinitely wide context.
// //
// The sys_task_arg flag is true if expressions are allowed to // The sys_task_arg flag is true if expressions are allowed to
// be incomplete. // be incomplete.
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
// This method elaborates the expression as gates, but // This method elaborates the expression as gates, but
// restricted for use as l-values of continuous assignments. // restricted for use as l-values of continuous assignments.
@ -140,9 +154,13 @@ class PExpr : public LineInfo {
virtual bool is_the_same(const PExpr*that) const; virtual bool is_the_same(const PExpr*that) const;
protected: protected:
unsigned fix_width_(width_mode_t mode);
// The derived class test_width methods should fill these in. // The derived class test_width methods should fill these in.
ivl_variable_type_t expr_type_; ivl_variable_type_t expr_type_;
unsigned expr_width_; unsigned expr_width_;
unsigned min_width_;
bool signed_flag_;
private: // not implemented private: // not implemented
PExpr(const PExpr&); PExpr(const PExpr&);
@ -165,14 +183,13 @@ class PEConcat : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const; virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual NetAssign_* elaborate_lval(Design*des, virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope, NetScope*scope,
bool is_force) const; bool is_force) const;
@ -181,9 +198,11 @@ class PEConcat : public PExpr {
bool bidirectional_flag) const; bool bidirectional_flag) const;
private: private:
vector<PExpr*>parms_; vector<PExpr*>parms_;
std::valarray<unsigned>tested_widths_; std::valarray<width_mode_t>width_modes_;
PExpr*repeat_; PExpr*repeat_;
NetScope*tested_scope_;
unsigned repeat_count_;
}; };
/* /*
@ -232,11 +251,10 @@ class PEFNumber : public PExpr {
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -262,9 +280,7 @@ class PEIdent : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
// Identifiers are allowed (with restrictions) is assign l-values. // Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
@ -277,7 +293,8 @@ class PEIdent : public PExpr {
bool is_force) const; bool is_force) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
// Elaborate the PEIdent as a port to a module. This method // Elaborate the PEIdent as a port to a module. This method
// only applies to Ident expressions. // only applies to Ident expressions.
@ -326,13 +343,14 @@ class PEIdent : public PExpr {
NetScope*found, NetScope*found,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb, const NetExpr*par_lsb,
int expr_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_param_part_(Design*des, NetExpr*elaborate_expr_param_part_(Design*des,
NetScope*scope, NetScope*scope,
const NetExpr*par, const NetExpr*par,
NetScope*found, NetScope*found,
const NetExpr*par_msb, const NetExpr*par_msb,
const NetExpr*par_lsb) const; const NetExpr*par_lsb,
unsigned expr_wid) const;
NetExpr*elaborate_expr_param_idx_up_(Design*des, NetExpr*elaborate_expr_param_idx_up_(Design*des,
NetScope*scope, NetScope*scope,
const NetExpr*par, const NetExpr*par,
@ -349,16 +367,19 @@ class PEIdent : public PExpr {
NetScope*scope, NetScope*scope,
NetNet*net, NetNet*net,
NetScope*found, NetScope*found,
unsigned expr_wid,
bool sys_task_arg) const; bool sys_task_arg) const;
NetExpr*elaborate_expr_net_word_(Design*des, NetExpr*elaborate_expr_net_word_(Design*des,
NetScope*scope, NetScope*scope,
NetNet*net, NetNet*net,
NetScope*found, NetScope*found,
unsigned expr_wid,
bool sys_task_arg) const; bool sys_task_arg) const;
NetExpr*elaborate_expr_net_part_(Design*des, NetExpr*elaborate_expr_net_part_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
NetScope*found) const; NetScope*found,
unsigned expr_wid) const;
NetExpr*elaborate_expr_net_idx_up_(Design*des, NetExpr*elaborate_expr_net_idx_up_(Design*des,
NetScope*scope, NetScope*scope,
NetESignal*net, NetESignal*net,
@ -390,12 +411,10 @@ class PENumber : public PExpr {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetEConst*elaborate_expr(Design*des, NetScope*, virtual NetEConst*elaborate_expr(Design*des, NetScope*,
int expr_width, bool) const; unsigned expr_wid, bool) const;
virtual NetAssign_* elaborate_lval(Design*des, virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope, NetScope*scope,
bool is_force) const; bool is_force) const;
@ -425,12 +444,10 @@ class PEString : public PExpr {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetEConst*elaborate_expr(Design*des, NetScope*, virtual NetEConst*elaborate_expr(Design*des, NetScope*,
int expr_width, bool) const; unsigned expr_wid, bool) const;
verinum* eval_const(Design*, NetScope*) const; verinum* eval_const(Design*, NetScope*) const;
private: private:
@ -450,16 +467,15 @@ class PEUnary : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
private: private:
NetExpr* elaborate_expr_bits_(NetExpr*operand, int expr_wid) const; NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;
private: private:
char op_; char op_;
@ -479,12 +495,11 @@ class PEBinary : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
protected: protected:
@ -493,22 +508,22 @@ class PEBinary : public PExpr {
PExpr*right_; PExpr*right_;
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_bits_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_bits_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_div_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_div_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp,
int use_wid) const; unsigned expr_wid) const;
}; };
@ -523,16 +538,14 @@ class PEBComp : public PEBinary {
~PEBComp(); ~PEBComp();
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&flag);
NetExpr* elaborate_expr(Design*des, NetScope*scope, NetExpr* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const; unsigned expr_wid, bool sys_task_arg) const;
private: private:
int left_width_; unsigned l_width_;
int right_width_; unsigned r_width_;
}; };
/* /*
@ -545,12 +558,10 @@ class PEBLogic : public PEBinary {
~PEBLogic(); ~PEBLogic();
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&flag);
NetExpr* elaborate_expr(Design*des, NetScope*scope, NetExpr* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const; unsigned expr_wid, bool sys_task_arg) const;
}; };
/* /*
@ -565,17 +576,15 @@ class PEBLeftWidth : public PEBinary {
~PEBLeftWidth() =0; ~PEBLeftWidth() =0;
virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
int expr_wid) const =0; unsigned expr_wid) const =0;
protected: protected:
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
}; };
class PEBPower : public PEBLeftWidth { class PEBPower : public PEBLeftWidth {
@ -585,7 +594,7 @@ class PEBPower : public PEBLeftWidth {
~PEBPower(); ~PEBPower();
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
int expr_wid) const; unsigned expr_wid) const;
}; };
class PEBShift : public PEBLeftWidth { class PEBShift : public PEBLeftWidth {
@ -595,7 +604,7 @@ class PEBShift : public PEBLeftWidth {
~PEBShift(); ~PEBShift();
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
int expr_wid) const; unsigned expr_wid) const;
}; };
/* /*
@ -615,17 +624,16 @@ class PETernary : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;
private: private:
NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope, NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope,
PExpr*expr, int use_wid) const; PExpr*expr, unsigned expr_wid) const;
private: private:
PExpr*expr_; PExpr*expr_;
@ -658,12 +666,11 @@ class PECallFunction : public PExpr {
virtual bool has_aa_term(Design*des, NetScope*scope) const; virtual bool has_aa_term(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool sys_task_arg) const; unsigned expr_wid,
bool sys_task_arg) const;
virtual unsigned test_width(Design*des, NetScope*scope, virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type,
bool&unsized_flag);
private: private:
pform_name_t path_; pform_name_t path_;
@ -671,14 +678,29 @@ class PECallFunction : public PExpr {
bool check_call_matches_definition_(Design*des, NetScope*dscope) const; bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
NetExpr* cast_to_width_(NetExpr*expr, int wid, bool signed_flag) const; NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t) const; unsigned expr_wid) const;
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t,
unsigned expr_wid) const;
unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned test_width_sfunc_(Design*des, NetScope*scope,
unsigned min, unsigned lval, width_mode_t&mode);
ivl_variable_type_t&expr_type, };
bool&unsized_flag);
/*
* This class is used for error recovery. All methods do nothing and return
* null or default values.
*/
class PEVoid : public PExpr {
public:
explicit PEVoid();
~PEVoid();
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
unsigned expr_wid,
bool sys_task_arg) const;
}; };
#endif #endif

View File

@ -1396,12 +1396,8 @@ void NetEBinary::dump(ostream&o) const
void NetEConcat::dump(ostream&o) const void NetEConcat::dump(ostream&o) const
{ {
if (repeat_calculated_) { if (repeat_ != 1)
if (repeat_value_ != 1) o << repeat_;
o << repeat_value_;
} else if (repeat_) {
o << "<" << *repeat_ << ">";
}
if (parms_[0]) if (parms_[0])
o << "{" << *parms_[0]; o << "{" << *parms_[0];

View File

@ -32,19 +32,103 @@ NetEAccess* NetEAccess::dup_expr() const
return tmp; return tmp;
} }
NetEBComp* NetEBComp::dup_expr() const NetEBinary* NetEBinary::dup_expr() const
{ {
NetEBComp*tmp = new NetEBComp(op_, left_->dup_expr(), ivl_assert(*this, 0);
right_->dup_expr()); return 0;
assert(tmp); }
NetEBAdd* NetEBAdd::dup_expr() const
{
NetEBAdd*tmp = new NetEBAdd(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
NetEBBits* NetEBBits::dup_expr() const
{
NetEBBits*tmp = new NetEBBits(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBComp* NetEBComp::dup_expr() const
{
NetEBComp*tmp = new NetEBComp(op_, left_->dup_expr(), right_->dup_expr());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBDiv* NetEBDiv::dup_expr() const
{
NetEBDiv*tmp = new NetEBDiv(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBLogic* NetEBLogic::dup_expr() const
{
NetEBLogic*tmp = new NetEBLogic(op_, left_->dup_expr(), right_->dup_expr());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBMult* NetEBMult::dup_expr() const
{
NetEBMult*tmp = new NetEBMult(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBPow* NetEBPow::dup_expr() const
{
NetEBPow*tmp = new NetEBPow(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEBShift* NetEBShift::dup_expr() const
{
NetEBShift*tmp = new NetEBShift(op_, left_->dup_expr(), right_->dup_expr(),
expr_width(), has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetEConcat* NetEConcat::dup_expr() const
{
NetEConcat*dup = new NetEConcat(parms_.count(), repeat_);
ivl_assert(*this, dup);
dup->set_line(*this);
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
if (parms_[idx]) {
NetExpr*tmp = parms_[idx]->dup_expr();
ivl_assert(*this, tmp);
dup->parms_[idx] = tmp;
}
dup->expr_width(expr_width());
return dup;
}
NetEConst* NetEConst::dup_expr() const NetEConst* NetEConst::dup_expr() const
{ {
NetEConst*tmp = new NetEConst(value_); NetEConst*tmp = new NetEConst(value_);
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -52,7 +136,7 @@ NetEConst* NetEConst::dup_expr() const
NetEConstEnum* NetEConstEnum::dup_expr() const NetEConstEnum* NetEConstEnum::dup_expr() const
{ {
NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value()); NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -60,7 +144,15 @@ NetEConstEnum* NetEConstEnum::dup_expr() const
NetEConstParam* NetEConstParam::dup_expr() const NetEConstParam* NetEConstParam::dup_expr() const
{ {
NetEConstParam*tmp = new NetEConstParam(scope_, name_, value()); NetEConstParam*tmp = new NetEConstParam(scope_, name_, value());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this);
return tmp;
}
NetECReal* NetECReal::dup_expr() const
{
NetECReal*tmp = new NetECReal(value_);
ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -68,26 +160,26 @@ NetEConstParam* NetEConstParam::dup_expr() const
NetECRealParam* NetECRealParam::dup_expr() const NetECRealParam* NetECRealParam::dup_expr() const
{ {
NetECRealParam*tmp = new NetECRealParam(scope_, name_, value()); NetECRealParam*tmp = new NetECRealParam(scope_, name_, value());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
NetEEvent* NetEEvent::dup_expr() const NetEEvent* NetEEvent::dup_expr() const
{ {
assert(0); ivl_assert(*this, 0);
return 0; return 0;
} }
NetENetenum* NetENetenum::dup_expr() const NetENetenum* NetENetenum::dup_expr() const
{ {
assert(0); ivl_assert(*this, 0);
return 0; return 0;
} }
NetEScope* NetEScope::dup_expr() const NetEScope* NetEScope::dup_expr() const
{ {
assert(0); ivl_assert(*this, 0);
return 0; return 0;
} }
@ -96,7 +188,7 @@ NetESelect* NetESelect::dup_expr() const
NetESelect*tmp = new NetESelect(expr_->dup_expr(), NetESelect*tmp = new NetESelect(expr_->dup_expr(),
base_? base_->dup_expr() : 0, base_? base_->dup_expr() : 0,
expr_width(), sel_type_); expr_width(), sel_type_);
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -104,11 +196,11 @@ NetESelect* NetESelect::dup_expr() const
NetESFunc* NetESFunc::dup_expr() const NetESFunc* NetESFunc::dup_expr() const
{ {
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms()); NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms());
assert(tmp); ivl_assert(*this, tmp);
tmp->cast_signed(has_sign()); tmp->cast_signed(has_sign());
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
assert(parm(idx)); ivl_assert(*this, parm(idx));
tmp->parm(idx, parm(idx)->dup_expr()); tmp->parm(idx, parm(idx)->dup_expr());
} }
@ -119,7 +211,7 @@ NetESFunc* NetESFunc::dup_expr() const
NetESignal* NetESignal::dup_expr() const NetESignal* NetESignal::dup_expr() const
{ {
NetESignal*tmp = new NetESignal(net_, word_); NetESignal*tmp = new NetESignal(net_, word_);
assert(tmp); ivl_assert(*this, tmp);
tmp->expr_width(expr_width()); tmp->expr_width(expr_width());
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
@ -129,8 +221,10 @@ NetETernary* NetETernary::dup_expr() const
{ {
NetETernary*tmp = new NetETernary(cond_->dup_expr(), NetETernary*tmp = new NetETernary(cond_->dup_expr(),
true_val_->dup_expr(), true_val_->dup_expr(),
false_val_->dup_expr()); false_val_->dup_expr(),
assert(tmp); expr_width(),
has_sign());
ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -141,29 +235,29 @@ NetEUFunc* NetEUFunc::dup_expr() const
svector<NetExpr*> tmp_parms (parms_.count()); svector<NetExpr*> tmp_parms (parms_.count());
for (unsigned idx = 0 ; idx < tmp_parms.count() ; idx += 1) { for (unsigned idx = 0 ; idx < tmp_parms.count() ; idx += 1) {
assert(parms_[idx]); ivl_assert(*this, parms_[idx]);
tmp_parms[idx] = parms_[idx]->dup_expr(); tmp_parms[idx] = parms_[idx]->dup_expr();
} }
tmp = new NetEUFunc(scope_, func_, result_sig_->dup_expr(), tmp_parms); tmp = new NetEUFunc(scope_, func_, result_sig_->dup_expr(), tmp_parms);
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
NetEUBits* NetEUBits::dup_expr() const NetEUBits* NetEUBits::dup_expr() const
{ {
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr()); NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr(), expr_width(), has_sign());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
NetEUnary* NetEUnary::dup_expr() const NetEUnary* NetEUnary::dup_expr() const
{ {
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr()); NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr(), expr_width(), has_sign());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
@ -171,15 +265,15 @@ NetEUnary* NetEUnary::dup_expr() const
NetEUReduce* NetEUReduce::dup_expr() const NetEUReduce* NetEUReduce::dup_expr() const
{ {
NetEUReduce*tmp = new NetEUReduce(op_, expr_->dup_expr()); NetEUReduce*tmp = new NetEUReduce(op_, expr_->dup_expr());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }
NetECast* NetECast::dup_expr() const NetECast* NetECast::dup_expr() const
{ {
NetECast*tmp = new NetECast(op_, expr_->dup_expr()); NetECast*tmp = new NetECast(op_, expr_->dup_expr(), expr_width(), has_sign());
assert(tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2011 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
@ -255,12 +255,6 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
ivl_assert(*this, index_head.msb != 0); ivl_assert(*this, index_head.msb != 0);
ivl_assert(*this, index_head.lsb == 0); ivl_assert(*this, index_head.lsb == 0);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_head.msb->test_width(des, scope, integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1); NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1);
// If there is a non-zero base to the memory, then build an // If there is a non-zero base to the memory, then build an
@ -335,12 +329,6 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetNet*reg = lv->sig(); NetNet*reg = lv->sig();
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_tail.msb->test_width(des, scope, integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
// Bit selects have a single select expression. Evaluate the // Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit // constant value and treat it as a part select with a bit
// width of 1. // width of 1.
@ -463,12 +451,6 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
unsigned long wid; unsigned long wid;
calculate_up_do_width_(des, scope, wid); calculate_up_do_width_(des, scope, wid);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_tail.msb->test_width(des, scope, integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1); NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
ivl_select_type_t sel_type = IVL_SEL_OTHER; ivl_select_type_t sel_type = IVL_SEL_OTHER;

View File

@ -198,12 +198,6 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
case index_component_t::SEL_IDX_DO: case index_component_t::SEL_IDX_DO:
case index_component_t::SEL_IDX_UP: { case index_component_t::SEL_IDX_UP: {
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_tail.msb->test_width(des, scope,
integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
need_constant_expr = true; need_constant_expr = true;
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1); NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
need_constant_expr = false; need_constant_expr = false;
@ -477,12 +471,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
} }
ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
// These are not used, but they need to have a default value.
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
bool unsized_flag_tmp = false;
index_head.msb->test_width(des, scope,
integer_width, integer_width,
expr_type_tmp, unsized_flag_tmp);
need_constant_expr = true; need_constant_expr = true;
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1); NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
need_constant_expr = false; need_constant_expr = false;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2011 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
@ -61,7 +61,6 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
tmp->high_open_flag = range->high_open_flag; tmp->high_open_flag = range->high_open_flag;
if (range->low_expr) { if (range->low_expr) {
probe_expr_width(des, scope, range->low_expr);
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1); tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
ivl_assert(*range->low_expr, tmp->low_expr); ivl_assert(*range->low_expr, tmp->low_expr);
} else { } else {
@ -78,7 +77,6 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
tmp->high_expr = tmp->low_expr; tmp->high_expr = tmp->low_expr;
} else if (range->high_expr) { } else if (range->high_expr) {
probe_expr_width(des, scope, range->high_expr);
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1); tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
ivl_assert(*range->high_expr, tmp->high_expr); ivl_assert(*range->high_expr, tmp->high_expr);
} else { } else {
@ -136,8 +134,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
{ {
bool rc_flag; bool rc_flag;
assert(enum_type->range->size() == 2); assert(enum_type->range->size() == 2);
NetExpr*msb_ex = enum_type->range->front()->elaborate_expr(des, scope, -2, false); NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1);
NetExpr*lsb_ex = enum_type->range->back() ->elaborate_expr(des, scope, -2, false); NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1);
long msb = 0; long msb = 0;
rc_flag = eval_as_long(msb, msb_ex); rc_flag = eval_as_long(msb, msb_ex);
@ -162,7 +160,6 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
// There is an explicit value. elaborate/evaluate // There is an explicit value. elaborate/evaluate
// the value and assign it to the enumeration name. // the value and assign it to the enumeration name.
NetExpr*val = elab_and_eval(des, scope, cur->parm, NetExpr*val = elab_and_eval(des, scope, cur->parm,
use_enum->base_width(),
use_enum->base_width()); use_enum->base_width());
NetEConst*val_const = dynamic_cast<NetEConst*> (val); NetEConst*val_const = dynamic_cast<NetEConst*> (val);
if (val_const == 0) { if (val_const == 0) {
@ -557,7 +554,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
// The initial value for the genvar does not need (nor can it // The initial value for the genvar does not need (nor can it
// use) the genvar itself, so we can evaluate this expression // use) the genvar itself, so we can evaluate this expression
// the same way any other parameter value is evaluated. // the same way any other parameter value is evaluated.
probe_expr_width(des, container, loop_init);
need_constant_expr = true; need_constant_expr = true;
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1); NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1);
need_constant_expr = false; need_constant_expr = false;
@ -624,7 +620,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
cerr << get_fileline() << ": debug: genvar init = " << genvar << endl; cerr << get_fileline() << ": debug: genvar init = " << genvar << endl;
container->genvar_tmp = loop_index; container->genvar_tmp = loop_index;
container->genvar_tmp_val = genvar; container->genvar_tmp_val = genvar;
probe_expr_width(des, container, loop_test);
need_constant_expr = true; need_constant_expr = true;
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false; need_constant_expr = false;
@ -673,7 +668,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
elaborate_subscope_(des, scope); elaborate_subscope_(des, scope);
// Calculate the step for the loop variable. // Calculate the step for the loop variable.
probe_expr_width(des, container, loop_step);
need_constant_expr = true; need_constant_expr = true;
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1); NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
need_constant_expr = false; need_constant_expr = false;
@ -692,7 +686,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
container->genvar_tmp_val = genvar; container->genvar_tmp_val = genvar;
delete step; delete step;
delete test_ex; delete test_ex;
probe_expr_width(des, container, loop_test);
test_ex = elab_and_eval(des, container, loop_test, -1); test_ex = elab_and_eval(des, container, loop_test, -1);
test = dynamic_cast<NetEConst*>(test_ex); test = dynamic_cast<NetEConst*>(test_ex);
assert(test); assert(test);
@ -707,7 +700,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag) bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else_flag)
{ {
probe_expr_width(des, container, loop_test);
need_constant_expr = true; need_constant_expr = true;
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false; need_constant_expr = false;
@ -800,7 +792,6 @@ bool PGenerate::generate_scope_condit_(Design*des, NetScope*container, bool else
bool PGenerate::generate_scope_case_(Design*des, NetScope*container) bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
{ {
probe_expr_width(des, container, loop_test);
need_constant_expr = true; need_constant_expr = true;
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1); NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
need_constant_expr = false; need_constant_expr = false;
@ -833,7 +824,6 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
bool match_flag = false; bool match_flag = false;
for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) { for (unsigned idx = 0 ; idx < item->item_test.size() && !match_flag ; idx +=1 ) {
probe_expr_width(des, container, item->item_test[idx]);
need_constant_expr = true; need_constant_expr = true;
NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1); NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1);
need_constant_expr = false; need_constant_expr = false;
@ -1206,8 +1196,6 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
*/ */
void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const
{ {
if (msb_) probe_expr_width(des, sc, msb_);
if (lsb_) probe_expr_width(des, sc, lsb_);
need_constant_expr = true; need_constant_expr = true;
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0; NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0; NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2011 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
@ -471,8 +471,6 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
case PTF_REG_S: case PTF_REG_S:
if (return_type_.range) { if (return_type_.range) {
ivl_assert(*this, return_type_.range->size() == 2); ivl_assert(*this, return_type_.range->size() == 2);
probe_expr_width(des, scope, return_type_.range->at(0));
probe_expr_width(des, scope, return_type_.range->at(1));
need_constant_expr = true; need_constant_expr = true;
NetExpr*me = elab_and_eval(des, scope, NetExpr*me = elab_and_eval(des, scope,
@ -545,8 +543,6 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
case PTF_ATOM2: case PTF_ATOM2:
case PTF_ATOM2_S: case PTF_ATOM2_S:
ivl_assert(*this, return_type_.range != 0); ivl_assert(*this, return_type_.range != 0);
probe_expr_width(des, scope, (*return_type_.range)[0]);
probe_expr_width(des, scope, (*return_type_.range)[1]);
long use_wid; long use_wid;
{ {
need_constant_expr = true; need_constant_expr = true;
@ -852,7 +848,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
bool bad_lsb = false, bad_msb = false; bool bad_lsb = false, bad_msb = false;
/* If they exist get the port definition MSB and LSB */ /* If they exist get the port definition MSB and LSB */
if (port_set_ && port_msb_ != 0) { if (port_set_ && port_msb_ != 0) {
probe_expr_width(des, scope, port_msb_);
/* We do not currently support constant user function. */ /* We do not currently support constant user function. */
need_constant_expr = true; need_constant_expr = true;
NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1); NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1);
@ -870,7 +865,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete texpr; delete texpr;
probe_expr_width(des, scope, port_lsb_);
/* We do not currently support constant user function. */ /* We do not currently support constant user function. */
need_constant_expr = true; need_constant_expr = true;
texpr = elab_and_eval(des, scope, port_lsb_, -1); texpr = elab_and_eval(des, scope, port_lsb_, -1);
@ -898,7 +892,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
/* If they exist get the net/etc. definition MSB and LSB */ /* If they exist get the net/etc. definition MSB and LSB */
if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
probe_expr_width(des, scope, net_msb_);
/* We do not currently support constant user function. */ /* We do not currently support constant user function. */
need_constant_expr = true; need_constant_expr = true;
NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1); NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1);
@ -916,7 +909,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
delete texpr; delete texpr;
probe_expr_width(des, scope, net_lsb_);
/* We do not currently support constant user function. */ /* We do not currently support constant user function. */
need_constant_expr = true; need_constant_expr = true;
texpr = elab_and_eval(des, scope, net_lsb_, -1); texpr = elab_and_eval(des, scope, net_lsb_, -1);
@ -1011,9 +1003,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
if (lidx_ || ridx_) { if (lidx_ || ridx_) {
assert(lidx_ && ridx_); assert(lidx_ && ridx_);
probe_expr_width(des, scope, lidx_);
probe_expr_width(des, scope, ridx_);
need_constant_expr = true; need_constant_expr = true;
NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1); NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1);
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1); NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1);

View File

@ -115,6 +115,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value" cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
<< " width="<< rval->vector_width() << " width="<< rval->vector_width()
<< ", type="<< rval->data_type() << ", type="<< rval->data_type()
<< ", signed="<< rval->get_signed()
<< ", expr=" << *rval_expr << endl; << ", expr=" << *rval_expr << endl;
} }
@ -227,11 +228,6 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
gate. Figure out how many are desired. */ gate. Figure out how many are desired. */
if (msb_) { if (msb_) {
need_constant_expr = true; need_constant_expr = true;
ivl_variable_type_t use_type;
bool flag = false;
msb_->test_width(des, scope, 0, 0, use_type, flag);
flag = false;
lsb_->test_width(des, scope, 0, 0, use_type, flag);
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1); NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1);
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1); NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1);
need_constant_expr = false; need_constant_expr = false;
@ -820,12 +816,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
sig = lval_sigs[idx]; sig = lval_sigs[idx];
} else { } else {
unsigned use_width = array_count * instance_width; NetExpr*tmp = elab_and_eval(des, scope, ex, -1);
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
bool flag = false;
ex->test_width(des, scope, 0, use_width, tmp_type, flag);
NetExpr*tmp = elab_and_eval(des, scope, ex,
use_width, use_width);
sig = tmp->synthesize(des, scope, tmp); sig = tmp->synthesize(des, scope, tmp);
delete tmp; delete tmp;
} }
@ -1332,13 +1323,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
port is actually empty on the inside. We assume port is actually empty on the inside. We assume
in that case that the port is input. */ in that case that the port is input. */
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE; NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], -1);
bool flag = false;
pins[idx]->test_width(des, scope, 0, desired_vector_width,
tmp_type, flag);
NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx],
desired_vector_width,
desired_vector_width);
if (tmp_expr == 0) { if (tmp_expr == 0) {
cerr << pins[idx]->get_fileline() cerr << pins[idx]->get_fileline()
<< ": internal error: Port expression " << ": internal error: Port expression "
@ -1891,7 +1876,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
if (pins[idx] == 0) if (pins[idx] == 0)
continue; continue;
NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1, 1); NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1);
if (expr_tmp == 0) { if (expr_tmp == 0) {
cerr << "internal error: Expression too complicated " cerr << "internal error: Expression too complicated "
"for elaboration:" << *pins[idx] << endl; "for elaboration:" << *pins[idx] << endl;
@ -2046,7 +2031,6 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
*/ */
static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope) static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
{ {
probe_expr_width(des, scope, expr);
NetExpr*dex = elab_and_eval(des, scope, expr, -1); NetExpr*dex = elab_and_eval(des, scope, expr, -1);
/* Print a warning if we find default and `timescale based /* Print a warning if we find default and `timescale based
@ -2101,12 +2085,11 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
NetExpr*scal_val = new NetECReal(verireal(round)); NetExpr*scal_val = new NetECReal(verireal(round));
scal_val->set_line(*expr); scal_val->set_line(*expr);
dex = new NetEBMult('*', dex, scal_val); dex = new NetEBMult('*', dex, scal_val, 1, true);
dex->set_line(*expr); dex->set_line(*expr);
// Cast this part of the expression to an integer. // Cast this part of the expression to an integer.
dex = new NetECast('i', dex); dex = new NetECast('i', dex, 64, false);
dex->set_width(64);
dex->set_line(*expr); dex->set_line(*expr);
// Now scale the integer value. // Now scale the integer value.
@ -2117,8 +2100,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
scal_val = new NetEConst(verinum(scale, 64)); scal_val = new NetEConst(verinum(scale, 64));
scal_val->set_line(*expr); scal_val->set_line(*expr);
dex = new NetEBMult('*', dex, scal_val); dex = new NetEBMult('*', dex, scal_val, 64, false);
dex->set_width(64);
dex->set_line(*expr); dex->set_line(*expr);
} else { } else {
int shift = scope->time_unit() - des->get_precision(); int shift = scope->time_unit() - des->get_precision();
@ -2128,7 +2110,7 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
NetExpr*scal_val = new NetEConst(verinum(scale, 64)); NetExpr*scal_val = new NetEConst(verinum(scale, 64));
scal_val->set_line(*expr); scal_val->set_line(*expr);
dex = new NetEBMult('*', dex, scal_val); dex = new NetEBMult('*', dex, scal_val, 64, false);
dex->set_line(*expr); dex->set_line(*expr);
} }
@ -2176,17 +2158,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
if (delay || event_) { if (delay || event_) {
unsigned wid = count_lval_width(lv); unsigned wid = count_lval_width(lv);
rv->set_width(wid);
rv = pad_to_width(rv, wid, *this);
if (wid > rv->expr_width()) {
cerr << get_fileline() << ": error: Unable to match "
"expression width of " << rv->expr_width() <<
" to l-value width of " << wid << "." << endl;
//XXXX delete rv;
return 0;
}
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::REG, wid); NetNet::REG, wid);
tmp->local_flag(true); tmp->local_flag(true);
@ -2276,22 +2247,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
return bl; return bl;
} }
/* Based on the specific type of the l-value, do cleanup
processing on the r-value. */
if (rv->expr_type() == IVL_VT_REAL) {
// The r-value is a real. Casting will happen in the
// code generator, so leave it.
} else {
unsigned wid = count_lval_width(lv);
if (wid > rv->expr_width()) {
rv->set_width(wid);
rv = pad_to_width(rv, wid, *this);
}
ivl_assert(*this, rv->expr_width() >= wid);
}
if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) { if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) {
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: Cast expression to int2" << endl; cerr << get_fileline() << ": debug: Cast expression to int2" << endl;
@ -2342,20 +2297,6 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
if (rv == 0) return 0; if (rv == 0) return 0;
/* Handle the (common) case that the r-value is a vector. This
includes just about everything but reals. In this case, we
need to pad the r-value to match the width of the l-value.
If in this case the l-val is a variable (i.e., real) then
the width to pad to will be 0, so this code is harmless. */
if (rv->expr_type() == IVL_VT_REAL) {
} else {
unsigned wid = count_lval_width(lv);
rv->set_width(wid);
rv = pad_to_width(rv, wid, *this);
}
NetExpr*delay = 0; NetExpr*delay = 0;
if (delay_ != 0) { if (delay_ != 0) {
assert(count_ == 0 && event_ == 0); assert(count_ == 0 && event_ == 0);
@ -2507,7 +2448,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);
probe_expr_width(des, scope, expr_);
NetExpr*expr = elab_and_eval(des, scope, expr_, -1); NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
if (expr == 0) { if (expr == 0) {
cerr << get_fileline() << ": error: Unable to elaborate this case" cerr << get_fileline() << ": error: Unable to elaborate this case"
@ -2562,7 +2502,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
NetExpr*gu = 0; NetExpr*gu = 0;
NetProc*st = 0; NetProc*st = 0;
assert(cur_expr); assert(cur_expr);
probe_expr_width(des, scope, cur_expr);
gu = elab_and_eval(des, scope, cur_expr, -1); gu = elab_and_eval(des, scope, cur_expr, -1);
if (cur->stat) if (cur->stat)
@ -2585,7 +2524,6 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
<< " with conditional: " << *expr_ << endl; << " with conditional: " << *expr_ << endl;
// Elaborate and try to evaluate the conditional expression. // Elaborate and try to evaluate the conditional expression.
probe_expr_width(des, scope, expr_);
NetExpr*expr = elab_and_eval(des, scope, expr_, -1); NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
if (expr == 0) { if (expr == 0) {
cerr << get_fileline() << ": error: Unable to elaborate" cerr << get_fileline() << ": error: Unable to elaborate"
@ -2701,29 +2639,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
svector<NetExpr*>eparms (parm_count); svector<NetExpr*>eparms (parm_count);
perm_string name = peek_tail_name(path_);
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parm(idx); PExpr*ex = parm(idx);
if (ex != 0) { if (ex != 0) {
ivl_variable_type_t use_type; eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
bool flag = false;
int use_wid = ex->test_width(des,scope,0,0, use_type, flag);
if (debug_elaborate)
cerr << ex->get_fileline() << ": debug: "
<< "Argument " << (idx+1)
<< " of system task tests its width as " << use_wid
<< ", type=" << use_type
<< ", unsized_flag=" << flag << endl;
// If the argument expression is unsized, then
// elaborate as self-determined *lossless* instead
// of sized.
if (flag==true)
use_wid = -2;
eparms[idx] = ex->elaborate_expr(des, scope, use_wid, true);
if (eparms[idx])
eval_expr(eparms[idx]);
} else { } else {
eparms[idx] = 0; eparms[idx] = 0;
} }
@ -2733,8 +2654,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
// $sdf_annotate system task. There will be nothing for $sdf // $sdf_annotate system task. There will be nothing for $sdf
// to annotate, and the user is intending to turn the behavior // to annotate, and the user is intending to turn the behavior
// off anyhow, so replace the system task invocation with a no-op. // off anyhow, so replace the system task invocation with a no-op.
if (gn_specify_blocks_flag == false if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
&& peek_tail_name(path_) == "$sdf_annotate") {
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() " cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
<< "since specify blocks are being omitted." << endl; << "since specify blocks are being omitted." << endl;
@ -2743,8 +2663,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
return noop; return noop;
} }
NetSTask*cur = new NetSTask(peek_tail_name(path_), def_sfunc_as_task, NetSTask*cur = new NetSTask(name, def_sfunc_as_task, eparms);
eparms);
cur->set_line(*this); cur->set_line(*this);
return cur; return cur;
} }
@ -2871,11 +2790,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
des->errors += 1; des->errors += 1;
continue; continue;
} }
if (wid > rv->expr_width()) {
rv->set_width(wid);
rv = pad_to_width(rv, wid, *this);
}
ivl_assert(*this, rv->expr_width() >= wid);
NetAssign*pr = new NetAssign(lv, rv); NetAssign*pr = new NetAssign(lv, rv);
pr->set_line(*this); pr->set_line(*this);
@ -2988,9 +2902,6 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
if (rexp == 0) if (rexp == 0)
return 0; return 0;
rexp->set_width(lwid);
rexp = pad_to_width(rexp, lwid, *this);
dev = new NetCAssign(lval, rexp); dev = new NetCAssign(lval, rexp);
if (debug_elaborate) { if (debug_elaborate) {
@ -3306,8 +3217,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
} }
} }
probe_expr_width(des, scope, expr_[idx]->expr()); NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), -1);
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0);
if (tmp == 0) { if (tmp == 0) {
expr_[idx]->dump(cerr); expr_[idx]->dump(cerr);
cerr << endl; cerr << endl;
@ -3409,8 +3319,9 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
/* Elaborate wait expression. Don't eval yet, we will do that /* Elaborate wait expression. Don't eval yet, we will do that
shortly, after we apply a reduction or. */ shortly, after we apply a reduction or. */
probe_expr_width(des, scope, pe); PExpr::width_mode_t mode;
NetExpr*expr = pe->elaborate_expr(des, scope, -1, false); pe->test_width(des, scope, mode);
NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), false);
if (expr == 0) { if (expr == 0) {
cerr << get_fileline() << ": error: Unable to elaborate" cerr << get_fileline() << ": error: Unable to elaborate"
" wait condition expression." << endl; " wait condition expression." << endl;
@ -3607,9 +3518,6 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
if (rexp == 0) if (rexp == 0)
return 0; return 0;
rexp->set_width(lwid, true);
rexp = pad_to_width(rexp, lwid, *this);
if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) { if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) {
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
@ -3670,32 +3578,14 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
assert(sig); assert(sig);
NetAssign_*lv = new NetAssign_(sig); NetAssign_*lv = new NetAssign_(sig);
/* Calculate the width of the initialization as if this were
any other assignment statement. */
unsigned use_width = lv->lwidth();
bool unsized_flag = false;
ivl_variable_type_t expr1_type = IVL_VT_NO_TYPE;
use_width = expr1_->test_width(des, scope, use_width, use_width, expr1_type, unsized_flag);
/* Make the r-value of the initial assignment, and size it /* Make the r-value of the initial assignment, and size it
properly. Then use it to build the assignment statement. */ properly. Then use it to build the assignment statement. */
etmp = elab_and_eval(des, scope, expr1_, use_width); etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
etmp->set_width(use_width); expr1_);
etmp = pad_to_width(etmp, use_width, *this);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: FOR initial assign: " cerr << get_fileline() << ": debug: FOR initial assign: "
<< sig->name() << " = " << *etmp << endl; << sig->name() << " = " << *etmp << endl;
assert(etmp->expr_width() >= lv->lwidth());
}
/* Based on the specific type of the l-value, do cleanup
processing on the r-value. */
if (etmp->expr_type() != IVL_VT_REAL) {
unsigned wid = count_lval_width(lv);
etmp->set_width(wid);
etmp = pad_to_width(etmp, wid, *this);
assert(etmp->expr_width() >= wid);
} }
NetAssign*init = new NetAssign(lv, etmp); NetAssign*init = new NetAssign(lv, etmp);
@ -3729,9 +3619,16 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
assert(sig); assert(sig);
lv = new NetAssign_(sig); lv = new NetAssign_(sig);
/* Make the rvalue of the increment expression, and size it /* Make the r-value of the increment assignment, and size it
for the lvalue. */ properly. Then use it to build the assignment statement. */
etmp = elab_and_eval(des, scope, expr2_, lv->lwidth()); etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
expr2_);
if (debug_elaborate) {
cerr << get_fileline() << ": debug: FOR increment assign: "
<< sig->name() << " = " << *etmp << endl;
}
NetAssign*step = new NetAssign(lv, etmp); NetAssign*step = new NetAssign(lv, etmp);
step->set_line(*this); step->set_line(*this);
@ -3741,7 +3638,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
/* Elaborate the condition expression. Try to evaluate it too, /* Elaborate the condition expression. Try to evaluate it too,
in case it is a constant. This is an interesting case in case it is a constant. This is an interesting case
worthy of a warning. */ worthy of a warning. */
probe_expr_width(des, scope, cond_);
NetExpr*ce = elab_and_eval(des, scope, cond_, -1); NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
if (ce == 0) { if (ce == 0) {
delete top; delete top;
@ -3832,7 +3728,6 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);
probe_expr_width(des, scope, expr_);
NetExpr*expr = elab_and_eval(des, scope, expr_, -1); NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
if (expr == 0) { if (expr == 0) {
cerr << get_fileline() << ": Unable to elaborate" cerr << get_fileline() << ": Unable to elaborate"
@ -3956,7 +3851,6 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
*/ */
NetProc* PWhile::elaborate(Design*des, NetScope*scope) const NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
{ {
probe_expr_width(des, scope, cond_);
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1); NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope)); NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
return loop; return loop;
@ -4059,8 +3953,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
them for the timescale/precision of the scope. */ them for the timescale/precision of the scope. */
for (unsigned idx = 0 ; idx < ndelays ; idx += 1) { for (unsigned idx = 0 ; idx < ndelays ; idx += 1) {
PExpr*exp = delays[idx]; PExpr*exp = delays[idx];
probe_expr_width(des, scope, exp); NetExpr*cur = elab_and_eval(des, scope, exp, -1);
NetExpr*cur = elab_and_eval(des, scope, exp, 0);
if (NetEConst*con = dynamic_cast<NetEConst*> (cur)) { if (NetEConst*con = dynamic_cast<NetEConst*> (cur)) {
verinum fn = con->value(); verinum fn = con->value();
@ -4098,7 +3991,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
NetNet*condit_sig = 0; NetNet*condit_sig = 0;
if (conditional && condition) { if (conditional && condition) {
probe_expr_width(des, scope, condition);
NetExpr*tmp = elab_and_eval(des, scope, condition, -1); NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
ivl_assert(*condition, tmp); ivl_assert(*condition, tmp);
@ -4255,7 +4147,6 @@ bool Module::elaborate(Design*des, NetScope*scope) const
for (specparam_it_t cur = specparams.begin() for (specparam_it_t cur = specparams.begin()
; cur != specparams.end() ; ++ cur ) { ; cur != specparams.end() ; ++ cur ) {
probe_expr_width(des, scope, (*cur).second);
need_constant_expr = true; need_constant_expr = true;
NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1); NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1);
need_constant_expr = false; need_constant_expr = false;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2008,2011 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
@ -28,8 +28,6 @@
NetProc* AContrib::elaborate(Design*des, NetScope*scope) const NetProc* AContrib::elaborate(Design*des, NetScope*scope) const
{ {
probe_expr_width(des, scope, lval_);
probe_expr_width(des, scope, rval_);
NetExpr*lval = elab_and_eval(des, scope, lval_, -1); NetExpr*lval = elab_and_eval(des, scope, lval_, -1);
NetExpr*rval = elab_and_eval(des, scope, rval_, -1); NetExpr*rval = elab_and_eval(des, scope, rval_, -1);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2011 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
@ -29,7 +29,7 @@
# include "ivl_assert.h" # include "ivl_assert.h"
# include "netmisc.h" # include "netmisc.h"
NetExpr* NetExpr::eval_tree(int) NetExpr* NetExpr::eval_tree()
{ {
return 0; return 0;
} }
@ -114,12 +114,12 @@ NetECReal* NetEBAdd::eval_tree_real_()
return res; return res;
} }
NetExpr* NetEBAdd::eval_tree(int prune_to_width) NetExpr* NetEBAdd::eval_tree()
{ {
eval_expr(left_, prune_to_width); eval_expr(left_);
eval_expr(right_, prune_to_width); eval_expr(right_);
if (left_->expr_type() == IVL_VT_REAL || right_->expr_type()==IVL_VT_REAL) if (expr_type() == IVL_VT_REAL)
return eval_tree_real_(); return eval_tree_real_();
NetEConst*lc = dynamic_cast<NetEConst*>(left_); NetEConst*lc = dynamic_cast<NetEConst*>(left_);
@ -131,33 +131,23 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum val; verinum val;
switch (op_) { switch (op_) {
case '+': case '+':
val = lval + rval; val = verinum(lval + rval, wid);
break; break;
case '-': case '-':
val = lval - rval; val = verinum(lval - rval, wid);
break; break;
default: default:
return 0; return 0;
} }
/* Result might have known width. */
if (has_width()) {
unsigned lwid = lc->expr_width();
unsigned rwid = rc->expr_width();
unsigned wid = (rwid > lwid) ? rwid : lwid;
if (prune_to_width < 0)
wid += 1;
verinum val2=verinum(val,wid);
val=val2;
} else {
/* No fixed width, so trim the bits losslessly. */
verinum val2 = trim_vnum(val);
val = val2;
}
NetEConst *res = new NetEConst(val); NetEConst *res = new NetEConst(val);
ivl_assert(*this, res); ivl_assert(*this, res);
res->set_line(*this); res->set_line(*this);
@ -188,37 +178,20 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
if (lval.len() < expr_width()) unsigned wid = expr_width();
lval = pad_to_width(lval, expr_width()); ivl_assert(*this, wid > 0);
if (rval.len() < expr_width()) ivl_assert(*this, lval.len() == wid);
rval = pad_to_width(rval, expr_width()); ivl_assert(*this, rval.len() == wid);
if (se->expr_width() > this->expr_width()) {
cerr << get_fileline() << ": internal error: "
<< "expr_width()=" << expr_width()
<< ", sub expr_width()=" << se->expr_width()
<< ", sub expression=" << *se << endl;
}
ivl_assert(*this, se->expr_width() <= this->expr_width());
verinum val; verinum val;
if (op_ == se->op_) { if (op_ == se->op_) {
/* (a + lval) + rval --> a + (rval+lval) */ /* (a + lval) + rval --> a + (rval+lval) */
/* (a - lval) - rval --> a - (rval+lval) */ /* (a - lval) - rval --> a - (rval+lval) */
val = rval + lval; val = verinum(rval + lval, wid);
} else { } else {
/* (a - lval) + rval --> a + (rval-lval) */ /* (a - lval) + rval --> a + (rval-lval) */
/* (a + lval) - rval --> a - (rval-lval) */ /* (a + lval) - rval --> a - (rval-lval) */
val = rval - lval; val = verinum(rval - lval, wid);
}
// Since we padded the operands above to be the minimum
// width, the val should also be at least expr_width().
ivl_assert(*this, val.len() >= expr_width());
if (val.len() > expr_width()) {
verinum tmp (val, expr_width());
tmp.has_sign(val.has_sign());
val = tmp;
} }
NetEConst*tmp = new NetEConst(val); NetEConst*tmp = new NetEConst(val);
@ -236,15 +209,15 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
return 0; return 0;
} }
NetEConst* NetEBBits::eval_tree(int prune_to_width) NetEConst* NetEBBits::eval_tree()
{ {
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluating expression:" cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << ", prune_to_width=" << prune_to_width << endl; << *this << endl;
} }
eval_expr(left_, prune_to_width); eval_expr(left_);
eval_expr(right_, prune_to_width); eval_expr(right_);
NetEConst*lc = dynamic_cast<NetEConst*>(left_); NetEConst*lc = dynamic_cast<NetEConst*>(left_);
NetEConst*rc = dynamic_cast<NetEConst*>(right_); NetEConst*rc = dynamic_cast<NetEConst*>(right_);
@ -266,79 +239,33 @@ NetEConst* NetEBBits::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
unsigned lwid = lc->expr_width();
if (lwid == 0) lwid = lval.len();
unsigned rwid = rc->expr_width();
if (rwid == 0) rwid = rval.len();
unsigned wid = expr_width(); unsigned wid = expr_width();
if (wid == 0) ivl_assert(*this, wid > 0);
wid = (rwid > lwid)? rwid : lwid; ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum res (verinum::V0, wid); verinum res (verinum::V0, wid);
if (lwid > wid)
lwid = wid;
if (rwid > wid)
rwid = wid;
// Sub-expressions of bitwise operators need to be the same
// width. Pad them out if necessary.
if (lwid < wid) {
lval = pad_to_width(lval, wid);
lwid = wid;
}
if (rwid < wid) {
rval = pad_to_width(rval, wid);
rwid = wid;
}
switch (op()) { switch (op()) {
case '|': { case '|': {
unsigned cnt = lwid; for (unsigned idx = 0 ; idx < wid ; idx += 1)
if (cnt > wid) cnt = wid;
if (cnt > rwid) cnt = rwid;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res.set(idx, lval.get(idx) | rval.get(idx)); res.set(idx, lval.get(idx) | rval.get(idx));
if (lwid < rwid)
for (unsigned idx = lwid ; idx < rwid ; idx += 1)
res.set(idx, rval.get(idx));
if (rwid < lwid)
for (unsigned idx = rwid ; idx < lwid ; idx += 1)
res.set(idx, lval.get(idx));
break; break;
} }
case '&': { case '&': {
unsigned cnt = lwid; for (unsigned idx = 0 ; idx < wid ; idx += 1)
if (cnt > wid) cnt = wid;
if (cnt > rwid) cnt = rwid;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res.set(idx, lval.get(idx) & rval.get(idx)); res.set(idx, lval.get(idx) & rval.get(idx));
break; break;
} }
case '^': { case '^': {
unsigned cnt = lwid; for (unsigned idx = 0 ; idx < wid ; idx += 1)
if (cnt > wid) cnt = wid;
if (cnt > rwid) cnt = rwid;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
res.set(idx, lval.get(idx) ^ rval.get(idx)); res.set(idx, lval.get(idx) ^ rval.get(idx));
if (lwid < rwid)
for (unsigned idx = lwid ; idx < rwid ; idx += 1)
res.set(idx, rval.get(idx));
if (rwid < lwid)
for (unsigned idx = rwid ; idx < lwid ; idx += 1)
res.set(idx, lval.get(idx));
break; break;
} }
@ -761,7 +688,7 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag)
return result; return result;
} }
NetEConst* NetEBComp::eval_tree(int) NetEConst* NetEBComp::eval_tree()
{ {
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -850,11 +777,8 @@ NetExpr* NetEBDiv::eval_tree_real_()
* The NetEBDiv operator includes the / and % operators. First evaluate * The NetEBDiv operator includes the / and % operators. First evaluate
* the sub-expressions, then perform the required operation. * the sub-expressions, then perform the required operation.
*/ */
NetExpr* NetEBDiv::eval_tree(int prune_to_width) NetExpr* NetEBDiv::eval_tree()
{ {
// assert(prune_to_width <= 0);
// HERE
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -865,20 +789,26 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
NetEConst*rc = dynamic_cast<NetEConst*>(right_); NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (lc == 0 || rc == 0) return 0; if (lc == 0 || rc == 0) return 0;
// Make sure the expression is evaluated at the verinum lval = lc->value();
// expression width. verinum rval = rc->value();
verinum lval = pad_to_width(lc->value(), expr_width());
verinum rval = pad_to_width(rc->value(), expr_width());
NetExpr*tmp = 0; unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum val;
switch (op_) { switch (op_) {
case '/': case '/':
tmp = new NetEConst(lval / rval); val = verinum(lval / rval, wid);
break; break;
case '%': case '%':
tmp = new NetEConst(lval % rval); val = verinum(lval % rval, wid);
break; break;
default:
return 0;
} }
NetExpr*tmp = new NetEConst(val);
ivl_assert(*this, tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
@ -928,7 +858,7 @@ NetEConst* NetEBLogic::eval_tree_real_()
return tmp; return tmp;
} }
NetEConst* NetEBLogic::eval_tree(int) NetEConst* NetEBLogic::eval_tree()
{ {
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -1024,11 +954,8 @@ NetExpr* NetEBMult::eval_tree_real_()
return res; return res;
} }
NetExpr* NetEBMult::eval_tree(int prune_to_width) NetExpr* NetEBMult::eval_tree()
{ {
// assert(prune_to_width <= 0);
// HERE
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -1042,7 +969,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
NetEConst*tmp = new NetEConst(lval * rval); unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
ivl_assert(*this, rval.len() == wid);
verinum val(lval * rval, wid);
NetEConst*tmp = new NetEConst(val);
ivl_assert(*this, tmp); ivl_assert(*this, tmp);
tmp->set_line(*this); tmp->set_line(*this);
@ -1072,11 +1005,8 @@ NetExpr* NetEBPow::eval_tree_real_()
return res; return res;
} }
NetExpr* NetEBPow::eval_tree(int prune_to_width) NetExpr* NetEBPow::eval_tree()
{ {
// assert(prune_to_width <= 0);
// HERE
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -1090,7 +1020,12 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
verinum lval = lc->value(); verinum lval = lc->value();
verinum rval = rc->value(); verinum rval = rc->value();
NetEConst*res = new NetEConst( pow(lval,rval) ); unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lval.len() == wid);
verinum val(pow(lval, rval), wid);
NetEConst*res = new NetEConst(val);
ivl_assert(*this, res); ivl_assert(*this, res);
res->set_line(*this); res->set_line(*this);
@ -1105,7 +1040,7 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
* Evaluate the shift operator if possible. For this to work, both * Evaluate the shift operator if possible. For this to work, both
* operands must be constant. * operands must be constant.
*/ */
NetEConst* NetEBShift::eval_tree(int prune_to_width) NetEConst* NetEBShift::eval_tree()
{ {
eval_expr(left_); eval_expr(left_);
eval_expr(right_); eval_expr(right_);
@ -1116,79 +1051,44 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
NetEConst*res; NetEConst*res;
verinum rv = re->value();
verinum lv = le->value(); verinum lv = le->value();
verinum rv = re->value();
/* Make an early estimate of the expression width. */
unsigned wid = expr_width(); unsigned wid = expr_width();
ivl_assert(*this, wid > 0);
ivl_assert(*this, lv.len() == wid);
if (rv.is_defined()) { if (rv.is_defined()) {
unsigned shift = rv.as_ulong(); unsigned shift = rv.as_ulong();
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
<< "Evaluate " << lv << "<<" << op() << ">> " << "Evaluate " << lv << "<<" << op() << ">> "
<< rv << ", wid=" << wid << ", shift=" << shift << rv << ", wid=" << wid << ", shift=" << shift << endl;
<< ", lv.has_len()=" << lv.has_len() << endl;
} }
if ((wid == 0) || ! lv.has_len()) { verinum val;
/* If the caller doesn't care what the width is, switch (op_) {
then calculate a width from the trimmed left case 'l':
expression, plus the shift. This avoids val = verinum(lv << shift, wid);
data loss. */ break;
lv = trim_vnum(lv); case 'r':
wid = lv.len(); lv.has_sign(false);
if (op() == 'l') val = verinum(lv >> shift, wid);
wid = lv.len() + shift; break;
case 'R':
lv.has_sign(true);
val = verinum(lv >> shift, wid);
break;
default:
return 0;
} }
val.has_sign(has_sign());
if (prune_to_width > 0 && wid > (unsigned)prune_to_width) res = new NetEConst(val);
wid = prune_to_width;
assert(wid > 0);
verinum::V pad = verinum::V0;
if (op() == 'R' && has_sign()) {
pad = lv[lv.len()-1];
}
verinum nv (pad, wid, lv.has_len());
if (op() == 'r' || op() == 'R') {
unsigned cnt = wid;
if (cnt > nv.len())
cnt = nv.len();
if (shift >= lv.len())
cnt = 0;
else if (cnt > (lv.len()-shift))
cnt = (lv.len()-shift);
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
nv.set(idx, lv[idx+shift]);
} else { } else {
unsigned cnt = wid; verinum val (verinum::Vx, wid);
if (cnt > lv.len()) res = new NetEConst(val);
cnt = lv.len();
if (shift >= nv.len())
cnt = 0;
else if (cnt > (nv.len()-shift))
cnt = nv.len() - shift;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
nv.set(idx+shift, lv[idx]);
}
res = new NetEConst(nv);
} else {
if (wid == 0) wid = left_->expr_width();
if (prune_to_width > 0 && wid > (unsigned)prune_to_width)
wid = prune_to_width;
assert(wid > 0);
verinum nv (verinum::Vx, wid);
res = new NetEConst(nv);
} }
res->set_line(*this); res->set_line(*this);
@ -1196,7 +1096,7 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
return res; return res;
} }
NetEConst* NetEConcat::eval_tree(int prune_to_width) NetEConst* NetEConcat::eval_tree()
{ {
// HERE // HERE
unsigned repeat_val = repeat(); unsigned repeat_val = repeat();
@ -1204,7 +1104,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluating expression:" cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << ", prune_to_width=" << prune_to_width << endl; << *this << endl;
} }
unsigned gap = 0; unsigned gap = 0;
@ -1225,7 +1125,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
// that is here. If I succeed, reset the parameter to // that is here. If I succeed, reset the parameter to
// the evaluated value. // the evaluated value.
assert(parms_[idx]); assert(parms_[idx]);
NetExpr*expr = parms_[idx]->eval_tree(0); NetExpr*expr = parms_[idx]->eval_tree();
if (expr) { if (expr) {
expr->set_line(*parms_[idx]); expr->set_line(*parms_[idx]);
delete parms_[idx]; delete parms_[idx];
@ -1285,16 +1185,15 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
val.has_sign( this->has_sign() ); val.has_sign( this->has_sign() );
NetEConst*res = new NetEConst(val); NetEConst*res = new NetEConst(val);
res->set_width(val.len());
return res; return res;
} }
NetEConst* NetESelect::eval_tree(int prune_to_width) NetEConst* NetESelect::eval_tree()
{ {
// HERE // HERE
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluating expression:" cerr << get_fileline() << ": debug: Evaluating expression:"
<< *this << ", prune_to_width=" << prune_to_width << endl; << *this << endl;
} }
eval_expr(expr_); eval_expr(expr_);
@ -1318,14 +1217,12 @@ NetEConst* NetESelect::eval_tree(int prune_to_width)
verinum::V pad_bit = verinum::Vx; verinum::V pad_bit = verinum::Vx;
if (base_ == 0) { if (base_ == 0) {
/* If the base is NULL (different from 0) the this /* If the base is NULL (different from 0) then this
select is here for sign extension. So calculate a select is here for zero or sign extension. So
proper pad bit. Extend x or z or 0, and sign extend 1 calculate a proper pad bit. */
if this is signed. */ if (has_sign())
unsigned top = expr->expr_width()-1; pad_bit = eval.get(expr->expr_width()-1);
else
pad_bit = eval.get(top);
if (pad_bit==verinum::V1 && !has_sign())
pad_bit = verinum::V0; pad_bit = verinum::V0;
} }
@ -1365,12 +1262,12 @@ static void print_ternary_cond(NetExpr*expr)
* evaluates to x or z, then merge the constant bits of the true and * evaluates to x or z, then merge the constant bits of the true and
* false expressions. * false expressions.
*/ */
NetExpr* NetETernary::eval_tree(int prune_to_width) NetExpr* NetETernary::eval_tree()
{ {
eval_expr(cond_); eval_expr(cond_);
switch (const_logical(cond_)) { switch (const_logical(cond_)) {
case C_0: case C_0:
eval_expr(false_val_, prune_to_width); eval_expr(false_val_);
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate ternary with " cerr << get_fileline() << ": debug: Evaluate ternary with "
@ -1393,7 +1290,7 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
return false_val_->dup_expr(); return false_val_->dup_expr();
case C_1: case C_1:
eval_expr(true_val_, prune_to_width); eval_expr(true_val_);
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: Evaluate ternary with " cerr << get_fileline() << ": debug: Evaluate ternary with "
<< "constant condition value: "; << "constant condition value: ";
@ -1425,8 +1322,8 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
expressions down to constants then compare the values to expressions down to constants then compare the values to
build up a constant result. */ build up a constant result. */
eval_expr(true_val_, prune_to_width); eval_expr(true_val_);
eval_expr(false_val_, prune_to_width); eval_expr(false_val_);
NetEConst*t = dynamic_cast<NetEConst*>(true_val_); NetEConst*t = dynamic_cast<NetEConst*>(true_val_);
NetEConst*f = dynamic_cast<NetEConst*>(false_val_); NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
@ -1509,7 +1406,7 @@ NetExpr* NetEUnary::eval_tree_real_()
return res; return res;
} }
NetExpr* NetEUnary::eval_tree(int prune_to_width) NetExpr* NetEUnary::eval_tree()
{ {
eval_expr(expr_); eval_expr(expr_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
@ -1529,7 +1426,7 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
if (val.is_defined()) { if (val.is_defined()) {
verinum tmp (verinum::V0, val.len()); verinum tmp (verinum::V0, val.len());
tmp.has_sign(val.has_sign()); tmp.has_sign(val.has_sign());
val = tmp - val; val = verinum(tmp - val, val.len());
} else { } else {
for (unsigned idx = 0 ; idx < val.len() ; idx += 1) for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
val.set(idx, verinum::Vx); val.set(idx, verinum::Vx);
@ -1572,9 +1469,9 @@ NetExpr* NetEUnary::eval_tree(int prune_to_width)
} }
NetExpr* NetEUBits::eval_tree(int prune_to_width) NetExpr* NetEUBits::eval_tree()
{ {
return NetEUnary::eval_tree(prune_to_width); return NetEUnary::eval_tree();
} }
NetEConst* NetEUReduce::eval_tree_real_() NetEConst* NetEUReduce::eval_tree_real_()
@ -1598,7 +1495,7 @@ NetEConst* NetEUReduce::eval_tree_real_()
return tmp; return tmp;
} }
NetEConst* NetEUReduce::eval_tree(int) NetEConst* NetEUReduce::eval_tree()
{ {
eval_expr(expr_); eval_expr(expr_);
if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); if (expr_type() == IVL_VT_REAL) return eval_tree_real_();
@ -1955,9 +1852,8 @@ static NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_,
return res; return res;
} }
NetExpr* NetESFunc::eval_tree(int prune_to_width) NetExpr* NetESFunc::eval_tree()
{ {
// assert(prune_to_width <= 0);
// HERE // HERE
/* If we are not targeting at least Verilog-2005, Verilog-AMS /* If we are not targeting at least Verilog-2005, Verilog-AMS
* or using the Icarus misc flag then we do not support these * or using the Icarus misc flag then we do not support these
@ -2056,7 +1952,7 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
return rtn; return rtn;
} }
NetExpr* NetEUFunc::eval_tree(int) NetExpr* NetEUFunc::eval_tree()
{ {
if (need_constant_expr) { if (need_constant_expr) {
cerr << get_fileline() << ": sorry: constant user " cerr << get_fileline() << ": sorry: constant user "

View File

@ -332,8 +332,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
/* Evaluate the msb expression, if it is present. */ /* Evaluate the msb expression, if it is present. */
PExpr*msb_expr = (*cur).second.msb_expr; PExpr*msb_expr = (*cur).second.msb_expr;
if (msb_expr) { if (msb_expr) {
probe_expr_width(des, this, msb_expr); (*cur).second.msb = elab_and_eval(des, this, msb_expr, -1);
(*cur).second.msb = elab_and_eval(des, this, msb_expr, -2);
if (! eval_as_long(msb, (*cur).second.msb)) { if (! eval_as_long(msb, (*cur).second.msb)) {
cerr << (*cur).second.val->get_fileline() cerr << (*cur).second.val->get_fileline()
<< ": error: Unable to evaluate msb expression " << ": error: Unable to evaluate msb expression "
@ -349,8 +348,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
/* Evaluate the lsb expression, if it is present. */ /* Evaluate the lsb expression, if it is present. */
PExpr*lsb_expr = (*cur).second.lsb_expr; PExpr*lsb_expr = (*cur).second.lsb_expr;
if (lsb_expr) { if (lsb_expr) {
probe_expr_width(des, this, lsb_expr); (*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1);
(*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -2);
if (! eval_as_long(lsb, (*cur).second.lsb)) { if (! eval_as_long(lsb, (*cur).second.lsb)) {
cerr << (*cur).second.val->get_fileline() cerr << (*cur).second.val->get_fileline()
<< ": error: Unable to evaluate lsb expression " << ": error: Unable to evaluate lsb expression "
@ -367,25 +365,11 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
PExpr*val_expr = (*cur).second.val_expr; PExpr*val_expr = (*cur).second.val_expr;
NetScope*val_scope = (*cur).second.val_scope; NetScope*val_scope = (*cur).second.val_scope;
unsigned lval_wid = 0; int lv_width = -2;
if (range_flag) if (range_flag)
lval_wid = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb; lv_width = (msb >= lsb) ? 1 + msb - lsb : 1 + lsb - msb;
bool unsized_flag = false; NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width);
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
int expr_wid = val_expr->test_width(des, val_scope, lval_wid, lval_wid,
rval_type, unsized_flag);
if (unsized_flag && !range_flag)
expr_wid = -1;
int prune_wid = -1;
if (gn_strict_expr_width_flag)
prune_wid = 0;
if (range_flag)
prune_wid = lval_wid;
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, expr_wid, prune_wid);
if (! expr) if (! expr)
return; return;
@ -427,7 +411,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
if (range_flag) { if (range_flag) {
/* If we have a real value convert it to an integer. */ /* If we have a real value convert it to an integer. */
if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) { if(NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
verinum nval(tmp->value().as_long64(), lval_wid); verinum nval(tmp->value().as_long64(), (unsigned)lv_width);
expr = new NetEConst(nval); expr = new NetEConst(nval);
expr->set_line(*((*cur).second.val)); expr->set_line(*((*cur).second.val));
(*cur).second.val = expr; (*cur).second.val = expr;
@ -504,18 +488,7 @@ void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
PExpr*val_expr = (*cur).second.val_expr; PExpr*val_expr = (*cur).second.val_expr;
NetScope*val_scope = (*cur).second.val_scope; NetScope*val_scope = (*cur).second.val_scope;
bool unsized_flag = false; NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1);
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
int expr_wid = val_expr->test_width(des, val_scope, 0, 0,
rval_type, unsized_flag);
if (unsized_flag)
expr_wid = -1;
int prune_wid = -1;
if (gn_strict_expr_width_flag)
prune_wid = 0;
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, expr_wid, prune_wid);
if (! expr) if (! expr)
return; return;

View File

@ -38,92 +38,17 @@ netenum_t*NetExpr::enumeration() const
} }
/* /*
* Create an add/sub node from the two operands. Make a best guess of * Create an add/sub node from the two operands.
* the
*/ */
NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, bool lossless_flag) NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
NetEConst* tmp;
/* Catch the special case that one of the operands is an
unsized constant number. If so, then we should set the
width of that number to the size of the other operand, plus
one. This expands the expression to account for the largest
possible result.
Remember to handle the special case of an unsized constant,
which we define to be at least "integer_width" bits.
The set_width applied to a constant value will only
truncate the constant so far as it can still hold its
logical value, so this is safe to do. */
if ( (tmp = dynamic_cast<NetEConst*>(r))
&& (! tmp->has_width())
&& (tmp->expr_width() > l->expr_width() || integer_width > l->expr_width()) ) {
verinum tmp_v = trim_vnum(tmp->value());
unsigned target_width = l->expr_width();
if (target_width < tmp_v.len())
target_width = tmp_v.len();
if (lossless_flag)
target_width += 1;
if (target_width < integer_width)
target_width = integer_width;
r->set_width(target_width);
/* Note: This constant value will not gain a defined
width from this. Make sure. */
assert(! r->has_width() );
expr_width(target_width);
} else if ( (tmp = dynamic_cast<NetEConst*>(l))
&& (! tmp->has_width())
&& (tmp->expr_width() > r->expr_width() || integer_width > r->expr_width()) ) {
verinum tmp_v = trim_vnum(tmp->value());
unsigned target_width = r->expr_width();
if (target_width < tmp_v.len())
target_width = tmp_v.len();
if (lossless_flag)
target_width += 1;
if (target_width < integer_width)
target_width = integer_width;
l->set_width(target_width);
/* Note: This constant value will not gain a defined
width from this. Make sure. */
assert(! l->has_width() );
expr_width(target_width);
} else if (r->expr_width() > l->expr_width()) {
unsigned loss_pad = lossless_flag? 1 : 0;
expr_width(r->expr_width() + loss_pad);
} else {
unsigned loss_pad = lossless_flag? 1 : 0;
expr_width(l->expr_width() + loss_pad);
}
cast_signed(l->has_sign() && r->has_sign());
} }
NetEBAdd::~NetEBAdd() NetEBAdd::~NetEBAdd()
{ {
} }
NetEBAdd* NetEBAdd::dup_expr() const
{
NetEBAdd*result = new NetEBAdd(op_, left_->dup_expr(),
right_->dup_expr());
result->set_line(*this);
return result;
}
ivl_variable_type_t NetEBAdd::expr_type() const ivl_variable_type_t NetEBAdd::expr_type() const
{ {
if (left_->expr_type() == IVL_VT_REAL) if (left_->expr_type() == IVL_VT_REAL)
@ -137,50 +62,10 @@ ivl_variable_type_t NetEBAdd::expr_type() const
/* /*
* Create a comparison operator with two sub-expressions. * Create a comparison operator with two sub-expressions.
*
* Handle the special case of an unsized constant on the left or right
* side by resizing the number to match the other
* expression. Otherwise, the netlist will have to allow the
* expressions to have different widths.
*/ */
NetEBComp::NetEBComp(char op__, NetExpr*l, NetExpr*r) NetEBComp::NetEBComp(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, 1, false)
{ {
// The output of compare is always unsigned.
cast_signed_base_(false);
if (NetEConst*tmp = dynamic_cast<NetEConst*>(r)) do {
if (tmp->has_width())
break;
if (l->expr_width() == 0)
break;
if (tmp->expr_width() == l->expr_width())
break;
tmp->set_width(l->expr_width());
} while (0);
if (NetEConst*tmp = dynamic_cast<NetEConst*>(l)) do {
if (tmp->has_width())
break;
if (r->expr_width() == 0)
break;
if (tmp->expr_width() == r->expr_width())
break;
tmp->set_width(r->expr_width());
} while (0);
expr_width(1);
} }
NetEBComp::~NetEBComp() NetEBComp::~NetEBComp()
@ -207,29 +92,15 @@ ivl_variable_type_t NetEBComp::expr_type() const
return IVL_VT_BOOL; return IVL_VT_BOOL;
} }
NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r) NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
unsigned w = l->expr_width();
if (r->expr_width() > w)
w = r->expr_width();
expr_width(w);
cast_signed(l->has_sign() && r->has_sign());
} }
NetEBDiv::~NetEBDiv() NetEBDiv::~NetEBDiv()
{ {
} }
NetEBDiv* NetEBDiv::dup_expr() const
{
NetEBDiv*result = new NetEBDiv(op_, left_->dup_expr(),
right_->dup_expr());
result->set_line(*this);
return result;
}
ivl_variable_type_t NetEBDiv::expr_type() const ivl_variable_type_t NetEBDiv::expr_type() const
{ {
if (left_->expr_type() == IVL_VT_REAL) if (left_->expr_type() == IVL_VT_REAL)
@ -241,11 +112,9 @@ ivl_variable_type_t NetEBDiv::expr_type() const
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }
NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r) NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
expr_width( max(l->expr_width(), r->expr_width()) );
cast_signed(l->has_sign() || r->has_sign());
} }
NetEBMinMax::~NetEBMinMax() NetEBMinMax::~NetEBMinMax()
@ -262,30 +131,15 @@ ivl_variable_type_t NetEBMinMax::expr_type() const
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r) NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
if (expr_type() == IVL_VT_REAL) {
expr_width(1);
cast_signed(true);
} else {
expr_width(l->expr_width() + r->expr_width());
cast_signed(l->has_sign() && r->has_sign());
}
} }
NetEBMult::~NetEBMult() NetEBMult::~NetEBMult()
{ {
} }
NetEBMult* NetEBMult::dup_expr() const
{
NetEBMult*result = new NetEBMult(op_, left_->dup_expr(),
right_->dup_expr());
result->set_line(*this);
return result;
}
ivl_variable_type_t NetEBMult::expr_type() const ivl_variable_type_t NetEBMult::expr_type() const
{ {
if (left_->expr_type() == IVL_VT_REAL) if (left_->expr_type() == IVL_VT_REAL)
@ -297,27 +151,15 @@ ivl_variable_type_t NetEBMult::expr_type() const
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }
NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r) NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
assert(op__ == 'p');
/* You could need up to a * (2^b - 1) bits. */
expr_width(l->expr_width());
cast_signed(l->has_sign() || r->has_sign());
} }
NetEBPow::~NetEBPow() NetEBPow::~NetEBPow()
{ {
} }
NetEBPow* NetEBPow::dup_expr() const
{
NetEBPow*result = new NetEBPow(op_, left_->dup_expr(),
right_->dup_expr());
result->set_line(*this);
return result;
}
ivl_variable_type_t NetEBPow::expr_type() const ivl_variable_type_t NetEBPow::expr_type() const
{ {
if (right_->expr_type() == IVL_VT_REAL) if (right_->expr_type() == IVL_VT_REAL)
@ -328,13 +170,9 @@ ivl_variable_type_t NetEBPow::expr_type() const
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }
NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r) NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
expr_width(l->expr_width());
// The >>> is signed if the left operand is signed.
if (op__ == 'R') cast_signed(l->has_sign());
} }
NetEBShift::~NetEBShift() NetEBShift::~NetEBShift()
@ -346,24 +184,9 @@ bool NetEBShift::has_width() const
return left_->has_width(); return left_->has_width();
} }
NetEBShift* NetEBShift::dup_expr() const NetEConcat::NetEConcat(unsigned cnt, unsigned r)
{
NetEBShift*result = new NetEBShift(op_, left_->dup_expr(),
right_->dup_expr());
result->set_line(*this);
return result;
}
NetEConcat::NetEConcat(unsigned cnt, NetExpr* r)
: parms_(cnt), repeat_(r) : parms_(cnt), repeat_(r)
{ {
if (repeat_ == 0) {
repeat_calculated_ = true;
repeat_value_ = 1;
} else {
repeat_calculated_ = false;
}
expr_width(0); expr_width(0);
} }
@ -383,63 +206,7 @@ void NetEConcat::set(unsigned idx, NetExpr*e)
assert(idx < parms_.count()); assert(idx < parms_.count());
assert(parms_[idx] == 0); assert(parms_[idx] == 0);
parms_[idx] = e; parms_[idx] = e;
expr_width( expr_width() + e->expr_width() ); expr_width( expr_width() + repeat_ * e->expr_width() );
}
NetEConcat* NetEConcat::dup_expr() const
{
NetEConcat*dup = new NetEConcat(parms_.count(), 0);
dup->set_line(*this);
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
if (parms_[idx]) {
NetExpr*tmp = parms_[idx]->dup_expr();
assert(tmp);
dup->parms_[idx] = tmp;
}
dup->repeat_ = repeat_? repeat_->dup_expr() : 0;
dup->repeat_value_ = repeat_value_;
dup->repeat_calculated_ = repeat_calculated_;
dup->expr_width(expr_width());
return dup;
}
unsigned NetEConcat::repeat()
{
if (repeat_calculated_)
return repeat_value_;
eval_expr(repeat_);
NetEConst*repeat_const = dynamic_cast<NetEConst*>(repeat_);
/* This should not be possible, as it was checked earlier to
assure that this is a constant expression. */
if (repeat_const == 0) {
cerr << get_fileline() << ": internal error: repeat expression "
<< "is not a compile time constant." << endl;
cerr << get_fileline() << ": : Expression is: "
<< *repeat_ << endl;
repeat_calculated_ = true;
repeat_value_ = 1;
return 1;
}
repeat_calculated_ = true;
repeat_value_ = repeat_const->value().as_ulong();
delete repeat_;
repeat_ = 0;
return repeat_value_;
}
unsigned NetEConcat::repeat() const
{
assert(repeat_calculated_);
return repeat_value_;
} }
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, netenum_t*eset, const verinum&v) NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, netenum_t*eset, const verinum&v)
@ -461,7 +228,7 @@ NetECReal::NetECReal(const verireal&val)
: value_(val) : value_(val)
{ {
expr_width(1); expr_width(1);
cast_signed(true); cast_signed_base_(true);
} }
NetECReal::~NetECReal() NetECReal::~NetECReal()
@ -475,14 +242,7 @@ const verireal& NetECReal::value() const
bool NetECReal::has_width() const bool NetECReal::has_width() const
{ {
return false; return true;
}
NetECReal* NetECReal::dup_expr() const
{
NetECReal*tmp = new NetECReal(value_);
tmp->set_line(*this);
return tmp;
} }
ivl_variable_type_t NetECReal::expr_type() const ivl_variable_type_t NetECReal::expr_type() const

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2011 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
@ -100,8 +100,6 @@ void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
assert(idx < nitems_); assert(idx < nitems_);
items_[idx].guard = e; items_[idx].guard = e;
items_[idx].statement = p; items_[idx].statement = p;
if (items_[idx].guard)
items_[idx].guard->set_width(expr_->expr_width());
} }
NetDisable::NetDisable(NetScope*tgt) NetDisable::NetDisable(NetScope*tgt)
@ -169,4 +167,3 @@ const NetExpr* NetRepeat::expr() const
{ {
return expr_; return expr_;
} }

View File

@ -2095,21 +2095,9 @@ NetExpr::~NetExpr()
{ {
} }
bool NetExpr::has_sign() const
{
return signed_flag_;
}
void NetExpr::cast_signed(bool flag) void NetExpr::cast_signed(bool flag)
{ {
signed_flag_ = flag; cast_signed_base_(flag);
}
void NetExpr::expr_width(unsigned w)
{
// Catch underflow wrap errors.
ivl_assert(*this, w < (UINT_MAX - 256));
width_ = w;
} }
bool NetExpr::has_width() const bool NetExpr::has_width() const
@ -2119,37 +2107,22 @@ bool NetExpr::has_width() const
/* /*
* Create a bitwise operator node from the opcode and the left and * Create a bitwise operator node from the opcode and the left and
* right expressions. Don't worry about the width of the expression * right expressions.
* yet, we'll get that from the l-value, whatever that turns out to
* be. However, if we don't, our default will be the width of the
* largest operand.
*/ */
NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r) NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, wid, signed_flag)
{ {
if (r->expr_width() > l->expr_width())
expr_width(r->expr_width());
else
expr_width(l->expr_width());
} }
NetEBBits::~NetEBBits() NetEBBits::~NetEBBits()
{ {
} }
NetEBBits* NetEBBits::dup_expr() const NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
{
NetEBBits*result = new NetEBBits(op_, left_->dup_expr(),
right_->dup_expr());
return result;
}
NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r)
: op_(op__), left_(l), right_(r) : op_(op__), left_(l), right_(r)
{ {
// Binary expressions of all sorts are signed if both the expr_width(wid);
// arguments are signed. cast_signed_base_(signed_flag);
cast_signed_base_( left_->has_sign() && right_->has_sign());
} }
NetEBinary::~NetEBinary() NetEBinary::~NetEBinary()
@ -2163,29 +2136,15 @@ bool NetEBinary::has_width() const
return left_->has_width() && right_->has_width(); return left_->has_width() && right_->has_width();
} }
NetEBinary* NetEBinary::dup_expr() const
{
assert(0);
return 0;
}
NetEBLogic::NetEBLogic(char op__, NetExpr*l, NetExpr*r) NetEBLogic::NetEBLogic(char op__, NetExpr*l, NetExpr*r)
: NetEBinary(op__, l, r) : NetEBinary(op__, l, r, 1, false)
{ {
expr_width(1);
} }
NetEBLogic::~NetEBLogic() NetEBLogic::~NetEBLogic()
{ {
} }
NetEBLogic* NetEBLogic::dup_expr() const
{
NetEBLogic*result = new NetEBLogic(op_, left_->dup_expr(),
right_->dup_expr());
return result;
}
NetEConst::NetEConst(const verinum&val) NetEConst::NetEConst(const verinum&val)
: NetExpr(val.len()), value_(val) : NetExpr(val.len()), value_(val)
{ {
@ -2196,6 +2155,12 @@ NetEConst::~NetEConst()
{ {
} }
void NetEConst::cast_signed(bool flag)
{
cast_signed_base_(flag);
value_.has_sign(flag);
}
const verinum& NetEConst::value() const const verinum& NetEConst::value() const
{ {
return value_; return value_;
@ -2218,6 +2183,17 @@ ivl_variable_type_t NetEConst::expr_type() const
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }
void NetEConst::trim()
{
if (value_.is_string())
return;
value_.has_len(false);
value_ = trim_vnum(value_);
expr_width(value_.len());
}
NetEConstParam::NetEConstParam(NetScope*s, perm_string n, const verinum&v) NetEConstParam::NetEConstParam(NetScope*s, perm_string n, const verinum&v)
: NetEConst(v), scope_(s), name_(n) : NetEConst(v), scope_(s), name_(n)
{ {
@ -2272,7 +2248,7 @@ NetESignal::NetESignal(NetNet*n)
{ {
net_->incr_eref(); net_->incr_eref();
set_line(*n); set_line(*n);
cast_signed(net_->get_signed()); cast_signed_base_(net_->get_signed());
} }
NetESignal::NetESignal(NetNet*n, NetExpr*w) NetESignal::NetESignal(NetNet*n, NetExpr*w)
@ -2280,7 +2256,7 @@ NetESignal::NetESignal(NetNet*n, NetExpr*w)
{ {
net_->incr_eref(); net_->incr_eref();
set_line(*n); set_line(*n);
cast_signed(net_->get_signed()); cast_signed_base_(net_->get_signed());
} }
NetESignal::~NetESignal() NetESignal::~NetESignal()
@ -2334,20 +2310,12 @@ ivl_variable_type_t NetESignal::expr_type() const
* should have the same width. NOTE: This matching of the widths really * should have the same width. NOTE: This matching of the widths really
* has to be done in elaboration. * has to be done in elaboration.
*/ */
NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f) NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f,
unsigned wid, bool signed_flag)
: cond_(c), true_val_(t), false_val_(f) : cond_(c), true_val_(t), false_val_(f)
{ {
if (type_is_vectorable(expr_type())) { expr_width(wid);
// use widest result cast_signed_base_(signed_flag);
if (true_val_->expr_width() > false_val_->expr_width())
expr_width(true_val_->expr_width());
else
expr_width(false_val_->expr_width());
} else {
expr_width(1);
}
cast_signed(c->has_sign() && t->has_sign() && f->has_sign());
} }
NetETernary::~NetETernary() NetETernary::~NetETernary()
@ -2399,23 +2367,10 @@ ivl_variable_type_t NetETernary::expr_type() const
return tru; return tru;
} }
NetEUnary::NetEUnary(char op__, NetExpr*ex) NetEUnary::NetEUnary(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
: NetExpr(ex->expr_width()), op_(op__), expr_(ex) : NetExpr(wid), op_(op__), expr_(ex)
{ {
switch (op_) { cast_signed_base_(signed_flag);
case '!':
expr_width(1);
break;
}
switch (op_) {
case '-':
case '+':
case 'm': // abs()
cast_signed(ex->has_sign());
break;
default:
;
}
} }
NetEUnary::~NetEUnary() NetEUnary::~NetEUnary()
@ -2428,8 +2383,8 @@ ivl_variable_type_t NetEUnary::expr_type() const
return expr_->expr_type(); return expr_->expr_type();
} }
NetEUBits::NetEUBits(char op__, NetExpr*ex) NetEUBits::NetEUBits(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
: NetEUnary(op__, ex) : NetEUnary(op__, ex, wid, signed_flag)
{ {
} }
@ -2443,9 +2398,8 @@ ivl_variable_type_t NetEUBits::expr_type() const
} }
NetEUReduce::NetEUReduce(char op__, NetExpr*ex) NetEUReduce::NetEUReduce(char op__, NetExpr*ex)
: NetEUnary(op__, ex) : NetEUnary(op__, ex, 1, false)
{ {
expr_width(1);
} }
NetEUReduce::~NetEUReduce() NetEUReduce::~NetEUReduce()
@ -2457,8 +2411,8 @@ ivl_variable_type_t NetEUReduce::expr_type() const
return expr_->expr_type(); return expr_->expr_type();
} }
NetECast::NetECast(char op__, NetExpr*ex) NetECast::NetECast(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
: NetEUnary(op__, ex) : NetEUnary(op__, ex, wid, signed_flag)
{ {
} }

144
netlist.h
View File

@ -1601,12 +1601,8 @@ class NetTran : public NetNode, public IslandBranch {
* There are cases where expressions need to be represented. The * There are cases where expressions need to be represented. The
* NetExpr class is the root of a hierarchy that serves that purpose. * NetExpr class is the root of a hierarchy that serves that purpose.
* *
* The expr_width() is the width of the expression, that accounts * The expr_width() is the width of the expression, which is calculated
* for the widths of the sub-expressions I might have. It is up to the * before the expression is elaborated.
* derived classes to properly set the expr width, if need be. The
* set_width() method is used to compel an expression to have a
* certain width, and is used particularly when the expression is an
* rvalue in an assignment statement.
*/ */
class NetExpr : public LineInfo { class NetExpr : public LineInfo {
public: public:
@ -1622,27 +1618,9 @@ class NetExpr : public LineInfo {
// How wide am I? // How wide am I?
unsigned expr_width() const { return width_; } unsigned expr_width() const { return width_; }
// Coerce the expression to have a specific width. If the
// coercion works, then return true. Otherwise, return false.
// A coercion will work or not depending on the implementation
// in the derived class. Normally, the width will be set if
// the expression is:
// - already the requested size, OR
// - otherwise unsized.
// Normally, the resize will not allow a width size that loses
// data. For example, it will not reduce a constant expression
// to the point where significant bits are lost. But if the
// last_chance flag is true, then the method assumes that high
// bits will be lost anyhow, so try harder. Loss will be
// allowed, but it still won't resize fixed size expressions
// such as vector signals. This flag is meant to be used by
// elaboration of procedural assignment to set the expression
// width to the l-value width, if possible.
virtual bool set_width(unsigned wid, bool last_chance =false);
// This method returns true if the expression is // This method returns true if the expression is
// signed. Unsigned expressions return false. // signed. Unsigned expressions return false.
bool has_sign() const; bool has_sign() const { return signed_flag_; }
virtual void cast_signed(bool flag); virtual void cast_signed(bool flag);
// This returns true if the expression has a definite // This returns true if the expression has a definite
@ -1664,14 +1642,7 @@ class NetExpr : public LineInfo {
// equivalent expression that is reduced as far as compile // equivalent expression that is reduced as far as compile
// time knows how. Essentially, this is designed to fold // time knows how. Essentially, this is designed to fold
// constants. // constants.
// virtual NetExpr*eval_tree();
// The prune_to_width is the maximum width that the result
// should be. If it is 0 or -1, then do not prune the
// result. If it is -1, go through special efforts to preserve
// values that may expand. A width of 0 corresponds to a
// self-determined context, and a width of -1 corresponds to
// an infinitely wide context.
virtual NetExpr*eval_tree(int prune_to_width = -1);
// Make a duplicate of myself, and subexpressions if I have // Make a duplicate of myself, and subexpressions if I have
// any. This is a deep copy operation. // any. This is a deep copy operation.
@ -1696,9 +1667,8 @@ class NetExpr : public LineInfo {
// the expression output. // the expression output.
virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root); virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
protected: protected:
void expr_width(unsigned w); void expr_width(unsigned wid) { width_ = wid; }
void cast_signed_base_(bool flag) { signed_flag_ = flag; } void cast_signed_base_(bool flag) { signed_flag_ = flag; }
private: private:
@ -1723,11 +1693,15 @@ class NetEConst : public NetExpr {
const verinum&value() const; const verinum&value() const;
virtual bool set_width(unsigned w, bool last_chance =false); virtual void cast_signed(bool flag);
virtual void cast_signed(bool sign_flag);
virtual bool has_width() const; virtual bool has_width() const;
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
/* This method allows the constant value to be converted
to an unsized value. This is used after evaluating a
unsized constant expression. */
virtual void trim();
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -1750,7 +1724,6 @@ class NetEConstEnum : public NetEConst {
const NetScope*scope() const; const NetScope*scope() const;
netenum_t*enumeration() const; netenum_t*enumeration() const;
virtual bool set_width(unsigned w, bool last_chance =false);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -1772,7 +1745,6 @@ class NetEConstParam : public NetEConst {
perm_string name() const; perm_string name() const;
const NetScope*scope() const; const NetScope*scope() const;
virtual bool set_width(unsigned w, bool last_chance =false);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -1794,10 +1766,6 @@ class NetECReal : public NetExpr {
const verireal&value() const; const verireal&value() const;
// Reals can be used in vector expressions. Conversions will
// be done at the right time.
virtual bool set_width(unsigned w, bool last_chance);
// This type has no self-determined width. This is false. // This type has no self-determined width. This is false.
virtual bool has_width() const; virtual bool has_width() const;
@ -3129,14 +3097,13 @@ class NetEUFunc : public NetExpr {
const NetScope* func() const; const NetScope* func() const;
virtual bool set_width(unsigned, bool last_chance);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEUFunc*dup_expr() const; virtual NetEUFunc*dup_expr() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);
private: private:
@ -3332,7 +3299,7 @@ class NetAnalogTop : public LineInfo, public Attrib {
class NetEBinary : public NetExpr { class NetEBinary : public NetExpr {
public: public:
NetEBinary(char op, NetExpr*l, NetExpr*r); NetEBinary(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBinary(); ~NetEBinary();
const NetExpr*left() const { return left_; } const NetExpr*left() const { return left_; }
@ -3340,8 +3307,6 @@ class NetEBinary : public NetExpr {
char op() const { return op_; } char op() const { return op_; }
virtual bool set_width(unsigned w, bool last_chance =false);
// A binary expression node only has a definite // A binary expression node only has a definite
// self-determinable width if the operands both have definite // self-determinable width if the operands both have definite
// widths. // widths.
@ -3371,15 +3336,13 @@ class NetEBinary : public NetExpr {
class NetEBAdd : public NetEBinary { class NetEBAdd : public NetEBinary {
public: public:
NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag =false); NetEBAdd(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBAdd(); ~NetEBAdd();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBAdd* dup_expr() const; virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3394,15 +3357,13 @@ class NetEBAdd : public NetEBinary {
class NetEBDiv : public NetEBinary { class NetEBDiv : public NetEBinary {
public: public:
NetEBDiv(char op, NetExpr*l, NetExpr*r); NetEBDiv(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBDiv(); ~NetEBDiv();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBDiv* dup_expr() const; virtual NetEBDiv* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3426,12 +3387,11 @@ class NetEBDiv : public NetEBinary {
class NetEBBits : public NetEBinary { class NetEBBits : public NetEBinary {
public: public:
NetEBBits(char op, NetExpr*l, NetExpr*r); NetEBBits(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBBits(); ~NetEBBits();
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBBits* dup_expr() const; virtual NetEBBits* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
}; };
@ -3456,13 +3416,11 @@ class NetEBComp : public NetEBinary {
NetEBComp(char op, NetExpr*l, NetExpr*r); NetEBComp(char op, NetExpr*l, NetExpr*r);
~NetEBComp(); ~NetEBComp();
virtual bool set_width(unsigned w, bool last_chance =false);
/* A compare expression has a definite width. */ /* A compare expression has a definite width. */
virtual bool has_width() const; virtual bool has_width() const;
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NetEBComp* dup_expr() const; virtual NetEBComp* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3492,9 +3450,8 @@ class NetEBLogic : public NetEBinary {
NetEBLogic(char op, NetExpr*l, NetExpr*r); NetEBLogic(char op, NetExpr*l, NetExpr*r);
~NetEBLogic(); ~NetEBLogic();
virtual bool set_width(unsigned w, bool last_chance =false);
virtual NetEBLogic* dup_expr() const; virtual NetEBLogic* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3511,7 +3468,7 @@ class NetEBLogic : public NetEBinary {
class NetEBMinMax : public NetEBinary { class NetEBMinMax : public NetEBinary {
public: public:
NetEBMinMax(char op, NetExpr*l, NetExpr*r); NetEBMinMax(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBMinMax(); ~NetEBMinMax();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
@ -3525,15 +3482,13 @@ class NetEBMinMax : public NetEBinary {
class NetEBMult : public NetEBinary { class NetEBMult : public NetEBinary {
public: public:
NetEBMult(char op, NetExpr*l, NetExpr*r); NetEBMult(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBMult(); ~NetEBMult();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance);
virtual void cast_signed(bool sign_flag);
virtual NetEBMult* dup_expr() const; virtual NetEBMult* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3546,14 +3501,13 @@ class NetEBMult : public NetEBinary {
class NetEBPow : public NetEBinary { class NetEBPow : public NetEBinary {
public: public:
NetEBPow(char op, NetExpr*l, NetExpr*r); NetEBPow(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBPow(); ~NetEBPow();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBPow* dup_expr() const; virtual NetEBPow* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
private: private:
@ -3572,17 +3526,15 @@ class NetEBPow : public NetEBinary {
class NetEBShift : public NetEBinary { class NetEBShift : public NetEBinary {
public: public:
NetEBShift(char op, NetExpr*l, NetExpr*r); NetEBShift(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
~NetEBShift(); ~NetEBShift();
virtual bool set_width(unsigned w, bool last_chance);
// A shift expression only needs the left expression to have a // A shift expression only needs the left expression to have a
// definite width to give the expression a definite width. // definite width to give the expression a definite width.
virtual bool has_width() const; virtual bool has_width() const;
virtual NetEBShift* dup_expr() const; virtual NetEBShift* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3602,31 +3554,27 @@ class NetEBShift : public NetEBinary {
class NetEConcat : public NetExpr { class NetEConcat : public NetExpr {
public: public:
NetEConcat(unsigned cnt, NetExpr* repeat =0); NetEConcat(unsigned cnt, unsigned repeat =1);
~NetEConcat(); ~NetEConcat();
// Manipulate the parameters. // Manipulate the parameters.
void set(unsigned idx, NetExpr*e); void set(unsigned idx, NetExpr*e);
unsigned repeat(); unsigned repeat() const { return repeat_; }
unsigned repeat() const;
unsigned nparms() const { return parms_.count() ; } unsigned nparms() const { return parms_.count() ; }
NetExpr* parm(unsigned idx) const { return parms_[idx]; } NetExpr* parm(unsigned idx) const { return parms_[idx]; }
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual bool has_width() const; virtual bool has_width() const;
virtual bool set_width(unsigned w, bool last_chance =false);
virtual NetEConcat* dup_expr() const; virtual NetEConcat* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
private: private:
svector<NetExpr*>parms_; svector<NetExpr*>parms_;
NetExpr* repeat_; unsigned repeat_;
unsigned repeat_value_;
bool repeat_calculated_;
}; };
@ -3656,10 +3604,9 @@ class NetESelect : public NetExpr {
ivl_select_type_t select_type() const; ivl_select_type_t select_type() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual bool set_width(unsigned w, bool last_chance =false);
virtual bool has_width() const; virtual bool has_width() const;
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual NetESelect* dup_expr() const; virtual NetESelect* dup_expr() const;
virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root); virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -3757,11 +3704,10 @@ class NetESFunc : public NetExpr {
NetExpr* parm(unsigned idx); NetExpr* parm(unsigned idx);
const NetExpr* parm(unsigned idx) const; const NetExpr* parm(unsigned idx) const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual bool set_width(unsigned, bool last_chance);
virtual netenum_t* enumeration() const; virtual netenum_t* enumeration() const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -3788,17 +3734,15 @@ class NetESFunc : public NetExpr {
class NetETernary : public NetExpr { class NetETernary : public NetExpr {
public: public:
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f); NetETernary(NetExpr*c, NetExpr*t, NetExpr*f, unsigned wid, bool signed_flag);
~NetETernary(); ~NetETernary();
virtual bool set_width(unsigned w, bool last_chance);
const NetExpr*cond_expr() const; const NetExpr*cond_expr() const;
const NetExpr*true_expr() const; const NetExpr*true_expr() const;
const NetExpr*false_expr() const; const NetExpr*false_expr() const;
virtual NetETernary* dup_expr() const; virtual NetETernary* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
@ -3837,16 +3781,14 @@ class NetETernary : public NetExpr {
class NetEUnary : public NetExpr { class NetEUnary : public NetExpr {
public: public:
NetEUnary(char op, NetExpr*ex); NetEUnary(char op, NetExpr*ex, unsigned wid, bool signed_flag);
~NetEUnary(); ~NetEUnary();
char op() const { return op_; } char op() const { return op_; }
const NetExpr* expr() const { return expr_; } const NetExpr* expr() const { return expr_; }
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEUnary* dup_expr() const; virtual NetEUnary* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
@ -3865,13 +3807,13 @@ class NetEUnary : public NetExpr {
class NetEUBits : public NetEUnary { class NetEUBits : public NetEUnary {
public: public:
NetEUBits(char op, NetExpr*ex); NetEUBits(char op, NetExpr*ex, unsigned wid, bool signed_flag);
~NetEUBits(); ~NetEUBits();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
virtual NetEUBits* dup_expr() const; virtual NetEUBits* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
}; };
@ -3881,10 +3823,9 @@ class NetEUReduce : public NetEUnary {
NetEUReduce(char op, NetExpr*ex); NetEUReduce(char op, NetExpr*ex);
~NetEUReduce(); ~NetEUReduce();
virtual bool set_width(unsigned w, bool last_chance);
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
virtual NetEUReduce* dup_expr() const; virtual NetEUReduce* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree();
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
private: private:
@ -3894,7 +3835,7 @@ class NetEUReduce : public NetEUnary {
class NetECast : public NetEUnary { class NetECast : public NetEUnary {
public: public:
NetECast(char op, NetExpr*ex); NetECast(char op, NetExpr*ex, unsigned wid, bool signed_flag);
~NetECast(); ~NetECast();
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
@ -3920,7 +3861,6 @@ class NetESignal : public NetExpr {
~NetESignal(); ~NetESignal();
perm_string name() const; perm_string name() const;
virtual bool set_width(unsigned, bool last_chance);
virtual NetESignal* dup_expr() const; virtual NetESignal* dup_expr() const;
NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);

View File

@ -184,9 +184,9 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
NetExpr* cast_to_int2(NetExpr*expr) NetExpr* cast_to_int2(NetExpr*expr)
{ {
NetECast*cast = new NetECast('2', expr); NetECast*cast = new NetECast('2', expr, expr->expr_width(),
expr->has_sign());
cast->set_line(*expr); cast->set_line(*expr);
cast->cast_signed(expr->has_sign());
return cast; return cast;
} }
@ -208,17 +208,14 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
val = -val; val = -val;
} }
verinum val_v (val); verinum val_v (val, expr->expr_width());
val_v.has_sign(true); val_v.has_sign(true);
if (expr->has_width()) {
val_v = verinum(val_v, expr->expr_width());
}
NetEConst*val_c = new NetEConst(val_v); NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr); val_c->set_line(*expr);
NetEBAdd*res = new NetEBAdd(add_op, expr, val_c); NetEBAdd*res = new NetEBAdd(add_op, expr, val_c, expr->expr_width(),
expr->has_sign());
res->set_line(*expr); res->set_line(*expr);
return res; return res;
@ -235,7 +232,8 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
NetEConst*val_c = new NetEConst(val_v); NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr); val_c->set_line(*expr);
NetEBAdd*res = new NetEBAdd('-', val_c, expr); NetEBAdd*res = new NetEBAdd('-', val_c, expr, expr->expr_width(),
expr->has_sign());
res->set_line(*expr); res->set_line(*expr);
return res; return res;
@ -444,11 +442,10 @@ NetExpr* condition_reduce(NetExpr*expr)
return expr; return expr;
verinum zero (verinum::V0, expr->expr_width()); verinum zero (verinum::V0, expr->expr_width());
zero.has_sign(expr->has_sign());
NetEConst*ezero = new NetEConst(zero); NetEConst*ezero = new NetEConst(zero);
ezero->set_line(*expr); ezero->set_line(*expr);
ezero->cast_signed(expr->has_sign());
ezero->set_width(expr->expr_width());
NetEBComp*cmp = new NetEBComp('n', expr, ezero); NetEBComp*cmp = new NetEBComp('n', expr, ezero);
cmp->set_line(*expr); cmp->set_line(*expr);
@ -457,43 +454,130 @@ NetExpr* condition_reduce(NetExpr*expr)
return cmp; return cmp;
} }
void probe_expr_width(Design*des, NetScope*scope, PExpr*pe) static const char*width_mode_name(PExpr::width_mode_t mode)
{ {
ivl_variable_type_t expr_type = IVL_VT_NO_TYPE; switch (mode) {
bool flag = false; case PExpr::SIZED:
pe->test_width(des, scope, 0, 0, expr_type, flag); return "sized";
case PExpr::LOSSLESS:
return "lossless";
case PExpr::UNSIZED:
return "unsized";
default:
return "??";
}
} }
NetExpr* elab_and_eval(Design*des, NetScope*scope, NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_width)
const PExpr*pe, int expr_wid, int prune_width)
{ {
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_wid, false); PExpr::width_mode_t mode = PExpr::SIZED;
if ((context_width == -2) && !gn_strict_expr_width_flag)
mode = PExpr::EXPAND;
pe->test_width(des, scope, mode);
// Get the final expression width. If the expression is unsized,
// this may be different from the value returned by test_width().
unsigned expr_width = pe->expr_width();
// If context_width is positive, this is the RHS of an assignment,
// so the LHS width must also be included in the width calculation.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
&& (expr_width < (unsigned)context_width))
expr_width = context_width;
if (debug_elaborate) {
cerr << pe->get_fileline() << ": debug: test_width of "
<< *pe << endl;
cerr << pe->get_fileline() << ": "
<< "returns type=" << pe->expr_type()
<< ", width=" << expr_width
<< ", signed=" << pe->has_sign()
<< ", mode=" << width_mode_name(mode) << endl;
}
// If we can get the same result using a smaller expression
// width, do so.
if ((context_width > 0) && (pe->expr_type() != IVL_VT_REAL)
&& (expr_width > (unsigned)context_width)) {
expr_width = max(pe->min_width(), (unsigned)context_width);
if (debug_elaborate) {
cerr << pe->get_fileline() << ": "
<< "pruned to width=" << expr_width << endl;
}
}
NetExpr*tmp = pe->elaborate_expr(des, scope, expr_width, false);
if (tmp == 0) return 0; if (tmp == 0) return 0;
eval_expr(tmp, prune_width); eval_expr(tmp, context_width);
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
if ((mode >= PExpr::LOSSLESS) && (context_width < 0))
ce->trim();
}
return tmp; return tmp;
} }
void eval_expr(NetExpr*&expr, int prune_width) NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
unsigned arg_idx, PExpr*pe)
{
PExpr::width_mode_t mode = PExpr::SIZED;
pe->test_width(des, scope, mode);
if (debug_elaborate) {
cerr << pe->get_fileline() << ": debug: test_width of "
<< name << " argument " << (arg_idx+1) << " " << *pe << endl;
cerr << pe->get_fileline() << ": "
<< "returns type=" << pe->expr_type()
<< ", width=" << pe->expr_width()
<< ", signed=" << pe->has_sign()
<< ", mode=" << width_mode_name(mode) << endl;
}
NetExpr*tmp = pe->elaborate_expr(des, scope, pe->expr_width(), true);
if (tmp == 0) return 0;
eval_expr(tmp, -1);
if (NetEConst*ce = dynamic_cast<NetEConst*>(tmp)) {
if (mode != PExpr::SIZED)
ce->trim();
}
return tmp;
}
void eval_expr(NetExpr*&expr, int context_width)
{ {
assert(expr); assert(expr);
if (dynamic_cast<NetECReal*>(expr)) return; if (dynamic_cast<NetECReal*>(expr)) return;
/* Resize a constant if allowed and needed. */
if (NetEConst *tmp = dynamic_cast<NetEConst*>(expr)) {
if (prune_width <= 0) return;
if (tmp->has_width()) return;
if ((unsigned)prune_width <= tmp->expr_width()) return;
expr = pad_to_width(expr, (unsigned)prune_width, *expr);
return;
}
NetExpr*tmp = expr->eval_tree(prune_width); NetExpr*tmp = expr->eval_tree();
if (tmp != 0) { if (tmp != 0) {
tmp->set_line(*expr); tmp->set_line(*expr);
delete expr; delete expr;
expr = tmp; expr = tmp;
} }
if (context_width <= 0) return;
NetEConst *ce = dynamic_cast<NetEConst*>(expr);
if (ce == 0) return;
// The expression is a constant, so resize it if needed.
if (ce->expr_width() < (unsigned)context_width) {
expr = pad_to_width(expr, context_width, *expr);
}
if (ce->expr_width() > (unsigned)context_width) {
verinum value(ce->value(), context_width);
ce = new NetEConst(value);
ce->set_line(*expr);
delete expr;
expr = ce;
}
} }
bool eval_as_long(long&value, NetExpr*expr) bool eval_as_long(long&value, NetExpr*expr)
@ -560,7 +644,6 @@ hname_t eval_path_component(Design*des, NetScope*scope,
assert(index.sel == index_component_t::SEL_BIT); assert(index.sel == index_component_t::SEL_BIT);
// Evaluate the bit select to get a number. // Evaluate the bit select to get a number.
probe_expr_width(des, scope, index.msb);
NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1); NetExpr*tmp = elab_and_eval(des, scope, index.msb, -1);
ivl_assert(*index.msb, tmp); ivl_assert(*index.msb, tmp);

View File

@ -1,7 +1,7 @@
#ifndef __netmisc_H #ifndef __netmisc_H
#define __netmisc_H #define __netmisc_H
/* /*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2011 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
@ -151,45 +151,38 @@ extern bool is_param_expr;
* constant expression. If it cannot be evaluated, it returns whatever * constant expression. If it cannot be evaluated, it returns whatever
* it can. If the expression cannot be elaborated, return 0. * it can. If the expression cannot be elaborated, return 0.
* *
* The expr_width is the width of the context where the expression is * The context_width is the width of the context where the expression is
* being elaborated, or -1 if the expression is self-determined width. * being elaborated, or -1 if the expression is self-determined, or -2
* * if the expression is lossless self-determined (this last option is
* The prune_width is the maximum width of the result, and is passed * treated as standard self-determined if the gn_strict_expr_width flag
* to the eval_tree method of the expression to limit constant * is set).
* results. The evaluation will prune any constant result down to the
* prune_width (if >0) so should only be used at the point where it is
* bound to the destination.
*/ */
class PExpr; class PExpr;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope, extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
const PExpr*pe, int expr_wid, PExpr*pe, int context_width);
int prune_width =-1);
void probe_expr_width(Design*des, NetScope*scope, PExpr*pe);
/*
* This function is a variant of elab_and_eval that elaborates and
* evaluates the arguments of a system task.
*/
extern NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
unsigned arg_idx, PExpr*pe);
/* /*
* This function elaborates an expression as if it is for the r-value * This function elaborates an expression as if it is for the r-value
* of an assignment, The data_type_lv and expr_wid_lv are the type and * of an assignment, The lv_type and lv_width are the type and width
* with of the l-value, and the expr is the expression to * of the l-value, and the expr is the expression to elaborate. The
* elaborate. The result is the NetExpr elaborated and evaluated. * result is the NetExpr elaborated and evaluated. (See elab_expr.cc)
* (See elab_expr.cc)
*/ */
extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_variable_type_t data_type_lv, ivl_variable_type_t lv_type,
int expr_wid_lv, PExpr*expr); unsigned lv_width, PExpr*expr);
/* /*
* Used by elaboration to suppress the sign of an operand if the other * This procedure evaluates an expression and if the evaluation is
* is unsigned.
*/
extern void suppress_binary_operand_sign_if_needed(NetExpr*lp, NetExpr*rp);
/*
* This procedure elaborates an expression and if the elaboration is
* successful the original expression is replaced with the new one. * successful the original expression is replaced with the new one.
*/ */
void eval_expr(NetExpr*&expr, int prune_width =-1); void eval_expr(NetExpr*&expr, int context_width =-1);
/* /*
* Get the long integer value for the passed in expression, if * Get the long integer value for the passed in expression, if

View File

@ -1,486 +0,0 @@
/*
* Copyright (c) 1999-2010 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include <iostream>
/*
* This file contains set_width methods for the various NetExpr
* classes. The set_width method is used by elaboration to ask the
* expression to resize itself. If the expression can't, then the
* set_width method will return false and the caller will arrange for
* whatever is needed to deal with the size mismatch.
*/
# include "netlist.h"
# include "netmisc.h"
# include "compiler.h"
# include <typeinfo>
bool NetExpr::set_width(unsigned w, bool)
{
cerr << get_fileline() << ": internal warning: "
<<typeid(*this).name() << ": set_width(unsigned) "
<< "not implemented." << endl;
expr_width(w);
return false;
}
bool NetEBinary::set_width(unsigned w, bool)
{
bool flag = true;
switch (op_) {
case 'l': // left shift (<<)
case 'r': // right shift (>>)
/* these operators are handled in the derived class. */
assert(0);
break;
/* The default rule is that the operands of the binary
operator might as well use the same width as the
output from the binary operation. */
default:
expr_width(left_->expr_width() > right_->expr_width()
? left_->expr_width() : right_->expr_width());
cerr << "NetEBinary::set_width(): Using default for " <<
op_ << "." << endl;
flag = false;
case '%':
case '/':
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
expr_width(w);
break;
}
return flag;
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess.
*/
bool NetEBAdd::set_width(unsigned w, bool)
{
unsigned wid = w;
if (left_->expr_width() > wid)
wid = left_->expr_width();
if (right_->expr_width() > wid)
wid = right_->expr_width();
left_->set_width(wid);
right_->set_width(wid);
if (left_->expr_width() < wid) {
NetExpr*tmp = new NetESelect(left_, 0, wid);
tmp->cast_signed(left_->has_sign());
left_ = tmp;
}
if (right_->expr_width() < wid) {
NetExpr*tmp = new NetESelect(right_, 0, wid);
tmp->cast_signed(right_->has_sign());
right_ = tmp;
}
expr_width(wid);
return w == wid;
}
void NetEBAdd::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess. I first try to get the operands to
* shrink to the desired size. I then expand operands that are too small.
*/
bool NetEBBits::set_width(unsigned w, bool)
{
/* First, give the operands a chance to adjust themselves to
the requested width. */
left_->set_width(w);
right_->set_width(w);
/* */
unsigned use_width = w;
if (left_->expr_width() > use_width)
use_width = left_->expr_width();
if (right_->expr_width() > use_width)
use_width = right_->expr_width();
/* If the operands end up too small, then pad them to suit. */
if (left_->expr_width() < use_width) {
NetExpr*tmp = pad_to_width(left_, use_width, *this);
assert(tmp);
left_ = tmp;
}
if (right_->expr_width() < w) {
NetExpr*tmp = pad_to_width(right_, use_width, *this);
assert(tmp);
right_ = tmp;
}
/* And here is the final width. If this is not the size the
caller requested, then return false. Otherwise, return
true. */
expr_width(use_width);
return w == use_width;
}
/*
* Comparison operators allow the subexpressions to have
* their own natural width, but the comparison operator result has a
* fixed width of 1.
*/
bool NetEBComp::set_width(unsigned w, bool)
{
return w == 1;
}
/*
* There is nothing we can do to the operands of a division to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBDiv::set_width(unsigned w, bool)
{
return w == expr_width();
}
void NetEBDiv::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
bool NetEBLogic::set_width(unsigned w, bool)
{
bool flag;
flag = left_->set_width(right_->expr_width());
if (!flag)
flag = right_->set_width(left_->expr_width());
return w == 1;
}
/*
* There is nothing we can do to the operands of a multiply to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBMult::set_width(unsigned w, bool)
{
if (w < left_->expr_width())
left_->set_width(w);
if (w < right_->expr_width())
right_->expr_width();
expr_width(w);
return true;
}
void NetEBMult::cast_signed(bool sign_flag)
{
if (has_sign() == sign_flag)
return;
if (sign_flag == false) {
left_->cast_signed(sign_flag);
right_->cast_signed(sign_flag);
}
cast_signed_base_(sign_flag);
}
bool NetEBPow::set_width(unsigned w, bool)
{
return w == expr_width();
}
/*
* The shift operator allows the shift amount to have its own
* natural width. The width of the operator result is the width of the
* left operand, the value that is to be shifted.
*/
bool NetEBShift::set_width(unsigned w, bool)
{
switch (op()) {
case 'l':
left_->set_width(w);
if (left_->expr_width() < w)
left_ = pad_to_width(left_, w, *this);
break;
case 'r':
case 'R':
if (left_->expr_width() < w)
left_ = pad_to_width(left_, w, *this);
break;
default:
assert(0);
}
expr_width(left_->expr_width());
return w == expr_width();
}
/*
* Add up the widths from all the expressions that are concatenated
* together. This is the width of the expression, tough luck if you
* want it otherwise.
*
* If during the course of elaboration one of the sub-expressions is
* broken, then don't count it in the width. This doesn't really
* matter because the null expression is indication of an error and
* the compiler will not go beyond elaboration.
*/
bool NetEConcat::set_width(unsigned w, bool)
{
unsigned sum = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
if (parms_[idx] != 0)
sum += parms_[idx]->expr_width();
sum *= repeat();
expr_width(sum);
return w == sum;
}
bool NetEConst::set_width(unsigned w, bool last_chance)
{
/* Make the value signed if the NetEConst is signed.
* This happens when $signed() is called, so this
* sign information needs to be propagated. */
value_.has_sign(has_sign());
if (w == value_.len()) {
expr_width(w);
return true;
}
assert(w != 0);
if (w > value_.len()) {
verinum::V pad = verinum::V0;
if (value_.has_sign()) {
pad = value_.get(value_.len()-1);
/* It appears that you always have a defined length here,
* so this logic may be in error. */
} else if (value_.len() != 0 && !value_.has_len())
switch (value_.get(value_.len()-1)) {
case verinum::V1:
case verinum::V0:
break;
case verinum::Vx:
pad = verinum::Vx;
break;
case verinum::Vz:
pad = verinum::Vz;
break;
}
verinum tmp (verinum::V0, w, has_width());
for (unsigned idx = 0 ; idx < value_.len() ; idx += 1)
tmp.set(idx, value_[idx]);
for (unsigned idx = value_.len() ; idx < w ; idx += 1)
tmp.set(idx, pad);
tmp.has_sign(value_.has_sign());
value_ = tmp;
expr_width(w);
return true;
} else {
unsigned use_w = w;
verinum::V pad_bit = value_.has_sign()
? value_[value_.len() - 1]
: verinum::V0;
if (! last_chance) {
// Don't reduce a number too small to hold all the
// significant bits.
for (unsigned idx = w ; idx < value_.len() ; idx += 1)
if (value_[idx] != pad_bit)
use_w = idx+1;
// Correct for the special case of signed value. We
// cannot have the result change sign on us.
if (value_.has_sign() && (use_w < value_.len())
&& (value_[use_w-1] != pad_bit))
use_w += 1;
}
verinum tmp (verinum::V0, use_w, has_width());
for (unsigned idx = 0 ; idx < use_w ; idx += 1)
tmp.set(idx, value_[idx]);
tmp.has_sign(value_.has_sign());
value_ = tmp;
expr_width(use_w);
return w == use_w;
}
}
void NetEConst::cast_signed(bool sign_flag)
{
value_.has_sign(sign_flag);
cast_signed_base_(sign_flag);
}
/*
* Parameter vectors cannot be resized because they refer to a common
* value. Ditto for enumeration names.
*/
bool NetEConstParam::set_width(unsigned w, bool)
{
return w == expr_width();
}
bool NetEConstEnum::set_width(unsigned w, bool)
{
return w == expr_width();
}
/*
* Real constants can have whatever width the environment wants,
* because it isn't really a vector. The environment will convert this
* to a vector at the right time.
*/
bool NetECReal::set_width(unsigned w, bool)
{
expr_width(w);
return true;
}
#if 0
bool NetEMemory::set_width(unsigned w, bool)
{
if (w != mem_->width())
return false;
expr_width(w);
return true;
}
#endif
bool NetESelect::set_width(unsigned, bool)
{
return expr_width() == 1;
}
bool NetESFunc::set_width(unsigned w, bool)
{
return w == expr_width();
}
/*
* The signal should automatically pad with zeros to get to the desired
* width. Do not allow signal bits to be truncated, however.
*/
bool NetESignal::set_width(unsigned w, bool)
{
return w == vector_width();
}
bool NetETernary::set_width(unsigned w, bool last_chance)
{
bool flag = true;
flag = flag && true_val_->set_width(w, last_chance);
flag = flag && false_val_->set_width(w, last_chance);
/* The ternary really insists that the true and false clauses
have the same width. Even if we fail to make the width that
the user requests, at least pad the smaller width to suit
the larger. */
if (true_val_->expr_width() < false_val_->expr_width())
true_val_ = pad_to_width(true_val_, false_val_->expr_width(),
*this);
if (false_val_->expr_width() < true_val_->expr_width())
false_val_ = pad_to_width(false_val_, true_val_->expr_width(),
*this);
expr_width(true_val_->expr_width());
return flag;
}
/*
* XXXX FIX ME: For now, just take whatever the caller says as my
* width. What I really need to do is note the width of the output
* parameter of the function definition and take that into account.
*/
bool NetEUFunc::set_width(unsigned w, bool)
{
return w == result_sig_->expr_width();
}
bool NetEUnary::set_width(unsigned w, bool)
{
bool flag = true;
switch (op_) {
case '~':
case '-':
case 'r':
case 'i':
flag = expr_->set_width(w);
expr_width(w);
break;
case '!':
return w == 1;
default:
flag = expr_width() == w;
break;
}
return flag;
}
/*
* Unary reduction operators allow its operand to have any width. The
* result is defined to be 1.
*/
bool NetEUReduce::set_width(unsigned w, bool)
{
return w == 1;
}

View File

@ -274,8 +274,8 @@ void dll_target::expr_param(const NetEConstParam*net)
<< ivl_scope_name(scop) << endl; << ivl_scope_name(scop) << endl;
} }
assert(par); assert(par);
assert(par->value); expr_const(net);
expr_ = par->value; expr_->u_.string_.parameter = par;
} }
void dll_target::expr_rparam(const NetECRealParam*net) void dll_target::expr_rparam(const NetECRealParam*net)

View File

@ -287,7 +287,7 @@ verinum::verinum(const verinum&that)
verinum::verinum(const verinum&that, unsigned nbits) verinum::verinum(const verinum&that, unsigned nbits)
{ {
string_flag_ = false; string_flag_ = that.string_flag_ && (that.nbits_ == nbits);
nbits_ = nbits; nbits_ = nbits;
bits_ = new V[nbits_]; bits_ = new V[nbits_];
has_len_ = true; has_len_ = true;
@ -591,6 +591,39 @@ verinum pad_to_width(const verinum&that, unsigned width)
return val; return val;
} }
verinum cast_to_width(const verinum&that, unsigned width)
{
if (that.has_len() && (that.len() == width))
return that;
if (that.len() >= width)
return verinum(that, width);
if (that.len() == 0) {
verinum val (verinum::V0, width, true);
val.has_sign(that.has_sign());
return val;
}
verinum::V pad = that[that.len()-1];
if (pad==verinum::V1 && !that.has_sign())
pad = verinum::V0;
if (that.has_len() && !that.has_sign()) {
if (pad==verinum::Vx)
pad = verinum::V0;
if (pad==verinum::Vz)
pad = verinum::V0;
}
verinum val(pad, width, true);
for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
val.set(idx, that[idx]);
val.has_sign(that.has_sign());
return val;
}
/* /*
* This function returns a version of the verinum that has only as * This function returns a version of the verinum that has only as
* many bits as are needed to accurately represent the value. It takes * many bits as are needed to accurately represent the value. It takes
@ -1097,6 +1130,7 @@ verinum pow(const verinum&left, const verinum&right)
verinum operator << (const verinum&that, unsigned shift) verinum operator << (const verinum&that, unsigned shift)
{ {
verinum result(verinum::V0, that.len() + shift, that.has_len()); verinum result(verinum::V0, that.len() + shift, that.has_len());
result.has_sign(that.has_sign());
for (unsigned idx = 0 ; idx < that.len() ; idx += 1) for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
result.set(idx+shift, that.get(idx)); result.set(idx+shift, that.get(idx));
@ -1119,6 +1153,7 @@ verinum operator >> (const verinum&that, unsigned shift)
verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0, verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0,
that.len() - shift, that.has_len()); that.len() - shift, that.has_len());
result.has_sign(that.has_sign());
for (unsigned idx = shift ; idx < that.len() ; idx += 1) for (unsigned idx = shift ; idx < that.len() ; idx += 1)
result.set(idx-shift, that.get(idx)); result.set(idx-shift, that.get(idx));

View File

@ -1,7 +1,7 @@
#ifndef __verinum_H #ifndef __verinum_H
#define __verinum_H #define __verinum_H
/* /*
* Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) * Copyright (c) 1998-2011 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
@ -64,6 +64,7 @@ class verinum {
// A number "has a length" if the length was specified fixed // A number "has a length" if the length was specified fixed
// in some way. // in some way.
bool has_len(bool flag) { has_len_ = flag; return has_len_; }
bool has_len() const { return has_len_; } bool has_len() const { return has_len_; }
bool has_sign(bool flag) { has_sign_ = flag; return has_sign_; } bool has_sign(bool flag) { has_sign_ = flag; return has_sign_; }
@ -126,6 +127,12 @@ inline verinum::V sign_bit(const verinum&val)
extension, if the value is signed. */ extension, if the value is signed. */
extern verinum pad_to_width(const verinum&, unsigned width); extern verinum pad_to_width(const verinum&, unsigned width);
/* Return a verinum that has the same value as the input, but is
exactly the requested width. This may involve sign extension,
if the value is signed. The returned verinum will have fixed
width. */
extern verinum cast_to_width(const verinum&, unsigned width);
/* Return a verinum that is minimal. That is, it has only the length /* Return a verinum that is minimal. That is, it has only the length
needed to accurately represent the contained value, signed or not. */ needed to accurately represent the contained value, signed or not. */
extern verinum trim_vnum(const verinum&); extern verinum trim_vnum(const verinum&);