diff --git a/PExpr.h b/PExpr.h index bf78578d7..fe05c8c62 100644 --- a/PExpr.h +++ b/PExpr.h @@ -281,7 +281,7 @@ class PEConcat : public PExpr { class PEEvent : public PExpr { public: - enum edge_t {ANYEDGE, POSEDGE, NEGEDGE, POSITIVE}; + enum edge_t {ANYEDGE, POSEDGE, NEGEDGE, EDGE, POSITIVE}; // Use this constructor to create events based on edges or levels. PEEvent(edge_t t, PExpr*e); diff --git a/design_dump.cc b/design_dump.cc index fbdbda160..0789e07a6 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2021 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 @@ -1285,6 +1285,9 @@ void NetEvProbe::dump_node(ostream&o, unsigned ind) const case NEGEDGE: o << "negedge "; break; + case EDGE: + o << "edge "; + break; } o << setw(ind) << "" << "-> " << event_->name() << "; " << endl; dump_node_pins(o, ind+4); diff --git a/elaborate.cc b/elaborate.cc index 21b131762..c972d3260 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4665,6 +4665,11 @@ cerr << endl; NetEvProbe::NEGEDGE, pins); break; + case PEEvent::EDGE: + pr = new NetEvProbe(scope, scope->local_symbol(), ev, + NetEvProbe::EDGE, pins); + break; + case PEEvent::ANYEDGE: pr = new NetEvProbe(scope, scope->local_symbol(), ev, NetEvProbe::ANYEDGE, pins); diff --git a/ivl.def b/ivl.def index ba57c2d2a..f02fd0519 100644 --- a/ivl.def +++ b/ivl.def @@ -41,10 +41,12 @@ ivl_enum_width ivl_event_any ivl_event_basename +ivl_event_edg ivl_event_file ivl_event_lineno ivl_event_name ivl_event_nany +ivl_event_nedg ivl_event_neg ivl_event_nneg ivl_event_npos diff --git a/ivl_target.h b/ivl_target.h index 8d7d8d714..787074c9e 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1,7 +1,7 @@ #ifndef IVL_ivl_target_H #define IVL_ivl_target_H /* - * Copyright (c) 2000-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2021 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 @@ -768,6 +768,9 @@ extern ivl_scope_t ivl_event_scope(ivl_event_t net); extern unsigned ivl_event_nany(ivl_event_t net); extern ivl_nexus_t ivl_event_any(ivl_event_t net, unsigned idx); +extern unsigned ivl_event_nedg(ivl_event_t net); +extern ivl_nexus_t ivl_event_edg(ivl_event_t net, unsigned idx); + extern unsigned ivl_event_nneg(ivl_event_t net); extern ivl_nexus_t ivl_event_neg(ivl_event_t net, unsigned idx); diff --git a/netlist.h b/netlist.h index 27d477413..e8267adae 100644 --- a/netlist.h +++ b/netlist.h @@ -3522,7 +3522,7 @@ class NetEvProbe : public NetNode { friend class NetEvent; public: - enum edge_t { ANYEDGE, POSEDGE, NEGEDGE }; + enum edge_t { ANYEDGE, POSEDGE, NEGEDGE, EDGE }; explicit NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt, edge_t t, unsigned p); diff --git a/parse.y b/parse.y index a4f1fb219..cc1ed99bf 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -3430,6 +3430,13 @@ event_expression (*tl)[0] = tmp; $$ = tl; } + | K_edge expression + { PEEvent*tmp = new PEEvent(PEEvent::EDGE, $2); + FILE_NAME(tmp, @1); + svector*tl = new svector(1); + (*tl)[0] = tmp; + $$ = tl; + } | expression { PEEvent*tmp = new PEEvent(PEEvent::ANYEDGE, $1); FILE_NAME(tmp, @1); diff --git a/pform_dump.cc b/pform_dump.cc index 2cdde73c6..2538be1dd 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -406,6 +406,9 @@ void PEEvent::dump(ostream&out) const case PEEvent::NEGEDGE: out << "negedge "; break; + case PEEvent::EDGE: + out << "edge "; + break; case PEEvent::POSITIVE: out << "positive "; break; diff --git a/t-dll-api.cc b/t-dll-api.cc index c0a8a9006..16098996b 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2021 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * @@ -366,6 +366,19 @@ extern "C" ivl_nexus_t ivl_event_any(ivl_event_t net, unsigned idx) return net->pins[idx]; } +extern "C" unsigned ivl_event_nedg(ivl_event_t net) +{ + assert(net); + return net->nedg; +} + +extern "C" ivl_nexus_t ivl_event_edg(ivl_event_t net, unsigned idx) +{ + assert(net); + assert(idx < net->nedg); + return net->pins[net->nany + net->nneg + net->npos + idx]; +} + extern "C" unsigned ivl_event_nneg(ivl_event_t net) { assert(net); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index a8ff2f05a..c4115277a 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2021 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 @@ -370,6 +370,7 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) unsigned iany = 0; unsigned ineg = ev_tmp->nany; unsigned ipos = ineg + ev_tmp->nneg; + unsigned iedg = ipos + ev_tmp->npos; for (unsigned idx = 0; idx < ev->nprobe(); idx += 1) { const NetEvProbe*pr = ev->probe(idx); @@ -388,6 +389,10 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) base = ipos; ipos += pr->pin_count(); break; + case NetEvProbe::EDGE: + base = iedg; + iedg += pr->pin_count(); + break; } for (unsigned bit = 0; bit < pr->pin_count(); @@ -895,6 +900,7 @@ bool dll_target::proc_wait(const NetEvWait*net) unsigned iany = 0; unsigned ineg = ev_tmp->nany; unsigned ipos = ineg + ev_tmp->nneg; + unsigned iedg = ipos + ev_tmp->npos; for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) { const NetEvProbe*pr = ev->probe(idx); @@ -913,6 +919,10 @@ bool dll_target::proc_wait(const NetEvWait*net) base = ipos; ipos += pr->pin_count(); break; + case NetEvProbe::EDGE: + base = iedg; + iedg += pr->pin_count(); + break; } for (unsigned bit = 0; bit < pr->pin_count(); bit += 1) { diff --git a/t-dll.cc b/t-dll.cc index 868a69b6f..618dfa855 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -914,6 +914,7 @@ void dll_target::event(const NetEvent*net) obj->nany = 0; obj->nneg = 0; obj->npos = 0; + obj->nedg = 0; if (net->nprobe() >= 1) { @@ -929,6 +930,9 @@ void dll_target::event(const NetEvent*net) case NetEvProbe::POSEDGE: obj->npos += pr->pin_count(); break; + case NetEvProbe::EDGE: + obj->nedg += pr->pin_count(); + break; } } diff --git a/t-dll.h b/t-dll.h index aa675bc66..5cd84542e 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef IVL_t_dll_H #define IVL_t_dll_H /* - * Copyright (c) 2000-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2021 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 @@ -217,7 +217,7 @@ struct ivl_event_s { ivl_scope_t scope; perm_string file; unsigned lineno; - unsigned nany, nneg, npos; + unsigned nany, nneg, npos, nedg; ivl_nexus_t*pins; }; diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c index 88a7428dc..7d05b750b 100644 --- a/tgt-vlog95/event.c +++ b/tgt-vlog95/event.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2019 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2021 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -77,6 +77,18 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) emit_nexus_as_ca(scope, ivl_event_neg(event, idx), 0, 0); } + /* Check for edge events. */ + count = ivl_event_nedg(event); + if (count) had_edge = 1; + for (idx = 0; idx < count; idx += 1) { + if (first) first = 0; + else fprintf(vlog_out, " or "); + fprintf(vlog_out, "posedge "); + emit_nexus_as_ca(scope, ivl_event_edg(event, idx), 0, 0); + fprintf(vlog_out, " or negedge "); + emit_nexus_as_ca(scope, ivl_event_edg(event, idx), 0, 0); + } + /* We have a named event if there were no edge events. */ if (!had_edge) { ivl_scope_t ev_scope = ivl_event_scope(event); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 557a45527..581c2d45f 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2021 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 @@ -1153,6 +1153,7 @@ static void draw_event_in_scope(ivl_event_t obj) unsigned nany = ivl_event_nany(obj); unsigned nneg = ivl_event_nneg(obj); unsigned npos = ivl_event_npos(obj); + unsigned nedg = ivl_event_nedg(obj); unsigned cnt = 0; @@ -1166,6 +1167,9 @@ static void draw_event_in_scope(ivl_event_t obj) if (npos > 0) cnt += (npos+ntmp-1) / ntmp; + if (nedg > 0) + cnt += (nedg+ntmp-1) / ntmp; + if (cnt == 0) { /* If none are needed, then this is a named event. The code needed is easy. */ @@ -1189,7 +1193,7 @@ static void draw_event_in_scope(ivl_event_t obj) strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0])); } - fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt); + fprintf(vvp_out, "E_%p/%u .event anyedge", obj, ecnt); for (sub = idx ; sub < top ; sub += 1) fprintf(vvp_out, ", %s", tmp[sub-idx]); @@ -1232,6 +1236,24 @@ static void draw_event_in_scope(ivl_event_t obj) fprintf(vvp_out, ";\n"); } + for (idx = 0 ; idx < nedg ; idx += ntmp, ecnt += 1) { + unsigned sub, top; + + top = idx + ntmp; + if (nedg < top) + top = nedg; + for (sub = idx ; sub < top ; sub += 1) { + ivl_nexus_t nex = ivl_event_edg(obj, sub); + strncpy(tmp[sub-idx], draw_input_from_net(nex), sizeof(tmp[0])); + } + + fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt); + for (sub = idx ; sub < top ; sub += 1) + fprintf(vvp_out, ", %s", tmp[sub-idx]); + + fprintf(vvp_out, ";\n"); + } + assert(ecnt == cnt); fprintf(vvp_out, "E_%p .event/or", obj); @@ -1243,15 +1265,15 @@ static void draw_event_in_scope(ivl_event_t obj) fprintf(vvp_out, ";\n"); } else { - unsigned num_input_strings = nany + nneg + npos; + unsigned num_input_strings = nany + nneg + npos + nedg; unsigned idx; const char*edge = 0; assert(num_input_strings <= ntmp); if (nany > 0) { - assert((nneg + npos) == 0); - edge = "edge"; + assert((nneg + npos + nedg) == 0); + edge = "anyedge"; for (idx = 0 ; idx < nany ; idx += 1) { ivl_nexus_t nex = ivl_event_any(obj, idx); @@ -1259,7 +1281,7 @@ static void draw_event_in_scope(ivl_event_t obj) } } else if (nneg > 0) { - assert((nany + npos) == 0); + assert((nany + npos + nedg) == 0); edge = "negedge"; for (idx = 0 ; idx < nneg ; idx += 1) { @@ -1267,14 +1289,22 @@ static void draw_event_in_scope(ivl_event_t obj) strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); } - } else { - assert((nany + nneg) == 0); + } else if (npos > 0) { + assert((nany + nneg + nedg) == 0); edge = "posedge"; for (idx = 0 ; idx < npos ; idx += 1) { ivl_nexus_t nex = ivl_event_pos(obj, idx); strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); } + } else { + assert((nany + nneg + npos) == 0); + edge = "edge"; + + for (idx = 0 ; idx < nedg ; idx += 1) { + ivl_nexus_t nex = ivl_event_edg(obj, idx); + strncpy(tmp[idx], draw_input_from_net(nex), sizeof(tmp[0])); + } } fprintf(vvp_out, "E_%p .event %s", obj, edge); diff --git a/vvp/README.txt b/vvp/README.txt index dea23ae1a..db3ee0cbd 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com) * */ @@ -458,9 +458,9 @@ itself in the notification list of the event and suspends. The is a set of inputs that can trigger the event. The describes the conditions needed to trigger the event. It -may be posedge, negedge or edge. If the type is instead a "name" -string, then this is a named event which receives events by the %set -instruction instead of from the output of a functor. +may be posedge, negedge, edge or anyedge. If the type is instead a +"name" string, then this is a named event which receives events by +the %set instruction instead of from the output of a functor. If the event has inputs (a requirement unless it is a named event) then it has up to 4 symbols that address functors. The event then diff --git a/vvp/event.cc b/vvp/event.cc index f194a1a3a..d19cb9e19 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2021 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 @@ -199,6 +199,19 @@ const vvp_fun_edge::edge_t vvp_edge_negedge | VVP_EDGE(BIT4_Z,BIT4_0) ; +const vvp_fun_edge::edge_t vvp_edge_edge + = VVP_EDGE(BIT4_0,BIT4_1) + | VVP_EDGE(BIT4_1,BIT4_0) + | VVP_EDGE(BIT4_0,BIT4_X) + | VVP_EDGE(BIT4_X,BIT4_0) + | VVP_EDGE(BIT4_0,BIT4_Z) + | VVP_EDGE(BIT4_Z,BIT4_0) + | VVP_EDGE(BIT4_X,BIT4_1) + | VVP_EDGE(BIT4_1,BIT4_X) + | VVP_EDGE(BIT4_Z,BIT4_1) + | VVP_EDGE(BIT4_1,BIT4_Z) + ; + const vvp_fun_edge::edge_t vvp_edge_none = 0; struct vvp_fun_edge_state_s : public waitable_state_s { @@ -975,7 +988,7 @@ void compile_event(char*label, char*type, unsigned argc, struct symb_s*argv) return; } - if (strcmp(type,"edge") == 0) { + if (strcmp(type,"anyedge") == 0) { free(type); @@ -993,6 +1006,8 @@ void compile_event(char*label, char*type, unsigned argc, struct symb_s*argv) edge_type = vvp_edge_posedge; else if (strcmp(type,"negedge") == 0) edge_type = vvp_edge_negedge; + else if (strcmp(type,"edge") == 0) + edge_type = vvp_edge_edge; assert(argc <= 4); free(type); diff --git a/vvp/event.h b/vvp/event.h index d439c43f8..237b8c0bf 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -1,7 +1,7 @@ #ifndef IVL_event_H #define IVL_event_H /* - * Copyright (c) 2004-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2021 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 @@ -166,6 +166,7 @@ class vvp_fun_edge : public vvp_net_fun_t, public waitable_hooks_s { edge_t edge_; }; +extern const vvp_fun_edge::edge_t vvp_edge_edge; extern const vvp_fun_edge::edge_t vvp_edge_posedge; extern const vvp_fun_edge::edge_t vvp_edge_negedge; extern const vvp_fun_edge::edge_t vvp_edge_none;