Handle expression bit widths with non-fatal errors.

This commit is contained in:
steve 1999-05-27 04:13:08 +00:00
parent c1dbb56b70
commit 5ef3970714
4 changed files with 200 additions and 46 deletions

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elaborate.cc,v 1.27 1999/05/20 04:31:45 steve Exp $"
#ident "$Id: elaborate.cc,v 1.28 1999/05/27 04:13:08 steve Exp $"
#endif
/*
@ -732,8 +732,24 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path) const
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
{
return new NetEBinary(op_, left_->elaborate_expr(des, path),
right_->elaborate_expr(des, path));
bool flag;
NetEBinary*tmp = new NetEBinary(op_, left_->elaborate_expr(des, path),
right_->elaborate_expr(des, path));
tmp->set_line(*this);
switch (op_) {
case 'e':
case 'n':
flag = tmp->set_width(1);
if (flag == false) {
cerr << get_line() << ": expression bit width"
" is ambiguous." << endl;
des->errors += 1;
}
break;
default:
;
}
return tmp;
}
NetExpr* PENumber::elaborate_expr(Design*des, const string&path) const
@ -746,7 +762,9 @@ NetExpr* PENumber::elaborate_expr(Design*des, const string&path) const
NetExpr* PEString::elaborate_expr(Design*des, const string&path) const
{
return new NetEConst(value());
NetEConst*tmp = new NetEConst(value());
tmp->set_line(*this);
return tmp;
}
NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const
@ -775,6 +793,7 @@ NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const
if (msb_) {
NetExpr*ex = msb_->elaborate_expr(des, path);
NetESubSignal*ss = new NetESubSignal(node, ex);
ss->set_line(*this);
return ss;
}
assert(msb_ == 0);
@ -797,6 +816,7 @@ NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const
}
NetEMemory*node = new NetEMemory(mem, i);
node->set_line(*this);
return node;
}
@ -815,7 +835,9 @@ NetExpr* PExpr::elaborate_expr(Design*des, const string&path) const
NetExpr* PEUnary::elaborate_expr(Design*des, const string&path) const
{
return new NetEUnary(op_, expr_->elaborate_expr(des, path));
NetEUnary*tmp = new NetEUnary(op_, expr_->elaborate_expr(des, path));
tmp->set_line(*this);
return tmp;
}
NetProc* Statement::elaborate(Design*des, const string&path) const
@ -881,7 +903,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
}
assert(rval);
NetAssign*cur = new NetAssign(reg, rval);
NetAssign*cur = new NetAssign(des, reg, rval);
cur->set_line(*this);
des->add_node(cur);
@ -1042,7 +1064,8 @@ NetProc* PForStatement::elaborate(Design*des, const string&path) const
NetBlock*top = new NetBlock(NetBlock::SEQU);
NetNet*sig = des->find_signal(path+"."+id1->name());
assert(sig);
NetAssign*init = new NetAssign(sig, expr1_->elaborate_expr(des, path));
NetAssign*init = new NetAssign(des, sig,
expr1_->elaborate_expr(des, path));
top->append(init);
NetBlock*body = new NetBlock(NetBlock::SEQU);
@ -1051,7 +1074,8 @@ NetProc* PForStatement::elaborate(Design*des, const string&path) const
sig = des->find_signal(path+"."+id2->name());
assert(sig);
NetAssign*step = new NetAssign(sig, expr2_->elaborate_expr(des, path));
NetAssign*step = new NetAssign(des, sig,
expr2_->elaborate_expr(des, path));
body->append(step);
NetWhile*loop = new NetWhile(cond_->elaborate_expr(des, path), body);
@ -1169,6 +1193,9 @@ Design* elaborate(const map<string,Module*>&modules,
/*
* $Log: elaborate.cc,v $
* Revision 1.28 1999/05/27 04:13:08 steve
* Handle expression bit widths with non-fatal errors.
*
* Revision 1.27 1999/05/20 04:31:45 steve
* Much expression parsing work,
* mark continuous assigns with source line info,

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netlist.cc,v 1.27 1999/05/20 05:07:37 steve Exp $"
#ident "$Id: netlist.cc,v 1.28 1999/05/27 04:13:08 steve Exp $"
#endif
# include <cassert>
@ -270,14 +270,19 @@ NetProc::~NetProc()
{
}
NetAssign::NetAssign(NetNet*lv, NetExpr*rv)
NetAssign::NetAssign(Design*des, NetNet*lv, NetExpr*rv)
: NetNode("@assign", lv->pin_count()), rval_(rv)
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
connect(pin(idx), lv->pin(idx));
}
rval_->set_width(lv->pin_count());
bool flag = rval_->set_width(lv->pin_count());
if (flag == false) {
cerr << rv->get_line() << ": Expression bit width" <<
" conflicts with l-value bit width." << endl;
des->errors += 1;
}
}
NetAssign::~NetAssign()
@ -391,11 +396,12 @@ NetExpr::~NetExpr()
{
}
void NetExpr::set_width(unsigned w)
bool NetExpr::set_width(unsigned w)
{
cerr << typeid(*this).name() << ": set_width(unsigned) "
"not implemented." << endl;
expr_width(w);
return false;
}
void NetExpr::REF::clr()
@ -454,32 +460,29 @@ NetEBinary::~NetEBinary()
NetEBinary::NetEBinary(char op, NetExpr*l, NetExpr*r)
: op_(op), left_(l), right_(r)
{
switch (op_) {
// comparison operators return a 1-bin wide result.
case 'e':
case 'n':
expr_width(1);
right_->set_width(left_->expr_width());
break;
default:
expr_width(left_->expr_width() > right_->expr_width()
? left_->expr_width() : right_->expr_width());
break;
}
}
void NetEBinary::set_width(unsigned w)
bool NetEBinary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
/* Comparison operators allow the subexpressions to have
their own natural width. However, I do need to make
sure that the subexpressions have the same width. */
case 'e':
case 'e': /* == */
case 'n': /* != */
assert(w == 1);
expr_width(w);
flag = right_->set_width(left_->expr_width());
break;
case 'l': // left shift (<<)
case 'r': // right shift (>>)
flag = left_->set_width(w);
expr_width(w);
break;
case 'o':
case 'o': // logical or (||)
assert(w == 1);
expr_width(w);
break;
@ -488,33 +491,40 @@ void NetEBinary::set_width(unsigned w)
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 '-':
case '^':
left_->set_width(w);
right_->set_width(w);
case '&':
case '|':
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
expr_width(w);
break;
}
return flag;
}
NetEConst::~NetEConst()
{
}
void NetEConst::set_width(unsigned w)
bool NetEConst::set_width(unsigned w)
{
if (w > value_.len()) {
cerr << get_line() << ": Cannot expand " << *this
<< " to " << w << " bits." << endl;
assert(0);
return false;
}
assert(w <= value_.len());
value_ = verinum(value_, w);
expr_width(w);
return true;
}
NetEMemory::NetEMemory(NetMemory*m, NetExpr*i)
@ -532,10 +542,11 @@ void NetMemory::set_attributes(const map<string,string>&attr)
attributes_ = attr;
}
void NetEMemory::set_width(unsigned w)
bool NetEMemory::set_width(unsigned w)
{
assert(w == mem_->width());
expr_width(w);
return true;
}
NetESignal::NetESignal(NetNet*n)
@ -550,15 +561,16 @@ NetESignal::~NetESignal()
{
}
void NetESignal::set_width(unsigned w)
bool NetESignal::set_width(unsigned w)
{
if (w != pin_count()) {
cerr << get_line() << ": Width of " << w << " does not match "
<< *this << endl;
assert(0);
return false;
}
assert(w == pin_count());
expr_width(w);
return true;
}
NetESubSignal::NetESubSignal(NetESignal*sig, NetExpr*ex)
@ -576,18 +588,25 @@ NetEUnary::~NetEUnary()
expr_.clr_and_delete();
}
void NetEUnary::set_width(unsigned w)
bool NetEUnary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
case '~':
flag = expr_->set_width(w);
break;
case '&':
assert(w == 1);
case '!':
if (w != 1) {
flag = false;
}
break;
default:
case '~':
expr_->set_width(w);
flag = false;
break;
}
expr_width(w);
return flag;
}
NetLogic::NetLogic(const string&n, unsigned pins, TYPE t)
@ -1059,6 +1078,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
/*
* $Log: netlist.cc,v $
* Revision 1.28 1999/05/27 04:13:08 steve
* Handle expression bit widths with non-fatal errors.
*
* Revision 1.27 1999/05/20 05:07:37 steve
* Line number info with match error message.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netlist.h,v 1.31 1999/05/16 05:08:42 steve Exp $"
#ident "$Id: netlist.h,v 1.32 1999/05/27 04:13:08 steve Exp $"
#endif
/*
@ -34,6 +34,7 @@
# include "sref.h"
# include "LineInfo.h"
class Design;
class NetNode;
class NetProc;
class NetProcTop;
@ -335,8 +336,12 @@ class NetExpr : public LineInfo {
virtual void expr_scan(struct expr_scan_t*) const =0;
virtual void dump(ostream&) const;
// How wide am I?
unsigned expr_width() const { return width_; }
virtual void set_width(unsigned);
// Coerce the expression to have a specific width. If the
// coersion works, then return true. Otherwise, return false.
virtual bool set_width(unsigned);
public:
class REF {
@ -597,7 +602,7 @@ class NetProc {
*/
class NetAssign : public NetProc, public NetNode, public LineInfo {
public:
explicit NetAssign(NetNet*lv, NetExpr*rv);
explicit NetAssign(Design*des, NetNet*lv, NetExpr*rv);
~NetAssign();
const NetExpr*rval() const { return rval_.ref(); }
@ -909,7 +914,7 @@ class NetEBinary : public NetExpr {
char op() const { return op_; }
void set_width(unsigned w);
virtual bool set_width(unsigned w);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
@ -929,7 +934,7 @@ class NetEConst : public NetExpr {
const verinum&value() const { return value_; }
virtual void set_width(unsigned w);
virtual bool set_width(unsigned w);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
@ -955,7 +960,7 @@ class NetEUnary : public NetExpr {
char op() const { return op_; }
const NetExpr* expr() const { return expr_.ref(); }
void set_width(unsigned w);
virtual bool set_width(unsigned w);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
@ -993,7 +998,7 @@ class NetEMemory : public NetExpr {
const string& name () const { return mem_->name(); }
const NetExpr* index() const { return idx_.ref(); }
virtual void set_width(unsigned);
virtual bool set_width(unsigned);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
@ -1018,7 +1023,7 @@ class NetESignal : public NetExpr, public NetNode {
const string& name() const { return NetNode::name(); }
virtual void set_width(unsigned);
virtual bool set_width(unsigned);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void emit_node(ostream&, struct target_t*) const;
@ -1185,6 +1190,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.32 1999/05/27 04:13:08 steve
* Handle expression bit widths with non-fatal errors.
*
* Revision 1.31 1999/05/16 05:08:42 steve
* Redo constant expression detection to happen
* after parsing.

97
netlist.txt Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 1998-1999 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
*/
#ident "$Id: netlist.txt,v 1.1 1999/05/27 04:13:08 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
things work. This is just an overview.
NETLIST FORMAT
The output from the parse and elaboration steps is a "netlist" rooted
in a Design object. Parsing translates the design described in the
initial source file into a temporary symbolic "pform". Elaboration
then expands the design, resolving references and expanding
hierarchies, to produce a flattened netlist. This is the form that
optimizers and code generators use.
The design optimization processes all manipulate the netlist,
translating it to a (hopefully) better netlist after each step. The
complete netlist is then passed to the code generator, the emit
function, where the final code (in the target format) is produced.
EXPRESSIONS
Expressions are represented as a tree of NetExpr nodes. The NetExpr
base class contains the core methods that represent an expression
node, including virtual methods to help with dealing with nested
complexities of expressions.
Expressions (as expressed in the source and p-form) may also be
elaborated structurally, where it makes sense. In this case, the
expression is represented as the equivilent set of gates. For example,
continuous assignment module items are elaborated as gates instead of
as a procedural expression as it is really a structural
description. Event expressions are also elaborated structurally as
events are like devices that trigger behavioral statements.
EXPRESSION BIT WIDTH
The NetExpr class represents an expression. The expression has a bit
width that it either explicitly specified, or implied by context or
contents.
When each node of the expression is first constructed during
elaboration, it is given, by type and parameters, an idea what its
width should be. It certain cases, this is definitive, for example
with signals. In others, it is ambiguous, as with unsized constants.
As the expression is built up by elaboration, operators that combine
expressions impose bit widths of the environment or expose the bit
widths of the sub expressions. For example, the bitwise AND (&)
operator has a bit size implied by its operands, whereas the
comparison (==) operator has a bit size of 1. The building up of the
elaborated expression checks and adjusts the bit widths as the
expression is built up, util finally the context of the expression
takes the final bit width and makes any final adjustments.
The NetExpr::expr_width() method returns the calculated (or guessed)
expression width. This method will return 0 until the width is set by
calculation or context. If this method returns false, then it is up to
the context that wants the width to set one. The elaboration phase
will call the NetExpr::set_width method on an expression as soon as it
gets to a point where it believes that it knows what the width should
be.
The NetExpr::set_width(unsigned) virtual method is used by the context
of an expression node to note to the expression that the width is
determined and please adapt. If the expression cannot reasonably
adapt, it will return false. Otherwise, it will adjust bit widths and
return true.
XXXX I do not yet properly deal with cases where elaboration knows for
XXXX certain that the bit width does not matter. In this case, I
XXXX really should tell the expression node about it so that it can
XXXX pick a practical (and optimal) width.
$Log: netlist.txt,v $
Revision 1.1 1999/05/27 04:13:08 steve
Handle expression bit widths with non-fatal errors.