From 9a2771bf0b41d6d8537d4716d7da90eadcde757f Mon Sep 17 00:00:00 2001 From: Thomas Dybdahl Ahle Date: Tue, 3 Mar 2026 13:19:16 +0100 Subject: [PATCH] [circt-sim] Add missing EventScheduler::peekCurrentRegion and stepDeltaUpTo ProcessScheduler.cpp (added in 827f1855f) calls peekCurrentRegion() and stepDeltaUpTo() on EventScheduler, but these methods were never declared in EventQueue.h or implemented in EventQueue.cpp, causing build failures. Add: - TimeWheel::peekCurrentRegion(): returns the next non-empty SchedulingRegion in the current delta without advancing the cursor (returns NumRegions if no events remain). - TimeWheel::processDeltaUpTo(limitRegion): processes all regions in the current delta up to and including limitRegion; advances the region cursor and cleans up empty queues. - EventScheduler::peekCurrentRegion(): thin wrapper around TimeWheel. - EventScheduler::stepDeltaUpTo(limitRegion): thin wrapper; updates stats. --- include/circt/Dialect/Sim/EventQueue.h | 16 +++++ lib/Dialect/Sim/EventQueue.cpp | 90 ++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/include/circt/Dialect/Sim/EventQueue.h b/include/circt/Dialect/Sim/EventQueue.h index 36ad43af68..1a1a8d8c45 100644 --- a/include/circt/Dialect/Sim/EventQueue.h +++ b/include/circt/Dialect/Sim/EventQueue.h @@ -390,6 +390,14 @@ class TimeWheel { /// Returns the number of events processed. size_t processCurrentDelta(); + /// Process all events in the current delta up to (inclusive) limitRegion. + /// Returns the number of events processed. + size_t processDeltaUpTo(SchedulingRegion limitRegion); + + /// Peek at the next non-empty region in the current delta without advancing. + /// Returns NumRegions if no events remain in the current delta. + SchedulingRegion peekCurrentRegion() const; + /// Process all events at the current real time (all deltas and regions). /// Returns the number of events processed. size_t processCurrentTime(); @@ -566,6 +574,14 @@ class EventScheduler { /// Returns false if simulation is complete. bool stepDelta(); + /// Step through the current delta up to (inclusive) the given region limit. + /// Returns true if any events were processed. + bool stepDeltaUpTo(SchedulingRegion limitRegion); + + /// Peek at the next non-empty region in the current delta without advancing. + /// Returns NumRegions if no events remain in the current delta. + SchedulingRegion peekCurrentRegion() const; + /// Advance time to the next scheduled event without processing it. /// This allows the caller to control when events are executed. /// Returns true if time was advanced, false if no events or already at next event. diff --git a/lib/Dialect/Sim/EventQueue.cpp b/lib/Dialect/Sim/EventQueue.cpp index 991f89410f..cf08458ac9 100644 --- a/lib/Dialect/Sim/EventQueue.cpp +++ b/lib/Dialect/Sim/EventQueue.cpp @@ -497,6 +497,81 @@ size_t TimeWheel::processCurrentDelta() { return total; } +SchedulingRegion TimeWheel::peekCurrentRegion() const { + size_t slotIdx = getSlotIndex(currentTime.realTime, 0); + const auto &slot = levels[0].slots[slotIdx]; + const DeltaCycleQueue *deltaQueuePtr = nullptr; + if (currentTime.deltaStep < Slot::kInlineDeltaSlots) { + if (slot.deltaQueues[currentTime.deltaStep].hasAnyEvents()) + deltaQueuePtr = &slot.deltaQueues[currentTime.deltaStep]; + } else { + auto it = slot.extraDeltaQueues.find(currentTime.deltaStep); + if (it != slot.extraDeltaQueues.end()) + deltaQueuePtr = &it->second; + } + if (!deltaQueuePtr) + return SchedulingRegion::NumRegions; + return deltaQueuePtr->getNextNonEmptyRegion( + static_cast(currentTime.region)); +} + +size_t TimeWheel::processDeltaUpTo(SchedulingRegion limitRegion) { + size_t total = 0; + size_t slotIdx = getSlotIndex(currentTime.realTime, 0); + auto &slot = levels[0].slots[slotIdx]; + + DeltaCycleQueue *deltaQueue = nullptr; + bool isInline = (currentTime.deltaStep < Slot::kInlineDeltaSlots); + if (isInline) { + if (slot.deltaQueues[currentTime.deltaStep].hasAnyEvents()) + deltaQueue = &slot.deltaQueues[currentTime.deltaStep]; + } else { + auto it = slot.extraDeltaQueues.find(currentTime.deltaStep); + if (it != slot.extraDeltaQueues.end()) + deltaQueue = &it->second; + } + + if (deltaQueue) { + bool madeProgress = true; + while (madeProgress) { + madeProgress = false; + auto region = deltaQueue->getNextNonEmptyRegion( + static_cast(currentTime.region)); + while (region != SchedulingRegion::NumRegions && + static_cast(region) <= + static_cast(limitRegion)) { + size_t count = deltaQueue->executeAndClearRegion(region); + totalEvents -= count; + total += count; + madeProgress = true; + + unsigned nextIdx = static_cast(region) + 1; + if (nextIdx > static_cast(limitRegion)) + break; + region = deltaQueue->getNextNonEmptyRegion( + static_cast(nextIdx)); + } + } + + // Advance region cursor to just past the limit so subsequent stepRegion() + // calls start from the correct position. + unsigned nextIdx = static_cast(limitRegion) + 1; + if (nextIdx < static_cast(SchedulingRegion::NumRegions)) { + auto nextRegion = deltaQueue->getNextNonEmptyRegion( + static_cast(nextIdx)); + if (nextRegion != SchedulingRegion::NumRegions) + currentTime.region = static_cast(nextRegion); + } + + if (!isInline && !deltaQueue->hasAnyEvents()) + slot.extraDeltaQueues.erase(currentTime.deltaStep); + } + + slot.hasEvents = slot.hasAnyEvents(); + updateSlotBit(0, slotIdx, slot.hasEvents); + return total; +} + size_t TimeWheel::processCurrentTime() { size_t total = 0; @@ -656,6 +731,21 @@ bool EventScheduler::stepDelta() { return processed > 0; } +bool EventScheduler::stepDeltaUpTo(SchedulingRegion limitRegion) { + if (!wheel->hasEvents()) + return false; + + size_t processed = wheel->processDeltaUpTo(limitRegion); + stats.eventsProcessed += processed; + if (processed > 0) + ++stats.deltaCycles; + return processed > 0; +} + +SchedulingRegion EventScheduler::peekCurrentRegion() const { + return wheel->peekCurrentRegion(); +} + bool EventScheduler::advanceToNextTime() { if (!wheel->hasEvents()) return false;