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:
parent
2df6850824
commit
312b4da46f
|
|
@ -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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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)
|
||||
{
|
||||
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
|
||||
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);
|
||||
NetExpr*dex = elab_and_eval(des, scope, expr, -1);
|
||||
|
||||
/* Print a warning if we find default and `timescale based
|
||||
* delays in the design, since this is likely an error. */
|
||||
|
|
|
|||
25
PExpr.cc
25
PExpr.cc
|
|
@ -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
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -31,8 +31,10 @@
|
|||
|
||||
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()
|
||||
|
|
@ -94,8 +96,8 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
|
|||
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
|
||||
: PEBinary(op, l, r)
|
||||
{
|
||||
left_width_ = 0;
|
||||
right_width_ = 0;
|
||||
l_width_ = 0;
|
||||
r_width_ = 0;
|
||||
}
|
||||
|
||||
PEBComp::~PEBComp()
|
||||
|
|
@ -204,13 +206,16 @@ bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const
|
|||
}
|
||||
|
||||
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;
|
||||
assert(parms_.size() == p.size());
|
||||
for (list<PExpr*>::const_iterator idx = p.begin()
|
||||
; idx != p.end() ; ++idx)
|
||||
parms_[tmp_idx++] = *idx;
|
||||
|
||||
tested_scope_ = 0;
|
||||
repeat_count_ = 1;
|
||||
}
|
||||
|
||||
PEConcat::~PEConcat()
|
||||
|
|
@ -437,3 +442,11 @@ bool PEUnary::has_aa_term(Design*des, NetScope*scope) const
|
|||
assert(expr_);
|
||||
return expr_->has_aa_term(des, scope);
|
||||
}
|
||||
|
||||
PEVoid::PEVoid()
|
||||
{
|
||||
}
|
||||
|
||||
PEVoid::~PEVoid()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
258
PExpr.h
258
PExpr.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __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
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -43,6 +43,8 @@ class NetScope;
|
|||
class PExpr : public LineInfo {
|
||||
|
||||
public:
|
||||
enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED };
|
||||
|
||||
PExpr();
|
||||
virtual ~PExpr();
|
||||
|
||||
|
|
@ -62,53 +64,65 @@ class PExpr : public LineInfo {
|
|||
// references to automatically allocated variables.
|
||||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
// This method tests the width that the expression wants to
|
||||
// be. It is used by elaboration of assignments to figure out
|
||||
// the width of the expression.
|
||||
// This method tests the type and width that the expression wants
|
||||
// to be. It should be called before elaborating an expression to
|
||||
// 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
|
||||
// minimum width that this function should return. Initially
|
||||
// this is the same as the lval width.
|
||||
// Normally mode should be initialised to SIZED before starting to
|
||||
// test the width of an expression. In SIZED mode the expression
|
||||
// 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
|
||||
// result is going to go. This can be used to constrain the
|
||||
// amount that an expression can reasonably expand. For
|
||||
// example, there is no point expanding an addition to beyond
|
||||
// the lval. This extra bit of information allows the
|
||||
// expression to optimize itself a bit. If the lval==0, then
|
||||
// the subexpression should not make l-value related
|
||||
// optimizations.
|
||||
// If mode is initialised to EXPAND instead of SIZED, the expression
|
||||
// width will be calculated as the minimum width necessary to avoid
|
||||
// arithmetic overflow or underflow, even if it contains no unsized
|
||||
// literals. mode will be changed LOSSLESS or UNSIZED as described
|
||||
// above. This supports a non-standard mode of expression width
|
||||
// calculation.
|
||||
//
|
||||
// The expr_type is an output argument that gives the
|
||||
// calculated type for the expression.
|
||||
//
|
||||
// The unsized_flag is set to true if the expression is
|
||||
// unsized and therefore expandable. This happens if a
|
||||
// sub-expression is an unsized literal. Some expressions make
|
||||
// special use of that.
|
||||
// When the final value of mode is UNSIZED, the width returned by
|
||||
// this method is the calculated lossless width, but the width
|
||||
// returned by a subsequent call to the expr_width method will be
|
||||
// the final expression width.
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
// After the test_width method is complete, these methods
|
||||
// return valid results.
|
||||
ivl_variable_type_t expr_type() const { return expr_type_; }
|
||||
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
|
||||
// the width of the context of the expression (i.e. the
|
||||
// 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 required width of the expression.
|
||||
//
|
||||
// The sys_task_arg flag is true if expressions are allowed to
|
||||
// be incomplete.
|
||||
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
|
||||
// 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;
|
||||
|
||||
protected:
|
||||
unsigned fix_width_(width_mode_t mode);
|
||||
|
||||
// The derived class test_width methods should fill these in.
|
||||
ivl_variable_type_t expr_type_;
|
||||
unsigned expr_width_;
|
||||
unsigned min_width_;
|
||||
bool signed_flag_;
|
||||
|
||||
private: // not implemented
|
||||
PExpr(const PExpr&);
|
||||
|
|
@ -165,14 +183,13 @@ class PEConcat : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
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,
|
||||
NetScope*scope,
|
||||
bool is_force) const;
|
||||
|
|
@ -181,9 +198,11 @@ class PEConcat : public PExpr {
|
|||
bool bidirectional_flag) const;
|
||||
private:
|
||||
vector<PExpr*>parms_;
|
||||
std::valarray<unsigned>tested_widths_;
|
||||
std::valarray<width_mode_t>width_modes_;
|
||||
|
||||
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 unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
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;
|
||||
|
||||
|
|
@ -262,9 +280,7 @@ class PEIdent : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
|
|
@ -277,7 +293,8 @@ class PEIdent : public PExpr {
|
|||
bool is_force) const;
|
||||
|
||||
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
|
||||
// only applies to Ident expressions.
|
||||
|
|
@ -326,13 +343,14 @@ class PEIdent : public PExpr {
|
|||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb,
|
||||
int expr_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
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,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
|
|
@ -349,28 +367,31 @@ class PEIdent : public PExpr {
|
|||
NetScope*scope,
|
||||
NetNet*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
NetExpr*elaborate_expr_net_word_(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid,
|
||||
bool sys_task_arg) const;
|
||||
NetExpr*elaborate_expr_net_part_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr*elaborate_expr_net_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetExpr*elaborate_expr_net_idx_do_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetExpr*elaborate_expr_net_bit_(Design*des,
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
NetScope*scope,
|
||||
NetESignal*net,
|
||||
NetScope*found) const;
|
||||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
|
|
@ -390,12 +411,10 @@ class PENumber : public PExpr {
|
|||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool) const;
|
||||
unsigned expr_wid, bool) const;
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
bool is_force) const;
|
||||
|
|
@ -425,12 +444,10 @@ class PEString : public PExpr {
|
|||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool) const;
|
||||
unsigned expr_wid, bool) const;
|
||||
verinum* eval_const(Design*, NetScope*) const;
|
||||
|
||||
private:
|
||||
|
|
@ -450,16 +467,15 @@ class PEUnary : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, int expr_wid) const;
|
||||
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;
|
||||
|
||||
private:
|
||||
char op_;
|
||||
|
|
@ -479,12 +495,11 @@ class PEBinary : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
|
|
@ -493,22 +508,22 @@ class PEBinary : public PExpr {
|
|||
PExpr*right_;
|
||||
|
||||
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,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
|
||||
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,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
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,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
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,
|
||||
int use_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -523,16 +538,14 @@ class PEBComp : public PEBinary {
|
|||
~PEBComp();
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
NetExpr* elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
unsigned expr_wid, bool sys_task_arg) const;
|
||||
|
||||
private:
|
||||
int left_width_;
|
||||
int right_width_;
|
||||
unsigned l_width_;
|
||||
unsigned r_width_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -545,12 +558,10 @@ class PEBLogic : public PEBinary {
|
|||
~PEBLogic();
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
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;
|
||||
|
||||
virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const =0;
|
||||
unsigned expr_wid) const =0;
|
||||
|
||||
protected:
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
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 {
|
||||
|
|
@ -585,7 +594,7 @@ class PEBPower : public PEBLeftWidth {
|
|||
~PEBPower();
|
||||
|
||||
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const;
|
||||
unsigned expr_wid) const;
|
||||
};
|
||||
|
||||
class PEBShift : public PEBLeftWidth {
|
||||
|
|
@ -595,7 +604,7 @@ class PEBShift : public PEBLeftWidth {
|
|||
~PEBShift();
|
||||
|
||||
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 unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope,
|
||||
PExpr*expr, int use_wid) const;
|
||||
PExpr*expr, unsigned expr_wid) const;
|
||||
|
||||
private:
|
||||
PExpr*expr_;
|
||||
|
|
@ -658,12 +666,11 @@ class PECallFunction : public PExpr {
|
|||
virtual bool has_aa_term(Design*des, NetScope*scope) const;
|
||||
|
||||
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,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
|
||||
private:
|
||||
pform_name_t path_;
|
||||
|
|
@ -671,14 +678,29 @@ class PECallFunction : public PExpr {
|
|||
|
||||
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_access_func_(Design*des, NetScope*scope, ivl_nature_t) const;
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
|
||||
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 min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&unsized_flag);
|
||||
width_mode_t&mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -1396,12 +1396,8 @@ void NetEBinary::dump(ostream&o) const
|
|||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
if (repeat_calculated_) {
|
||||
if (repeat_value_ != 1)
|
||||
o << repeat_value_;
|
||||
} else if (repeat_) {
|
||||
o << "<" << *repeat_ << ">";
|
||||
}
|
||||
if (repeat_ != 1)
|
||||
o << repeat_;
|
||||
|
||||
if (parms_[0])
|
||||
o << "{" << *parms_[0];
|
||||
|
|
|
|||
146
dup_expr.cc
146
dup_expr.cc
|
|
@ -32,19 +32,103 @@ NetEAccess* NetEAccess::dup_expr() const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEBComp* NetEBComp::dup_expr() const
|
||||
NetEBinary* NetEBinary::dup_expr() const
|
||||
{
|
||||
NetEBComp*tmp = new NetEBComp(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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*tmp = new NetEConst(value_);
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -52,7 +136,7 @@ NetEConst* NetEConst::dup_expr() const
|
|||
NetEConstEnum* NetEConstEnum::dup_expr() const
|
||||
{
|
||||
NetEConstEnum*tmp = new NetEConstEnum(scope_, name_, enum_set_, value());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -60,7 +144,15 @@ NetEConstEnum* NetEConstEnum::dup_expr() const
|
|||
NetEConstParam* NetEConstParam::dup_expr() const
|
||||
{
|
||||
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);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -68,26 +160,26 @@ NetEConstParam* NetEConstParam::dup_expr() const
|
|||
NetECRealParam* NetECRealParam::dup_expr() const
|
||||
{
|
||||
NetECRealParam*tmp = new NetECRealParam(scope_, name_, value());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEEvent* NetEEvent::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetENetenum* NetENetenum::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEScope* NetEScope::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +188,7 @@ NetESelect* NetESelect::dup_expr() const
|
|||
NetESelect*tmp = new NetESelect(expr_->dup_expr(),
|
||||
base_? base_->dup_expr() : 0,
|
||||
expr_width(), sel_type_);
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -104,11 +196,11 @@ NetESelect* NetESelect::dup_expr() const
|
|||
NetESFunc* NetESFunc::dup_expr() const
|
||||
{
|
||||
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
tmp->cast_signed(has_sign());
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
assert(parm(idx));
|
||||
ivl_assert(*this, parm(idx));
|
||||
tmp->parm(idx, parm(idx)->dup_expr());
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +211,7 @@ NetESFunc* NetESFunc::dup_expr() const
|
|||
NetESignal* NetESignal::dup_expr() const
|
||||
{
|
||||
NetESignal*tmp = new NetESignal(net_, word_);
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->expr_width(expr_width());
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
|
|
@ -129,8 +221,10 @@ NetETernary* NetETernary::dup_expr() const
|
|||
{
|
||||
NetETernary*tmp = new NetETernary(cond_->dup_expr(),
|
||||
true_val_->dup_expr(),
|
||||
false_val_->dup_expr());
|
||||
assert(tmp);
|
||||
false_val_->dup_expr(),
|
||||
expr_width(),
|
||||
has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -141,29 +235,29 @@ NetEUFunc* NetEUFunc::dup_expr() const
|
|||
svector<NetExpr*> tmp_parms (parms_.count());
|
||||
|
||||
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 = new NetEUFunc(scope_, func_, result_sig_->dup_expr(), tmp_parms);
|
||||
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEUBits* NetEUBits::dup_expr() const
|
||||
{
|
||||
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEUnary* NetEUnary::dup_expr() const
|
||||
{
|
||||
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
@ -171,15 +265,15 @@ NetEUnary* NetEUnary::dup_expr() const
|
|||
NetEUReduce* NetEUReduce::dup_expr() const
|
||||
{
|
||||
NetEUReduce*tmp = new NetEUReduce(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetECast* NetECast::dup_expr() const
|
||||
{
|
||||
NetECast*tmp = new NetECast(op_, expr_->dup_expr());
|
||||
assert(tmp);
|
||||
NetECast*tmp = new NetECast(op_, expr_->dup_expr(), expr_width(), has_sign());
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
|
|
|||
1865
elab_expr.cc
1865
elab_expr.cc
File diff suppressed because it is too large
Load Diff
20
elab_lval.cc
20
elab_lval.cc
|
|
@ -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
|
||||
* 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.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);
|
||||
|
||||
// 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();
|
||||
|
||||
// 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
|
||||
// constant value and treat it as a part select with a bit
|
||||
// width of 1.
|
||||
|
|
@ -463,12 +451,6 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
unsigned long 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);
|
||||
ivl_select_type_t sel_type = IVL_SEL_OTHER;
|
||||
|
||||
|
|
|
|||
12
elab_net.cc
12
elab_net.cc
|
|
@ -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_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;
|
||||
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
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);
|
||||
|
||||
// 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;
|
||||
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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;
|
||||
|
||||
if (range->low_expr) {
|
||||
probe_expr_width(des, scope, range->low_expr);
|
||||
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
|
||||
ivl_assert(*range->low_expr, tmp->low_expr);
|
||||
} else {
|
||||
|
|
@ -78,7 +77,6 @@ static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
|
|||
tmp->high_expr = tmp->low_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);
|
||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||
} else {
|
||||
|
|
@ -136,8 +134,8 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope,
|
|||
{
|
||||
bool rc_flag;
|
||||
assert(enum_type->range->size() == 2);
|
||||
NetExpr*msb_ex = enum_type->range->front()->elaborate_expr(des, scope, -2, false);
|
||||
NetExpr*lsb_ex = enum_type->range->back() ->elaborate_expr(des, scope, -2, false);
|
||||
NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1);
|
||||
NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1);
|
||||
|
||||
long msb = 0;
|
||||
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
|
||||
// the value and assign it to the enumeration name.
|
||||
NetExpr*val = elab_and_eval(des, scope, cur->parm,
|
||||
use_enum->base_width(),
|
||||
use_enum->base_width());
|
||||
NetEConst*val_const = dynamic_cast<NetEConst*> (val);
|
||||
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
|
||||
// use) the genvar itself, so we can evaluate this expression
|
||||
// the same way any other parameter value is evaluated.
|
||||
probe_expr_width(des, container, loop_init);
|
||||
need_constant_expr = true;
|
||||
NetExpr*init_ex = elab_and_eval(des, container, loop_init, -1);
|
||||
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;
|
||||
container->genvar_tmp = loop_index;
|
||||
container->genvar_tmp_val = genvar;
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -673,7 +668,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
elaborate_subscope_(des, scope);
|
||||
|
||||
// Calculate the step for the loop variable.
|
||||
probe_expr_width(des, container, loop_step);
|
||||
need_constant_expr = true;
|
||||
NetExpr*step_ex = elab_and_eval(des, container, loop_step, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -692,7 +686,6 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
|||
container->genvar_tmp_val = genvar;
|
||||
delete step;
|
||||
delete test_ex;
|
||||
probe_expr_width(des, container, loop_test);
|
||||
test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
test = dynamic_cast<NetEConst*>(test_ex);
|
||||
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)
|
||||
{
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*test_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
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)
|
||||
{
|
||||
probe_expr_width(des, container, loop_test);
|
||||
need_constant_expr = true;
|
||||
NetExpr*case_value_ex = elab_and_eval(des, container, loop_test, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -833,7 +824,6 @@ bool PGenerate::generate_scope_case_(Design*des, NetScope*container)
|
|||
|
||||
bool match_flag = false;
|
||||
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;
|
||||
NetExpr*item_value_ex = elab_and_eval(des, container, item->item_test[idx], -1);
|
||||
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
|
||||
{
|
||||
if (msb_) probe_expr_width(des, sc, msb_);
|
||||
if (lsb_) probe_expr_width(des, sc, lsb_);
|
||||
need_constant_expr = true;
|
||||
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1) : 0;
|
||||
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1) : 0;
|
||||
|
|
|
|||
13
elab_sig.cc
13
elab_sig.cc
|
|
@ -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
|
||||
* 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:
|
||||
if (return_type_.range) {
|
||||
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;
|
||||
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_S:
|
||||
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;
|
||||
{
|
||||
need_constant_expr = true;
|
||||
|
|
@ -852,7 +848,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
bool bad_lsb = false, bad_msb = false;
|
||||
/* If they exist get the port definition MSB and LSB */
|
||||
if (port_set_ && port_msb_ != 0) {
|
||||
probe_expr_width(des, scope, port_msb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
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;
|
||||
|
||||
probe_expr_width(des, scope, port_lsb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
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 (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) {
|
||||
probe_expr_width(des, scope, net_msb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
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;
|
||||
|
||||
probe_expr_width(des, scope, net_lsb_);
|
||||
/* We do not currently support constant user function. */
|
||||
need_constant_expr = true;
|
||||
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_) {
|
||||
assert(lidx_ && ridx_);
|
||||
|
||||
probe_expr_width(des, scope, lidx_);
|
||||
probe_expr_width(des, scope, ridx_);
|
||||
|
||||
need_constant_expr = true;
|
||||
NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1);
|
||||
NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1);
|
||||
|
|
|
|||
169
elaborate.cc
169
elaborate.cc
|
|
@ -115,6 +115,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
|
||||
<< " width="<< rval->vector_width()
|
||||
<< ", type="<< rval->data_type()
|
||||
<< ", signed="<< rval->get_signed()
|
||||
<< ", expr=" << *rval_expr << endl;
|
||||
}
|
||||
|
||||
|
|
@ -227,11 +228,6 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
|
|||
gate. Figure out how many are desired. */
|
||||
if (msb_) {
|
||||
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*lsb_exp = elab_and_eval(des, scope, lsb_, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
@ -820,12 +816,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
|||
sig = lval_sigs[idx];
|
||||
|
||||
} else {
|
||||
unsigned use_width = array_count * instance_width;
|
||||
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);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, ex, -1);
|
||||
sig = tmp->synthesize(des, scope, 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
|
||||
in that case that the port is input. */
|
||||
|
||||
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
|
||||
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);
|
||||
NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], -1);
|
||||
if (tmp_expr == 0) {
|
||||
cerr << pins[idx]->get_fileline()
|
||||
<< ": internal error: Port expression "
|
||||
|
|
@ -1891,7 +1876,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
|||
if (pins[idx] == 0)
|
||||
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) {
|
||||
cerr << "internal error: Expression too complicated "
|
||||
"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)
|
||||
{
|
||||
probe_expr_width(des, scope, expr);
|
||||
NetExpr*dex = elab_and_eval(des, scope, expr, -1);
|
||||
|
||||
/* 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));
|
||||
scal_val->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex = new NetEBMult('*', dex, scal_val, 1, true);
|
||||
dex->set_line(*expr);
|
||||
|
||||
// Cast this part of the expression to an integer.
|
||||
dex = new NetECast('i', dex);
|
||||
dex->set_width(64);
|
||||
dex = new NetECast('i', dex, 64, false);
|
||||
dex->set_line(*expr);
|
||||
|
||||
// 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->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex->set_width(64);
|
||||
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
||||
dex->set_line(*expr);
|
||||
} else {
|
||||
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));
|
||||
scal_val->set_line(*expr);
|
||||
dex = new NetEBMult('*', dex, scal_val);
|
||||
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
||||
dex->set_line(*expr);
|
||||
}
|
||||
|
||||
|
|
@ -2176,17 +2158,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
if (delay || event_) {
|
||||
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::REG, wid);
|
||||
tmp->local_flag(true);
|
||||
|
|
@ -2276,22 +2247,6 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
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 (debug_elaborate)
|
||||
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());
|
||||
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;
|
||||
if (delay_ != 0) {
|
||||
assert(count_ == 0 && event_ == 0);
|
||||
|
|
@ -2507,7 +2448,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
|||
{
|
||||
assert(scope);
|
||||
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate this case"
|
||||
|
|
@ -2562,7 +2502,6 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
|||
NetExpr*gu = 0;
|
||||
NetProc*st = 0;
|
||||
assert(cur_expr);
|
||||
probe_expr_width(des, scope, cur_expr);
|
||||
gu = elab_and_eval(des, scope, cur_expr, -1);
|
||||
|
||||
if (cur->stat)
|
||||
|
|
@ -2585,7 +2524,6 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
|||
<< " with conditional: " << *expr_ << endl;
|
||||
|
||||
// Elaborate and try to evaluate the conditional expression.
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
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);
|
||||
|
||||
perm_string name = peek_tail_name(path_);
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
if (ex != 0) {
|
||||
ivl_variable_type_t use_type;
|
||||
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]);
|
||||
|
||||
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
||||
} else {
|
||||
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
|
||||
// to annotate, and the user is intending to turn the behavior
|
||||
// off anyhow, so replace the system task invocation with a no-op.
|
||||
if (gn_specify_blocks_flag == false
|
||||
&& peek_tail_name(path_) == "$sdf_annotate") {
|
||||
if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
|
||||
|
||||
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
|
||||
<< "since specify blocks are being omitted." << endl;
|
||||
|
|
@ -2743,8 +2663,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
return noop;
|
||||
}
|
||||
|
||||
NetSTask*cur = new NetSTask(peek_tail_name(path_), def_sfunc_as_task,
|
||||
eparms);
|
||||
NetSTask*cur = new NetSTask(name, def_sfunc_as_task, eparms);
|
||||
cur->set_line(*this);
|
||||
return cur;
|
||||
}
|
||||
|
|
@ -2871,11 +2790,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
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);
|
||||
pr->set_line(*this);
|
||||
|
|
@ -2988,9 +2902,6 @@ NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
|
|||
if (rexp == 0)
|
||||
return 0;
|
||||
|
||||
rexp->set_width(lwid);
|
||||
rexp = pad_to_width(rexp, lwid, *this);
|
||||
|
||||
dev = new NetCAssign(lval, rexp);
|
||||
|
||||
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(), 0);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), -1);
|
||||
if (tmp == 0) {
|
||||
expr_[idx]->dump(cerr);
|
||||
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
|
||||
shortly, after we apply a reduction or. */
|
||||
|
||||
probe_expr_width(des, scope, pe);
|
||||
NetExpr*expr = pe->elaborate_expr(des, scope, -1, false);
|
||||
PExpr::width_mode_t mode;
|
||||
pe->test_width(des, scope, mode);
|
||||
NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(), false);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": error: Unable to elaborate"
|
||||
" wait condition expression." << endl;
|
||||
|
|
@ -3607,9 +3518,6 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
if (rexp == 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 (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
|
|
@ -3670,32 +3578,14 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
assert(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
|
||||
properly. Then use it to build the assignment statement. */
|
||||
etmp = elab_and_eval(des, scope, expr1_, use_width);
|
||||
etmp->set_width(use_width);
|
||||
etmp = pad_to_width(etmp, use_width, *this);
|
||||
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
|
||||
expr1_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: FOR initial assign: "
|
||||
<< 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);
|
||||
|
|
@ -3729,9 +3619,16 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
assert(sig);
|
||||
lv = new NetAssign_(sig);
|
||||
|
||||
/* Make the rvalue of the increment expression, and size it
|
||||
for the lvalue. */
|
||||
etmp = elab_and_eval(des, scope, expr2_, lv->lwidth());
|
||||
/* Make the r-value of the increment assignment, and size it
|
||||
properly. Then use it to build the assignment statement. */
|
||||
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);
|
||||
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,
|
||||
in case it is a constant. This is an interesting case
|
||||
worthy of a warning. */
|
||||
probe_expr_width(des, scope, cond_);
|
||||
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
||||
if (ce == 0) {
|
||||
delete top;
|
||||
|
|
@ -3832,7 +3728,6 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
|
|||
{
|
||||
assert(scope);
|
||||
|
||||
probe_expr_width(des, scope, expr_);
|
||||
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
||||
if (expr == 0) {
|
||||
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
|
||||
{
|
||||
probe_expr_width(des, scope, cond_);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
|
||||
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
|
||||
return loop;
|
||||
|
|
@ -4059,8 +3953,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
|||
them for the timescale/precision of the scope. */
|
||||
for (unsigned idx = 0 ; idx < ndelays ; idx += 1) {
|
||||
PExpr*exp = delays[idx];
|
||||
probe_expr_width(des, scope, exp);
|
||||
NetExpr*cur = elab_and_eval(des, scope, exp, 0);
|
||||
NetExpr*cur = elab_and_eval(des, scope, exp, -1);
|
||||
|
||||
if (NetEConst*con = dynamic_cast<NetEConst*> (cur)) {
|
||||
verinum fn = con->value();
|
||||
|
|
@ -4098,7 +3991,6 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
|||
NetNet*condit_sig = 0;
|
||||
if (conditional && condition) {
|
||||
|
||||
probe_expr_width(des, scope, condition);
|
||||
NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
|
||||
ivl_assert(*condition, tmp);
|
||||
|
||||
|
|
@ -4255,7 +4147,6 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
|||
for (specparam_it_t cur = specparams.begin()
|
||||
; cur != specparams.end() ; ++ cur ) {
|
||||
|
||||
probe_expr_width(des, scope, (*cur).second);
|
||||
need_constant_expr = true;
|
||||
NetExpr*val = elab_and_eval(des, scope, (*cur).second, -1);
|
||||
need_constant_expr = false;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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
|
||||
{
|
||||
probe_expr_width(des, scope, lval_);
|
||||
probe_expr_width(des, scope, rval_);
|
||||
NetExpr*lval = elab_and_eval(des, scope, lval_, -1);
|
||||
NetExpr*rval = elab_and_eval(des, scope, rval_, -1);
|
||||
|
||||
|
|
|
|||
318
eval_tree.cc
318
eval_tree.cc
|
|
@ -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
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
# include "ivl_assert.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
NetExpr* NetExpr::eval_tree(int)
|
||||
NetExpr* NetExpr::eval_tree()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -114,12 +114,12 @@ NetECReal* NetEBAdd::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEBAdd::eval_tree()
|
||||
{
|
||||
eval_expr(left_, prune_to_width);
|
||||
eval_expr(right_, prune_to_width);
|
||||
eval_expr(left_);
|
||||
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_();
|
||||
|
||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||
|
|
@ -131,33 +131,23 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->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;
|
||||
switch (op_) {
|
||||
case '+':
|
||||
val = lval + rval;
|
||||
val = verinum(lval + rval, wid);
|
||||
break;
|
||||
case '-':
|
||||
val = lval - rval;
|
||||
val = verinum(lval - rval, wid);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
ivl_assert(*this, res);
|
||||
res->set_line(*this);
|
||||
|
|
@ -188,37 +178,20 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
if (lval.len() < expr_width())
|
||||
lval = pad_to_width(lval, expr_width());
|
||||
if (rval.len() < expr_width())
|
||||
rval = pad_to_width(rval, expr_width());
|
||||
|
||||
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());
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == wid);
|
||||
|
||||
verinum val;
|
||||
if (op_ == se->op_) {
|
||||
/* (a + lval) + rval --> a + (rval+lval) */
|
||||
/* (a - lval) - rval --> a - (rval+lval) */
|
||||
val = rval + lval;
|
||||
val = verinum(rval + lval, wid);
|
||||
} else {
|
||||
/* (a - lval) + rval --> a + (rval-lval) */
|
||||
/* (a + lval) - rval --> a - (rval-lval) */
|
||||
val = rval - lval;
|
||||
}
|
||||
|
||||
// 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;
|
||||
val = verinum(rval - lval, wid);
|
||||
}
|
||||
|
||||
NetEConst*tmp = new NetEConst(val);
|
||||
|
|
@ -236,15 +209,15 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetEConst* NetEBBits::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEBBits::eval_tree()
|
||||
{
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
eval_expr(left_, prune_to_width);
|
||||
eval_expr(right_, prune_to_width);
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
||||
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
|
||||
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
|
||||
|
|
@ -266,79 +239,33 @@ NetEConst* NetEBBits::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->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();
|
||||
if (wid == 0)
|
||||
wid = (rwid > lwid)? rwid : lwid;
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lval.len() == wid);
|
||||
ivl_assert(*this, rval.len() == 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()) {
|
||||
|
||||
case '|': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
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;
|
||||
}
|
||||
|
||||
case '&': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
res.set(idx, lval.get(idx) & rval.get(idx));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '^': {
|
||||
unsigned cnt = lwid;
|
||||
if (cnt > wid) cnt = wid;
|
||||
if (cnt > rwid) cnt = rwid;
|
||||
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +688,7 @@ NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag)
|
|||
return result;
|
||||
}
|
||||
|
||||
NetEConst* NetEBComp::eval_tree(int)
|
||||
NetEConst* NetEBComp::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -850,11 +777,8 @@ NetExpr* NetEBDiv::eval_tree_real_()
|
|||
* The NetEBDiv operator includes the / and % operators. First evaluate
|
||||
* 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(right_);
|
||||
|
||||
|
|
@ -865,20 +789,26 @@ NetExpr* NetEBDiv::eval_tree(int prune_to_width)
|
|||
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
|
||||
if (lc == 0 || rc == 0) return 0;
|
||||
|
||||
// Make sure the expression is evaluated at the
|
||||
// expression width.
|
||||
verinum lval = pad_to_width(lc->value(), expr_width());
|
||||
verinum rval = pad_to_width(rc->value(), expr_width());
|
||||
verinum lval = lc->value();
|
||||
verinum rval = rc->value();
|
||||
|
||||
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_) {
|
||||
case '/':
|
||||
tmp = new NetEConst(lval / rval);
|
||||
val = verinum(lval / rval, wid);
|
||||
break;
|
||||
case '%':
|
||||
tmp = new NetEConst(lval % rval);
|
||||
val = verinum(lval % rval, wid);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
NetExpr*tmp = new NetEConst(val);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
|
|
@ -928,7 +858,7 @@ NetEConst* NetEBLogic::eval_tree_real_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* NetEBLogic::eval_tree(int)
|
||||
NetEConst* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -1024,11 +954,8 @@ NetExpr* NetEBMult::eval_tree_real_()
|
|||
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(right_);
|
||||
|
||||
|
|
@ -1042,7 +969,13 @@ NetExpr* NetEBMult::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->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);
|
||||
tmp->set_line(*this);
|
||||
|
||||
|
|
@ -1072,11 +1005,8 @@ NetExpr* NetEBPow::eval_tree_real_()
|
|||
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(right_);
|
||||
|
||||
|
|
@ -1090,7 +1020,12 @@ NetExpr* NetEBPow::eval_tree(int prune_to_width)
|
|||
verinum lval = lc->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);
|
||||
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
|
||||
* operands must be constant.
|
||||
*/
|
||||
NetEConst* NetEBShift::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEBShift::eval_tree()
|
||||
{
|
||||
eval_expr(left_);
|
||||
eval_expr(right_);
|
||||
|
|
@ -1116,79 +1051,44 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
|
|||
|
||||
NetEConst*res;
|
||||
|
||||
verinum rv = re->value();
|
||||
verinum lv = le->value();
|
||||
verinum rv = re->value();
|
||||
|
||||
/* Make an early estimate of the expression width. */
|
||||
unsigned wid = expr_width();
|
||||
ivl_assert(*this, wid > 0);
|
||||
ivl_assert(*this, lv.len() == wid);
|
||||
|
||||
if (rv.is_defined()) {
|
||||
|
||||
unsigned shift = rv.as_ulong();
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Evaluate " << lv << "<<" << op() << ">> "
|
||||
<< rv << ", wid=" << wid << ", shift=" << shift
|
||||
<< ", lv.has_len()=" << lv.has_len() << endl;
|
||||
<< rv << ", wid=" << wid << ", shift=" << shift << endl;
|
||||
}
|
||||
|
||||
if ((wid == 0) || ! lv.has_len()) {
|
||||
/* If the caller doesn't care what the width is,
|
||||
then calculate a width from the trimmed left
|
||||
expression, plus the shift. This avoids
|
||||
data loss. */
|
||||
lv = trim_vnum(lv);
|
||||
wid = lv.len();
|
||||
if (op() == 'l')
|
||||
wid = lv.len() + shift;
|
||||
verinum val;
|
||||
switch (op_) {
|
||||
case 'l':
|
||||
val = verinum(lv << shift, wid);
|
||||
break;
|
||||
case 'r':
|
||||
lv.has_sign(false);
|
||||
val = verinum(lv >> shift, wid);
|
||||
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)
|
||||
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 {
|
||||
unsigned cnt = wid;
|
||||
if (cnt > lv.len())
|
||||
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);
|
||||
|
||||
res = new NetEConst(val);
|
||||
} 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);
|
||||
verinum val (verinum::Vx, wid);
|
||||
res = new NetEConst(val);
|
||||
}
|
||||
|
||||
res->set_line(*this);
|
||||
|
|
@ -1196,7 +1096,7 @@ NetEConst* NetEBShift::eval_tree(int prune_to_width)
|
|||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
||||
NetEConst* NetEConcat::eval_tree()
|
||||
{
|
||||
// HERE
|
||||
unsigned repeat_val = repeat();
|
||||
|
|
@ -1204,7 +1104,7 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
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
|
||||
// the evaluated value.
|
||||
assert(parms_[idx]);
|
||||
NetExpr*expr = parms_[idx]->eval_tree(0);
|
||||
NetExpr*expr = parms_[idx]->eval_tree();
|
||||
if (expr) {
|
||||
expr->set_line(*parms_[idx]);
|
||||
delete parms_[idx];
|
||||
|
|
@ -1285,16 +1185,15 @@ NetEConst* NetEConcat::eval_tree(int prune_to_width)
|
|||
val.has_sign( this->has_sign() );
|
||||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
res->set_width(val.len());
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* NetESelect::eval_tree(int prune_to_width)
|
||||
NetEConst* NetESelect::eval_tree()
|
||||
{
|
||||
// HERE
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluating expression:"
|
||||
<< *this << ", prune_to_width=" << prune_to_width << endl;
|
||||
<< *this << endl;
|
||||
}
|
||||
|
||||
eval_expr(expr_);
|
||||
|
|
@ -1318,14 +1217,12 @@ NetEConst* NetESelect::eval_tree(int prune_to_width)
|
|||
verinum::V pad_bit = verinum::Vx;
|
||||
if (base_ == 0) {
|
||||
|
||||
/* If the base is NULL (different from 0) the this
|
||||
select is here for sign extension. So calculate a
|
||||
proper pad bit. Extend x or z or 0, and sign extend 1
|
||||
if this is signed. */
|
||||
unsigned top = expr->expr_width()-1;
|
||||
|
||||
pad_bit = eval.get(top);
|
||||
if (pad_bit==verinum::V1 && !has_sign())
|
||||
/* If the base is NULL (different from 0) then this
|
||||
select is here for zero or sign extension. So
|
||||
calculate a proper pad bit. */
|
||||
if (has_sign())
|
||||
pad_bit = eval.get(expr->expr_width()-1);
|
||||
else
|
||||
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
|
||||
* false expressions.
|
||||
*/
|
||||
NetExpr* NetETernary::eval_tree(int prune_to_width)
|
||||
NetExpr* NetETernary::eval_tree()
|
||||
{
|
||||
eval_expr(cond_);
|
||||
switch (const_logical(cond_)) {
|
||||
case C_0:
|
||||
eval_expr(false_val_, prune_to_width);
|
||||
eval_expr(false_val_);
|
||||
if (debug_eval_tree) {
|
||||
|
||||
cerr << get_fileline() << ": debug: Evaluate ternary with "
|
||||
|
|
@ -1393,7 +1290,7 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
|
|||
return false_val_->dup_expr();
|
||||
|
||||
case C_1:
|
||||
eval_expr(true_val_, prune_to_width);
|
||||
eval_expr(true_val_);
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": debug: Evaluate ternary with "
|
||||
<< "constant condition value: ";
|
||||
|
|
@ -1425,8 +1322,8 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
|
|||
expressions down to constants then compare the values to
|
||||
build up a constant result. */
|
||||
|
||||
eval_expr(true_val_, prune_to_width);
|
||||
eval_expr(false_val_, prune_to_width);
|
||||
eval_expr(true_val_);
|
||||
eval_expr(false_val_);
|
||||
|
||||
NetEConst*t = dynamic_cast<NetEConst*>(true_val_);
|
||||
NetEConst*f = dynamic_cast<NetEConst*>(false_val_);
|
||||
|
|
@ -1509,7 +1406,7 @@ NetExpr* NetEUnary::eval_tree_real_()
|
|||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEUnary::eval_tree(int prune_to_width)
|
||||
NetExpr* NetEUnary::eval_tree()
|
||||
{
|
||||
eval_expr(expr_);
|
||||
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()) {
|
||||
verinum tmp (verinum::V0, val.len());
|
||||
tmp.has_sign(val.has_sign());
|
||||
val = tmp - val;
|
||||
val = verinum(tmp - val, val.len());
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
||||
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_()
|
||||
|
|
@ -1598,7 +1495,7 @@ NetEConst* NetEUReduce::eval_tree_real_()
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* NetEUReduce::eval_tree(int)
|
||||
NetEConst* NetEUReduce::eval_tree()
|
||||
{
|
||||
eval_expr(expr_);
|
||||
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;
|
||||
}
|
||||
|
||||
NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||
NetExpr* NetESFunc::eval_tree()
|
||||
{
|
||||
// assert(prune_to_width <= 0);
|
||||
// HERE
|
||||
/* If we are not targeting at least Verilog-2005, Verilog-AMS
|
||||
* 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;
|
||||
}
|
||||
|
||||
NetExpr* NetEUFunc::eval_tree(int)
|
||||
NetExpr* NetEUFunc::eval_tree()
|
||||
{
|
||||
if (need_constant_expr) {
|
||||
cerr << get_fileline() << ": sorry: constant user "
|
||||
|
|
|
|||
|
|
@ -332,8 +332,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
/* Evaluate the msb expression, if it is present. */
|
||||
PExpr*msb_expr = (*cur).second.msb_expr;
|
||||
if (msb_expr) {
|
||||
probe_expr_width(des, this, msb_expr);
|
||||
(*cur).second.msb = elab_and_eval(des, this, msb_expr, -2);
|
||||
(*cur).second.msb = elab_and_eval(des, this, msb_expr, -1);
|
||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||
cerr << (*cur).second.val->get_fileline()
|
||||
<< ": 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. */
|
||||
PExpr*lsb_expr = (*cur).second.lsb_expr;
|
||||
if (lsb_expr) {
|
||||
probe_expr_width(des, this, lsb_expr);
|
||||
(*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -2);
|
||||
(*cur).second.lsb = elab_and_eval(des, this, lsb_expr, -1);
|
||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||
cerr << (*cur).second.val->get_fileline()
|
||||
<< ": 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;
|
||||
NetScope*val_scope = (*cur).second.val_scope;
|
||||
|
||||
unsigned lval_wid = 0;
|
||||
int lv_width = -2;
|
||||
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;
|
||||
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);
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, lv_width);
|
||||
if (! expr)
|
||||
return;
|
||||
|
||||
|
|
@ -427,7 +411,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
|||
if (range_flag) {
|
||||
/* If we have a real value convert it to an integer. */
|
||||
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->set_line(*((*cur).second.val));
|
||||
(*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;
|
||||
NetScope*val_scope = (*cur).second.val_scope;
|
||||
|
||||
bool unsized_flag = false;
|
||||
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);
|
||||
NetExpr*expr = elab_and_eval(des, val_scope, val_expr, -1);
|
||||
if (! expr)
|
||||
return;
|
||||
|
||||
|
|
|
|||
276
net_expr.cc
276
net_expr.cc
|
|
@ -38,92 +38,17 @@ netenum_t*NetExpr::enumeration() const
|
|||
}
|
||||
|
||||
/*
|
||||
* Create an add/sub node from the two operands. Make a best guess of
|
||||
* the
|
||||
* Create an add/sub node from the two operands.
|
||||
*/
|
||||
NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, bool lossless_flag)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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::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
|
||||
{
|
||||
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.
|
||||
*
|
||||
* 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)
|
||||
: 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()
|
||||
|
|
@ -207,29 +92,15 @@ ivl_variable_type_t NetEBComp::expr_type() const
|
|||
return IVL_VT_BOOL;
|
||||
}
|
||||
|
||||
NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBDiv::NetEBDiv(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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::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
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -241,11 +112,9 @@ ivl_variable_type_t NetEBDiv::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBMinMax::NetEBMinMax(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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()
|
||||
|
|
@ -262,30 +131,15 @@ ivl_variable_type_t NetEBMinMax::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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::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
|
||||
{
|
||||
if (left_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -297,27 +151,15 @@ ivl_variable_type_t NetEBMult::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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::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
|
||||
{
|
||||
if (right_->expr_type() == IVL_VT_REAL)
|
||||
|
|
@ -328,13 +170,9 @@ ivl_variable_type_t NetEBPow::expr_type() const
|
|||
return IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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()
|
||||
|
|
@ -346,24 +184,9 @@ bool NetEBShift::has_width() const
|
|||
return left_->has_width();
|
||||
}
|
||||
|
||||
NetEBShift* NetEBShift::dup_expr() const
|
||||
{
|
||||
NetEBShift*result = new NetEBShift(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
result->set_line(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEConcat::NetEConcat(unsigned cnt, NetExpr* r)
|
||||
NetEConcat::NetEConcat(unsigned cnt, unsigned r)
|
||||
: parms_(cnt), repeat_(r)
|
||||
{
|
||||
if (repeat_ == 0) {
|
||||
repeat_calculated_ = true;
|
||||
repeat_value_ = 1;
|
||||
} else {
|
||||
repeat_calculated_ = false;
|
||||
}
|
||||
|
||||
expr_width(0);
|
||||
}
|
||||
|
||||
|
|
@ -383,63 +206,7 @@ void NetEConcat::set(unsigned idx, NetExpr*e)
|
|||
assert(idx < parms_.count());
|
||||
assert(parms_[idx] == 0);
|
||||
parms_[idx] = e;
|
||||
expr_width( expr_width() + 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_;
|
||||
expr_width( expr_width() + repeat_ * e->expr_width() );
|
||||
}
|
||||
|
||||
NetEConstEnum::NetEConstEnum(NetScope*s, perm_string n, netenum_t*eset, const verinum&v)
|
||||
|
|
@ -461,7 +228,7 @@ NetECReal::NetECReal(const verireal&val)
|
|||
: value_(val)
|
||||
{
|
||||
expr_width(1);
|
||||
cast_signed(true);
|
||||
cast_signed_base_(true);
|
||||
}
|
||||
|
||||
NetECReal::~NetECReal()
|
||||
|
|
@ -475,14 +242,7 @@ const verireal& NetECReal::value() const
|
|||
|
||||
bool NetECReal::has_width() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NetECReal* NetECReal::dup_expr() const
|
||||
{
|
||||
NetECReal*tmp = new NetECReal(value_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetECReal::expr_type() const
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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_);
|
||||
items_[idx].guard = e;
|
||||
items_[idx].statement = p;
|
||||
if (items_[idx].guard)
|
||||
items_[idx].guard->set_width(expr_->expr_width());
|
||||
}
|
||||
|
||||
NetDisable::NetDisable(NetScope*tgt)
|
||||
|
|
@ -169,4 +167,3 @@ const NetExpr* NetRepeat::expr() const
|
|||
{
|
||||
return expr_;
|
||||
}
|
||||
|
||||
|
|
|
|||
124
netlist.cc
124
netlist.cc
|
|
@ -2095,21 +2095,9 @@ NetExpr::~NetExpr()
|
|||
{
|
||||
}
|
||||
|
||||
bool NetExpr::has_sign() const
|
||||
{
|
||||
return signed_flag_;
|
||||
}
|
||||
|
||||
void NetExpr::cast_signed(bool flag)
|
||||
{
|
||||
signed_flag_ = flag;
|
||||
}
|
||||
|
||||
void NetExpr::expr_width(unsigned w)
|
||||
{
|
||||
// Catch underflow wrap errors.
|
||||
ivl_assert(*this, w < (UINT_MAX - 256));
|
||||
width_ = w;
|
||||
cast_signed_base_(flag);
|
||||
}
|
||||
|
||||
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
|
||||
* right expressions. Don't worry about the width of the expression
|
||||
* 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.
|
||||
* right expressions.
|
||||
*/
|
||||
NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r)
|
||||
: NetEBinary(op__, l, r)
|
||||
NetEBBits::NetEBBits(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: 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::dup_expr() const
|
||||
{
|
||||
NetEBBits*result = new NetEBBits(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r)
|
||||
NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag)
|
||||
: op_(op__), left_(l), right_(r)
|
||||
{
|
||||
// Binary expressions of all sorts are signed if both the
|
||||
// arguments are signed.
|
||||
cast_signed_base_( left_->has_sign() && right_->has_sign());
|
||||
expr_width(wid);
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetEBinary::~NetEBinary()
|
||||
|
|
@ -2163,29 +2136,15 @@ bool NetEBinary::has_width() const
|
|||
return left_->has_width() && right_->has_width();
|
||||
}
|
||||
|
||||
NetEBinary* NetEBinary::dup_expr() const
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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::dup_expr() const
|
||||
{
|
||||
NetEBLogic*result = new NetEBLogic(op_, left_->dup_expr(),
|
||||
right_->dup_expr());
|
||||
return result;
|
||||
}
|
||||
|
||||
NetEConst::NetEConst(const verinum&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
|
||||
{
|
||||
return value_;
|
||||
|
|
@ -2218,6 +2183,17 @@ ivl_variable_type_t NetEConst::expr_type() const
|
|||
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)
|
||||
: NetEConst(v), scope_(s), name_(n)
|
||||
{
|
||||
|
|
@ -2272,7 +2248,7 @@ NetESignal::NetESignal(NetNet*n)
|
|||
{
|
||||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
cast_signed(net_->get_signed());
|
||||
cast_signed_base_(net_->get_signed());
|
||||
}
|
||||
|
||||
NetESignal::NetESignal(NetNet*n, NetExpr*w)
|
||||
|
|
@ -2280,7 +2256,7 @@ NetESignal::NetESignal(NetNet*n, NetExpr*w)
|
|||
{
|
||||
net_->incr_eref();
|
||||
set_line(*n);
|
||||
cast_signed(net_->get_signed());
|
||||
cast_signed_base_(net_->get_signed());
|
||||
}
|
||||
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
if (type_is_vectorable(expr_type())) {
|
||||
// use widest result
|
||||
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());
|
||||
expr_width(wid);
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetETernary::~NetETernary()
|
||||
|
|
@ -2399,23 +2367,10 @@ ivl_variable_type_t NetETernary::expr_type() const
|
|||
return tru;
|
||||
}
|
||||
|
||||
NetEUnary::NetEUnary(char op__, NetExpr*ex)
|
||||
: NetExpr(ex->expr_width()), op_(op__), expr_(ex)
|
||||
NetEUnary::NetEUnary(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetExpr(wid), op_(op__), expr_(ex)
|
||||
{
|
||||
switch (op_) {
|
||||
case '!':
|
||||
expr_width(1);
|
||||
break;
|
||||
}
|
||||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
cast_signed_base_(signed_flag);
|
||||
}
|
||||
|
||||
NetEUnary::~NetEUnary()
|
||||
|
|
@ -2428,8 +2383,8 @@ ivl_variable_type_t NetEUnary::expr_type() const
|
|||
return expr_->expr_type();
|
||||
}
|
||||
|
||||
NetEUBits::NetEUBits(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
NetEUBits::NetEUBits(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetEUnary(op__, ex, wid, signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -2443,9 +2398,8 @@ ivl_variable_type_t NetEUBits::expr_type() const
|
|||
}
|
||||
|
||||
NetEUReduce::NetEUReduce(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
: NetEUnary(op__, ex, 1, false)
|
||||
{
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
NetEUReduce::~NetEUReduce()
|
||||
|
|
@ -2457,8 +2411,8 @@ ivl_variable_type_t NetEUReduce::expr_type() const
|
|||
return expr_->expr_type();
|
||||
}
|
||||
|
||||
NetECast::NetECast(char op__, NetExpr*ex)
|
||||
: NetEUnary(op__, ex)
|
||||
NetECast::NetECast(char op__, NetExpr*ex, unsigned wid, bool signed_flag)
|
||||
: NetEUnary(op__, ex, wid, signed_flag)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
146
netlist.h
146
netlist.h
|
|
@ -1601,12 +1601,8 @@ class NetTran : public NetNode, public IslandBranch {
|
|||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a hierarchy that serves that purpose.
|
||||
*
|
||||
* The expr_width() is the width of the expression, that accounts
|
||||
* for the widths of the sub-expressions I might have. It is up to the
|
||||
* 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.
|
||||
* The expr_width() is the width of the expression, which is calculated
|
||||
* before the expression is elaborated.
|
||||
*/
|
||||
class NetExpr : public LineInfo {
|
||||
public:
|
||||
|
|
@ -1622,27 +1618,9 @@ class NetExpr : public LineInfo {
|
|||
// How wide am I?
|
||||
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
|
||||
// signed. Unsigned expressions return false.
|
||||
bool has_sign() const;
|
||||
bool has_sign() const { return signed_flag_; }
|
||||
virtual void cast_signed(bool flag);
|
||||
|
||||
// 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
|
||||
// time knows how. Essentially, this is designed to fold
|
||||
// constants.
|
||||
//
|
||||
// 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);
|
||||
virtual NetExpr*eval_tree();
|
||||
|
||||
// Make a duplicate of myself, and subexpressions if I have
|
||||
// any. This is a deep copy operation.
|
||||
|
|
@ -1696,10 +1667,9 @@ class NetExpr : public LineInfo {
|
|||
// the expression output.
|
||||
virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
|
||||
|
||||
protected:
|
||||
void expr_width(unsigned w);
|
||||
void cast_signed_base_(bool flag) {signed_flag_ = flag; }
|
||||
void expr_width(unsigned wid) { width_ = wid; }
|
||||
void cast_signed_base_(bool flag) { signed_flag_ = flag; }
|
||||
|
||||
private:
|
||||
unsigned width_;
|
||||
|
|
@ -1723,11 +1693,15 @@ class NetEConst : public NetExpr {
|
|||
|
||||
const verinum&value() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual void cast_signed(bool sign_flag);
|
||||
virtual void cast_signed(bool flag);
|
||||
virtual bool has_width() 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 dump(ostream&) const;
|
||||
|
||||
|
|
@ -1750,7 +1724,6 @@ class NetEConstEnum : public NetEConst {
|
|||
const NetScope*scope() 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 dump(ostream&) const;
|
||||
|
||||
|
|
@ -1772,7 +1745,6 @@ class NetEConstParam : public NetEConst {
|
|||
perm_string name() 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 dump(ostream&) const;
|
||||
|
||||
|
|
@ -1794,10 +1766,6 @@ class NetECReal : public NetExpr {
|
|||
|
||||
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.
|
||||
virtual bool has_width() const;
|
||||
|
||||
|
|
@ -3129,14 +3097,13 @@ class NetEUFunc : public NetExpr {
|
|||
|
||||
const NetScope* func() const;
|
||||
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEUFunc*dup_expr() const;
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
@ -3332,7 +3299,7 @@ class NetAnalogTop : public LineInfo, public Attrib {
|
|||
class NetEBinary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEBinary(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBinary(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBinary();
|
||||
|
||||
const NetExpr*left() const { return left_; }
|
||||
|
|
@ -3340,8 +3307,6 @@ class NetEBinary : public NetExpr {
|
|||
|
||||
char op() const { return op_; }
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
|
||||
// A binary expression node only has a definite
|
||||
// self-determinable width if the operands both have definite
|
||||
// widths.
|
||||
|
|
@ -3371,15 +3336,13 @@ class NetEBinary : public NetExpr {
|
|||
class NetEBAdd : public NetEBinary {
|
||||
|
||||
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();
|
||||
|
||||
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 NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3394,15 +3357,13 @@ class NetEBAdd : public NetEBinary {
|
|||
class NetEBDiv : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBDiv(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBDiv(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBDiv();
|
||||
|
||||
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 NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3426,12 +3387,11 @@ class NetEBDiv : public NetEBinary {
|
|||
class NetEBBits : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBBits(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBBits(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBBits();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
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);
|
||||
};
|
||||
|
|
@ -3456,13 +3416,11 @@ class NetEBComp : public NetEBinary {
|
|||
NetEBComp(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBComp();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
|
||||
/* A compare expression has a definite width. */
|
||||
virtual bool has_width() const;
|
||||
virtual ivl_variable_type_t expr_type() 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);
|
||||
|
||||
|
|
@ -3492,9 +3450,8 @@ class NetEBLogic : public NetEBinary {
|
|||
NetEBLogic(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBLogic();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
@ -3511,7 +3468,7 @@ class NetEBLogic : public NetEBinary {
|
|||
class NetEBMinMax : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBMinMax(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBMinMax();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
|
@ -3525,15 +3482,13 @@ class NetEBMinMax : public NetEBinary {
|
|||
class NetEBMult : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBMult(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBMult(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBMult();
|
||||
|
||||
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 NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
private:
|
||||
|
|
@ -3546,14 +3501,13 @@ class NetEBMult : public NetEBinary {
|
|||
class NetEBPow : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBPow(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBPow(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBPow();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
@ -3572,17 +3526,15 @@ class NetEBPow : public NetEBinary {
|
|||
class NetEBShift : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBShift(char op, NetExpr*l, NetExpr*r);
|
||||
NetEBShift(char op, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag);
|
||||
~NetEBShift();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
// A shift expression only needs the left expression to have a
|
||||
// definite width to give the expression a definite width.
|
||||
virtual bool has_width() 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);
|
||||
|
||||
|
|
@ -3602,31 +3554,27 @@ class NetEBShift : public NetEBinary {
|
|||
class NetEConcat : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConcat(unsigned cnt, NetExpr* repeat =0);
|
||||
NetEConcat(unsigned cnt, unsigned repeat =1);
|
||||
~NetEConcat();
|
||||
|
||||
// Manipulate the parameters.
|
||||
void set(unsigned idx, NetExpr*e);
|
||||
|
||||
unsigned repeat();
|
||||
unsigned repeat() const;
|
||||
unsigned repeat() const { return repeat_; }
|
||||
unsigned nparms() const { return parms_.count() ; }
|
||||
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool has_width() const;
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
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 void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
svector<NetExpr*>parms_;
|
||||
NetExpr* repeat_;
|
||||
unsigned repeat_value_;
|
||||
bool repeat_calculated_;
|
||||
unsigned repeat_;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -3656,10 +3604,9 @@ class NetESelect : public NetExpr {
|
|||
ivl_select_type_t select_type() const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool set_width(unsigned w, bool last_chance =false);
|
||||
virtual bool has_width() 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 NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
virtual void dump(ostream&) const;
|
||||
|
|
@ -3757,11 +3704,10 @@ class NetESFunc : public NetExpr {
|
|||
NetExpr* parm(unsigned idx);
|
||||
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 NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
virtual netenum_t* enumeration() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
|
|
@ -3788,17 +3734,15 @@ class NetESFunc : public NetExpr {
|
|||
class NetETernary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f);
|
||||
NetETernary(NetExpr*c, NetExpr*t, NetExpr*f, unsigned wid, bool signed_flag);
|
||||
~NetETernary();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
const NetExpr*cond_expr() const;
|
||||
const NetExpr*true_expr() const;
|
||||
const NetExpr*false_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 NexusSet* nex_input(bool rem_out = true);
|
||||
|
|
@ -3837,16 +3781,14 @@ class NetETernary : public NetExpr {
|
|||
class NetEUnary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEUnary(char op, NetExpr*ex);
|
||||
NetEUnary(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetEUnary();
|
||||
|
||||
char op() const { return op_; }
|
||||
const NetExpr* expr() const { return expr_; }
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
|
||||
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 ivl_variable_type_t expr_type() const;
|
||||
|
|
@ -3865,13 +3807,13 @@ class NetEUnary : public NetExpr {
|
|||
class NetEUBits : public NetEUnary {
|
||||
|
||||
public:
|
||||
NetEUBits(char op, NetExpr*ex);
|
||||
NetEUBits(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetEUBits();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -3881,10 +3823,9 @@ class NetEUReduce : public NetEUnary {
|
|||
NetEUReduce(char op, NetExpr*ex);
|
||||
~NetEUReduce();
|
||||
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
@ -3894,7 +3835,7 @@ class NetEUReduce : public NetEUnary {
|
|||
class NetECast : public NetEUnary {
|
||||
|
||||
public:
|
||||
NetECast(char op, NetExpr*ex);
|
||||
NetECast(char op, NetExpr*ex, unsigned wid, bool signed_flag);
|
||||
~NetECast();
|
||||
|
||||
virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root);
|
||||
|
|
@ -3920,7 +3861,6 @@ class NetESignal : public NetExpr {
|
|||
~NetESignal();
|
||||
|
||||
perm_string name() const;
|
||||
virtual bool set_width(unsigned, bool last_chance);
|
||||
|
||||
virtual NetESignal* dup_expr() const;
|
||||
NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root);
|
||||
|
|
|
|||
143
netmisc.cc
143
netmisc.cc
|
|
@ -184,9 +184,9 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src)
|
|||
|
||||
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->cast_signed(expr->has_sign());
|
||||
return cast;
|
||||
}
|
||||
|
||||
|
|
@ -208,17 +208,14 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
|
|||
val = -val;
|
||||
}
|
||||
|
||||
verinum val_v (val);
|
||||
verinum val_v (val, expr->expr_width());
|
||||
val_v.has_sign(true);
|
||||
|
||||
if (expr->has_width()) {
|
||||
val_v = verinum(val_v, expr->expr_width());
|
||||
}
|
||||
|
||||
NetEConst*val_c = new NetEConst(val_v);
|
||||
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);
|
||||
|
||||
return res;
|
||||
|
|
@ -235,7 +232,8 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
|
|||
NetEConst*val_c = new NetEConst(val_v);
|
||||
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);
|
||||
|
||||
return res;
|
||||
|
|
@ -444,11 +442,10 @@ NetExpr* condition_reduce(NetExpr*expr)
|
|||
return expr;
|
||||
|
||||
verinum zero (verinum::V0, expr->expr_width());
|
||||
zero.has_sign(expr->has_sign());
|
||||
|
||||
NetEConst*ezero = new NetEConst(zero);
|
||||
ezero->set_line(*expr);
|
||||
ezero->cast_signed(expr->has_sign());
|
||||
ezero->set_width(expr->expr_width());
|
||||
|
||||
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
|
||||
cmp->set_line(*expr);
|
||||
|
|
@ -457,43 +454,130 @@ NetExpr* condition_reduce(NetExpr*expr)
|
|||
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;
|
||||
bool flag = false;
|
||||
pe->test_width(des, scope, 0, 0, expr_type, flag);
|
||||
switch (mode) {
|
||||
case PExpr::SIZED:
|
||||
return "sized";
|
||||
case PExpr::LOSSLESS:
|
||||
return "lossless";
|
||||
case PExpr::UNSIZED:
|
||||
return "unsized";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
const PExpr*pe, int expr_wid, int prune_width)
|
||||
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe, int context_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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
tmp->set_line(*expr);
|
||||
delete expr;
|
||||
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)
|
||||
|
|
@ -560,7 +644,6 @@ hname_t eval_path_component(Design*des, NetScope*scope,
|
|||
assert(index.sel == index_component_t::SEL_BIT);
|
||||
|
||||
// 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);
|
||||
ivl_assert(*index.msb, tmp);
|
||||
|
||||
|
|
|
|||
47
netmisc.h
47
netmisc.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __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
|
||||
* 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
|
||||
* it can. If the expression cannot be elaborated, return 0.
|
||||
*
|
||||
* The expr_width is the width of the context where the expression is
|
||||
* being elaborated, or -1 if the expression is self-determined width.
|
||||
*
|
||||
* The prune_width is the maximum width of the result, and is passed
|
||||
* to the eval_tree method of the expression to limit constant
|
||||
* 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.
|
||||
* The context_width is the width of the context where the expression is
|
||||
* being elaborated, or -1 if the expression is self-determined, or -2
|
||||
* if the expression is lossless self-determined (this last option is
|
||||
* treated as standard self-determined if the gn_strict_expr_width flag
|
||||
* is set).
|
||||
*/
|
||||
class PExpr;
|
||||
|
||||
extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
|
||||
const PExpr*pe, int expr_wid,
|
||||
int prune_width =-1);
|
||||
|
||||
void probe_expr_width(Design*des, NetScope*scope, PExpr*pe);
|
||||
PExpr*pe, int context_width);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* of an assignment, The data_type_lv and expr_wid_lv are the type and
|
||||
* with of the l-value, and the expr is the expression to
|
||||
* elaborate. The result is the NetExpr elaborated and evaluated.
|
||||
* (See elab_expr.cc)
|
||||
* of an assignment, The lv_type and lv_width are the type and width
|
||||
* of the l-value, and the expr is the expression to elaborate. The
|
||||
* result is the NetExpr elaborated and evaluated. (See elab_expr.cc)
|
||||
*/
|
||||
extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
||||
ivl_variable_type_t data_type_lv,
|
||||
int expr_wid_lv, PExpr*expr);
|
||||
ivl_variable_type_t lv_type,
|
||||
unsigned lv_width, PExpr*expr);
|
||||
|
||||
/*
|
||||
* Used by elaboration to suppress the sign of an operand if the other
|
||||
* is unsigned.
|
||||
*/
|
||||
extern void suppress_binary_operand_sign_if_needed(NetExpr*lp, NetExpr*rp);
|
||||
|
||||
/*
|
||||
* This procedure elaborates an expression and if the elaboration is
|
||||
* This procedure evaluates an expression and if the evaluation is
|
||||
* 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
|
||||
|
|
|
|||
486
set_width.cc
486
set_width.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -274,8 +274,8 @@ void dll_target::expr_param(const NetEConstParam*net)
|
|||
<< ivl_scope_name(scop) << endl;
|
||||
}
|
||||
assert(par);
|
||||
assert(par->value);
|
||||
expr_ = par->value;
|
||||
expr_const(net);
|
||||
expr_->u_.string_.parameter = par;
|
||||
}
|
||||
|
||||
void dll_target::expr_rparam(const NetECRealParam*net)
|
||||
|
|
|
|||
37
verinum.cc
37
verinum.cc
|
|
@ -287,7 +287,7 @@ verinum::verinum(const verinum&that)
|
|||
|
||||
verinum::verinum(const verinum&that, unsigned nbits)
|
||||
{
|
||||
string_flag_ = false;
|
||||
string_flag_ = that.string_flag_ && (that.nbits_ == nbits);
|
||||
nbits_ = nbits;
|
||||
bits_ = new V[nbits_];
|
||||
has_len_ = true;
|
||||
|
|
@ -591,6 +591,39 @@ verinum pad_to_width(const verinum&that, unsigned width)
|
|||
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
|
||||
* 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 result(verinum::V0, that.len() + shift, that.has_len());
|
||||
result.has_sign(that.has_sign());
|
||||
|
||||
for (unsigned idx = 0 ; idx < that.len() ; idx += 1)
|
||||
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,
|
||||
that.len() - shift, that.has_len());
|
||||
result.has_sign(that.has_sign());
|
||||
|
||||
for (unsigned idx = shift ; idx < that.len() ; idx += 1)
|
||||
result.set(idx-shift, that.get(idx));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __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
|
||||
* 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
|
||||
// in some way.
|
||||
bool has_len(bool flag) { has_len_ = flag; return has_len_; }
|
||||
bool has_len() const { return has_len_; }
|
||||
|
||||
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. */
|
||||
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
|
||||
needed to accurately represent the contained value, signed or not. */
|
||||
extern verinum trim_vnum(const verinum&);
|
||||
|
|
|
|||
Loading…
Reference in New Issue