SST  11.0.0
StructuralSimulationToolkit
stdMem.h
1 // -*- mode: c++ -*-
2 // Copyright 2009-2021 NTESS. Under the terms
3 // of Contract DE-NA0003525 with NTESS, the U.S.
4 // Government retains certain rights in this software.
5 //
6 // Copyright (c) 2009-2021, NTESS
7 // All rights reserved.
8 //
9 // This file is part of the SST software package. For license
10 // information, see the LICENSE file in the top level directory of the
11 // distribution.
12 //
13 
14 #ifndef SST_CORE_INTERFACES_STANDARDMEM_H_
15 #define SST_CORE_INTERFACES_STANDARDMEM_H_
16 
17 #include <string>
18 #include <utility>
19 #include <map>
20 #include <atomic>
21 
22 #include "sst/core/sst_types.h"
23 #include "sst/core/warnmacros.h"
24 #include "sst/core/subcomponent.h"
25 #include "sst/core/params.h"
26 #include "sst/core/link.h"
27 
28 namespace SST {
29 
30 class Component;
31 class Event;
32 
33 namespace Experimental {
34 
35 /** Note: EXPERIMENTAL CLASS
36  * This interface is ultimately intended to become an update for SimpleMem that
37  * offers greater flexibility and customizability, as well as support for memory-mapped devices.
38  *
39  * As of SST 11, this interface is experimental and subject to change (possibly breaking) in future releases.
40  * Users are encouraged to try it out and provide the SST team with questions and/or feedback.
41  */
42 
43 namespace Interfaces {
44 /**
45  * Generic interface to Memory models
46  *
47  * Implementation notes
48  * Instructions can be sent into a memory system using derivatives of Request().
49  * This interface can be used by both compute hosts (e.g., CPUs) and MMIO devices (e.g., accelerator).
50  * Not all interfaces/memory systems support all Request types. The interface should return
51  * an error if it encounters an unhandled type.
52  *
53  * Request class:
54  * - Uses a separate class for each request type
55  * - Additional classes can be defined outside sst-core to add custom types
56  * - Requests and responses share the same ID
57  * - req.makeResponse() should be used to generate a correctly populated response event.
58  * - Any additional fields that need to be set manually are noted in function comments
59  * - req.needsResponse() should be used to determine whether a response should be sent.
60  *
61  * Built-in commands
62  * Basic:
63  * - Reads, writes
64  * - Noncacheable reads, writes
65  * Flushes:
66  * - By address: flush and flush-invalidate
67  * Atomic updates:
68  * - Read-lock, Write-unlock
69  * - Load-link, Store-conditional
70  * Data movement:
71  * - Data move (copy data from one memory location to another, e.g., for scratchpad)
72  * Notifications:
73  * - Cache invalidation
74  * Custom:
75  * - CustomRequest, this is intended to be extended by users
76  * - CustomResponse, this is intended to be extended by users
77  */
78 class StandardMem : public SubComponent {
79 public:
80  class HandlerBase; // Handler base class for callback
81  class RequestConverter; // Convert request to SST::Event* according to type
82  class RequestHandler; // Handle a request according to type
83 
84  SST_ELI_REGISTER_SUBCOMPONENT_API(SST::Experimental::Interfaces::StandardMem,TimeConverter*,HandlerBase*)
85 
86  /** All Addresses can be 64-bit */
87  typedef uint64_t Addr;
88 
89  /**
90  * Base class for StandardMem commands
91  */
92  class Request {
93  public:
94  typedef uint64_t id_t;
95  typedef uint32_t flags_t;
96 
97  /** Flags that modify requests.
98  * Each bit in a 32-bit field (flags_t) defines a seperate flag.
99  * Values less than F_RESERVED are reserved for futgure expansion.
100  * Users may define custom flags above F_RESERVED
101  */
102  enum class Flag {
103  F_NONCACHEABLE = 1<<1, /* Bypass caches for this event */
104  F_SUCCESS = 1<<2, /* For events that can fail, this indicates success. */
105  F_TRACE = 1<<3, /* This flag requests that debug/trace output be generated for this event if possible. */
106  F_RESERVED = 1 << 16, /* Flags <= F_RESERVED are reserved for future expansion */
107  };
108 
109  Request(flags_t fl = 0) { id = main_id++; flags = fl; } /* Requests get a new ID */
110  Request(id_t rid, flags_t flags = 0) : id(rid), flags(flags) {} /* Responses share an ID with the matching request */
111 
112  virtual ~Request() {}
113 
114  id_t getID() { return id; }
115 
116  virtual Request* makeResponse() = 0; // Helper for properly formatting responses; returns nullptr if no response type exists
117  virtual bool needsResponse() = 0; // Indicates whether event requires a response
118 
119  /* Convert Request to an Event type - intended to be called by standardInterface */
120  virtual SST::Event* convert(RequestConverter* converter) = 0;
121 
122  virtual void handle(RequestHandler* handler) = 0;
123 
124  /* Flag handling */
125  void setNoncacheable() { flags |= static_cast<int>(Flag::F_NONCACHEABLE); }
126  void unsetNoncacheable() { flags &= ~(static_cast<int>(Flag::F_NONCACHEABLE)); }
127  bool getNoncacheable() { return flags & static_cast<int>(Flag::F_NONCACHEABLE); }
128 
129  void setSuccess() { flags |= static_cast<int>(Flag::F_SUCCESS); }
130  void unsetSuccess() { flags &= ~(static_cast<int>(Flag::F_SUCCESS)); }
131  bool getSuccess() { return flags & static_cast<int>(Flag::F_SUCCESS); }
132 
133  void setTrace() { flags |= static_cast<int>(Flag::F_TRACE); }
134  void unsetTrace() { flags &= (~static_cast<int>(Flag::F_TRACE)); }
135  bool getTrace() { return flags & static_cast<int>(Flag::F_TRACE); }
136 
137  void setFlag(flags_t flag) { flags |= flag; }
138  void setFlag(Flag flag) { flags |= static_cast<flags_t>(flag); }
139  void unsetFlag(flags_t flag) { flags &= (~flag); }
140  void unsetFlag(Flag flag) { flags &= ~(static_cast<flags_t>(flag)); }
141  bool getFlag(flags_t flag) { return flags & flag; }
142  bool getFlag(Flag flag) { return flags & static_cast<flags_t>(flag); }
143 
144  void clearAllFlags() { flags = 0; }
145  flags_t getAllFlags() { return flags; }
146 
147  protected:
148  id_t id;
149  flags_t flags;
150 
151  private:
152  static std::atomic<id_t> main_id;
153  };
154 
155  /* Forward declarations */
156  class Read; /* Request to read data */
157  class ReadResp; /* Response to read requests */
158  class Write; /* Request to write data */
159  class WriteResp; /* Response to write requests */
160  class FlushAddr; /* Flush an address from cache */
161  class FlushResp; /* Response to flush request */
162  class ReadLock; /* Read and lock an address */
163  class WriteUnlock; /* Write and unlock an address */
164  class LoadLink; /* First part of LLSC, read and track access atomicity */
165  class StoreConditional; /* Second part of LLSC, check access atomicity and write if atomic */
166  class MoveData; /* Copy data from one address to another (e.g., Get/Put) */
167  class CustomReq; /* Encapsulates a custom class that defines some request event type */
168  class CustomResp; /* Encapsulates a custom class that defines some response event type */
169  class InvNotify; /* Notification that data has been invalidated */
170 
171  /** Read request.
172  * Can be marked noncacheable to bypass caches.
173  * Response type is ReadResp
174  */
175  class Read : public Request {
176  public:
177  Read(Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
178  Request(flags), pAddr(physAddr), vAddr(virtAddr), size(size), iPtr(instPtr), tid(tid) { }
179  virtual ~Read() {}
180 
181  /** Create read response.
182  * User must manually set read data on response if simulation is using actual data values
183  * @return ReadResp formatted as a response to this Read request
184  */
185  Request* makeResponse() override {
186  std::vector<uint8_t> datavec(size, 0); /* Placeholder. If actual data values are used in simulation, the model should update this */
187  ReadResp* resp = new ReadResp(this, datavec);
188  return resp;
189  }
190 
191  bool needsResponse() override { return true; }
192 
193  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
194  void handle(RequestHandler* handler) override { return handler->handle(this); }
195 
196  /* Data members */
197  Addr pAddr; /* Physical address */
198  Addr vAddr; /* Virtual address */
199  uint64_t size; /* Number of bytes to read */
200  Addr iPtr; /* Instruction pointer - optional metadata */
201  uint32_t tid; /* Thread ID */
202  };
203 
204  /** Response to a Read */
205  class ReadResp : public Request {
206  public:
207  ReadResp(id_t rid, Addr physAddr, uint64_t size, std::vector<uint8_t> respData, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
208  Request(rid, flags), pAddr(physAddr), vAddr(virtAddr), size(size), data(respData), iPtr(instPtr), tid(tid) { }
209 
210  ReadResp(Read* readEv, std::vector<uint8_t> respData) :
211  Request(readEv->getID(), readEv->getAllFlags()), pAddr(readEv->pAddr), vAddr(readEv->vAddr), size(readEv->size), data(respData),
212  iPtr(readEv->iPtr), tid(readEv->tid) { }
213 
214  virtual ~ReadResp() {}
215 
216  Request* makeResponse() override { return nullptr; } /* No response type */
217  bool needsResponse() override { return false; }
218  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
219  void handle(RequestHandler* handler) override { return handler->handle(this); }
220 
221  /* Data members */
222  Addr pAddr; /* Physical address */
223  Addr vAddr; /* Virtual address */
224  uint64_t size; /* Number of bytes to read */
225  std::vector<uint8_t> data; /* Read data */
226  Addr iPtr; /* Instruction pointer - optional metadata */
227  uint32_t tid; /* Thread ID */
228  };
229 
230  /** Request to write data.
231  * Can be marked noncacheable to bypass caches
232  * Response type is WriteResp
233  */
234  class Write : public Request {
235  public:
236  /* Constructor */
237  Write(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, bool posted = false, flags_t flags = 0,
238  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) : Request(flags), pAddr(physAddr), vAddr(virtAddr),
239  size(size), data(wData), posted(posted), iPtr(instPtr), tid(tid) {}
240  /* Destructor */
241  virtual ~Write() {}
242 
243  virtual Request* makeResponse() override { return new WriteResp(this); }
244  virtual bool needsResponse() override { return !posted; }
245  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
246  void handle(RequestHandler* handler) override { return handler->handle(this); }
247 
248  /* Data members */
249  Addr pAddr; /* Physical address */
250  Addr vAddr; /* Virtual address */
251  uint64_t size; /* Number of bytes to write */
252  std::vector<uint8_t> data; /* Written data */
253  bool posted; /* Whether write is posted (requires no response) */
254  Addr iPtr; /* Instruction pointer - optional metadata */
255  uint32_t tid; /* Thread ID */
256  };
257 
258  /** Response to a Write */
259  class WriteResp : public Request {
260  public:
261  /** Manually construct a write response */
262  WriteResp(id_t id, Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
263  Request(id, flags), pAddr(physAddr), vAddr(virtAddr), size(size), iPtr(instPtr), tid(tid) {}
264  /** Automatically construct a write response from a Write */
265  WriteResp(Write* wr) : Request(wr->getID(), wr->getAllFlags()), pAddr(wr->pAddr), vAddr(wr->vAddr), size(wr->size),
266  iPtr(wr->iPtr), tid(wr->tid) {}
267  /** Destructor */
268  virtual ~WriteResp() {}
269 
270  virtual Request* makeResponse() override { return nullptr; }
271  virtual bool needsResponse() override { return false; }
272  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
273  void handle(RequestHandler* handler) override { return handler->handle(this); }
274 
275  /* Data members */
276  Addr pAddr; /* Physical address */
277  Addr vAddr; /* Virtual address */
278  uint64_t size; /* Number of bytes to read */
279  Addr iPtr; /* Instruction pointer - optional metadata */
280  uint32_t tid; /* Thread ID */
281  };
282 
283  /* Flush an address from cache
284  * Response type is FlushResp
285  * inv = false: Write back dirty data to memory, leave clean data in cache
286  * inv = true: Write back dirty data to memory, invalidate data in cache
287  */
288  class FlushAddr : public Request {
289  public:
290  FlushAddr(Addr physAddr, uint64_t size, bool inv, uint32_t depth, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
291  Request(flags), pAddr(physAddr), vAddr(virtAddr), size(size), inv(inv), depth(depth), iPtr(instPtr), tid(tid) {}
292  virtual ~FlushAddr() {}
293 
294  virtual Request* makeResponse() override { return new FlushResp(this); }
295  virtual bool needsResponse() override { return true; }
296  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
297  void handle(RequestHandler* handler) override { return handler->handle(this); }
298 
299  Addr pAddr; /* Physical address */
300  Addr vAddr; /* Virtual address */
301  uint64_t size; /* Number of bytes to invalidate */
302  bool inv; /* Whether flush should also invalidate line */
303  uint32_t depth; /* How many levels down the memory hierarchy this flush should propogate. E.g., 1 = L1 only, 2 = L1 + L2, etc. */
304  Addr iPtr; /* Instruction pointer */
305  uint32_t tid; /* Thread ID */
306  };
307 
308  /** Response to a flush request.
309  * Flushes can occasionally fail, check getSuccess() to determine success.
310  */
311  class FlushResp : public Request {
312  public:
313  FlushResp(id_t id, Addr physAddr, uint64_t size, flags_t flags = static_cast<int>(Request::Flag::F_SUCCESS),
314  Addr vAddr = 0, Addr instPtr = 0, uint32_t tid = 0) : Request(id, flags), pAddr(physAddr), vAddr(vAddr), size(size),
315  iPtr(instPtr), tid(tid) {}
316  FlushResp(FlushAddr* fl, flags_t newFlags = static_cast<int>(Request::Flag::F_SUCCESS)) :
317  Request(fl->getID(), fl->getAllFlags() | newFlags), pAddr(fl->pAddr), vAddr(fl->vAddr), size(fl->size),
318  iPtr(fl->iPtr), tid(fl->tid) {}
319  virtual ~FlushResp() {}
320 
321  virtual Request* makeResponse() override { return nullptr; }
322  virtual bool needsResponse() override { return false; }
323  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
324  void handle(RequestHandler* handler) override { return handler->handle(this); }
325 
326  Addr pAddr; /* Physical address */
327  Addr vAddr; /* Virtual address */
328  uint64_t size; /* Number of bytes to invalidate */
329  Addr iPtr; /* Instruction pointer */
330  uint32_t tid; /* Thread ID */
331  };
332 
333  /**
334  * Locked atomic update -> guaranteed success
335  * A ReadLock **must** be followed by a WriteUnlock
336  */
337 
338  /** ReadLock acquires and locks an address
339  * Returns a ReadResp with the current data value
340  */
341  class ReadLock : public Request {
342  public:
343  ReadLock(Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
344  Request(flags), pAddr(physAddr), vAddr(virtAddr), size(size), iPtr(instPtr), tid(tid) { }
345  virtual ~ReadLock() {}
346 
347  Request* makeResponse() override {
348  std::vector<uint8_t> datavec(size, 0); /* This is a placeholder. If actual data values are used in simulation, the model should update this */
349  return new ReadResp(id, pAddr, size, datavec, flags, vAddr, iPtr, tid);
350  }
351 
352  bool needsResponse() override { return true; }
353  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
354  void handle(RequestHandler* handler) override { return handler->handle(this); }
355 
356  /* Data members */
357  Addr pAddr; /* Physical address */
358  Addr vAddr; /* Virtual address */
359  uint64_t size; /* Number of bytes to read */
360  Addr iPtr; /* Instruction pointer - optional metadata */
361  uint32_t tid; /* Thread ID */
362  };
363 
364  /* WriteUnlock writes a locked address
365  * WriteUnlock will fatally error if lock is not acquired first
366  * Returns a WriteResp
367  */
368  class WriteUnlock : public Request {
369  public:
370  WriteUnlock(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, bool posted = false, flags_t flags = 0,
371  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) : Request(flags), pAddr(physAddr), vAddr(virtAddr),
372  size(size), data(wData), posted(posted), iPtr(instPtr), tid(tid) {}
373 
374  virtual ~WriteUnlock() {}
375 
376  virtual Request* makeResponse() override { return new WriteResp(id, pAddr, size, flags, vAddr = 0, iPtr, tid); }
377  virtual bool needsResponse() override { return !posted; }
378  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
379  void handle(RequestHandler* handler) override { return handler->handle(this); }
380 
381  /* Data members */
382  Addr pAddr; /* Physical address */
383  Addr vAddr; /* Virtual address */
384  uint64_t size; /* Number of bytes to write */
385  std::vector<uint8_t> data; /* Written data */
386  bool posted; /* Whether write is posted (requires no response) */
387  Addr iPtr; /* Instruction pointer - optional metadata */
388  uint32_t tid; /* Thread ID */
389  };
390 
391  /**
392  * Conditional atomic update. Can fail.
393  * A LoadLink should be followed by a StoreConditional
394  */
395 
396  /* LoadLink loads an address and tracks it for atomicity
397  * Returns a ReadResp
398  */
399  class LoadLink : public Request {
400  public:
401  LoadLink(Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
402  Request(flags), pAddr(physAddr), vAddr(virtAddr), size(size), iPtr(instPtr), tid(tid) { }
403  virtual ~LoadLink() {}
404 
405  Request* makeResponse() override {
406  std::vector<uint8_t> datavec(size, 0); /* This is a placeholder. If actual data values are used in simulation, the model should update this */
407  return new ReadResp(id, pAddr, size, datavec, flags, vAddr, iPtr, tid);
408  }
409 
410  bool needsResponse() override { return true; }
411  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
412  void handle(RequestHandler* handler) override { return handler->handle(this); }
413 
414  /* Data members */
415  Addr pAddr; /* Physical address */
416  Addr vAddr; /* Virtual address */
417  uint64_t size; /* Number of bytes to read */
418  Addr iPtr; /* Instruction pointer - optional metadata */
419  uint32_t tid; /* Thread ID */
420  };
421 
422  /* StoreConditional checks if a write to a prior LoadLink address will be atomic,
423  * if so, writes the address and returns a WriteResp with getSuccess() == true
424  * if not, does not write the address and returns a WriteResp with getSuccess() == false
425  */
426  class StoreConditional : public Request {
427  public:
428  StoreConditional(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, flags_t flags = 0,
429  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) : Request(flags), pAddr(physAddr), vAddr(virtAddr),
430  size(size), data(wData), iPtr(instPtr), tid(tid) {}
431 
432  virtual ~StoreConditional() {}
433 
434  /* Model must also call setSuccess() on response if LLSC succeeded */
435  virtual Request* makeResponse() override { return new WriteResp(id, pAddr, size, flags, vAddr, iPtr, tid); }
436  virtual bool needsResponse() override { return true; }
437  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
438  void handle(RequestHandler* handler) override { return handler->handle(this); }
439 
440  /* Data members */
441  Addr pAddr; /* Physical address */
442  Addr vAddr; /* Virtual address */
443  uint64_t size; /* Number of bytes to write */
444  std::vector<uint8_t> data; /* Written data */
445  Addr iPtr; /* Instruction pointer - optional metadata */
446  uint32_t tid; /* Thread ID */
447  };
448 
449  /* Explicit data movement */
450  /** Move: move data from one address to another
451  * Returns a WriteResp
452  */
453  class MoveData : public Request {
454  public:
455  MoveData(Addr pSrc, Addr pDst, uint64_t size, bool posted = false, flags_t flags = 0, Addr vSrc = 0, Addr vDst = 0, Addr iPtr = 0, uint32_t tid = 0) :
456  Request(flags), pSrc(pSrc), vSrc(vSrc), pDst(pDst), vDst(vDst), size(size), posted(posted), iPtr(iPtr), tid(tid) {}
457  virtual ~MoveData() {}
458 
459  virtual Request* makeResponse() override { return new WriteResp(id, pDst, size, flags, vDst, iPtr, tid); }
460  virtual bool needsResponse() override { return posted; }
461  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
462  void handle(RequestHandler* handler) override { return handler->handle(this); }
463 
464  /* Data members */
465  Addr pSrc; /* Physical address of source */
466  Addr vSrc; /* Virtual address of source */
467  Addr pDst; /* Physical address of destination */
468  Addr vDst; /* Virtual address of destination */
469  uint64_t size; /* Number of bytes to move */
470  bool posted; /* True if a response is needed */
471  Addr iPtr; /* Instruction pointer */
472  uint32_t tid; /* Thread ID */
473  };
474 
475  /** Notifies endpoint that an address has been invalidated from the L1.
476  */
477  class InvNotify : public Request {
478  public:
479  InvNotify(Addr pAddr, uint64_t size, flags_t flags = 0, Addr vAddr = 0, Addr iPtr = 0, uint32_t tid = 0) :
480  Request(flags), pAddr(pAddr), vAddr(vAddr), size(size), iPtr(iPtr), tid(tid) {}
481  virtual ~InvNotify() {}
482 
483  virtual Request* makeResponse() override { return nullptr; }
484  virtual bool needsResponse() override { return false; }
485  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
486  void handle(RequestHandler* handler) override { return handler->handle(this); }
487 
488  Addr pAddr; /* Physical address */
489  Addr vAddr; /* Virtual address */
490  uint64_t size; /* Number of bytes invalidated */
491  Addr iPtr; /* Instruction pointer */
492  uint32_t tid; /* Thread ID */
493  };
494 
495  /* This class can be inherited to create custom events that can be handled in a limited fashion by existing interfaces
496  * Child class must be serializable
497  */
499  public:
500  CustomData() {}
501  virtual ~CustomData() {}
502  virtual Addr getRoutingAddress() = 0; /* Return address to use for routing this event to its destination */
503  virtual uint64_t getSize() = 0; /* Return size to use when accounting for bandwidth used is needed */
504  virtual CustomData* makeResponse() = 0; /* Return a CustomData* object formatted as a response */
505  virtual bool needsResponse() = 0; /* Return whether a response is needed */
506 
507  /* This needs to be serializable so that we can use it in events in parallel simulations */
508  virtual void serialize_order(SST::Core::Serialization::serializer &UNUSED(ser)) override = 0;
509  //ImplementSerializable(SST::Experimental::Interfaces::StandardMem::CustomData);
510  ImplementVirtualSerializable(CustomData);
511  };
512 
513 
514  class CustomReq : public Request {
515  public:
516  CustomReq(CustomData* data, flags_t flags = 0, Addr iPtr = 0, uint32_t tid = 0) :
517  Request(flags), data(data), iPtr(iPtr), tid(tid) {}
518  virtual ~CustomReq() {}
519 
520  virtual Request* makeResponse() override { return new CustomResp(this); }
521  virtual bool needsResponse() override { return data->needsResponse(); }
522  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
523  void handle(RequestHandler* handler) override { return handler->handle(this); }
524 
525  CustomData* data; /* Custom class that holds data for this event */
526  Addr iPtr; /* Instruction pointer */
527  uint32_t tid; /* Thread ID */
528  };
529 
530  class CustomResp : public Request {
531  public:
532  CustomResp(id_t id, CustomData* data, flags_t flags = 0, Addr iPtr = 0, uint32_t tid = 0) :
533  Request(id, flags), data(data), iPtr(iPtr), tid(tid) {}
534  CustomResp(CustomReq * req) : Request(req->getID(), req->getAllFlags()), data(req->data->makeResponse()),
535  iPtr(req->iPtr), tid(req->tid) {}
536  virtual ~CustomResp() {}
537 
538  virtual Request* makeResponse() override { return nullptr; }
539  virtual bool needsResponse() override { return false; }
540  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
541  void handle(RequestHandler* handler) override { return handler->handle(this); }
542 
543  CustomData* data; /* Custom class that holds data for this event */
544  Addr iPtr; /* Instruction pointer */
545  uint32_t tid; /* Thread ID */
546  };
547 
548  /* Class for implementation-specific converter functions */
550  public:
551  RequestConverter() {}
552  virtual ~RequestConverter() {}
553 
554  /* Built in command converters */
555  virtual SST::Event* convert(Read* request) = 0;
556  virtual SST::Event* convert(ReadResp* request) = 0;
557  virtual SST::Event* convert(Write* request) = 0;
558  virtual SST::Event* convert(WriteResp* request) = 0;
559  virtual SST::Event* convert(FlushAddr* request) = 0;
560  virtual SST::Event* convert(FlushResp* request) = 0;
561  virtual SST::Event* convert(ReadLock* request) = 0;
562  virtual SST::Event* convert(WriteUnlock* request) = 0;
563  virtual SST::Event* convert(LoadLink* request) = 0;
564  virtual SST::Event* convert(StoreConditional* request) = 0;
565  virtual SST::Event* convert(MoveData* request) = 0;
566  virtual SST::Event* convert(CustomReq* request) = 0;
567  virtual SST::Event* convert(CustomResp* request) = 0;
568  virtual SST::Event* convert(InvNotify* request) = 0;
569  };
570 
571  /* Class for implementation-specific handler functions */
573  public:
574  RequestHandler(SST::Output* o) : out(o) {}
575  virtual ~RequestHandler() {}
576 
577  /* Built in command handlers */
578  virtual void handle(Read* UNUSED(request)) {
579  out->fatal(CALL_INFO, -1, "Error: RequestHandler for Read requests is not implemented\n"); }
580  virtual void handle(ReadResp* UNUSED(request)) {
581  out->fatal(CALL_INFO, -1, "Error: RequestHandler for ReadResp requests is not implemented\n"); }
582  virtual void handle(Write* UNUSED(request)) {
583  out->fatal(CALL_INFO, -1, "Error: RequestHandler for Write requests is not implemented\n"); }
584  virtual void handle(WriteResp* UNUSED(request)) {
585  out->fatal(CALL_INFO, -1, "Error: RequestHandler for WriteResp requests is not implemented\n"); }
586  virtual void handle(FlushAddr* UNUSED(request)) {
587  out->fatal(CALL_INFO, -1, "Error: RequestHandler for FlushAddr requests is not implemented\n"); }
588  virtual void handle(FlushResp* UNUSED(request)) {
589  out->fatal(CALL_INFO, -1, "Error: RequestHandler for FlushResp requests is not implemented\n"); }
590  virtual void handle(ReadLock* UNUSED(request)) {
591  out->fatal(CALL_INFO, -1, "Error: RequestHandler for ReadLock requests is not implemented\n"); }
592  virtual void handle(WriteUnlock* UNUSED(request)) {
593  out->fatal(CALL_INFO, -1, "Error: RequestHandler for WriteUnlock requests is not implemented\n"); }
594  virtual void handle(LoadLink* UNUSED(request)) {
595  out->fatal(CALL_INFO, -1, "Error: RequestHandler for LoadLink requests is not implemented\n"); }
596  virtual void handle(StoreConditional* UNUSED(request)) {
597  out->fatal(CALL_INFO, -1, "Error: RequestHandler for StoreConditional requests is not implemented\n"); }
598  virtual void handle(MoveData* UNUSED(request)) {
599  out->fatal(CALL_INFO, -1, "Error: RequestHandler for MoveData requests is not implemented\n"); }
600  virtual void handle(CustomReq* UNUSED(request)) {
601  out->fatal(CALL_INFO, -1, "Error: RequestHandler for CustomReq requests is not implemented\n"); }
602  virtual void handle(CustomResp* UNUSED(request)) {
603  out->fatal(CALL_INFO, -1, "Error: RequestHandler for CustomResp requests is not implemented\n"); }
604  virtual void handle(InvNotify* UNUSED(request)) {
605  out->fatal(CALL_INFO, -1, "Error: RequestHandler for InvNotify requests is not implemented\n"); }
606 
607  SST::Output* out;
608  };
609 
610  /** Functor classes for Request handling */
611  class HandlerBase {
612  public:
613  /** Function called when Handler is invoked */
614  virtual void operator()(Request*) = 0;
615  virtual ~HandlerBase() {}
616  };
617 
618 
619  /** Event Handler class with user-data argument
620  * @tparam classT Type of the Object
621  * @tparam argT Type of the argument
622  */
623  template <typename classT, typename argT = void>
624  class Handler : public HandlerBase {
625  private:
626  typedef void (classT::*PtrMember)(Request*, argT);
627  classT* object;
628  const PtrMember member;
629  argT data;
630 
631  public:
632  /** Constructor
633  * @param object - Pointer to Object upon which to call the handler
634  * @param member - Member function to call as the handler
635  * @param data - Additional argument to pass to handler
636  */
637  Handler( classT* const object, PtrMember member, argT data ) :
638  object(object),
639  member(member),
640  data(data)
641  {}
642 
643  void operator()(Request* req) {
644  return (object->*member)(req,data);
645  }
646  };
647 
648  /** Event Handler class without user-data
649  * @tparam classT Type of the Object
650  */
651  template <typename classT>
652  class Handler<classT, void> : public HandlerBase {
653  private:
654  typedef void (classT::*PtrMember)(Request*);
655  classT* object;
656  const PtrMember member;
657 
658  public:
659  /** Constructor
660  * @param object - Pointer to Object upon which to call the handler
661  * @param member - Member function to call as the handler
662  */
663  Handler( classT* const object, PtrMember member ) :
664  object(object),
665  member(member)
666  {}
667 
668  void operator()(Request* req) {
669  return (object->*member)(req);
670  }
671  };
672 
673  /** Constructor, designed to be used via 'loadUserSubComponent' and 'loadAnonymousSubComponent'.
674  *
675  * @param id Component ID assigned to this subcomponent
676  * @param params Parameters passed to this subcomponent
677  * @param time TimeConverter indicating the time base (e.g., clock period) associated with this endpoint
678  * @param handler Callback function to use for event receives
679  */
680  StandardMem(SST::ComponentId_t id, Params &UNUSED(params), TimeConverter* &UNUSED(time), HandlerBase* &UNUSED(handler)) :
681  SubComponent(id)
682  { }
683 
684  /**
685  * Sends a memory-based request during the init()/complete() phases
686  * @param req Request to send
687  */
688  virtual void sendUntimedData(Request *req) = 0;
689 
690  /**
691  * Receive any data during the init()/complete() phases.
692  * @see SST::Link::recvInitData()
693  * Handler is not used during init()/complete(), parent must
694  * poll this interface to get received events.
695  *
696  * @return Event if one was received, otherwise nullptr
697  */
698  virtual Request* recvUntimedData() = 0;
699 
700  /**
701  * Send a Request through the interface
702  *
703  * @param req Request to send
704  */
705  virtual void send(Request *req) = 0;
706 
707  /**
708  * Receive a Request response from the side of the link.
709  *
710  * Use this method for polling-based applications.
711  * Register a handler for push-based notification of responses.
712  *
713  * @return nullptr if nothing is available.
714  * @return Pointer to a Request response
715  * Upon receipt, the receiver takes responsibility for deleting the event
716  */
717  virtual Request* poll(void) = 0;
718 
719  /**
720  * Get cache/memory line size from the memory system
721  *
722  * The memory system should provide this and it should be
723  * valid after the init() phase is complete, so processors
724  * can safely call this function during setup().
725  *
726  * @return 0 if the interface does not provide this capability or not relevant
727  * @return line size of the memory system
728  */
729  virtual Addr getLineSize() = 0;
730 
731  /**
732  * Sets the physical memory address(es), if any, that are mapped
733  * to this endpoint. Not required for endpoints that are not mapped
734  * into the memory address space.
735  *
736  * Components loading this subcomponent as an MMIO device must call this
737  * function prior to SST's init() phase.
738  *
739  * @param start Base address of the region mapped to this endpoint
740  * @param size Size, in bytes, of the region mapped to this endpoint
741  */
742  virtual void setMemoryMappedAddressRegion(Addr start, Addr size) = 0;
743 };
744 
745 } /* Interfaces */
746 } /* Experimental */
747 } /* SST */
748 
749 #endif
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:54
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:35
Base class for StandardMem commands.
Definition: stdMem.h:92
WriteResp(Write *wr)
Automatically construct a write response from a Write.
Definition: stdMem.h:265
void operator()(Request *req)
Function called when Handler is invoked.
Definition: stdMem.h:668
A class to convert between a component&#39;s view of time and the core&#39;s view of time.
Definition: timeConverter.h:25
virtual void sendUntimedData(Request *req)=0
Sends a memory-based request during the init()/complete() phases.
uint64_t Addr
All Addresses can be 64-bit.
Definition: stdMem.h:82
Move: move data from one address to another Returns a WriteResp.
Definition: stdMem.h:453
Flag
Flags that modify requests.
Definition: stdMem.h:102
void operator()(Request *req)
Function called when Handler is invoked.
Definition: stdMem.h:643
Definition: serializable.h:109
virtual void send(Request *req)=0
Send a Request through the interface.
Handler(classT *const object, PtrMember member, argT data)
Constructor.
Definition: stdMem.h:637
Generic interface to Memory models.
Definition: stdMem.h:78
virtual Request * recvUntimedData()=0
Receive any data during the init()/complete() phases.
virtual Addr getLineSize()=0
Get cache/memory line size from the memory system.
virtual void setMemoryMappedAddressRegion(Addr start, Addr size)=0
Sets the physical memory address(es), if any, that are mapped to this endpoint.
void fatal(uint32_t line, const char *file, const char *func, int exit_code, const char *format,...) const
Output the fatal message with formatting as specified by the format parameter.
Definition: output.cc:155
Notifies endpoint that an address has been invalidated from the L1.
Definition: stdMem.h:477
StandardMem(SST::ComponentId_t id, Params &UNUSED(params), TimeConverter *&UNUSED(time), HandlerBase *&UNUSED(handler))
Constructor, designed to be used via &#39;loadUserSubComponent&#39; and &#39;loadAnonymousSubComponent&#39;.
Definition: stdMem.h:680
Request * makeResponse() override
Create read response.
Definition: stdMem.h:185
Functor classes for Request handling.
Definition: stdMem.h:611
Locked atomic update -&gt; guaranteed success A ReadLock must be followed by a WriteUnlock.
Definition: stdMem.h:341
Response to a flush request.
Definition: stdMem.h:311
Handler(classT *const object, PtrMember member)
Constructor.
Definition: stdMem.h:663
Parameter store.
Definition: params.h:44
Event Handler class with user-data argument.
Definition: stdMem.h:624
virtual ~WriteResp()
Destructor.
Definition: stdMem.h:268
Base class for Events - Items sent across links to communicate between components.
Definition: event.h:31
Response to a Read.
Definition: stdMem.h:205
Response to a Write.
Definition: stdMem.h:259
virtual void operator()(Request *)=0
Function called when Handler is invoked.
SubComponent is a class loadable through the factory which allows dynamic functionality to be added t...
Definition: subcomponent.h:29
WriteResp(id_t id, Addr physAddr, uint64_t size, flags_t flags=0, Addr virtAddr=0, Addr instPtr=0, uint32_t tid=0)
Manually construct a write response.
Definition: stdMem.h:262
Request to write data.
Definition: stdMem.h:234
virtual Request * poll(void)=0
Receive a Request response from the side of the link.
Read request.
Definition: stdMem.h:175