The Sparta Modeling Framework
Loading...
Searching...
No Matches
Dispatch.cpp
1// <Dispatch.cpp> -*- C++ -*-
2
3
4
5#include <algorithm>
6#include "Dispatch.hpp"
8
9namespace core_example
10{
11 const char Dispatch::name[] = "dispatch";
12
13 // Constructor
15 const DispatchParameterSet * p) :
16 sparta::Unit(node),
17 dispatch_queue_("dispatch_queue", p->dispatch_queue_depth,
18 node->getClock(), getStatisticSet()),
19 num_to_dispatch_(p->num_to_dispatch)
20 {
21 weighted_unit_distribution_context_.assignContextWeights(p->context_weights);
22 dispatch_queue_.enableCollection(node);
23
24 // Start the no instructions counter
25 stall_counters_[current_stall_].startCounting();
26
27 // Register consuming events with the InPorts.
28 in_dispatch_queue_write_.
29 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, dispatchQueueAppended_, InstGroup));
30
31 in_fpu_credits_.
32 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, fpuCredits_, uint32_t));
33 in_fpu_credits_.enableCollection(node);
34
35 in_alu0_credits_.
36 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, alu0Credits_, uint32_t));
37 in_alu0_credits_.enableCollection(node);
38
39 in_alu1_credits_.
40 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, alu1Credits_, uint32_t));
41 in_alu1_credits_.enableCollection(node);
42
43 in_br_credits_.
44 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, brCredits_, uint32_t));
45 in_br_credits_.enableCollection(node);
46
47 in_lsu_credits_.
48 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, lsuCredits_, uint32_t));
49 in_lsu_credits_.enableCollection(node);
50
51 in_reorder_credits_.
52 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, robCredits_, uint32_t));
53 in_reorder_credits_.enableCollection(node);
54
55 in_reorder_flush_.
56 registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(Dispatch, handleFlush_, FlushManager::FlushingCriteria));
57 in_reorder_flush_.enableCollection(node);
58
59 sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(Dispatch, sendInitialCredits_));
60 }
61
62 void Dispatch::sendInitialCredits_()
63 {
64 out_dispatch_queue_credits_.send(dispatch_queue_.capacity());
65 }
66
67 void Dispatch::fpuCredits_ (const uint32_t& credits) {
68 credits_fpu_ += credits;
69 if (credits_rob_ >0 && dispatch_queue_.size() > 0) {
70 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
71 }
73 info_logger_ << "FPU got " << credits << " credits, total: " << credits_fpu_;
74 }
75 }
76
77 void Dispatch::alu0Credits_ (const uint32_t& credits) {
78 credits_alu0_ += credits;
79 if (credits_rob_ >0 && dispatch_queue_.size() > 0) {
80 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
81 }
83 info_logger_ << "ALU0 got " << credits << " credits, total: " << credits_alu0_;
84 }
85 }
86
87 void Dispatch::alu1Credits_ (const uint32_t& credits) {
88 credits_alu1_ += credits;
89 if (credits_rob_ >0 && dispatch_queue_.size() > 0) {
90 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
91 }
93 info_logger_ << "ALU1 got " << credits << " credits, total: " << credits_alu1_;
94 }
95 }
96
97 void Dispatch::brCredits_ (const uint32_t& credits) {
98 credits_br_ += credits;
99 if (credits_rob_ >0 && dispatch_queue_.size() > 0) {
100 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
101 }
103 info_logger_ << "BR got " << credits << " credits, total: " << credits_br_;
104 }
105 }
106
107 void Dispatch::lsuCredits_(const uint32_t& credits) {
108 credits_lsu_ += credits;
109 if (credits_rob_ >0 && dispatch_queue_.size() > 0) {
110 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
111 }
113 info_logger_ << "LSU got " << credits << " credits, total: " << credits_lsu_;
114 }
115 }
116
117 void Dispatch::robCredits_(const uint32_t&) {
118 uint32_t nc = in_reorder_credits_.pullData();
119 credits_rob_ += nc;
120 if (((credits_fpu_ > 0)|| (credits_alu0_ > 0) || (credits_alu1_ > 0) || (credits_br_ > 0))
121 && dispatch_queue_.size() > 0) {
122 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
123 }
125 info_logger_ << "ROB got " << nc << " credits, total: " << credits_rob_;
126 }
127 }
128
129 void Dispatch::dispatchQueueAppended_(const InstGroup &) {
130 for(auto & i : in_dispatch_queue_write_.pullData()) {
131 dispatch_queue_.push(i);
132 }
133
134 if (((credits_fpu_ > 0)|| (credits_alu0_ > 0) || (credits_alu1_ > 0) || (credits_br_ > 0) || credits_lsu_ > 0)
135 && credits_rob_ >0) {
136 ev_dispatch_insts_.schedule(sparta::Clock::Cycle(0));
137 }
138 }
139
140 void Dispatch::handleFlush_(const FlushManager::FlushingCriteria & criteria)
141 {
143 info_logger_ << "Got a flush call for " << criteria;
144 }
145 out_dispatch_queue_credits_.send(dispatch_queue_.size());
146 dispatch_queue_.clear();
147 credits_fpu_ += out_fpu_write_.cancel();
148 credits_alu0_ += out_alu0_write_.cancel();
149 credits_alu1_ += out_alu1_write_.cancel();
150 credits_br_ += out_br_write_.cancel();
151 credits_lsu_ += out_lsu_write_.cancel();
152 out_reorder_write_.cancel();
153 }
154
155 void Dispatch::dispatchInstructions_()
156 {
157 uint32_t num_dispatch = std::min(dispatch_queue_.size(), num_to_dispatch_);
158 num_dispatch = std::min(credits_rob_, num_dispatch);
159
161 info_logger_ << "Num to dispatch: " << num_dispatch;
162 }
163
164 // Stop the current counter
165 stall_counters_[current_stall_].stopCounting();
166
167 if(num_dispatch == 0) {
168 stall_counters_[current_stall_].startCounting();
169 return;
170 }
171
172 current_stall_ = NOT_STALLED;
173
174 InstGroup insts_dispatched;
175 bool keep_dispatching = true;
176 for(uint32_t i = 0; (i < num_dispatch) && keep_dispatching; ++i)
177 {
178 bool dispatched = false;
179 ExampleInstPtr & ex_inst_ptr = dispatch_queue_.access(0);
180 ExampleInst & ex_inst = *ex_inst_ptr;
181
182 switch(ex_inst.getUnit())
183 {
184 case ExampleInst::TargetUnit::FPU:
185 {
186 if(credits_fpu_ > 0) {
187 --credits_fpu_;
188 dispatched = true;
189 out_fpu_write_.send(ex_inst_ptr);
190 ++unit_distribution_[static_cast<uint32_t>(ExampleInst::TargetUnit::FPU)];
191 ++(unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::FPU)));
192 ++(weighted_unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::FPU)));
193
195 info_logger_ << "Sending instruction: "
196 << ex_inst_ptr << " to FPU ";
197 }
198 }
199 else {
200 current_stall_ = FPU_BUSY;
201 keep_dispatching = false;
202 }
203 }
204 break;
205 case ExampleInst::TargetUnit::ALU0:
206 {
207 if(credits_alu0_ > 0) {
208 --credits_alu0_;
209 dispatched = true;
210 //out_alu0_write_.send(ex_inst_ptr); // <- This will cause an assert in the Port!
211 out_alu0_write_.send(ex_inst_ptr, 1);
212 ++unit_distribution_[static_cast<uint32_t>(ExampleInst::TargetUnit::ALU0)];
213 ++(unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::ALU0)));
214 ++(weighted_unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::ALU0)));
215 ++(alu0_context_.context(0));
216
218 info_logger_ << "Sending instruction: "
219 << ex_inst_ptr << " to ALU0 ";
220 }
221 }
222 else {
223 current_stall_ = ALU0_BUSY;
224 keep_dispatching = false;
225 }
226 }
227 break;
228 case ExampleInst::TargetUnit::ALU1:
229 {
230 if(credits_alu1_ > 0)
231 {
232 --credits_alu1_;
233 dispatched = true;
234 out_alu1_write_.send(ex_inst_ptr, 1);
235 ++unit_distribution_[static_cast<uint32_t>(ExampleInst::TargetUnit::ALU1)];
236 ++(unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::ALU1)));
237 ++(weighted_unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::ALU1)));
238
240 info_logger_ << "Sending instruction: "
241 << ex_inst_ptr << " to ALU1 ";
242 }
243 }
244 else {
245 current_stall_ = ALU0_BUSY;
246 keep_dispatching = false;
247 }
248 }
249 break;
250 case ExampleInst::TargetUnit::BR:
251 {
252 if(credits_br_ > 0)
253 {
254 --credits_br_;
255 dispatched = true;
256 out_br_write_.send(ex_inst_ptr, 1);
257 ++unit_distribution_[static_cast<uint32_t>(ExampleInst::TargetUnit::BR)];
258 ++(unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::BR)));
259 ++(weighted_unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::BR)));
260
262 info_logger_ << "Sending instruction: "
263 << ex_inst_ptr << " to BR ";
264 }
265 }
266 else {
267 current_stall_ = BR_BUSY;
268 keep_dispatching = false;
269 }
270 }
271 break;
272 case ExampleInst::TargetUnit::LSU:
273 {
274 if(credits_lsu_ > 0)
275 {
276 --credits_lsu_;
277 dispatched = true;
278 out_lsu_write_.send(ex_inst_ptr, 1);
279 ++unit_distribution_[static_cast<uint32_t>(ExampleInst::TargetUnit::LSU)];
280 ++(unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::LSU)));
281 ++(weighted_unit_distribution_context_.context(static_cast<uint32_t>(ExampleInst::TargetUnit::LSU)));
282
284 info_logger_ << "sending instruction: "
285 << ex_inst_ptr << " to LSU ";
286 }
287 }
288 else {
289 current_stall_ = LSU_BUSY;
290 keep_dispatching = false;
291 }
292 }
293 break;
294 case ExampleInst::TargetUnit::ROB:
295 {
296 ex_inst.setStatus(ExampleInst::Status::COMPLETED);
297 // Indicate that this instruction was dispatched
298 // -- it goes right to the ROB
299 dispatched = true;
300 }
301 break;
302 default:
303 sparta_assert(!"Should not have gotten here");
304 }
305
306 if(dispatched) {
307 insts_dispatched.emplace_back(ex_inst_ptr);
308 dispatch_queue_.pop();
309 --credits_rob_;
310 } else {
312 info_logger_ << "Could not dispatch: "
313 << ex_inst_ptr
314 << " ALU0_B(" << std::boolalpha << (credits_alu0_ == 0)
315 << ") ALU1_B(" << (credits_alu1_ == 0)
316 << ") FPU_B(" << (credits_fpu_ == 0)
317 << ") BR_B(" << (credits_br_ == 0) << ")";
318 }
319 break;
320 }
321 }
322
323 if(!insts_dispatched.empty()) {
324 out_dispatch_queue_credits_.send(insts_dispatched.size());
325 out_reorder_write_.send(insts_dispatched);
326 }
327
328 if ((credits_rob_ > 0) && (dispatch_queue_.size() > 0) && (current_stall_ == NOT_STALLED)) {
329 ev_dispatch_insts_.schedule(1);
330 }
331
332 stall_counters_[current_stall_].startCounting();
333 }
334}
#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 Dispatch model.
Definition Dispatch.hpp:40
Dispatch(sparta::TreeNode *node, const DispatchParameterSet *p)
Constructor for Dispatch.
Definition Dispatch.cpp:14
static const char name[]
Name of this resource. Required by sparta::UnitFactory.
Definition Dispatch.hpp:66
const counter_type & context(const uint32_t idx) const
Return the internal counter at the given context.
DataT pullData()
Return the last data received by the port, then clear it.
void enableCollection(TreeNode *node) override
Enable pipeline collection.
Definition DataPort.hpp:447
uint32_t cancel()
Cancel all outstanding port sends regardless of criteria.
Definition DataPort.hpp:193
void send(const DataT &dat, sparta::Clock::Cycle rel_time=0)
Send data to bound receivers.
Definition DataPort.hpp:145
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
void schedule(Clock::Cycle rel_cycle=0)
Schedule this PhasedSingleCycleUniqueEvent exactly zero or one cycle into the future....
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
log::MessageSource info_logger_
Default info logger.
Definition Unit.hpp:161
Macros for handling exponential backoff.