Support non-blocking assignment down to vvm.
This commit is contained in:
parent
2f69505953
commit
4932dc7c5e
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT)
|
#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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -794,6 +794,8 @@ NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'n':
|
case 'n':
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
flag = tmp->set_width(1);
|
flag = tmp->set_width(1);
|
||||||
if (flag == false) {
|
if (flag == false) {
|
||||||
cerr << get_line() << ": expression bit width"
|
cerr << get_line() << ": expression bit width"
|
||||||
|
|
@ -1367,6 +1369,9 @@ Design* elaborate(const map<string,Module*>&modules,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: elaborate.cc,v $
|
* $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
|
* Revision 1.35 1999/06/06 23:07:43 steve
|
||||||
* Drop degenerate blocks.
|
* Drop degenerate blocks.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
15
netlist.cc
15
netlist.cc
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT)
|
#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
|
#endif
|
||||||
|
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
@ -277,6 +277,7 @@ NetAssign::NetAssign(Design*des, NetNet*lv, NetExpr*rv)
|
||||||
: NetNode("@assign", lv->pin_count()), rval_(rv)
|
: NetNode("@assign", lv->pin_count()), rval_(rv)
|
||||||
{
|
{
|
||||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||||
|
pin(idx).set_dir(NetObj::Link::OUTPUT);
|
||||||
connect(pin(idx), lv->pin(idx));
|
connect(pin(idx), lv->pin(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,6 +296,10 @@ NetAssign::~NetAssign()
|
||||||
NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w, NetExpr*rv)
|
NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w, NetExpr*rv)
|
||||||
: NetNode(n, w), rval_(rv), bmux_(0)
|
: 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);
|
bool flag = rval_->set_width(w);
|
||||||
if (flag == false) {
|
if (flag == false) {
|
||||||
cerr << rv->get_line() << ": Expression bit width" <<
|
cerr << rv->get_line() << ": Expression bit width" <<
|
||||||
|
|
@ -307,6 +312,10 @@ NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w,
|
||||||
NetExpr*mu, NetExpr*rv)
|
NetExpr*mu, NetExpr*rv)
|
||||||
: NetNode(n, w), rval_(rv), bmux_(mu)
|
: 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);
|
bool flag = rval_->set_width(1);
|
||||||
if (flag == false) {
|
if (flag == false) {
|
||||||
cerr << rv->get_line() << ": Expression bit width" <<
|
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. */
|
sure that the subexpressions have the same width. */
|
||||||
case 'e': /* == */
|
case 'e': /* == */
|
||||||
case 'n': /* != */
|
case 'n': /* != */
|
||||||
|
case '<': /* < */
|
||||||
assert(w == 1);
|
assert(w == 1);
|
||||||
expr_width(w);
|
expr_width(w);
|
||||||
flag = left_->set_width(right_->expr_width());
|
flag = left_->set_width(right_->expr_width());
|
||||||
|
|
@ -1154,6 +1164,9 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: netlist.cc,v $
|
* $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
|
* Revision 1.32 1999/06/06 20:45:38 steve
|
||||||
* Add parse and elaboration of non-blocking assignments,
|
* Add parse and elaboration of non-blocking assignments,
|
||||||
* Replace list<PCase::Item*> with an svector version,
|
* Replace list<PCase::Item*> with an svector version,
|
||||||
|
|
|
||||||
180
t-vvm.cc
180
t-vvm.cc
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT)
|
#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
|
#endif
|
||||||
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
|
@ -45,12 +45,14 @@ class target_vvm : public target_t {
|
||||||
virtual void logic(ostream&os, const NetLogic*);
|
virtual void logic(ostream&os, const NetLogic*);
|
||||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||||
virtual void udp(ostream&os, const NetUDP*);
|
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_const(ostream&os, const NetConst*);
|
||||||
virtual void net_esignal(ostream&os, const NetESignal*);
|
virtual void net_esignal(ostream&os, const NetESignal*);
|
||||||
virtual void net_event(ostream&os, const NetNEvent*);
|
virtual void net_event(ostream&os, const NetNEvent*);
|
||||||
virtual void start_process(ostream&os, const NetProcTop*);
|
virtual void start_process(ostream&os, const NetProcTop*);
|
||||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||||
virtual void proc_assign_mem(ostream&os, const NetAssignMem*);
|
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_block(ostream&os, const NetBlock*);
|
||||||
virtual void proc_case(ostream&os, const NetCase*net);
|
virtual void proc_case(ostream&os, const NetCase*net);
|
||||||
virtual void proc_condit(ostream&os, const NetCondit*);
|
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("
|
os_ << setw(indent_) << "" << result << " = vvm_binop_ne("
|
||||||
<< lres << "," << rres << ");" << endl;
|
<< lres << "," << rres << ");" << endl;
|
||||||
break;
|
break;
|
||||||
|
case '<':
|
||||||
|
os_ << setw(indent_) << "" << result << " = vvm_binop_lt("
|
||||||
|
<< lres << "," << rres << ");" << endl;
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
os_ << setw(indent_) << "" << result << " = vvm_binop_lor("
|
os_ << setw(indent_) << "" << result << " = vvm_binop_lor("
|
||||||
<< lres << "," << rres << ");" << endl;
|
<< 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<const NetNet*>(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<const NetNet*>(cur))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
delayed << " " << mangle(cur->name()) <<
|
||||||
|
".set(sim_, " << pin << ", value_[" <<
|
||||||
|
idx << "]);" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delayed << "}" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The NetConst is a synthetic device created to represent constant
|
* The NetConst is a synthetic device created to represent constant
|
||||||
* values. I represent them in the output as a vvm_bufz object that
|
* 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)
|
; net->pin(idx) != cur->pin(pin)
|
||||||
; cur->pin(pin).next_link(cur, pin)) {
|
; cur->pin(pin).next_link(cur, pin)) {
|
||||||
|
|
||||||
// Skip NetAssign nodes. They are output-only.
|
// Skip output only pins.
|
||||||
if (dynamic_cast<const NetAssign*>(cur))
|
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip signals, I'll hit them when I handle the
|
// 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;
|
<< "[" << 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)
|
void target_vvm::proc_block(ostream&os, const NetBlock*net)
|
||||||
{
|
{
|
||||||
net->emit_recurse(os, this);
|
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)
|
void target_vvm::proc_while(ostream&os, const NetWhile*net)
|
||||||
{
|
{
|
||||||
os << " for (;;) {" << endl;
|
unsigned head_step = ++thread_step_;
|
||||||
string expr = emit_proc_rval(os, 12, net->expr());
|
unsigned out_step = ++thread_step_;
|
||||||
os << " if (" << expr << "[0] != V1) break;" << endl;
|
|
||||||
net->emit_proc_recurse(os, this);
|
os << " step_ = &step_" << head_step << "_;" << endl;
|
||||||
|
os << " return true;" << endl;
|
||||||
os << " }" << 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 $
|
* $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
|
* Revision 1.21 1999/05/12 04:03:19 steve
|
||||||
* emit NetAssignMem objects in vvm target.
|
* emit NetAssignMem objects in vvm target.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#if !defined(WINNT)
|
#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
|
#endif
|
||||||
|
|
||||||
# include "vvm.h"
|
# include "vvm.h"
|
||||||
|
|
@ -248,6 +248,13 @@ vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <unsigned LW, unsigned RW>
|
||||||
|
vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t<LW>&l,
|
||||||
|
const vvm_bitset_t<RW>&r)
|
||||||
|
{
|
||||||
|
assert(0); // Not implemented yet.
|
||||||
|
}
|
||||||
|
|
||||||
template <unsigned LW, unsigned RW>
|
template <unsigned LW, unsigned RW>
|
||||||
vvm_bitset_t<1> vvm_binop_land(const vvm_bitset_t<LW>&l,
|
vvm_bitset_t<1> vvm_binop_land(const vvm_bitset_t<LW>&l,
|
||||||
const vvm_bitset_t<RW>&r)
|
const vvm_bitset_t<RW>&r)
|
||||||
|
|
@ -270,6 +277,9 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: vvm_func.h,v $
|
* $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
|
* Revision 1.4 1999/05/01 20:43:55 steve
|
||||||
* Handle wide events, such as @(a) where a has
|
* Handle wide events, such as @(a) where a has
|
||||||
* many bits in it.
|
* many bits in it.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue