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 num_retired_(&unit_stat_set_,
21 "total_number_retired",
22 "The total number of instructions retired by this core",
23 sparta::Counter::COUNT_NORMAL),
24 num_flushes_(&unit_stat_set_,
25 "total_number_of_flushes",
26 "The total number of flushes performed by the ROB",
27 sparta::Counter::COUNT_NORMAL),
28 num_to_retire_(p->num_to_retire),
29 num_insts_to_retire_(p->num_insts_to_retire),
30 reorder_buffer_("ReorderBuffer", p->retire_queue_depth,
31 node->getClock(), &unit_stat_set_)
32 {
33 // Set a cycle delay on the retire, just for kicks
34 ev_retire_.setDelay(1);
35
36 // Set up the reorder buffer to support pipeline collection.
37 reorder_buffer_.enableCollection(node);
38
39 in_reorder_buffer_write_.
40 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(ROB, robAppended_, InstGroup));
41
42 in_reorder_flush_.
43 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(ROB, handleFlush_,
44 FlushManager::FlushingCriteria));
45
46 // This event is ALWAYS scheduled, but it should not keep
47 // simulation continuing on.
48 ev_ensure_forward_progress_.setContinuing(false);
49
50 // Send initial credits to anyone that cares. Probably Dispatch.
51 sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(ROB, sendInitialCredits_));
52 }
53
56 // Logging can be done from destructors in the correct simulator setup
57 info_logger_ << "ROB is destructing now, but you can still see this message";
58 }
59
60 void ROB::sendInitialCredits_()
61 {
62 out_reorder_buffer_credits_.send(reorder_buffer_.capacity());
63 ev_ensure_forward_progress_.schedule(retire_timeout_interval_);
64 }
65
66 void ROB::retireEvent_() {
67 retireInstructions_();
68 if (reorder_buffer_.size() > 0) {
69 ev_retire_.schedule(sparta::Clock::Cycle(1));
70 }
71
73 info_logger_ << "Retire event";
74 }
75 }
76
77 // An illustration of the use of the callback -- instead of
78 // getting a reference, you can pull the data from the port
79 // directly, albeit inefficient and superfluous here...
80 void ROB::robAppended_(const InstGroup &) {
81 for(auto & i : in_reorder_buffer_write_.pullData()) {
82 reorder_buffer_.push(i);
83 }
84
85 ev_retire_.schedule(sparta::Clock::Cycle(0));
86 if(info_logger_) {
87 info_logger_ << "Retire appended";
88 }
89 }
90
91 void ROB::handleFlush_(const FlushManager::FlushingCriteria &)
92 {
93 // Clean up internals and send new credit count
94 out_reorder_buffer_credits_.send(reorder_buffer_.size());
95 reorder_buffer_.clear();
96 }
97
98 void ROB::retireInstructions_() {
99 const uint32_t num_to_retire = std::min(reorder_buffer_.size(), num_to_retire_);
100
102 info_logger_ << "Retire event, num to retire: " << num_to_retire;
103 }
104
105 uint32_t retired_this_cycle = 0;
106 for(uint32_t i = 0; i < num_to_retire; ++i)
107 {
108 auto & ex_inst_ptr = reorder_buffer_.access(0);
109 auto & ex_inst = *ex_inst_ptr;
110 sparta_assert(ex_inst.isSpeculative() == false,
111 "Uh, oh! A speculative instruction is being retired: " << ex_inst);
112 if(ex_inst.getStatus() == ExampleInst::Status::COMPLETED)
113 {
114 // UPDATE:
115 ex_inst.setStatus(ExampleInst::Status::RETIRED);
116 if (ex_inst.isStoreInst()) {
117 out_rob_retire_ack_.send(ex_inst_ptr);
118 }
119
120 ++num_retired_;
121 ++retired_this_cycle;
122 reorder_buffer_.pop();
123
125 info_logger_ << "Retiring " << ex_inst;
126 }
127
128 if(SPARTA_EXPECT_FALSE((num_retired_ % 1000000) == 0)) {
129 std::cout << "Retired " << num_retired_
130 << " instructions" << std::endl;
131 }
132 // Will be true if the user provides a -i option
133 if (SPARTA_EXPECT_FALSE((num_retired_ == num_insts_to_retire_))) {
135 break;
136 }
137
138 // This is rare for the example
139 if(SPARTA_EXPECT_FALSE(ex_inst.getUnit() == ExampleInst::TargetUnit::ROB))
140 {
142 info_logger_ << "Instigating flush... " << ex_inst;
143 }
144 // Signal flush to the system
145 out_retire_flush_.send(ex_inst.getUniqueID());
146
147 // Redirect fetch
148 out_fetch_flush_redirect_.send(ex_inst.getVAdr() + 4);
149
150 ++num_flushes_;
151 break;
152 }
153
154 }
155 else {
156 ex_inst.setLast(true, &ev_retire_);
157 break;
158 }
159 }
160 out_reorder_buffer_credits_.send(retired_this_cycle);
161 last_retirement_ = getClock()->currentCycle();
162 }
163
164 // Make sure the pipeline is making forward progress
165 void ROB::checkForwardProgress_()
166 {
167 if(getClock()->currentCycle() - last_retirement_ >= retire_timeout_interval_)
168 {
170 e << "Been a while since we've retired an instruction. Is the pipe stalled indefinitely?";
171 throw e;
172 }
173 ev_ensure_forward_progress_.schedule(retire_timeout_interval_);
174 }
175
176}
#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:55
Cycle currentCycle() const
Get the current cycle (uses current tick from the Scheduler)
Definition Clock.hpp:176
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 enableCollection(TreeNode *parent)
Request that this queue begin collecting its contents for pipeline collection.
Definition Queue.hpp:603
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 setContinuing(bool continuing)
This event, if continuing == true, will keep the simulation running.
void setDelay(Clock::Cycle delay)
Set a fixed delay for this event.
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 ...
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
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:156
Macros for handling exponential backoff.