mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Allow assigning events (#4403)
Signed-off-by: Krzysztof Boronski <kboronski@antmicro.com>
This commit is contained in:
parent
34708bbba1
commit
a87fb57656
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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*)");
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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; }
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
25
test_regress/t/t_event_control_assign.pl
Executable file
25
test_regress/t/t_event_control_assign.pl
Executable 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;
|
68
test_regress/t/t_event_control_assign.v
Normal file
68
test_regress/t/t_event_control_assign.v
Normal 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
|
24
test_regress/t/t_event_control_pass.pl
Executable file
24
test_regress/t/t_event_control_pass.pl
Executable 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;
|
51
test_regress/t/t_event_control_pass.v
Normal file
51
test_regress/t/t_event_control_pass.v
Normal 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
|
@ -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
|
||||
|
@ -13,6 +13,7 @@ scenarios(simulator => 1);
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
threads => 1,
|
||||
);
|
||||
|
||||
execute(
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user