The Sparta Modeling Framework
Loading...
Searching...
No Matches
ROB.cpp
1// <ROB.cpp> -*- C++ -*-
2
3
4#include <algorithm>
5#include "ROB.hpp"
7
8namespace core_example
9{
10 const char ROB::name[] = "rob";
11
13 const ROBParameterSet * p) :
14 sparta::Unit(node),
15 stat_ipc_(&unit_stat_set_,
16 "ipc",
17 "Instructions retired per cycle",
18 &unit_stat_set_,
19 "total_number_retired/cycles",
20 {
22 {
23 {"low", "0"},
24 {"high", std::to_string(uint32_t(p->num_to_retire))},
25 {"semantic", "higher"}
26 }
27 }),
28 num_retired_(&unit_stat_set_,
29 "total_number_retired",
30 "The total number of instructions retired by this core",
32 num_flushes_(&unit_stat_set_,
33 "total_number_of_flushes",
34 "The total number of flushes performed by the ROB",
36 num_to_retire_(p->num_to_retire),
37 num_insts_to_retire_(p->num_insts_to_retire),
38 reorder_buffer_("ReorderBuffer", p->retire_queue_depth,
39 node->getClock(), &unit_stat_set_)
40 {
41 // Set a cycle delay on the retire, just for kicks
42 ev_retire_.setDelay(1);
43
44 // Set up the reorder buffer to support pipeline collection.
45 reorder_buffer_.enableCollection(node);
46
47 in_reorder_buffer_write_.
48 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(ROB, robAppended_, InstGroup));
49
50 in_reorder_flush_.
51 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(ROB, handleFlush_,
52 FlushManager::FlushingCriteria));
53
54 // This event is ALWAYS scheduled, but it should not keep
55 // simulation continuing on.
56 ev_ensure_forward_progress_.setContinuing(false);
57
58 // Send initial credits to anyone that cares. Probably Dispatch.
59 sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(ROB, sendInitialCredits_));
60 }
61
64 // Logging can be done from destructors in the correct simulator setup
65 info_logger_ << "ROB is destructing now, but you can still see this message";
66 }
67
68 void ROB::sendInitialCredits_()
69 {
70 out_reorder_buffer_credits_.send(reorder_buffer_.capacity());
71 ev_ensure_forward_progress_.schedule(retire_timeout_interval_);
72 }
73
74 void ROB::retireEvent_() {
75 retireInstructions_();
76 if (reorder_buffer_.size() > 0) {
77 ev_retire_.schedule(sparta::Clock::Cycle(1));
78 }
79
81 info_logger_ << "Retire event";
82 }
83 }
84
85 // An illustration of the use of the callback -- instead of
86 // getting a reference, you can pull the data from the port
87 // directly, albeit inefficient and superfluous here...
88 void ROB::robAppended_(const InstGroup &) {
89 for(auto & i : in_reorder_buffer_write_.pullData()) {
90 reorder_buffer_.push(i);
91 }
92
93 ev_retire_.schedule(sparta::Clock::Cycle(0));
94 if(info_logger_) {
95 info_logger_ << "Retire appended";
96 }
97 }
98
99 void ROB::handleFlush_(const FlushManager::FlushingCriteria &)
100 {
101 // Clean up internals and send new credit count
102 out_reorder_buffer_credits_.send(reorder_buffer_.size());
103 reorder_buffer_.clear();
104 }
105
106 void ROB::retireInstructions_() {
107 const uint32_t num_to_retire = std::min(reorder_buffer_.size(), num_to_retire_);
108
110 info_logger_ << "Retire event, num to retire: " << num_to_retire;
111 }
112
113 uint32_t retired_this_cycle = 0;
114 for(uint32_t i = 0; i < num_to_retire; ++i)
115 {
116 auto & ex_inst_ptr = reorder_buffer_.access(0);
117 auto & ex_inst = *ex_inst_ptr;
118 sparta_assert(ex_inst.isSpeculative() == false,
119 "Uh, oh! A speculative instruction is being retired: " << ex_inst);
120 if(ex_inst.getStatus() == ExampleInst::Status::COMPLETED)
121 {
122 // UPDATE:
123 ex_inst.setStatus(ExampleInst::Status::RETIRED);
124 if (ex_inst.isStoreInst()) {
125 out_rob_retire_ack_.send(ex_inst_ptr);
126 }
127
128 ++num_retired_;
129 ++retired_this_cycle;
130 reorder_buffer_.pop();
131
133 info_logger_ << "Retiring " << ex_inst;
134 }
135
136 if(SPARTA_EXPECT_FALSE((num_retired_ % 1000000) == 0)) {
137 std::cout << "Retired " << num_retired_
138 << " instructions" << std::endl;
139 }
140 // Will be true if the user provides a -i option
141 if (SPARTA_EXPECT_FALSE((num_retired_ == num_insts_to_retire_))) {
143 break;
144 }
145
146 // This is rare for the example
147 if(SPARTA_EXPECT_FALSE(ex_inst.getUnit() == ExampleInst::TargetUnit::ROB))
148 {
150 info_logger_ << "Instigating flush... " << ex_inst;
151 }
152 // Signal flush to the system
153 out_retire_flush_.send(ex_inst.getUniqueID());
154
155 // Redirect fetch
156 out_fetch_flush_redirect_.send(ex_inst.getVAdr() + 4);
157
158 ++num_flushes_;
159 break;
160 }
161
162 }
163 else {
164 ex_inst.setLast(true, &ev_retire_);
165 break;
166 }
167 }
168 out_reorder_buffer_credits_.send(retired_this_cycle);
169 last_retirement_ = getClock()->currentCycle();
170 }
171
172 // Make sure the pipeline is making forward progress
173 void ROB::checkForwardProgress_()
174 {
175 if(getClock()->currentCycle() - last_retirement_ >= retire_timeout_interval_)
176 {
178 e << "Been a while since we've retired an instruction. Is the pipe stalled indefinitely?";
179 throw e;
180 }
181 ev_ensure_forward_progress_.schedule(retire_timeout_interval_);
182 }
183
184}
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
#define CREATE_SPARTA_HANDLER_WITH_DATA(clname, meth, dataT)
#define CREATE_SPARTA_HANDLER(clname, meth)
File that defines the StartupEvent class.
Parameters for ROB model.
Definition ROB.hpp:32
ROB(sparta::TreeNode *node, const ROBParameterSet *p)
Constructor for ROB.
Definition ROB.cpp:12
static const char name[]
Name of this resource. Required by sparta::UnitFactory.
Definition ROB.hpp:60
~ROB()
Destroy!
Definition ROB.cpp:63
Cycle currentCycle() const
Get the current cycle (uses current tick from the Scheduler)
Definition Clock.hpp:169
@ COUNT_NORMAL
Counter counts the number of times something happens like one would expect. This is a weakly monotoni...
DataT pullData()
Return the last data received by the port, then clear it.
void send(const DataT &dat, sparta::Clock::Cycle rel_time=0)
Send data to bound receivers.
Definition DataPort.hpp:145
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
bool observed() const noexcept
Is this NotificationSourceBase being observed at this node or an ancestor of any distance.
size_type size() const
Return the number of valid entries.
Definition Queue.hpp:552
uint32_t capacity() const
Return the fixed size of this queue.
Definition Queue.hpp:544
iterator push(const value_type &dat)
push data to the Queue.
Definition Queue.hpp:615
value_type & access(uint32_t idx)
Read and return the data at the given index, reference, non-const method.
Definition Queue.hpp:515
void clear()
Empty the queue.
Definition Queue.hpp:580
void pop()
Pops the data at the front of the structure (oldest element) After pop iterator always points to the ...
Definition Queue.hpp:636
Scheduler * getScheduler(const bool must_exist=true) const
const Clock * getClock() const
void stopRunning()
Tell the scheduler to stop running.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
StartupEvent is a simple class for scheduling a starting event on the Scheduler. It does not support ...
@ VS_ABSOLUTE
An absolute number having no units (typical default)
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:204
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
log::MessageSource info_logger_
Default info logger.
Definition Unit.hpp:161
Macros for handling exponential backoff.