Allow assigning events (#4403)

Signed-off-by: Krzysztof Boronski <kboronski@antmicro.com>
This commit is contained in:
Krzysztof Boroński 2023-10-26 16:38:47 +02:00 committed by GitHub
parent 34708bbba1
commit a87fb57656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 331 additions and 43 deletions

View File

@ -293,7 +293,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
}

View File

@ -177,7 +177,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);

View File

@ -475,7 +475,7 @@ public:
void fullQData(uint32_t* oldp, QData newval, int bits);
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
void fullDouble(uint32_t* oldp, double newval);
void fullEvent(uint32_t* oldp, VlEvent newval);
void fullEvent(uint32_t* oldp, const VlEventBase* newval);
// In non-offload mode, these are called directly by the trace callbacks,
// and are called chg*. In offload mode, they are called by the worker
@ -512,7 +512,9 @@ public:
}
}
}
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
fullEvent(oldp, newval);
}
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
double old;
std::memcpy(&old, oldp, sizeof(old));
@ -591,7 +593,7 @@ public:
m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
}
void chgEvent(uint32_t code, VlEvent newval) {
void chgEvent(uint32_t code, const VlEventBase* newval) {
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
m_offloadBufferWritep[1] = code;
m_offloadBufferWritep += 2;

View File

@ -185,7 +185,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
continue;
case VerilatedTraceOffloadCommand::CHG_EVENT:
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
continue;
//===
@ -846,7 +846,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
}
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newval) {
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = 1; // Do we really store an "event" ?
emitEvent(code, newval);

View File

@ -33,6 +33,7 @@
#include <atomic>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
@ -191,7 +192,18 @@ public:
//===================================================================
// SystemVerilog event type
class VlEvent final {
class VlEventBase VL_NOT_FINAL {
public:
virtual ~VlEventBase() = default;
virtual void fire() = 0;
virtual bool isFired() const = 0;
virtual bool isTriggered() const = 0;
virtual void clearFired() = 0;
virtual void clearTriggered() = 0;
};
class VlEvent final : public VlEventBase {
// MEMBERS
bool m_fired = false; // Fired on this scheduling iteration
bool m_triggered = false; // Triggered state of event persisting until next time step
@ -199,20 +211,50 @@ class VlEvent final {
public:
// CONSTRUCTOR
VlEvent() = default;
~VlEvent() = default;
~VlEvent() override = default;
friend std::string VL_TO_STRING(const VlEvent& e);
friend class VlAssignableEvent;
// METHODS
void fire() { m_fired = m_triggered = true; }
bool isFired() const { return m_fired; }
bool isTriggered() const { return m_triggered; }
void clearFired() { m_fired = false; }
void clearTriggered() { m_triggered = false; }
void fire() override { m_fired = m_triggered = true; }
bool isFired() const override { return m_fired; }
bool isTriggered() const override { return m_triggered; }
void clearFired() override { m_fired = false; }
void clearTriggered() override { m_triggered = false; }
};
class VlAssignableEvent final : public std::shared_ptr<VlEvent>, public VlEventBase {
public:
// Constructor
VlAssignableEvent()
: std::shared_ptr<VlEvent>(new VlEvent) {}
~VlAssignableEvent() override = default;
// METHODS
void fire() override { (*this)->m_fired = (*this)->m_triggered = true; }
bool isFired() const override { return (*this)->m_fired; }
bool isTriggered() const override { return (*this)->m_triggered; }
void clearFired() override { (*this)->m_fired = false; }
void clearTriggered() override { (*this)->m_triggered = false; }
};
inline std::string VL_TO_STRING(const VlEventBase& e);
inline std::string VL_TO_STRING(const VlEvent& e) {
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
}
inline std::string VL_TO_STRING(const VlAssignableEvent& e) {
return "&{ " + VL_TO_STRING(*e) + " }";
}
inline std::string VL_TO_STRING(const VlEventBase& e) {
if (const VlAssignableEvent& assignable = dynamic_cast<const VlAssignableEvent&>(e)) {
return VL_TO_STRING(assignable);
}
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
}
//===================================================================
// Random

View File

@ -574,8 +574,8 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEvent newval) {
const bool triggered = newval.isTriggered();
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
const bool triggered = newval->isTriggered();
// TODO : It seems that untriggered events are not filtered
// should be tested before this last step
if (triggered) {

View File

@ -214,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// Implementation of VerilatedTraceBuffer interface
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);

View File

@ -324,7 +324,7 @@ public:
ET_BOTHEDGE, // POSEDGE | NEGEDGE (i.e.: 'edge' in Verilog)
ET_POSEDGE,
ET_NEGEDGE,
ET_EVENT, // VlEvent::isFired
ET_EVENT, // VlEventBase::isFired
// Involving an expression
ET_TRUE,
//
@ -2016,6 +2016,7 @@ public:
inline bool isDouble() const VL_MT_STABLE;
inline bool isSigned() const VL_MT_STABLE;
inline bool isString() const VL_MT_STABLE;
inline bool isEvent() const VL_MT_STABLE;
// clang-format off
VNUser user1u() const VL_MT_STABLE {

View File

@ -39,6 +39,10 @@ bool AstNode::isDouble() const VL_MT_STABLE {
bool AstNode::isString() const VL_MT_STABLE {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
}
bool AstNode::isEvent() const VL_MT_STABLE {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isEvent();
}
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
bool AstNode::isClassHandleValue() const {

View File

@ -829,7 +829,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
} else if (bdtypep->isProcessRef()) {
info.m_type = "VlProcessRef";
} else if (bdtypep->isEvent()) {
info.m_type = "VlEvent";
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) {

View File

@ -190,7 +190,7 @@ private:
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor)
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
&& !nodep->varp()->basicp()->isForkSync()
&& !nodep->varp()->basicp()->isProcessRef())
&& !nodep->varp()->basicp()->isProcessRef() && !nodep->varp()->basicp()->isEvent())
&& backp->width() && castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);

View File

@ -781,6 +781,7 @@ class EmitCTrace final : EmitCFunc {
void emitTraceValue(AstTraceInc* nodep, int arrayindex) {
if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
AstVar* const varp = varrefp->varp();
if (varp->isEvent()) { puts("&"); }
puts("(");
if (emitTraceIsScBigUint(nodep)) {
puts("(uint32_t*)");

View File

@ -460,7 +460,13 @@ void EmitCSyms::emitSymHdr() {
puts("uint32_t __Vm_baseCode = 0;"
" ///< Used by trace routines when tracing multiple models\n");
}
if (v3Global.hasEvents()) puts("std::vector<VlEvent*> __Vm_triggeredEvents;\n");
if (v3Global.hasEvents()) {
if (v3Global.assignsEvents()) {
puts("std::vector<VlAssignableEvent> __Vm_triggeredEvents;\n");
} else {
puts("std::vector<VlEvent*> __Vm_triggeredEvents;\n");
}
}
if (v3Global.hasClasses()) puts("VlDeleter __Vm_deleter;\n");
puts("bool __Vm_didInit = false;\n");
@ -528,17 +534,29 @@ void EmitCSyms::emitSymHdr() {
puts("const char* name() { return TOP.name(); }\n");
if (v3Global.hasEvents()) {
puts("void enqueueTriggeredEventForClearing(VlEvent& event) {\n");
if (v3Global.assignsEvents()) {
puts("void enqueueTriggeredEventForClearing(VlAssignableEvent& event) {\n");
} else {
puts("void enqueueTriggeredEventForClearing(VlEvent& event) {\n");
}
puts("#ifdef VL_DEBUG\n");
puts("if (VL_UNLIKELY(!event.isTriggered())) {\n");
puts("VL_FATAL_MT(__FILE__, __LINE__, __FILE__, \"event passed to "
"'enqueueTriggeredEventForClearing' was not triggered\");\n");
puts("}\n");
puts("#endif\n");
puts("__Vm_triggeredEvents.push_back(&event);\n");
if (v3Global.assignsEvents()) {
puts("__Vm_triggeredEvents.push_back(event);\n");
} else {
puts("__Vm_triggeredEvents.push_back(&event);\n");
}
puts("}\n");
puts("void clearTriggeredEvents() {\n");
puts("for (const auto eventp : __Vm_triggeredEvents) eventp->clearTriggered();\n");
if (v3Global.assignsEvents()) {
puts("for (auto& event : __Vm_triggeredEvents) event.clearTriggered();\n");
} else {
puts("for (const auto eventp : __Vm_triggeredEvents) eventp->clearTriggered();\n");
}
puts("__Vm_triggeredEvents.clear();\n");
puts("}\n");
}

View File

@ -195,8 +195,8 @@ public:
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG",
"DECLFILENAME", "DEFPARAM", "DEPRECATED",
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED",
"HIERBLOCK",
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK",
"GENUNNAMED", "HIERBLOCK",
"IFDEPTH", "IGNOREDRETURN",
"IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",

View File

@ -105,6 +105,7 @@ class V3Global final {
std::atomic_int m_debugFileNumber{0}; // Number to append to debug files created
bool m_assertDTypesResolved = false; // Tree should have dtypep()'s
bool m_assertScoped = false; // Tree is scoped
bool m_assignsEvents = false; // Design uses assignments on SystemVerilog Events
bool m_constRemoveXs = false; // Const needs to strip any Xs
// Experimenting with always requiring heavy, see issue #2701
bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols
@ -155,6 +156,8 @@ public:
void needTraceDumper(bool flag) { m_needTraceDumper = flag; }
bool dpi() const VL_MT_SAFE { return m_dpi; }
void dpi(bool flag) { m_dpi = flag; }
bool assignsEvents() const { return m_assignsEvents; }
void setAssignsEvents() { m_assignsEvents = true; }
bool hasEvents() const { return m_hasEvents; }
void setHasEvents() { m_hasEvents = true; }
bool hasClasses() const { return m_hasClasses; }

View File

@ -68,6 +68,8 @@
#include "V3Width.h"
#include "V3Const.h"
#include "V3Error.h"
#include "V3Global.h"
#include "V3MemberMap.h"
#include "V3Number.h"
#include "V3Randomize.h"
@ -4319,6 +4321,47 @@ private:
return valuep;
}
static void checkEventAssignement(const AstNodeAssign* const asgnp) {
string unsupEvtAsgn;
if (!usesDynamicScheduler(asgnp->lhsp())) unsupEvtAsgn = "to";
if (asgnp->rhsp()->dtypep()->isEvent() && !usesDynamicScheduler(asgnp->rhsp())) {
unsupEvtAsgn += (unsupEvtAsgn.empty() ? "from" : " and from");
}
if (!unsupEvtAsgn.empty()) {
asgnp->v3warn(E_UNSUPPORTED, "Assignement "
<< unsupEvtAsgn
<< " event in statically scheduled context.\n"
<< asgnp->warnMore()
<< "Static event "
"scheduling won't be able to handle this.\n"
<< asgnp->warnMore()
<< "... Suggest move the event into a "
"completely dynamic context, eg. a class, and "
"reference it only from such context.");
}
}
static bool usesDynamicScheduler(AstNode* nodep) {
UASSERT_OBJ(nodep->dtypep()->isEvent(), nodep, "Node does not have an event dtype");
AstVarRef* vrefp;
while (true) {
vrefp = VN_CAST(nodep, VarRef);
if (vrefp) return usesDynamicScheduler(vrefp);
if (VN_IS(nodep, MemberSel)) {
return true;
} else if (AstNodeSel* selp = VN_CAST(nodep, NodeSel)) {
nodep = selp->fromp();
} else {
return false;
}
}
}
static bool usesDynamicScheduler(AstVarRef* vrefp) {
return VN_IS(vrefp->classOrPackagep(), Class) || vrefp->varp()->isFuncLocal();
}
void visit(AstPatMember* nodep) override {
AstNodeDType* const vdtypep = m_vup->dtypeNullp();
UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor");
@ -4713,12 +4756,6 @@ private:
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
// if (debug()) nodep->dumpTree("- AssignOut: ");
}
if (const AstBasicDType* const basicp = nodep->rhsp()->dtypep()->basicp()) {
if (basicp->isEvent()) {
// see t_event_copy.v for commentary on the mess involved
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type");
}
}
if (auto* const controlp = nodep->timingControlp()) {
if (VN_IS(m_ftaskp, Func)) {
controlp->v3error("Timing controls are not legal in functions. Suggest use a task "
@ -4773,7 +4810,12 @@ private:
newp->dtypeSetVoid();
nodep->replaceWith(newp->makeStmt());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
// return;
return;
}
if (nodep->hasDType() && nodep->dtypep()->isEvent()) {
checkEventAssignement(nodep);
v3Global.setAssignsEvents();
}
}

View File

@ -3586,9 +3586,9 @@ statement_item<nodep>: // IEEE: statement_item
| yDISABLE idAny '.' idDotted ';'
{ $$ = nullptr; BBUNSUP($4, "Unsupported: disable with '.'"); }
// // IEEE: event_trigger
| yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';'
| yP_MINUSGT expr ';'
{ $$ = new AstFireEvent{$1, $2, false}; }
| yP_MINUSGTGT delay_or_event_controlE idDotted/*hierarchical_identifier-event*/ ';'
| yP_MINUSGTGT delay_or_event_controlE expr ';'
{ $$ = new AstFireEvent{$1, $3, true}; }
//
// // IEEE: loop_statement

View File

@ -0,0 +1,25 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2023 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
verilator_flags2 => ["--exe --main --timing"],
make_main => 0,
# Multithreading would cause a warning on event assignments
threads => 1,
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,68 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
int evt_recv_cnt;
int new_evt_recv_cnt;
module t();
class Foo;
event evt1;
task automatic send_evt();
fork
#10 begin ->evt1; end
begin
event new_event;
#20;
// This should cause an event merge but for now we don't support that.
evt1 = new_event;
end
#30 begin
@evt1 $display("Received a new event");
new_evt_recv_cnt++;
end
join_none
endtask
task wait_for_event();
fork begin
@evt1 $display("Received evt1");
evt_recv_cnt++;
end join_none
endtask
endclass
initial begin
Foo foo1;
foo1 = new;
evt_recv_cnt = 0;
new_evt_recv_cnt = 0;
for (int i = 0; i < 4; i++) begin
foo1.wait_for_event();
#10;
foo1.send_evt();
#90;
$display("- end of iteration -");
if (evt_recv_cnt != i + 1)
$stop;
if (new_evt_recv_cnt != i)
$stop;
end
if (evt_recv_cnt != 4)
$stop;
if (new_evt_recv_cnt != 3)
$stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2023 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
verilator_flags2 => ["--exe --main --timing"],
make_main => 0,
threads => 1,
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,51 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
class Bar;
event evt;
task automatic wait_for_event();
@evt;
endtask
function automatic event get_event();
return evt;
endfunction
endclass
class Foo;
task automatic send_event(Bar b);
->b.get_event();
endtask
endclass
bit got_event;
module t();
initial begin
Bar bar;
Foo foo;
foo = new;
bar = new;
got_event = 0;
fork
begin
bar.wait_for_event();
$display("Got the event!");
got_event = 1;
end
#10 foo.send_event(bar);
join
#99;
if (!got_event)
$stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,10 +1,20 @@
%Error-UNSUPPORTED: t/t_event_copy.v:100:13: Unsupported: assignment of event data type
%Error-UNSUPPORTED: t/t_event_copy.v:100:13: Assignement to and from event in statically scheduled context.
: ... note: In instance 't'
: Static event scheduling won't be able to handle this.
: ... Suggest move the event into a completely dynamic context, eg. a class, and reference it only from such context.
100 | e4 = e3;
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_event_copy.v:101:13: Unsupported: assignment of event data type
%Error-UNSUPPORTED: t/t_event_copy.v:101:13: Assignement to and from event in statically scheduled context.
: ... note: In instance 't'
: Static event scheduling won't be able to handle this.
: ... Suggest move the event into a completely dynamic context, eg. a class, and reference it only from such context.
101 | e3 = e2;
| ^
%Error-UNSUPPORTED: t/t_event_copy.v:128:13: Assignement to event in statically scheduled context.
: ... note: In instance 't'
: Static event scheduling won't be able to handle this.
: ... Suggest move the event into a completely dynamic context, eg. a class, and reference it only from such context.
128 | e3 = null;
| ^
%Error: Exiting due to

View File

@ -13,6 +13,7 @@ scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
threads => 1,
);
execute(

View File

@ -7524,9 +7524,7 @@ virtual class uvm_event_base extends uvm_object;
event e;
if (wakeup)
->m_event;
//TODO issue #4468 - Fix UVM assignment of event data types
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:7477:25: Unsupported: assignment of event data type
//TODO m_event = e;
m_event = e;
num_waiters = 0;
on = 0;
trigger_time = 0;
@ -7547,9 +7545,7 @@ virtual class uvm_event_base extends uvm_object;
uvm_event_base e;
super.do_copy(rhs);
if(!$cast(e, rhs) || (e==null)) return;
//TODO issue #4468 - Fix UVM assignment of event data types
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:7498:25: Unsupported: assignment of event data type
//TODO m_event = e.m_event;
m_event = e.m_event;
num_waiters = e.num_waiters;
on = e.on;
trigger_time = e.trigger_time;