gem5  v22.1.0.0
AbstractController.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017,2019-2022 ARM Limited
3  * All rights reserved.
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2011-2014 Mark D. Hill and David A. Wood
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
42 
43 #include "debug/RubyQueue.hh"
45 #include "mem/ruby/protocol/MemoryMsg.hh"
48 #include "sim/system.hh"
49 
50 namespace gem5
51 {
52 
53 namespace ruby
54 {
55 
57  : ClockedObject(p), Consumer(this), m_version(p.version),
58  m_clusterID(p.cluster_id),
59  m_id(p.system->getRequestorId(this)), m_is_blocking(false),
60  m_number_of_TBEs(p.number_of_TBEs),
61  m_transitions_per_cycle(p.transitions_per_cycle),
62  m_buffer_size(p.buffer_size), m_recycle_latency(p.recycle_latency),
63  m_mandatory_queue_latency(p.mandatory_queue_latency),
64  m_waiting_mem_retry(false),
65  memoryPort(csprintf("%s.memory", name()), this),
66  addrRanges(p.addr_ranges.begin(), p.addr_ranges.end()),
67  stats(this)
68 {
69  if (m_version == 0) {
70  // Combine the statistics from all controllers
71  // of this particular type.
73  }
74 }
75 
76 void
78 {
80  uint32_t size = Network::getNumberOfVirtualNetworks();
81  for (uint32_t i = 0; i < size; i++) {
82  stats.delayVCHistogram.push_back(new statistics::Histogram(this));
83  stats.delayVCHistogram[i]->init(10);
84  }
85 
86  if (getMemReqQueue()) {
87  getMemReqQueue()->setConsumer(this);
88  }
89 
90  // Initialize the addr->downstream machine mappings. Multiple machines
91  // in downstream_destinations can have the same address range if they have
92  // different types. If this is the case, mapAddressToDownstreamMachine
93  // needs to specify the machine type
95  for (auto abs_cntrl : params().downstream_destinations) {
96  MachineID mid = abs_cntrl->getMachineID();
97  const AddrRangeList &ranges = abs_cntrl->getAddrRanges();
98  for (const auto &addr_range : ranges) {
99  auto i = downstreamAddrMap.find(mid.getType());
100  if ((i != downstreamAddrMap.end()) &&
101  (i->second.intersects(addr_range) != i->second.end())) {
102  fatal("%s: %s mapped to multiple machines of the same type\n",
103  name(), addr_range.to_string());
104  }
105  downstreamAddrMap[mid.getType()].insert(addr_range, mid);
106  }
108  }
109  // Initialize the addr->upstream machine list.
110  // We do not need to map address -> upstream machine,
111  // so we don't examine the address ranges
113  for (auto abs_cntrl : params().upstream_destinations) {
114  upstreamDestinations.add(abs_cntrl->getMachineID());
115  }
116 }
117 
118 void
120 {
122  uint32_t size = Network::getNumberOfVirtualNetworks();
123  for (uint32_t i = 0; i < size; i++) {
124  stats.delayVCHistogram[i]->reset();
125  }
126 }
127 
128 void
130 {
132 }
133 
134 void
135 AbstractController::profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
136 {
137  assert(virtualNetwork < stats.delayVCHistogram.size());
138  stats.delayHistogram.sample(delay);
139  stats.delayVCHistogram[virtualNetwork]->sample(delay);
140 }
141 
142 void
144 {
145  if (m_waiting_buffers.count(addr) == 0) {
146  MsgVecType* msgVec = new MsgVecType;
147  msgVec->resize(m_in_ports, NULL);
148  m_waiting_buffers[addr] = msgVec;
149  }
150  DPRINTF(RubyQueue, "stalling %s port %d addr %#x\n", buf, m_cur_in_port,
151  addr);
152  assert(m_in_ports > m_cur_in_port);
153  (*(m_waiting_buffers[addr]))[m_cur_in_port] = buf;
154 }
155 
156 void
158 {
159  auto iter = m_waiting_buffers.find(addr);
160  if (iter != m_waiting_buffers.end()) {
161  bool has_other_msgs = false;
162  MsgVecType* msgVec = iter->second;
163  for (unsigned int port = 0; port < msgVec->size(); ++port) {
164  if ((*msgVec)[port] == buf) {
166  (*msgVec)[port] = NULL;
167  } else if ((*msgVec)[port] != NULL) {
168  has_other_msgs = true;
169  }
170  }
171  if (!has_other_msgs) {
172  delete msgVec;
173  m_waiting_buffers.erase(iter);
174  }
175  }
176 }
177 
178 void
180 {
181  if (m_waiting_buffers.count(addr) > 0) {
182  //
183  // Wake up all possible lower rank (i.e. lower priority) buffers that could
184  // be waiting on this message.
185  //
186  for (int in_port_rank = m_cur_in_port - 1;
187  in_port_rank >= 0;
188  in_port_rank--) {
189  if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
190  (*(m_waiting_buffers[addr]))[in_port_rank]->
191  reanalyzeMessages(addr, clockEdge());
192  }
193  }
194  delete m_waiting_buffers[addr];
195  m_waiting_buffers.erase(addr);
196  }
197 }
198 
199 void
201 {
202  if (m_waiting_buffers.count(addr) > 0) {
203  //
204  // Wake up all possible buffers that could be waiting on this message.
205  //
206  for (int in_port_rank = m_in_ports - 1;
207  in_port_rank >= 0;
208  in_port_rank--) {
209  if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
210  (*(m_waiting_buffers[addr]))[in_port_rank]->
211  reanalyzeMessages(addr, clockEdge());
212  }
213  }
214  delete m_waiting_buffers[addr];
215  m_waiting_buffers.erase(addr);
216  }
217 }
218 
219 void
221 {
222  //
223  // Wake up all possible buffers that could be waiting on any message.
224  //
225 
226  std::vector<MsgVecType*> wokeUpMsgVecs;
227  MsgBufType wokeUpMsgBufs;
228 
229  if (m_waiting_buffers.size() > 0) {
230  for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
231  buf_iter != m_waiting_buffers.end();
232  ++buf_iter) {
233  for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
234  vec_iter != buf_iter->second->end();
235  ++vec_iter) {
236  //
237  // Make sure the MessageBuffer has not already be reanalyzed
238  //
239  if (*vec_iter != NULL &&
240  (wokeUpMsgBufs.count(*vec_iter) == 0)) {
241  (*vec_iter)->reanalyzeAllMessages(clockEdge());
242  wokeUpMsgBufs.insert(*vec_iter);
243  }
244  }
245  wokeUpMsgVecs.push_back(buf_iter->second);
246  }
247 
248  for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
249  wb_iter != wokeUpMsgVecs.end();
250  ++wb_iter) {
251  delete (*wb_iter);
252  }
253 
254  m_waiting_buffers.clear();
255  }
256 }
257 
258 bool
260 {
261  auto mem_queue = getMemReqQueue();
262  assert(mem_queue);
263  if (m_waiting_mem_retry || !mem_queue->isReady(clockEdge())) {
264  return false;
265  }
266 
267  const MemoryMsg *mem_msg = (const MemoryMsg*)mem_queue->peek();
268  unsigned int req_size = RubySystem::getBlockSizeBytes();
269  if (mem_msg->m_Len > 0) {
270  req_size = mem_msg->m_Len;
271  }
272 
273  RequestPtr req
274  = std::make_shared<Request>(mem_msg->m_addr, req_size, 0, m_id);
275  PacketPtr pkt;
276  if (mem_msg->getType() == MemoryRequestType_MEMORY_WB) {
277  pkt = Packet::createWrite(req);
278  pkt->allocate();
279  pkt->setData(mem_msg->m_DataBlk.getData(getOffset(mem_msg->m_addr),
280  req_size));
281  } else if (mem_msg->getType() == MemoryRequestType_MEMORY_READ) {
282  pkt = Packet::createRead(req);
283  uint8_t *newData = new uint8_t[req_size];
284  pkt->dataDynamic(newData);
285  } else {
286  panic("Unknown memory request type (%s) for addr %p",
287  MemoryRequestType_to_string(mem_msg->getType()),
288  mem_msg->m_addr);
289  }
290 
291  SenderState *s = new SenderState(mem_msg->m_Sender);
292  pkt->pushSenderState(s);
293 
295  // Use functional rather than timing accesses during warmup
296  mem_queue->dequeue(clockEdge());
298  // Since the queue was popped the controller may be able
299  // to make more progress. Make sure it wakes up
300  scheduleEvent(Cycles(1));
301  recvTimingResp(pkt);
302  } else if (memoryPort.sendTimingReq(pkt)) {
303  mem_queue->dequeue(clockEdge());
304  // Since the queue was popped the controller may be able
305  // to make more progress. Make sure it wakes up
306  scheduleEvent(Cycles(1));
307  } else {
308  scheduleEvent(Cycles(1));
309  m_waiting_mem_retry = true;
310  delete pkt;
311  delete s;
312  }
313 
314  return true;
315 }
316 
317 void
319 {
320  m_is_blocking = true;
321  m_block_map[addr] = port;
322 }
323 
324 bool
326 {
327  return m_is_blocking && (m_block_map.find(addr) != m_block_map.end());
328 }
329 
330 void
332 {
333  m_block_map.erase(addr);
334  if (m_block_map.size() == 0) {
335  m_is_blocking = false;
336  }
337 }
338 
339 bool
341 {
342  return (m_block_map.count(addr) > 0);
343 }
344 
345 Port &
346 AbstractController::getPort(const std::string &if_name, PortID idx)
347 {
348  return memoryPort;
349 }
350 
351 void
353 {
354  // read from mem. req. queue if write data is pending there
355  MessageBuffer *req_queue = getMemReqQueue();
356  if (!req_queue || !req_queue->functionalRead(pkt))
358 }
359 
360 int
362 {
363  int num_functional_writes = 0;
364 
365  // Update memory itself.
367  return num_functional_writes + 1;
368 }
369 
370 void
372 {
373  assert(getMemRespQueue());
374  assert(pkt->isResponse());
375 
376  std::shared_ptr<MemoryMsg> msg = std::make_shared<MemoryMsg>(clockEdge());
377  (*msg).m_addr = pkt->getAddr();
378  (*msg).m_Sender = m_machineID;
379 
380  SenderState *s = dynamic_cast<SenderState *>(pkt->senderState);
381  (*msg).m_OriginalRequestorMachId = s->id;
382  delete s;
383 
384  if (pkt->isRead()) {
385  (*msg).m_Type = MemoryRequestType_MEMORY_READ;
386  (*msg).m_MessageSize = MessageSizeType_Response_Data;
387 
388  // Copy data from the packet
389  (*msg).m_DataBlk.setData(pkt->getPtr<uint8_t>(), 0,
391  } else if (pkt->isWrite()) {
392  (*msg).m_Type = MemoryRequestType_MEMORY_WB;
393  (*msg).m_MessageSize = MessageSizeType_Writeback_Control;
394  } else {
395  panic("Incorrect packet type received from memory controller!");
396  }
397 
399  delete pkt;
400 }
401 
402 Tick
404 {
405  return ticksToCycles(memoryPort.sendAtomic(pkt));
406 }
407 
408 MachineID
410 {
411  NodeID node = m_net_ptr->addressToNodeID(addr, mtype);
412  MachineID mach = {mtype, node};
413  return mach;
414 }
415 
416 MachineID
418 const
419 {
420  if (mtype == MachineType_NUM) {
421  // map to the first match
422  for (const auto &i : downstreamAddrMap) {
423  const auto mapping = i.second.contains(addr);
424  if (mapping != i.second.end())
425  return mapping->second;
426  }
427  }
428  else {
429  const auto i = downstreamAddrMap.find(mtype);
430  if (i != downstreamAddrMap.end()) {
431  const auto mapping = i->second.contains(addr);
432  if (mapping != i->second.end())
433  return mapping->second;
434  }
435  }
436  fatal("%s: couldn't find mapping for address %x mtype=%s\n",
437  name(), addr, mtype);
438 }
439 
440 
441 bool
443 {
445  return true;
446 }
447 
448 void
450 {
451  controller->m_waiting_mem_retry = false;
452  controller->serviceMemoryQueue();
453 }
454 
456  AbstractController *_controller,
457  PortID id)
458  : RequestPort(_name, _controller, id), controller(_controller)
459 {
460 }
461 
464  : statistics::Group(parent),
465  ADD_STAT(fullyBusyCycles,
466  "cycles for which number of transistions == max transitions"),
467  ADD_STAT(delayHistogram, "delay_histogram")
468 {
473 }
474 
475 } // namespace ruby
476 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
ClockedObjectParams Params
Parameters of ClockedObject.
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Tick cyclesToTicks(Cycles c) const
Cycles ticksToCycles(Tick t) const
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
const std::string _name
Definition: named.hh:41
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
bool isRead() const
Definition: packet.hh:592
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1212
Addr getAddr() const
Definition: packet.hh:805
bool isResponse() const
Definition: packet.hh:597
static PacketPtr createWrite(const RequestPtr &req)
Definition: packet.hh:1041
SenderState * senderState
This packet's sender state.
Definition: packet.hh:544
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition: packet.cc:334
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition: packet.hh:1280
bool isWrite() const
Definition: packet.hh:593
static PacketPtr createRead(const RequestPtr &req)
Constructor-like methods that return Packets based on Request objects.
Definition: packet.hh:1035
void dataDynamic(T *p)
Set the data pointer to a value that should have delete [] called on it.
Definition: packet.hh:1200
void allocate()
Allocate memory for the packet.
Definition: packet.hh:1354
Ports are used to interface objects to each other.
Definition: port.hh:62
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
Definition: port.hh:79
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
Definition: port.hh:464
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition: port.hh:495
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
Definition: port.hh:485
MemoryPort(const std::string &_name, AbstractController *_controller, PortID id=InvalidPortID)
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
void recvReqRetry()
Called by the peer if sendTimingReq was called on this peer (causing recvTimingReq to be called on th...
std::vector< MessageBuffer * > MsgVecType
void profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
Profiles the delay associated with messages.
virtual MessageBuffer * getMemReqQueue() const =0
void wakeUpBuffer(MessageBuffer *buf, Addr addr)
virtual void regStats()
Callback to set stat parameters.
std::unordered_map< MachineType, AddrRangeMap< MachineID, 3 > > downstreamAddrMap
std::set< MessageBuffer * > MsgBufType
MachineID mapAddressToDownstreamMachine(Addr addr, MachineType mtype=MachineType_NUM) const
Maps an address to the correct dowstream MachineID (i.e.
virtual void collateStats()
Function for collating statistics from all the controllers of this particular type.
void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
virtual void resetStats()=0
Callback to reset stats.
void blockOnQueue(Addr, MessageBuffer *)
MachineID mapAddressToMachine(Addr addr, MachineType mtype) const
Map an address to the correct MachineID.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
A function used to return the port associated with this bus object.
gem5::ruby::AbstractController::ControllerStats stats
std::map< Addr, MessageBuffer * > m_block_map
virtual MessageBuffer * getMemRespQueue() const =0
void stallBuffer(MessageBuffer *buf, Addr addr)
void scheduleEvent(Cycles timeDelta)
Definition: Consumer.cc:56
void setConsumer(Consumer *consumer)
bool functionalRead(Packet *pkt)
void enqueue(MsgPtr message, Tick curTime, Tick delta)
void reanalyzeMessages(Addr addr, Tick current_time)
void add(MachineID newElement)
Definition: NetDest.cc:45
static uint32_t getNumberOfVirtualNetworks()
Definition: Network.hh:90
NodeID addressToNodeID(Addr addr, MachineType mtype)
Map an address to the correct NodeID.
Definition: Network.cc:235
static bool getWarmupEnabled()
Definition: RubySystem.hh:75
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:72
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:358
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1328
void reset()
Reset stat value to default.
Definition: statistics.hh:1352
Statistics container.
Definition: group.hh:94
A simple histogram stat.
Definition: statistics.hh:2127
Histogram & init(size_type size)
Set the parameters of this histogram.
Definition: statistics.hh:2154
STL vector class.
Definition: stl.hh:37
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
const Params & params() const
Definition: sim_object.hh:176
virtual void regStats()
Callback to set stat parameters.
Definition: group.cc:69
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 33 > id
Definition: misc_types.hh:257
Bitfield< 1 > s
Definition: pagetable.hh:64
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 3 > addr
Definition: types.hh:84
unsigned int NodeID
Definition: TypeDefines.hh:42
Addr getOffset(Addr addr)
Definition: Address.cc:54
void registerDumpCallback(const std::function< void()> &callback)
Register a callback that should be called whenever statistics are about to be dumped.
Definition: statistics.cc:330
const FlagsType nozero
Don't print if this is zero.
Definition: info.hh:68
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< Request > RequestPtr
Definition: request.hh:92
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:245
uint64_t Tick
Tick count type.
Definition: types.hh:58
RubyTester::SenderState SenderState
Definition: Check.cc:40
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
statistics::Scalar fullyBusyCycles
Counter for the number of cycles when the transitions carried out were equal to the maximum allowed.
statistics::Histogram delayHistogram
Histogram for profiling delay for the messages this controller cares for.
std::vector< statistics::Histogram * > delayVCHistogram
MachineType getType() const
Definition: MachineID.hh:66
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:38 for gem5 by doxygen 1.9.1