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
|
||||
*/
|
||||
#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<string,Module*>&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.
|
||||
*
|
||||
|
|
|
|||
15
netlist.cc
15
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 <cassert>
|
||||
|
|
@ -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<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
|
||||
*/
|
||||
#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 <iostream>
|
||||
|
|
@ -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<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
|
||||
* 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<const NetAssign*>(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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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<LW>&l,
|
|||
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>
|
||||
vvm_bitset_t<1> vvm_binop_land(const vvm_bitset_t<LW>&l,
|
||||
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 $
|
||||
* 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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue