From b6ce313e9183bf1dcc942d67f46d05f791952582 Mon Sep 17 00:00:00 2001 From: steve Date: Sat, 9 Sep 2000 15:21:26 +0000 Subject: [PATCH] move lval elaboration to PExpr virtual methods. --- Makefile.in | 6 +- PExpr.h | 13 ++- Statement.h | 10 +-- elab_lval.cc | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++ elaborate.cc | 182 ++-------------------------------------- 5 files changed, 258 insertions(+), 186 deletions(-) create mode 100644 elab_lval.cc diff --git a/Makefile.in b/Makefile.in index 1a7359ea2..20e23af2b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.64 2000/09/02 20:54:20 steve Exp $" +#ident "$Id: Makefile.in,v 1.65 2000/09/09 15:21:26 steve Exp $" # # SHELL = /bin/sh @@ -73,8 +73,8 @@ TT = t-dll.o t-null.o t-verilog.o t-vvm.o t-xnf.o FF = nodangle.o synth.o syn-rules.o xnfio.o O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \ -elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o eval_tree.o \ -expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ +elab_lval.o elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o \ +eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ mangle.o netlist.o net_assign.o \ net_design.o net_event.o net_force.o net_link.o net_proc.o net_scope.o \ net_udp.o \ diff --git a/PExpr.h b/PExpr.h index 77ed22c45..5417a3b11 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: PExpr.h,v 1.42 2000/09/07 22:38:13 steve Exp $" +#ident "$Id: PExpr.h,v 1.43 2000/09/09 15:21:26 steve Exp $" #endif # include @@ -75,6 +75,10 @@ class PExpr : public LineInfo { // restricted for use as l-values of continuous assignments. virtual NetNet* elaborate_lnet(Design*des, const string&path) const; + // Expressions that can be in the l-value of procedural + // assignments can be elaborated with this method. + virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const; + // This attempts to evaluate a constant expression, and return // a verinum as a result. If the expression cannot be // evaluated, return 0. @@ -115,6 +119,7 @@ class PEConcat : public PExpr { Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*) const; virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const; + virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const; virtual bool is_constant(Module*) const; private: @@ -160,6 +165,9 @@ class PEIdent : public PExpr { // Identifiers are allowed (with restrictions) is assign l-values. virtual NetNet* elaborate_lnet(Design*des, const string&path) const; + // Identifiers are also allowed as procedural assignment l-values. + virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const; + // Structural r-values are OK. virtual NetNet* elaborate_net(Design*des, const string&path, unsigned lwidth, @@ -384,6 +392,9 @@ class PECallFunction : public PExpr { /* * $Log: PExpr.h,v $ + * Revision 1.43 2000/09/09 15:21:26 steve + * move lval elaboration to PExpr virtual methods. + * * Revision 1.42 2000/09/07 22:38:13 steve * Support unary + and - in constants. * diff --git a/Statement.h b/Statement.h index 8631e483a..bc2926fb4 100644 --- a/Statement.h +++ b/Statement.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: Statement.h,v 1.28 2000/09/03 17:58:35 steve Exp $" +#ident "$Id: Statement.h,v 1.29 2000/09/09 15:21:26 steve Exp $" #endif # include @@ -94,11 +94,6 @@ class PAssign_ : public Statement { const PExpr* rval() const { return rval_; } protected: -#if 0 - NetNet*elaborate_lval(Design*, const string&path, - unsigned&lsb, unsigned&msb, - NetExpr*&mux) const; -#endif NetAssign_* elaborate_lval(Design*, NetScope*scope) const; PDelays delay_; @@ -458,6 +453,9 @@ class PWhile : public Statement { /* * $Log: Statement.h,v $ + * Revision 1.29 2000/09/09 15:21:26 steve + * move lval elaboration to PExpr virtual methods. + * * Revision 1.28 2000/09/03 17:58:35 steve * Change elaborate_lval to return NetAssign_ objects. * diff --git a/elab_lval.cc b/elab_lval.cc new file mode 100644 index 000000000..aad866511 --- /dev/null +++ b/elab_lval.cc @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2000 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 + */ +#if !defined(WINNT) && !defined(macintosh) +#ident "$Id: elab_lval.cc,v 1.1 2000/09/09 15:21:26 steve Exp $" +#endif + +# include "PExpr.h" +# include "netlist.h" + +/* + * These methods generate a NetAssign_ object for the l-value of the + * assignemnt. This is common code for the = and <= statements. + * + * What gets generated depends on the structure of the l-value. If the + * l-value is a simple name (i.e. foo <= ) the the NetAssign_ + * is created the width of the foo reg and connected to all the + * bits. + * + * If there is a part select (i.e. foo[3:1] <= ) the NetAssign_ + * is made only as wide as it needs to be (3 bits in this example) and + * connected to the correct bits of foo. A constant bit select is a + * special case of the part select. + * + * If the bit-select is non-constant (i.e. foo[] = ) the + * NetAssign_ is made wide enough to connect to all the bits of foo, + * then the mux expression is elaborated and attached to the + * NetAssign_ node as a b_mux value. The target must interpret the + * presense of a bmux value as taking a single bit and assigning it to + * the bit selected by the bmux expression. + * + * If the l-value expression is non-trivial, but can be fully + * evaluated at compile time (meaning any bit selects are constant) + * then elaboration will make a single NetAssign_ that connects to a + * synthetic reg that in turn connects to all the proper pins of the + * l-value. + * + * This last case can turn up in statements like: {a, b[1]} = c; + * rather then create a NetAssign_ for each item in the contatenation, + * elaboration makes a single NetAssign_ and connects it up properly. + */ + + +/* + * The default interpretation of an l-value to a procedural assignment + * is to try to make a net elaboration, and see if the result is + * suitable for assignment. + */ +NetAssign_* PExpr::elaborate_lval(Design*des, NetScope*scope) const +{ + NetNet*ll = elaborate_net(des, scope->name(), 0, 0, 0, 0); + if (ll == 0) { + cerr << get_line() << ": Assignment l-value too complex." + << endl; + return 0; + } + + NetAssign_*lv = new NetAssign_(scope->local_symbol(), ll->pin_count()); + for (unsigned idx = 0 ; idx < ll->pin_count() ; idx += 1) + connect(lv->pin(idx), ll->pin(idx)); + des->add_node(lv); + return lv; +} + +/* + * Concatenation expressions can appear as l-values. Handle them here. + * XXXX For now, cheat and use elaborate_net to cope. + */ +NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const +{ + NetNet*ll = elaborate_net(des, scope->name(), 0, 0, 0, 0, + Link::STRONG, Link::STRONG); + if (ll == 0) { + cerr << get_line() << ": Assignment l-value too complex." + << endl; + return 0; + } + + NetAssign_*lv = new NetAssign_(scope->local_symbol(), ll->pin_count()); + for (unsigned idx = 0 ; idx < ll->pin_count() ; idx += 1) + connect(lv->pin(idx), ll->pin(idx)); + des->add_node(lv); + return lv; +} + +/* + * Handle the ident as an l-value. This includes bit and part selects + * of that ident. + */ +NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const +{ + /* Get the signal referenced by the identifier, and make sure + it is a register. (Wires are not allows in this context. */ + NetNet*reg = des->find_signal(scope, name()); + + if (reg == 0) { + cerr << get_line() << ": error: Could not match signal ``" << + name() << "'' in ``" << scope->name() << "''" << endl; + des->errors += 1; + return 0; + } + assert(reg); + + if ((reg->type() != NetNet::REG) && (reg->type() != NetNet::INTEGER)) { + cerr << get_line() << ": error: " << name() << + " is not a reg in " << scope->name() << "." << endl; + des->errors += 1; + return 0; + } + + long msb, lsb; + NetExpr*mux; + + if (msb_ && lsb_) { + /* This handles part selects. In this case, there are + two bit select expressions, and both must be + constant. Evaluate them and pass the results back to + the caller. */ + verinum*vl = lsb_->eval_const(des, scope->name()); + if (vl == 0) { + cerr << lsb_->get_line() << ": error: " + "Part select expressions must be constant: " + << *lsb_; + des->errors += 1; + return 0; + } + verinum*vm = msb_->eval_const(des, scope->name()); + if (vl == 0) { + cerr << msb_->get_line() << ": error: " + "Part select expressions must be constant: " + << *msb_; + des->errors += 1; + return 0; + } + + msb = vm->as_long(); + lsb = vl->as_long(); + mux = 0; + + } else if (msb_) { + + /* If there is only a single select expression, it is a + bit select. Evaluate the constant value and treat it + as a part select with a bit width of 1. If the + expression it not constant, then return the + expression as a mux. */ + assert(lsb_ == 0); + verinum*v = msb_->eval_const(des, scope->name()); + if (v == 0) { + NetExpr*m = msb_->elaborate_expr(des, scope); + assert(m); + msb = 0; + lsb = 0; + mux = m; + + } else { + + msb = v->as_long(); + lsb = v->as_long(); + mux = 0; + } + + } else { + + /* No select expressions, so presume a part select the + width of the register. */ + + assert(msb_ == 0); + assert(lsb_ == 0); + msb = reg->msb(); + lsb = reg->lsb(); + mux = 0; + } + + + NetAssign_*lv; + if (mux) { + + /* If there is a non-constant bit select, make a + NetAssign_ the width of the target reg and attach a + bmux to select the target bit. */ + unsigned wid = reg->pin_count(); + lv = new NetAssign_(scope->local_symbol(), wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) + connect(lv->pin(idx), reg->pin(idx)); + + lv->set_bmux(mux); + + } else { + + /* If the bit/part select is constant, then make the + NetAssign_ only as wide as it needs to be and connect + only to the selected bits of the reg. */ + unsigned wid = (msb >= lsb)? (msb-lsb+1) : (lsb-msb+1); + assert(wid <= reg->pin_count()); + + lv = new NetAssign_(scope->local_symbol(), wid); + unsigned off = reg->sb_to_idx(lsb); + assert((off+wid) <= reg->pin_count()); + for (unsigned idx = 0 ; idx < wid ; idx += 1) + connect(lv->pin(idx), reg->pin(idx+off)); + + } + + + des->add_node(lv); + + return lv; +} + +/* + * $Log: elab_lval.cc,v $ + * Revision 1.1 2000/09/09 15:21:26 steve + * move lval elaboration to PExpr virtual methods. + * + */ + diff --git a/elaborate.cc b/elaborate.cc index f856d28ee..22fbd1aca 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: elaborate.cc,v 1.188 2000/09/07 01:29:44 steve Exp $" +#ident "$Id: elaborate.cc,v 1.189 2000/09/09 15:21:26 steve Exp $" #endif /* @@ -761,182 +761,9 @@ NetProc* PAssign::assign_to_memory_(NetMemory*mem, PExpr*ix, return am; } -/* - * This method generates a NetAssign_ object for the l-value of the - * assignemnt. This is common code for the = and <= statements. - * - * What gets generated depends on the structure of the l-value. If the - * l-value is a simple name (i.e. foo <= ) the the NetAssign_ - * is created the width of the foo reg and connected to all the - * bits. - * - * If there is a part select (i.e. foo[3:1] <= ) the NetAssign_ - * is made only as wide as it needs to be (3 bits in this example) and - * connected to the correct bits of foo. A constant bit select is a - * special case of the part select. - * - * If the bit-select is non-constant (i.e. foo[] = ) the - * NetAssign_ is made wide enough to connect to all the bits of foo, - * then the mux expression is elaborated and attached to the - * NetAssign_ node as a b_mux value. The target must interpret the - * presense of a bmux value as taking a single bit and assigning it to - * the bit selected by the bmux expression. - * - * If the l-value expression is non-trivial, but can be fully - * evaluated at compile time (meaning any bit selects are constant) - * then elaboration will make a single NetAssign_ that connects to a - * synthetic reg that in turn connects to all the proper pins of the - * l-value. - * - * This last case can turn up in statements like: {a, b[1]} = c; - * rather then create a NetAssign_ for each item in the contatenation, - * elaboration makes a single NetAssign_ and connects it up properly. - */ -NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope)const +NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const { - - /* Get the l-value, and assume that it is an identifier. */ - const PEIdent*id = dynamic_cast(lval()); - - /* If the l-value is not a reg, then make a structural - elaboration. Make a synthetic register that connects to the - generated circuit and return that as the l-value. */ - if (id == 0) { - NetNet*ll = lval_->elaborate_net(des, scope->name(), 0, 0, 0, 0); - if (ll == 0) { - cerr << get_line() << ": Assignment l-value too complex." - << endl; - return 0; - } - - NetAssign_*lv = new NetAssign_(scope->local_symbol(), - ll->pin_count()); - for (unsigned idx = 0 ; idx < ll->pin_count() ; idx += 1) - connect(lv->pin(idx), ll->pin(idx)); - des->add_node(lv); - return lv; - } - - assert(id); - - /* Get the signal referenced by the identifier, and make sure - it is a register. (Wires are not allows in this context. */ - NetNet*reg = des->find_signal(scope, id->name()); - - if (reg == 0) { - cerr << get_line() << ": error: Could not match signal ``" << - id->name() << "'' in ``" << scope->name() << "''" << endl; - des->errors += 1; - return 0; - } - assert(reg); - - if ((reg->type() != NetNet::REG) && (reg->type() != NetNet::INTEGER)) { - cerr << get_line() << ": error: " << *lval() << - " is not a reg." << endl; - des->errors += 1; - return 0; - } - - long msb, lsb; - NetExpr*mux; - - if (id->msb_ && id->lsb_) { - /* This handles part selects. In this case, there are - two bit select expressions, and both must be - constant. Evaluate them and pass the results back to - the caller. */ - verinum*vl = id->lsb_->eval_const(des, scope->name()); - if (vl == 0) { - cerr << id->lsb_->get_line() << ": error: " - "Expression must be constant in this context: " - << *id->lsb_; - des->errors += 1; - return 0; - } - verinum*vm = id->msb_->eval_const(des, scope->name()); - if (vl == 0) { - cerr << id->msb_->get_line() << ": error: " - "Expression must be constant in this context: " - << *id->msb_; - des->errors += 1; - return 0; - } - - msb = vm->as_ulong(); - lsb = vl->as_ulong(); - mux = 0; - - } else if (id->msb_) { - - /* If there is only a single select expression, it is a - bit select. Evaluate the constant value and treat it - as a part select with a bit width of 1. If the - expression it not constant, then return the - expression as a mux. */ - assert(id->lsb_ == 0); - verinum*v = id->msb_->eval_const(des, scope->name()); - if (v == 0) { - NetExpr*m = id->msb_->elaborate_expr(des, scope); - assert(m); - msb = 0; - lsb = 0; - mux = m; - - } else { - - msb = v->as_ulong(); - lsb = v->as_ulong(); - mux = 0; - } - - } else { - - /* No select expressions, so presume a part select the - width of the register. */ - - assert(id->msb_ == 0); - assert(id->lsb_ == 0); - msb = reg->msb(); - lsb = reg->lsb(); - mux = 0; - } - - - NetAssign_*lv; - if (mux) { - - /* If there is a non-constant bit select, make a - NetAssign_ the width of the target reg and attach a - bmux to select the target bit. */ - unsigned wid = reg->pin_count(); - lv = new NetAssign_(scope->local_symbol(), wid); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) - connect(lv->pin(idx), reg->pin(idx)); - - lv->set_bmux(mux); - - } else { - - /* If the bit/part select is constant, then make the - NetAssign_ only as wide as it needs to be and connect - only to the selected bits of the reg. */ - unsigned wid = (msb >= lsb)? (msb-lsb+1) : (lsb-msb+1); - assert(wid <= reg->pin_count()); - - lv = new NetAssign_(scope->local_symbol(), wid); - unsigned off = reg->sb_to_idx(lsb); - assert((off+wid) <= reg->pin_count()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) - connect(lv->pin(idx), reg->pin(idx+off)); - - } - - - des->add_node(lv); - - return lv; + return lval_->elaborate_lval(des, scope); } NetProc* PAssign::elaborate(Design*des, const string&path) const @@ -2430,6 +2257,9 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.189 2000/09/09 15:21:26 steve + * move lval elaboration to PExpr virtual methods. + * * Revision 1.188 2000/09/07 01:29:44 steve * Fix bit padding of assign signal-to-signal *