From 1e60754ff03f9012edd913040350755ffef5ba19 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 10 Sep 2008 19:37:11 -0700 Subject: [PATCH] Partial non-blocking event control implementation This patch pushes the non-blocking event control information to the code generator. It adds the %evctl statements that are used to put the event control information into the special thread event control registers. The signed version (%evctl/s) required the implementation of %ix/getv/s to load a signed value into an index register. It then adds %assign/wr/e event control based non-blocking assignment for real values. It also fixes the other non-blocking real assignments to use Transport instead of inertial delays. --- design_dump.cc | 24 ++++++++++ elaborate.cc | 39 +++++++++++----- net_assign.cc | 57 +++++++++--------------- netlist.h | 13 +++++- t-dll-api.cc | 14 ++++++ t-dll-proc.cc | 97 +++++++++++++++++++++++++++++++++++++++- t-dll.h | 7 +++ tgt-vvp/eval_expr.c | 4 +- tgt-vvp/vvp_process.c | 62 +++++++++++++++++++++++++- vvp/codes.h | 5 +++ vvp/compile.cc | 9 +++- vvp/event.cc | 101 ++++++++++++++++++++++++------------------ vvp/event.h | 73 +++++++++++++----------------- vvp/opcodes.txt | 24 ++++++++-- vvp/vthread.cc | 87 +++++++++++++++++++++++++++++++++++- 15 files changed, 471 insertions(+), 145 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 87deca3dd..c90e7262c 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -758,6 +758,11 @@ void NetAssignNB::dump(ostream&o, unsigned ind) const if (const NetExpr*de = get_delay()) o << "#(" << *de << ") "; + if (count_) + o << "repeat(" << *count_ << ") "; + if (event_) { + o << *event_; + } o << *rval() << ";" << endl; @@ -902,6 +907,25 @@ void NetEvWait::dump(ostream&o, unsigned ind) const o << setw(ind+2) << "" << "/* noop */ ;" << endl; } +ostream& operator << (ostream&out, const NetEvWait&obj) +{ + obj.dump_inline(out); + return out; +} + +void NetEvWait::dump_inline(ostream&o) const +{ + o << "@("; + + if (nevents() > 0) + o << event(0)->name(); + + for (unsigned idx = 1 ; idx < nevents() ; idx += 1) + o << " or " << event(idx)->name(); + + o << ") "; +} + void NetForce::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "force "; diff --git a/elaborate.cc b/elaborate.cc index 63240538d..a2cb6e6c0 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1906,11 +1906,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const } NetExpr*delay = 0; - if (delay_ != 0) + if (delay_ != 0) { + assert(count_ == 0 && event_ == 0); delay = elaborate_delay_expr(delay_, des, scope); + } + NetExpr*count = 0; + NetEvWait*event = 0; if (count_ != 0 || event_ != 0) { - NetExpr*count = 0; if (count_ != 0) { assert(event_ != 0); count = elab_and_eval(des, scope, count_, -1); @@ -1918,27 +1921,39 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": Unable to elaborate " "repeat expression." << endl; des->errors += 1; -// return 0; + return 0; } } - NetProc* event = event_->elaborate(des, scope); - if (event == 0) { + NetProc*st = event_->elaborate(des, scope); + if (st == 0) { cerr << get_fileline() << ": unable to elaborate " "event expression." << endl; des->errors += 1; -// return 0; + return 0; } + event = dynamic_cast(st) ; + assert(event); - cerr << get_fileline() << ": sorry: non blocking "; - if (count_) cerr << "repeat "; - cerr << "event controls are not supported." << endl; - des->errors += 1; - return 0; + // Some constant values are special. + if (NetEConst*ce = dynamic_cast(count)) { + long val = ce->value().as_long(); + // We only need the assignment statement. + if (val <= 0) { + delete count; + delete event; + count = 0; + event = 0; + // We only need the event. + } else if (val == 1) { + delete count; + count = 0; + } + } } /* All done with this node. Mark its line number and check it in. */ - NetAssignNB*cur = new NetAssignNB(lv, rv); + NetAssignNB*cur = new NetAssignNB(lv, rv, event, count); cur->set_delay(delay); cur->set_line(*this); return cur; diff --git a/net_assign.cc b/net_assign.cc index 485b2cc45..4b84e6324 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2008 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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: net_assign.cc,v 1.22 2007/01/16 05:44:15 steve Exp $" -#endif # include "config.h" @@ -212,15 +209,34 @@ NetAssign::~NetAssign() { } -NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv) +NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, NetExpr*cnt) : NetAssignBase(lv, rv) { + event_ = ev; + count_ = cnt; } NetAssignNB::~NetAssignNB() { } +unsigned NetAssignNB::nevents() const +{ + if (event_) return event_->nevents(); + return 0; +} + +const NetEvent*NetAssignNB::event(unsigned idx) const +{ + if (event_) return event_->event(idx); + return 0; +} + +const NetExpr*NetAssignNB::get_count() const +{ + return count_; +} + NetCAssign::NetCAssign(NetAssign_*lv, NetExpr*rv) : NetAssignBase(lv, rv) { @@ -256,34 +272,3 @@ NetRelease::NetRelease(NetAssign_*l) NetRelease::~NetRelease() { } - -/* - * $Log: net_assign.cc,v $ - * Revision 1.22 2007/01/16 05:44:15 steve - * Major rework of array handling. Memories are replaced with the - * more general concept of arrays. The NetMemory and NetEMemory - * classes are removed from the ivl core program, and the IVL_LPM_RAM - * lpm type is removed from the ivl_target API. - * - * Revision 1.21 2006/02/02 02:43:58 steve - * Allow part selects of memory words in l-values. - * - * Revision 1.20 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.19 2004/12/11 02:31:26 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.18 2004/08/28 15:08:31 steve - * Do not change reg to wire in NetAssign_ unless synthesizing. - * - * Revision 1.17 2004/02/18 17:11:56 steve - * Use perm_strings for named langiage items. - * - * Revision 1.16 2003/01/26 21:15:58 steve - * Rework expression parsing and elaboration to - * accommodate real/realtime values and expressions. - */ - diff --git a/netlist.h b/netlist.h index 1cb4ea890..4777cf700 100644 --- a/netlist.h +++ b/netlist.h @@ -2230,7 +2230,8 @@ class NetAssign : public NetAssignBase { class NetAssignNB : public NetAssignBase { public: - explicit NetAssignNB(NetAssign_*lv, NetExpr*rv); + explicit NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, + NetExpr*cnt); ~NetAssignNB(); @@ -2238,7 +2239,13 @@ class NetAssignNB : public NetAssignBase { virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + unsigned nevents() const; + const NetEvent*event(unsigned) const; + const NetExpr* get_count() const; + private: + NetEvWait*event_; + NetExpr*count_; }; /* @@ -2620,6 +2627,8 @@ class NetEvWait : public NetProc { const svector&events); virtual void dump(ostream&, unsigned ind) const; + // This will ignore any statement. + virtual void dump_inline(ostream&) const; virtual DelayType delay_type() const; private: @@ -2629,6 +2638,8 @@ class NetEvWait : public NetProc { NetEvent**events_; }; +ostream& operator << (ostream&out, const NetEvWait&obj); + class NetEvProbe : public NetNode { friend class NetEvent; diff --git a/t-dll-api.cc b/t-dll-api.cc index 5d9c49c41..d5ab959ea 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1972,6 +1972,9 @@ extern "C" ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned idx) extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.count; + case IVL_ST_CONDIT: return net->u_.condit_.cond_; @@ -2034,6 +2037,9 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.nevent; + case IVL_ST_WAIT: return net->u_.wait_.nevent; @@ -2049,6 +2055,13 @@ extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + assert(idx < net->u_.assign_.nevent); + if (net->u_.assign_.nevent == 1) + return net->u_.assign_.event; + else + return net->u_.assign_.events[idx]; + case IVL_ST_WAIT: assert(idx < net->u_.wait_.nevent); if (net->u_.wait_.nevent == 1) @@ -2059,6 +2072,7 @@ extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) case IVL_ST_TRIGGER: assert(idx == 0); return net->u_.wait_.event; + default: assert(0); } diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 8e26f6d3d..badf7cd78 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -59,7 +59,7 @@ bool dll_target::process(const NetProcTop*net) /* This little bit causes the process to be completely generated so that it can be passed to the DLL. The - stmt_cur_ member us used to hold a pointer to the current + stmt_cur_ member is used to hold a pointer to the current statement in progress, and the emit_proc() method fills in that object. @@ -222,6 +222,7 @@ bool dll_target::proc_assign(const NetAssign*net) void dll_target::proc_assign_nb(const NetAssignNB*net) { const NetExpr* delay_exp = net->get_delay(); + const NetExpr* cnt_exp = net->get_count(); assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); @@ -229,6 +230,8 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) FILE_NAME(stmt_cur_, net); stmt_cur_->u_.assign_.delay = 0; + stmt_cur_->u_.assign_.count = 0; + stmt_cur_->u_.assign_.nevent = 0; /* Make the lval fields. */ make_assign_lvals_(net); @@ -239,6 +242,7 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.rval_ = expr_; expr_ = 0; + /* Process a delay if it exists. */ if (const NetEConst*delay_num = dynamic_cast(delay_exp)) { verinum val = delay_num->value(); ivl_expr_t de = new struct ivl_expr_s; @@ -253,6 +257,96 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.delay = expr_; expr_ = 0; } + + /* Process a count if it exists. */ + if (const NetEConst*cnt_num = dynamic_cast(cnt_exp)) { + verinum val = cnt_num->value(); + ivl_expr_t cnt = new struct ivl_expr_s; + cnt->type_ = IVL_EX_ULONG; + cnt->width_ = 8 * sizeof(unsigned long); + cnt->signed_ = 0; + cnt->u_.ulong_.value = val.as_ulong(); + stmt_cur_->u_.assign_.count = cnt; + + } else if (cnt_exp != 0) { + cnt_exp->expr_scan(this); + stmt_cur_->u_.assign_.count = expr_; + expr_ = 0; + } + + /* Process the events if they exist. This is a copy of code + * from NetEvWait below. */ + if (net->nevents() > 0) { + stmt_cur_->u_.assign_.nevent = net->nevents(); + if (net->nevents() > 1) { + stmt_cur_->u_.assign_.events = (ivl_event_t*) + calloc(net->nevents(), sizeof(ivl_event_t*)); + } + + for (unsigned edx = 0 ; edx < net->nevents() ; edx += 1) { + + /* Locate the event by name. Save the ivl_event_t in the + statement so that the generator can find it easily. */ + const NetEvent*ev = net->event(edx); + ivl_scope_t ev_scope = lookup_scope_(ev->scope()); + ivl_event_t ev_tmp=0; + + assert(ev_scope); + assert(ev_scope->nevent_ > 0); + for (unsigned idx = 0; idx < ev_scope->nevent_; idx += 1) { + const char*ename = + ivl_event_basename(ev_scope->event_[idx]); + if (strcmp(ev->name(), ename) == 0) { + ev_tmp = ev_scope->event_[idx]; + break; + } + } + // XXX should we assert(ev_tmp)? + + if (net->nevents() == 1) + stmt_cur_->u_.assign_.event = ev_tmp; + else + stmt_cur_->u_.assign_.events[edx] = ev_tmp; + + /* If this is an event with a probe, then connect up the + pins. This wasn't done during the ::event method because + the signals weren't scanned yet. */ + + if (ev->nprobe() >= 1) { + unsigned iany = 0; + unsigned ineg = ev_tmp->nany; + unsigned ipos = ineg + ev_tmp->nneg; + + for (unsigned idx = 0; idx < ev->nprobe(); idx += 1) { + const NetEvProbe*pr = ev->probe(idx); + unsigned base = 0; + + switch (pr->edge()) { + case NetEvProbe::ANYEDGE: + base = iany; + iany += pr->pin_count(); + break; + case NetEvProbe::NEGEDGE: + base = ineg; + ineg += pr->pin_count(); + break; + case NetEvProbe::POSEDGE: + base = ipos; + ipos += pr->pin_count(); + break; + } + + for (unsigned bit = 0; bit < pr->pin_count(); + bit += 1) { + ivl_nexus_t nex = (ivl_nexus_t) + pr->pin(bit).nexus()->t_cookie(); + assert(nex); + ev_tmp->pins[base+bit] = nex; + } + } + } + } + } } bool dll_target::proc_block(const NetBlock*net) @@ -643,6 +737,7 @@ bool dll_target::proc_wait(const NetEvWait*net) stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*) calloc(1, sizeof(struct ivl_statement_s)); + // This event processing code is also in the NB assign above. stmt_cur_->u_.wait_.nevent = net->nevents(); if (net->nevents() > 1) { stmt_cur_->u_.wait_.events = (ivl_event_t*) diff --git a/t-dll.h b/t-dll.h index 02a6418c8..87047b9d4 100644 --- a/t-dll.h +++ b/t-dll.h @@ -671,6 +671,13 @@ struct ivl_statement_s { struct ivl_lval_s*lval_; ivl_expr_t rval_; ivl_expr_t delay; + // The following are only for NB event control. + ivl_expr_t count; + unsigned nevent; + union { + ivl_event_t event; + ivl_event_t*events; + }; } assign_; struct { /* IVL_ST_BLOCK, IVL_ST_FORK */ diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 069ab9278..f9a2a89a7 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -162,7 +162,9 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) break; } } - fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); + char*type = ivl_signal_signed(sig) ? "/s" : ""; + fprintf(vvp_out, " %%ix/getv%s %u, v%p_%u;\n", type, ix, + sig, word); break; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 861ce2232..14fba22e6 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -532,6 +532,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* thread address for a word value. */ int word; unsigned long delay = 0; + unsigned nevents = ivl_stmt_nevent(net); /* Must be exactly 1 l-value. */ assert(ivl_stmt_lvals(net) == 1); @@ -557,13 +558,17 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* We need to calculate the delay expression. */ if (del) { + assert(nevents == 0 && ivl_stmt_cond_expr(net) == 0); int delay_index = allocate_word(); draw_eval_expr_into_integer(del, delay_index); - fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", sig, use_word, delay_index, word); clr_word(delay_index); + } else if (nevents) { + fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n", + sig, use_word, word); } else { - fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", sig, use_word, delay, word); } @@ -578,6 +583,49 @@ static int show_stmt_assign_nb(ivl_statement_t net) ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t del = ivl_stmt_delay_expr(net); ivl_signal_t sig; + unsigned nevents = ivl_stmt_nevent(net); + + // If we have an event control build the control structure. + if (nevents) { + assert(del == 0); + + ivl_expr_t cnt = ivl_stmt_cond_expr(net); + unsigned long count = 1; + if (cnt && (ivl_expr_type(cnt) == IVL_EX_ULONG)) { + count = ivl_expr_uvalue(cnt); + cnt = 0; + } + + char name[256]; + if (nevents == 1) { + ivl_event_t ev = ivl_stmt_events(net, 0); + snprintf(name, sizeof(name), "E_%p", ev); + } else { + unsigned idx; + static unsigned int cascade_counter = 0; + ivl_event_t ev = ivl_stmt_events(net, 0); + fprintf(vvp_out, "Eassign_%u .event/or E_%p", + cascade_counter, ev); + + for (idx = 1; idx < nevents; idx += 1) { + ev = ivl_stmt_events(net, idx); + fprintf(vvp_out, ", E_%p", ev); + } + snprintf(name, sizeof(name), "Eassign_%u", cascade_counter); + cascade_counter += 1; + } + + if (cnt) { + int count_index = allocate_word(); + char*type = ivl_expr_signed(cnt) ? "/s" : ""; + draw_eval_expr_into_integer(cnt, count_index); + fprintf(vvp_out, " %%evctl%s %s, %d;\n", type, name, + count_index); + clr_word(count_index); + } else { + fprintf(vvp_out, " %%evctl/i %s, %lu;\n", name, count); + } + } unsigned long delay = 0; @@ -592,6 +640,16 @@ static int show_stmt_assign_nb(ivl_statement_t net) } } + if (nevents) { + fprintf(stderr, "%s:%u: vvp-tgt sorry: non-blocking ", + ivl_stmt_file(net), ivl_stmt_lineno(net)); + if (ivl_stmt_cond_expr(net)) { + fprintf(stderr, "repeat "); + } + fprintf(stderr, "event controls are not supported!\n"); + exit(1); + } + if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); del = 0; diff --git a/vvp/codes.h b/vvp/codes.h index 3a803b5e6..1c5d87d4f 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -49,6 +49,7 @@ extern bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code); extern bool of_BLEND(vthread_t thr, vvp_code_t code); extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code); @@ -78,6 +79,9 @@ extern bool of_DIV(vthread_t thr, vvp_code_t code); extern bool of_DIV_S(vthread_t thr, vvp_code_t code); extern bool of_DIV_WR(vthread_t thr, vvp_code_t code); extern bool of_END(vthread_t thr, vvp_code_t code); +extern bool of_EVCTL(vthread_t thr, vvp_code_t code); +extern bool of_EVCTLI(vthread_t thr, vvp_code_t code); +extern bool of_EVCTLS(vthread_t thr, vvp_code_t code); extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code); extern bool of_FORCE_V(vthread_t thr, vvp_code_t code); extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code); @@ -87,6 +91,7 @@ extern bool of_INV(vthread_t thr, vvp_code_t code); extern bool of_IX_ADD(vthread_t thr, vvp_code_t code); extern bool of_IX_GET(vthread_t thr, vvp_code_t code); extern bool of_IX_GETV(vthread_t thr, vvp_code_t code); +extern bool of_IX_GETVS(vthread_t thr, vvp_code_t code); extern bool of_IX_GET_S(vthread_t thr, vvp_code_t code); extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code); extern bool of_IX_MUL(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index bdf8d9262..821d7852f 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -92,8 +92,9 @@ const static struct opcode_table_s opcode_table[] = { { "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, - { "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, - { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/wr", of_ASSIGN_WR, 3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, + { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, + { "%assign/wr/e",of_ASSIGN_WRE,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} }, { "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%blend/wr", of_BLEND_WR,2, {OA_BIT1, OA_BIT2, OA_NONE} }, @@ -122,6 +123,9 @@ const static struct opcode_table_s opcode_table[] = { { "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%div/wr", of_DIV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%evctl", of_EVCTL, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%evctl/i",of_EVCTLI, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} }, { "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, @@ -131,6 +135,7 @@ const static struct opcode_table_s opcode_table[] = { { "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, + { "%ix/getv/s",of_IX_GETVS,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, { "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, diff --git a/vvp/event.cc b/vvp/event.cc index eeea27924..60f9dd620 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2008 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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: event.cc,v 1.23 2006/12/09 19:06:53 steve Exp $" -#endif # include "event.h" # include "compile.h" @@ -37,6 +34,20 @@ void waitable_hooks_s::run_waiting_threads_() { + // Run the non-blocking event controls. + last = &event_ctls; + for (evctl*cur = event_ctls; cur != 0;) { + if (cur->dec_and_run()) { + evctl*nxt = cur->next; + delete cur; + cur = nxt; + *last = cur; + } else { + last = &(cur->next); + cur = cur->next; + } + } + if (threads == 0) return; @@ -45,6 +56,48 @@ void waitable_hooks_s::run_waiting_threads_() vthread_schedule_list(tmp); } +evctl::evctl(unsigned long ecount) +{ + ecount_ = ecount; + next = 0; +} + +evctl_real::evctl_real(struct __vpiHandle*handle, double value, + unsigned long ecount) +:evctl(ecount) +{ + handle_ = handle; + value_ = value; +} + +bool evctl_real::dec_and_run() +{ + assert(ecount_ != 0); + + ecount_ -= 1; + + if (ecount_ == 0) { + t_vpi_value val; + + val.format = vpiRealVal; + val.value.real = value_; + vpi_put_value(handle_, &val, 0, vpiNoDelay); + } + + return ecount_ == 0; +} + +void schedule_evctl(struct __vpiHandle*handle, double value, + vvp_net_t*event, unsigned long ecount) +{ + // Get the functor we are going to wait on. + waitable_hooks_s*ep = dynamic_cast (event->fun); + assert(ep); + // Now add this call to the end of the event list. + *(ep->last) = new evctl_real(handle, value, ecount); + ep->last = &((*(ep->last))->next); +} + inline vvp_fun_edge::edge_t VVP_EDGE(vvp_bit4_t from, vvp_bit4_t to) { return 1 << ((from << 2) | to); @@ -270,43 +323,3 @@ void compile_named_event(char*label, char*name) free(label); free(name); } - -/* - * $Log: event.cc,v $ - * Revision 1.23 2006/12/09 19:06:53 steve - * Handle vpiRealVal reads of signals, and real anyedge events. - * - * Revision 1.22 2006/11/22 06:10:05 steve - * Fix spurious event from net8 that is forced. - * - * Revision 1.21 2006/02/21 04:57:26 steve - * Callbacks for named event triggers. - * - * Revision 1.20 2005/06/22 00:04:49 steve - * Reduce vvp_vector4 copies by using const references. - * - * Revision 1.19 2005/06/17 23:47:02 steve - * threads member for waitable_hook_s needs initailizing. - * - * Revision 1.18 2005/05/25 05:44:51 steve - * Handle event/or with specific, efficient nodes. - * - * Revision 1.17 2004/12/29 23:45:13 steve - * Add the part concatenation node (.concat). - * - * Add a vvp_event_anyedge class to handle the special - * case of .event statements of edge type. This also - * frees the posedge/negedge types to handle all 4 inputs. - * - * Implement table functor recv_vec4 method to receive - * and process vectors. - * - * Revision 1.16 2004/12/18 18:52:44 steve - * Rework named events and event/or. - * - * Revision 1.15 2004/12/11 02:31:29 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - */ diff --git a/vvp/event.h b/vvp/event.h index 7f21d1536..0cea1a184 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -1,7 +1,7 @@ #ifndef __event_H #define __event_H /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2008 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 @@ -18,13 +18,38 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: event.h,v 1.13 2006/12/09 19:06:53 steve Exp $" -#endif # include "vvp_net.h" # include "pointers.h" +class evctl { + + public: + explicit evctl(unsigned long ecount); + virtual bool dec_and_run() = 0; + virtual ~evctl() {} + evctl*next; + + protected: + unsigned long ecount_; +}; + +class evctl_real : public evctl { + + public: + explicit evctl_real(struct __vpiHandle*handle, double value, + unsigned long ecount); + virtual ~evctl_real() {} + bool dec_and_run(); + + private: + __vpiHandle*handle_; + double value_; +}; + +extern void schedule_evctl(struct __vpiHandle*handle, double value, + vvp_net_t*event, unsigned long ecount); + /* * Event / edge detection functors */ @@ -36,8 +61,10 @@ struct waitable_hooks_s { public: - waitable_hooks_s() : threads(0) { } + waitable_hooks_s() : threads(0), event_ctls(0) { last = &event_ctls; } vthread_t threads; + evctl*event_ctls; + evctl**last; protected: void run_waiting_threads_(); @@ -126,40 +153,4 @@ class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { struct __vpiHandle*handle_; }; - -/* - * $Log: event.h,v $ - * Revision 1.13 2006/12/09 19:06:53 steve - * Handle vpiRealVal reads of signals, and real anyedge events. - * - * Revision 1.12 2006/11/22 06:10:05 steve - * Fix spurious event from net8 that is forced. - * - * Revision 1.11 2005/06/22 00:04:49 steve - * Reduce vvp_vector4 copies by using const references. - * - * Revision 1.10 2005/06/17 23:47:02 steve - * threads member for waitable_hook_s needs initailizing. - * - * Revision 1.9 2005/05/25 05:44:51 steve - * Handle event/or with specific, efficient nodes. - * - * Revision 1.8 2004/12/29 23:45:13 steve - * Add the part concatenation node (.concat). - * - * Add a vvp_event_anyedge class to handle the special - * case of .event statements of edge type. This also - * frees the posedge/negedge types to handle all 4 inputs. - * - * Implement table functor recv_vec4 method to receive - * and process vectors. - * - * Revision 1.7 2004/12/18 18:52:44 steve - * Rework named events and event/or. - * - * Revision 1.6 2004/12/11 02:31:29 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - */ #endif // __event_H diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 556c0cb27..b7b117fc6 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -105,6 +105,7 @@ vector is to be written. This allows for part writes into the vector. * %assign/wr , , * %assign/wr/d , , +* %assign/wr/e , This instruction provides a non-blocking assign of the real value given in to the real object addressed by the @@ -113,6 +114,10 @@ label after the given . The %assign/wr/d variation gets the delay from integer register . +The %assign/wr/e variation uses the information in the thread +event control registers to determine when to perform the assign. +%evctl is used to set the event control information. + * %assign/x0 , , (OBSOLETE -- See %assign/v0x) This does a non-blocking assignment to a functor, similar to the @@ -296,6 +301,18 @@ This opcode divides the left operand by the right operand. If the right operand is 0, then the result is NaN. +* %evctl +* %evctl/s +* %evctl/i + +These instructions are used to put event and repetition information +into the thread event control registers. These values are then used +by the %assign/e instructions to do not blocking event control. The + is the event to trigger on and the is an index +register to read the repetition count from (signed or unsigned). +%evctl/i sets the repetition to an immediate unsigned value. + + * %force/v