Skip to content

Commit

Permalink
Merge remote-tracking branch 'antmicro/event_assign'
Browse files Browse the repository at this point in the history
  • Loading branch information
kbieganski committed Oct 25, 2023
2 parents cf6e362 + 4866b0d commit 4bfbaca
Show file tree
Hide file tree
Showing 24 changed files with 331 additions and 43 deletions.
2 changes: 1 addition & 1 deletion include/verilated_fst_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion include/verilated_fst_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 5 additions & 3 deletions include/verilated_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,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, 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
Expand Down Expand Up @@ -512,7 +512,9 @@ class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
}
}
}
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));
Expand Down Expand Up @@ -591,7 +593,7 @@ class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer>
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;
Expand Down
4 changes: 2 additions & 2 deletions include/verilated_trace_imp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//===
Expand Down Expand Up @@ -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);
Expand Down
56 changes: 49 additions & 7 deletions include/verilated_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <atomic>
#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
Expand Down Expand Up @@ -191,28 +192,69 @@ 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

public:
// CONSTRUCTOR
VlEvent() = default;
~VlEvent() = default;
~VlEvent() override = default;

friend std::string VL_TO_STRING(const VlEvent& e);
friend class VlAssignableEvent;
// METHODS
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() { 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 { (*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

Expand Down
4 changes: 2 additions & 2 deletions include/verilated_vcd_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion include/verilated_vcd_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/V3Ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
//
Expand Down Expand Up @@ -2016,6 +2016,7 @@ class AstNode VL_NOT_FINAL {
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 {
Expand Down
4 changes: 4 additions & 0 deletions src/V3AstInlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/V3AstNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/V3Cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class CastVisitor final : public VNVisitor {
&& !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);
Expand Down
1 change: 1 addition & 0 deletions src/V3EmitCImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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*)");
Expand Down
26 changes: 22 additions & 4 deletions src/V3EmitCSyms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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");
}
Expand Down
4 changes: 2 additions & 2 deletions src/V3Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ class V3ErrorCode final {
"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",
Expand Down
3 changes: 3 additions & 0 deletions src/V3Global.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -155,6 +156,8 @@ class V3Global final {
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; }
Expand Down
56 changes: 49 additions & 7 deletions src/V3Width.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -4319,6 +4321,47 @@ class WidthVisitor final : public VNVisitor {
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");
Expand Down Expand Up @@ -4713,12 +4756,6 @@ class WidthVisitor final : public VNVisitor {
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 "
Expand Down Expand Up @@ -4773,7 +4810,12 @@ class WidthVisitor final : public VNVisitor {
newp->dtypeSetVoid();
nodep->replaceWith(newp->makeStmt());
VL_DO_DANGLING(pushDeletep(nodep), nodep);
// return;
return;
}

if (nodep->hasDType() && nodep->dtypep()->isEvent()) {
checkEventAssignement(nodep);
v3Global.setAssignsEvents();
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/verilog.y
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 4bfbaca

Please sign in to comment.