diff --git a/elaborate.cc b/elaborate.cc index 9f6d76294..27b7a011d 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) -#ident "$Id: elaborate.cc,v 1.35 1999/06/06 23:07:43 steve Exp $" +#ident "$Id: elaborate.cc,v 1.36 1999/06/07 02:23:31 steve Exp $" #endif /* @@ -794,6 +794,8 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const switch (op_) { case 'e': case 'n': + case '<': + case '>': flag = tmp->set_width(1); if (flag == false) { cerr << get_line() << ": expression bit width" @@ -1367,6 +1369,9 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.36 1999/06/07 02:23:31 steve + * Support non-blocking assignment down to vvm. + * * Revision 1.35 1999/06/06 23:07:43 steve * Drop degenerate blocks. * diff --git a/netlist.cc b/netlist.cc index a8fa86615..0c50e946f 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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.32 1999/06/06 20:45:38 steve Exp $" +#ident "$Id: netlist.cc,v 1.33 1999/06/07 02:23:31 steve Exp $" #endif # include @@ -277,6 +277,7 @@ NetAssign::NetAssign(Design*des, NetNet*lv, NetExpr*rv) : NetNode("@assign", lv->pin_count()), rval_(rv) { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { + pin(idx).set_dir(NetObj::Link::OUTPUT); connect(pin(idx), lv->pin(idx)); } @@ -295,6 +296,10 @@ NetAssign::~NetAssign() NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w, NetExpr*rv) : NetNode(n, w), rval_(rv), bmux_(0) { + for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { + pin(idx).set_dir(NetObj::Link::OUTPUT); + } + bool flag = rval_->set_width(w); if (flag == false) { cerr << rv->get_line() << ": Expression bit width" << @@ -307,6 +312,10 @@ NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w, NetExpr*mu, NetExpr*rv) : NetNode(n, w), rval_(rv), bmux_(mu) { + for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { + pin(idx).set_dir(NetObj::Link::OUTPUT); + } + bool flag = rval_->set_width(1); if (flag == false) { cerr << rv->get_line() << ": Expression bit width" << @@ -462,6 +471,7 @@ bool NetEBinary::set_width(unsigned w) sure that the subexpressions have the same width. */ case 'e': /* == */ case 'n': /* != */ + case '<': /* < */ assert(w == 1); expr_width(w); flag = left_->set_width(right_->expr_width()); @@ -1154,6 +1164,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.33 1999/06/07 02:23:31 steve + * Support non-blocking assignment down to vvm. + * * Revision 1.32 1999/06/06 20:45:38 steve * Add parse and elaboration of non-blocking assignments, * Replace list with an svector version, diff --git a/t-vvm.cc b/t-vvm.cc index ff478eeee..916769001 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.21 1999/05/12 04:03:19 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.22 1999/06/07 02:23:31 steve Exp $" #endif # include @@ -45,12 +45,14 @@ class target_vvm : public target_t { virtual void logic(ostream&os, const NetLogic*); virtual void bufz(ostream&os, const NetBUFZ*); virtual void udp(ostream&os, const NetUDP*); + virtual void net_assign_nb(ostream&os, const NetAssignNB*); virtual void net_const(ostream&os, const NetConst*); virtual void net_esignal(ostream&os, const NetESignal*); virtual void net_event(ostream&os, const NetNEvent*); virtual void start_process(ostream&os, const NetProcTop*); virtual void proc_assign(ostream&os, const NetAssign*); virtual void proc_assign_mem(ostream&os, const NetAssignMem*); + virtual void proc_assign_nb(ostream&os, const NetAssignNB*); virtual void proc_block(ostream&os, const NetBlock*); virtual void proc_case(ostream&os, const NetCase*net); virtual void proc_condit(ostream&os, const NetCondit*); @@ -215,6 +217,10 @@ void vvm_proc_rval::expr_binary(const NetEBinary*expr) os_ << setw(indent_) << "" << result << " = vvm_binop_ne(" << lres << "," << rres << ");" << endl; break; + case '<': + os_ << setw(indent_) << "" << result << " = vvm_binop_lt(" + << lres << "," << rres << ");" << endl; + break; case 'o': os_ << setw(indent_) << "" << result << " = vvm_binop_lor(" << lres << "," << rres << ");" << endl; @@ -547,6 +553,109 @@ void target_vvm::udp(ostream&os, const NetUDP*gate) } +/* + * The non-blocking assignment works by creating an event to do the + * assignment at the right time. The value to be assigned is saved in + * the event and the event function performs the actual assignment. + * + * The net part of the assign generates a type ot represent the + * assignment. Creating instances of this event will be dealt with + * later. + */ +void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net) +{ + const string name = mangle(net->name()); + unsigned iwid = net->rval()->expr_width(); + os << "class " << name << " : public vvm_event {" << endl; + os << " public:" << endl; + + if (net->bmux()) { + os << " " << name << "(vvm_simulation*s, const vvm_bitset_t<" + << iwid << ">&v, unsigned idx)" << endl; + os << " : sim_(s), value_(v), idx_(idx) { }" << endl; + } else { + os << " " << name << "(vvm_simulation*s, const vvm_bitset_t<" + << iwid << ">&v)" << endl; + os << " : sim_(s), value_(v) { }" << endl; + } + os << " void event_function();" << endl; + + os << " private:" << endl; + os << " vvm_simulation*sim_;" << endl; + os << " vvm_bitset_t<" << iwid << ">value_;" << endl; + + if (net->bmux()) + os << " unsigned idx_;" << endl; + + os << "};" << endl; + + + /* Write the event_function to do the actual assignment. */ + + delayed << "void " << name << "::event_function()" << endl; + delayed << "{" << endl; + + if (net->bmux()) { + /* If the assignment is to a single bit (with a mux) + then write a switch statement that selects which pins + to write to. */ + delayed << " switch (idx_) {" << endl; + for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { + const NetObj*cur; + unsigned pin; + + delayed << " case " << idx << ":" << endl; + for (net->pin(idx).next_link(cur, pin) + ; net->pin(idx) != cur->pin(pin) + ; cur->pin(pin).next_link(cur, pin)) { + + // Skip output only pins. + if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT) + continue; + + // Skip signals, I'll hit them when I handle the + // NetESignal nodes. + if (dynamic_cast(cur)) + continue; + + delayed << " " << mangle(cur->name()) << + ".set(sim_, " << pin << ", value_[0]);" << endl; + } + + delayed << " break;" << endl; + } + delayed << " }" << endl; + + } else { + + /* If there is no BMUX, then write all the bits of the + value to all the pins. */ + for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) { + const NetObj*cur; + unsigned pin; + + for (net->pin(idx).next_link(cur, pin) + ; net->pin(idx) != cur->pin(pin) + ; cur->pin(pin).next_link(cur, pin)) { + + // Skip output only pins. + if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT) + continue; + + // Skip signals, I'll hit them when I handle the + // NetESignal nodes. + if (dynamic_cast(cur)) + continue; + + delayed << " " << mangle(cur->name()) << + ".set(sim_, " << pin << ", value_[" << + idx << "]);" << endl; + } + } + } + delayed << "}" << endl; +} + /* * The NetConst is a synthetic device created to represent constant * values. I represent them in the output as a vvm_bufz object that @@ -685,8 +794,8 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net) ; net->pin(idx) != cur->pin(pin) ; cur->pin(pin).next_link(cur, pin)) { - // Skip NetAssign nodes. They are output-only. - if (dynamic_cast(cur)) + // Skip output only pins. + if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT) continue; // Skip signals, I'll hit them when I handle the @@ -712,6 +821,22 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem) << "[" << index << ".as_unsigned()] = " << rval << ";" << endl; } +void target_vvm::proc_assign_nb(ostream&os, const NetAssignNB*net) +{ + string rval = emit_proc_rval(os, 8, net->rval()); + + if (net->bmux()) { + string bval = emit_proc_rval(os, 8, net->bmux()); + os << " sim_->insert_event(0, new " << + mangle(net->name()) << "(sim_, " << rval << ", " << bval + << ".as_unsigned()));" << endl; + + } else { + os << " sim_->insert_event(0, new " << + mangle(net->name()) << "(sim_, " << rval << "));" << endl; + } +} + void target_vvm::proc_block(ostream&os, const NetBlock*net) { net->emit_recurse(os, this); @@ -852,13 +977,51 @@ void target_vvm::proc_task(ostream&os, const NetTask*net) } } +/* + * The while loop is implemented by making each iteration one [or + * more] basic block and letting the loop condition skip to the block + * after or continue with the current block. This is similar to how + * the condit is handled. The basic structure of the loop is as follows: + * + * head_step: + * evaluate condition + * if false, go to out_step + * execute body + * + * out_step: + */ void target_vvm::proc_while(ostream&os, const NetWhile*net) { - os << " for (;;) {" << endl; - string expr = emit_proc_rval(os, 12, net->expr()); - os << " if (" << expr << "[0] != V1) break;" << endl; - net->emit_proc_recurse(os, this); + unsigned head_step = ++thread_step_; + unsigned out_step = ++thread_step_; + + os << " step_ = &step_" << head_step << "_;" << endl; + os << " return true;" << endl; + os << " }" << endl; + + os << " // " << net->expr()->get_line() << + ": top of while condition." << endl; + os << " bool step_" << head_step << "_()" << endl; + os << " {" << endl; + + string expr = emit_proc_rval(os, 8, net->expr()); + os << " // " << net->expr()->get_line() << + ": test while condition." << endl; + os << " if (" << expr << "[0] != V1) {" << endl; + os << " step_ = &step_" << out_step << "_;" << endl; + os << " return true;" << endl; os << " }" << endl; + + net->emit_proc_recurse(os, this); + + os << " // " << net->expr()->get_line() << + ": end of while loop." << endl; + os << " step_ = &step_" << head_step << "_;" << endl; + os << " return true;" << endl; + os << " }" << endl; + + os << " bool step_" << out_step << "_()" << endl; + os << " {" << endl; } /* @@ -958,6 +1121,9 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.22 1999/06/07 02:23:31 steve + * Support non-blocking assignment down to vvm. + * * Revision 1.21 1999/05/12 04:03:19 steve * emit NetAssignMem objects in vvm target. * diff --git a/vvm/vvm_func.h b/vvm/vvm_func.h index e4bbc811a..fb0d9db43 100644 --- a/vvm/vvm_func.h +++ b/vvm/vvm_func.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_func.h,v 1.4 1999/05/01 20:43:55 steve Exp $" +#ident "$Id: vvm_func.h,v 1.5 1999/06/07 02:23:31 steve Exp $" #endif # include "vvm.h" @@ -248,6 +248,13 @@ vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t&l, return result; } +template +vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t&l, + const vvm_bitset_t&r) +{ + assert(0); // Not implemented yet. +} + template vvm_bitset_t<1> vvm_binop_land(const vvm_bitset_t&l, const vvm_bitset_t&r) @@ -270,6 +277,9 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t&l, /* * $Log: vvm_func.h,v $ + * Revision 1.5 1999/06/07 02:23:31 steve + * Support non-blocking assignment down to vvm. + * * Revision 1.4 1999/05/01 20:43:55 steve * Handle wide events, such as @(a) where a has * many bits in it.