diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index b3dc26c8dc..5924bc5b87 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -284,7 +284,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) { // so always inline them. VL_ATTR_ALWINLINE -void VerilatedFstBuffer::emitEvent(uint32_t code, VlEventHandle newval) { +void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) { VL_DEBUG_IFDEF(assert(m_symbolp[code]);); fstWriterEmitValueChange(m_fst, m_symbolp[code], "1"); } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index c3a6eacbdd..07e1102aa2 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -163,7 +163,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, VlEventHandle 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); diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 4a969ded26..4eee175c82 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -423,7 +423,7 @@ class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer { 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, VlEventHandle 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 @@ -460,7 +460,7 @@ class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer { } } } - VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEventHandle 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) { @@ -541,7 +541,7 @@ class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer m_offloadBufferWritep += 4; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - void chgEvent(uint32_t code, VlEventHandle newval) { + void chgEvent(uint32_t code, const VlEventBase* newval) { m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT; m_offloadBufferWritep[1] = code; m_offloadBufferWritep += 2; diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index 5a16a1176e..a66792c656 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -185,7 +185,7 @@ void VerilatedTrace::offloadWorkerThreadMain() { continue; case VerilatedTraceOffloadCommand::CHG_EVENT: VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top); - traceBufp->chgEvent(oldp, *reinterpret_cast(readp)); + traceBufp->chgEvent(oldp, reinterpret_cast(readp)); continue; //=== @@ -839,7 +839,7 @@ void VerilatedTraceBuffer::fullBit(uint32_t* oldp, CData newval) { } template <> -void VerilatedTraceBuffer::fullEvent(uint32_t* oldp, VlEventHandle newval) { +void VerilatedTraceBuffer::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); diff --git a/include/verilated_types.h b/include/verilated_types.h index e5ebf1fbbc..66475a88de 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -163,7 +163,18 @@ class VlTriggerVec final { //=================================================================== // 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 @@ -171,44 +182,49 @@ class VlEvent final { public: // CONSTRUCTOR VlEvent() = default; - ~VlEvent() = default; + ~VlEvent() override = default; friend std::string VL_TO_STRING(const VlEvent& e); -#ifdef VL_EVENT_ASSIGN - friend class VlEventHandle; -#else + 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; } -#endif + 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; } }; -inline std::string VL_TO_STRING(const VlEvent& e) { - return std::string{"triggered="} + (e.m_triggered ? "true" : "false"); -} - -#ifdef VL_EVENT_ASSIGN -class VlEventHandle final : public std::shared_ptr { +class VlAssignableEvent final : public std::shared_ptr, public VlEventBase { public: // Constructor - VlEventHandle() + VlAssignableEvent() : std::shared_ptr(new VlEvent) {} + ~VlAssignableEvent() override = default; // METHODS - void fire() { (*this)->m_fired = (*this)->m_triggered = true; } - bool isFired() const { return (*this)->m_fired; } - bool isTriggered() const { return (*this)->m_triggered; } - void clearFired() { (*this)->m_fired = false; } - void clearTriggered() { (*this)->m_triggered = false; } + 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 VlEventHandle& e) { return "&{ " + VL_TO_STRING(*e) + " }"; } -#else -using VlEventHandle = VlEvent; -#endif +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(e)) { + return VL_TO_STRING(assignable); + } + return std::string{"triggered="} + (e.isTriggered() ? "true" : "false"); +} //=================================================================== // Random diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index b57babeaa9..9ca46e062a 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -669,8 +669,8 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) { // so always inline them. VL_ATTR_ALWINLINE -void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEventHandle 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) { diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index d806f6214a..a07508f62e 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -207,7 +207,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, VlEventHandle 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); diff --git a/src/V3Ast.h b/src/V3Ast.h index 71a9399979..23ec2bc283 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -324,7 +324,7 @@ class VEdgeType final { 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, // diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 7f129df82c..371e63ba0b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -858,7 +858,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { } else if (bdtypep->isProcessRef()) { info.m_type = "VlProcessRef"; } else if (bdtypep->isEvent()) { - info.m_type = "VlEventHandle"; + 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) { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index f84e9442c5..d39667a45d 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -812,6 +812,9 @@ 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*)"); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index c7b6554c0d..8254a39999 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -466,9 +466,9 @@ void EmitCSyms::emitSymHdr() { } if (v3Global.hasEvents()) { if (v3Global.assignsEvents()) { - puts("std::vector __Vm_triggeredEvents;\n"); + puts("std::vector __Vm_triggeredEvents;\n"); } else { - puts("std::vector __Vm_triggeredEvents;\n"); + puts("std::vector __Vm_triggeredEvents;\n"); } } if (v3Global.hasClasses()) puts("VlDeleter __Vm_deleter;\n"); @@ -538,7 +538,11 @@ void EmitCSyms::emitSymHdr() { puts("const char* name() { return TOP.name(); }\n"); if (v3Global.hasEvents()) { - puts("void enqueueTriggeredEventForClearing(VlEventHandle& 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 " diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 4a84dd1eda..ef3969d5a7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4320,8 +4320,8 @@ class WidthVisitor final : public VNVisitor { << asgnp->warnMore() << "Static event " "scheduling won't be able to handle this.\n" - << asgnp->warnMore() << - "... Suggest move the event into a " + << asgnp->warnMore() + << "... Suggest move the event into a " "completely dynamic context, eg. a class, and " "reference it only from such context."); }