SST  15.1.0
StructuralSimulationToolkit
stdMem.h
1 // -*- mode: c++ -*-
2 // Copyright 2009-2025 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-2025, 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 "sst/core/link.h"
18 #include "sst/core/params.h"
19 #include "sst/core/serialization/serializable.h"
20 #include "sst/core/sst_types.h"
21 #include "sst/core/ssthandler.h"
22 #include "sst/core/subcomponent.h"
23 #include "sst/core/warnmacros.h"
24 
25 #include <atomic>
26 #include <climits>
27 #include <cstdint>
28 #include <iomanip>
29 #include <ios>
30 #include <map>
31 #include <string>
32 #include <utility>
33 #include <vector>
34 
35 namespace SST {
36 class Component;
37 class Event;
38 } // namespace SST
39 
40 namespace SST::Interfaces {
41 /**
42  * Generic interface to Memory models
43  *
44  * Implementation notes
45  * Instructions can be sent into a memory system using derivatives of Request().
46  * This interface can be used by both compute hosts (e.g., CPUs) and MMIO devices (e.g., accelerator).
47  * Not all interfaces/memory systems support all Request types. The interface should return
48  * an error if it encounters an unhandled type.
49  *
50  * Request class:
51  * - Uses a separate class for each request type
52  * - Additional classes can be defined outside sst-core to add custom types
53  * - Requests and responses share the same ID
54  * - req.makeResponse() should be used to generate a correctly populated response event.
55  * - Any additional fields that need to be set manually are noted in function comments
56  * - req.needsResponse() should be used to determine whether a response should be sent.
57  *
58  * Built-in commands
59  * Basic:
60  * - Reads, writes
61  * - Noncacheable reads, writes
62  * Flushes:
63  * - By address: flush and flush-invalidate
64  * Atomic updates:
65  * - Read-lock, Write-unlock
66  * - Load-link, Store-conditional
67  * Data movement:
68  * - Data move (copy data from one memory location to another, e.g., for scratchpad)
69  * Notifications:
70  * - Cache invalidation
71  * Custom:
72  * - CustomRequest, this is intended to be extended by users
73  * - CustomResponse, this is intended to be extended by users
74  */
75 class StandardMem : public SubComponent
76 {
77 public:
78  class Request; // Needed for HandlerBase definition
79  /**
80  Base handler for request handling.
81  */
83 
84  /**
85  Used to create handlers for request handling. The callback
86  function is expected to be in the form of:
87 
88  void func(Request* event)
89 
90  In which case, the class is created with:
91 
92  new StdMem::Handler<classname>(this, &classname::function_name)
93 
94  Or, to add static data, the callback function is:
95 
96  void func(Request* event, dataT data)
97 
98  and the class is created with:
99 
100  new stdMem::Handler<classname, dataT>(this, &classname::function_name, data)
101  */
102  template <typename classT, typename dataT = void>
103  using Handler
104  [[deprecated("Handler has been deprecated. Please use Handler2 instead as it supports checkpointing.")]] =
106 
107  /**
108  Used to create checkpointable handlers for request handling.
109  The callback function is expected to be in the form of:
110 
111  void func(Request* event)
112 
113  In which case, the class is created with:
114 
115  new StdMem::Handler<classname, &classname::function_name>(this)
116 
117  Or, to add static data, the callback function is:
118 
119  void func(Request* event, dataT data)
120 
121  and the class is created with:
122 
123  new stdMem::Handler<classname, &classname::function_name, dataT>(this, data)
124  */
125  template <typename classT, auto funcT, typename dataT = void>
127 
128  class RequestConverter; // Convert request to SST::Event* according to type
129  class RequestHandler; // Handle a request according to type
130 
131  SST_ELI_REGISTER_SUBCOMPONENT_API(SST::Interfaces::StandardMem,TimeConverter*,HandlerBase*)
132 
133  /** All Addresses can be 64-bit */
134  using Addr = uint64_t;
135 #define PRI_ADDR PRIx64
136 
137  /**
138  * Base class for StandardMem commands
139  */
141  {
142  public:
143  using id_t = uint64_t;
144  using flags_t = uint32_t;
145 
146  /** Flags that modify requests.
147  * Each bit in a 32-bit field (flags_t) defines a seperate flag.
148  * Values less than F_RESERVED are reserved for futgure expansion.
149  * Users may define custom flags above F_RESERVED
150  */
151  enum class Flag {
152  F_NONCACHEABLE = 1 << 1, /* Bypass caches for this event */
153  F_FAIL = 1 << 2, /* For events that can fail, this indicates failure. */
154  F_TRACE = 1 << 3, /* This flag requests that debug/trace output be generated for this event if possible. */
155  F_RESERVED = 1 << 16, /* Flags <= F_RESERVED are reserved for future expansion */
156  };
157 
158  explicit Request(flags_t fl = 0)
159  {
160  id = main_id++;
161  flags = fl;
162  } /* Requests get a new ID */
163  Request(id_t rid, flags_t flags = 0) :
164  id(rid),
165  flags(flags)
166  {} /* Responses share an ID with the matching request */
167 
168  virtual ~Request() {}
169 
170  id_t getID() { return id; }
171 
172  virtual Request*
173  makeResponse() = 0; // Helper for properly formatting responses; returns nullptr if no response type exists
174  virtual bool needsResponse() = 0; // Indicates whether event requires a response
175 
176  /* Convert Request to an Event type - intended to be called by standardInterface */
177  virtual SST::Event* convert(RequestConverter* converter) = 0;
178 
179  virtual void handle(RequestHandler* handler) = 0;
180 
181  /* Return string representation of event for debug/output/etc. */
182  virtual std::string getString() = 0;
183 
184  /* Flag handling */
185  void setNoncacheable() { flags |= static_cast<int>(Flag::F_NONCACHEABLE); }
186  void unsetNoncacheable() { flags &= ~(static_cast<int>(Flag::F_NONCACHEABLE)); }
187  bool getNoncacheable() { return flags & static_cast<int>(Flag::F_NONCACHEABLE); }
188 
189  void setSuccess() { unsetFail(); }
190  void unsetSuccess() { setFail(); }
191  bool getSuccess() { return (flags & static_cast<int>(Flag::F_FAIL)) == 0; }
192  bool getFail() { return flags & static_cast<int>(Flag::F_FAIL); }
193  void setFail() { flags |= static_cast<int>(Flag::F_FAIL); }
194  void unsetFail() { flags &= ~(static_cast<int>(Flag::F_FAIL)); }
195 
196  void setTrace() { flags |= static_cast<int>(Flag::F_TRACE); }
197  void unsetTrace() { flags &= (~static_cast<int>(Flag::F_TRACE)); }
198  bool getTrace() { return flags & static_cast<int>(Flag::F_TRACE); }
199 
200  void setFlag(flags_t flag) { flags |= flag; }
201  void setFlag(Flag flag) { flags |= static_cast<flags_t>(flag); }
202  void unsetFlag(flags_t flag) { flags &= (~flag); }
203  void unsetFlag(Flag flag) { flags &= ~(static_cast<flags_t>(flag)); }
204  bool getFlag(flags_t flag) { return flags & flag; }
205  bool getFlag(Flag flag) { return flags & static_cast<flags_t>(flag); }
206 
207  void clearAllFlags() { flags = 0; }
208  flags_t getAllFlags() { return flags; }
209 
210  std::string getFlagString()
211  {
212  /* Print flag name for known ones and F_XX where XX is the bit index for unknown ones */
213  std::ostringstream str;
214  bool comma = false;
215  if ( getNoncacheable() ) {
216  str << "F_NONCACHEABLE";
217  comma = true;
218  }
219  if ( getFail() ) {
220  if ( comma ) {
221  str << ",";
222  }
223  else {
224  comma = true;
225  }
226  str << "F_FAIL";
227  }
228  if ( getTrace() ) {
229  if ( comma ) {
230  str << ",";
231  }
232  else {
233  comma = true;
234  }
235  str << "F_TRACE";
236  }
237  for ( unsigned int i = 4; i < sizeof(flags_t) * CHAR_BIT; i++ ) {
238  flags_t shift = 1 << i;
239  if ( getFlag(shift) ) {
240  if ( comma ) {
241  str << ",";
242  }
243  else {
244  comma = true;
245  }
246  str << "F_" << i;
247  }
248  }
249  return str.str();
250  }
251 
252  // Serialization
253  ImplementVirtualSerializable(SST::Interfaces::StandardMem::Request);
254  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
255  {
256  SST_SER(id);
257  SST_SER(flags);
258  SST_SER(main_id);
259  }
260 
261  protected:
262  id_t id;
263  flags_t flags;
264 
265  private:
266  static std::atomic<id_t> main_id;
267  };
268 
269  /* Forward declarations */
270  class Read; /* Request to read data */
271  class ReadResp; /* Response to read requests */
272  class Write; /* Request to write data */
273  class WriteResp; /* Response to write requests */
274  class FlushAddr; /* Flush an address from cache */
275  class FlushCache; /* Flush an entire cache */
276  class FlushResp; /* Response to flush request */
277  class ReadLock; /* Read and lock an address */
278  class WriteUnlock; /* Write and unlock an address */
279  class LoadLink; /* First part of LLSC, read and track access atomicity */
280  class StoreConditional; /* Second part of LLSC, check access atomicity and write if atomic */
281  class MoveData; /* Copy data from one address to another (e.g., Get/Put) */
282  class CustomReq; /* Encapsulates a custom class that defines some request event type */
283  class CustomResp; /* Encapsulates a custom class that defines some response event type */
284  class InvNotify; /* Notification that data has been invalidated */
285 
286  /** Read request.
287  * Can be marked noncacheable to bypass caches.
288  * Response type is ReadResp
289  */
290  class Read : public Request
291  {
292  public:
293  Read(Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
294  Request(flags),
295  pAddr(physAddr),
296  vAddr(virtAddr),
297  size(size),
298  iPtr(instPtr),
299  tid(tid)
300  {}
301  virtual ~Read() {}
302  Read() :
303  Request(0, 0)
304  {}
305 
306  /** Create read response.
307  * User must manually set read data on response if simulation is using actual data values
308  * @return ReadResp formatted as a response to this Read request
309  */
310  Request* makeResponse() override
311  {
312  std::vector<uint8_t> datavec(
313  size, 0); /* Placeholder. If actual data values are used in simulation, the model should update this */
314  ReadResp* resp = new ReadResp(this, datavec);
315  return resp;
316  }
317 
318  bool needsResponse() override { return true; }
319 
320  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
321 
322  void handle(RequestHandler* handler) override { return handler->handle(this); }
323 
324  std::string getString() override
325  {
326  std::ostringstream str;
327  str << "ID: " << id << ", Type: Read, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex << pAddr
328  << ", VirtAddr: 0x" << vAddr;
329  str << ", Size: " << std::dec << size << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec
330  << tid;
331  return str.str();
332  }
333 
334  /* Data members */
335  Addr pAddr; /* Physical address */
336  Addr vAddr; /* Virtual address */
337  uint64_t size; /* Number of bytes to read */
338  Addr iPtr; /* Instruction pointer - optional metadata */
339  uint32_t tid; /* Thread ID */
340 
341  /* Serialization */
342  void serialize_order(SST::Core::Serialization::serializer& ser) override
343  {
344  StandardMem::Request::serialize_order(ser);
345  SST_SER(pAddr);
346  SST_SER(vAddr);
347  SST_SER(size);
348  SST_SER(iPtr);
349  SST_SER(tid);
350  }
351 
352  ImplementSerializable(SST::Interfaces::StandardMem::Read);
353  };
354 
355  /** Response to a Read */
356  class ReadResp : public Request
357  {
358  public:
359  ReadResp(id_t rid, Addr physAddr, uint64_t size, std::vector<uint8_t> respData, flags_t flags = 0,
360  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
361  Request(rid, flags),
362  pAddr(physAddr),
363  vAddr(virtAddr),
364  size(size),
365  data(respData),
366  iPtr(instPtr),
367  tid(tid)
368  {}
369 
370  ReadResp(Read* readEv, std::vector<uint8_t> respData) :
371  Request(readEv->getID(), readEv->getAllFlags()),
372  pAddr(readEv->pAddr),
373  vAddr(readEv->vAddr),
374  size(readEv->size),
375  data(respData),
376  iPtr(readEv->iPtr),
377  tid(readEv->tid)
378  {}
379 
380  virtual ~ReadResp() {}
381 
382  Request* makeResponse() override { return nullptr; } /* No response type */
383 
384  bool needsResponse() override { return false; }
385 
386  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
387 
388  void handle(RequestHandler* handler) override { return handler->handle(this); }
389 
390  std::string getString() override
391  {
392  std::ostringstream str;
393  str << "ID: " << id << ", Type: ReadResp, Flags: [" << getFlagString() << "] PhysAddr: 0x" << std::hex
394  << pAddr;
395  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size << ", InstPtr: 0x" << std::hex << iPtr;
396  str << ", ThreadID: " << std::dec << tid << ", Payload: 0x" << std::hex;
397  str << std::setfill('0');
398  for ( std::vector<uint8_t>::iterator it = data.begin(); it != data.end(); it++ ) {
399  str << std::setw(2) << static_cast<unsigned>(*it);
400  }
401  return str.str();
402  }
403 
404  /* Data members */
405  Addr pAddr; /* Physical address */
406  Addr vAddr; /* Virtual address */
407  uint64_t size; /* Number of bytes to read */
408  std::vector<uint8_t> data; /* Read data */
409  Addr iPtr; /* Instruction pointer - optional metadata */
410  uint32_t tid; /* Thread ID */
411 
412  /* Serialization */
413  ReadResp() :
414  Request(0, 0)
415  {}
416 
417  void serialize_order(SST::Core::Serialization::serializer& ser) override
418  {
419  StandardMem::Request::serialize_order(ser);
420  SST_SER(pAddr);
421  SST_SER(vAddr);
422  SST_SER(size);
423  SST_SER(iPtr);
424  SST_SER(tid);
425  }
426 
427  ImplementSerializable(SST::Interfaces::StandardMem::Read);
428  };
429 
430  /** Request to write data.
431  * Can be marked noncacheable to bypass caches
432  * Response type is WriteResp
433  */
434  class Write : public Request
435  {
436  public:
437  /* Constructor */
438  Write(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, bool posted = false, flags_t flags = 0,
439  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
440  Request(flags),
441  pAddr(physAddr),
442  vAddr(virtAddr),
443  size(size),
444  data(wData),
445  posted(posted),
446  iPtr(instPtr),
447  tid(tid)
448  {}
449  /* Destructor */
450  virtual ~Write() {}
451 
452  virtual Request* makeResponse() override { return new WriteResp(this); }
453 
454  virtual bool needsResponse() override { return !posted; }
455 
456  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
457 
458  void handle(RequestHandler* handler) override { return handler->handle(this); }
459 
460  std::string getString() override
461  {
462  std::ostringstream str;
463  str << "ID: " << id << ", Type: Write, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
464  << pAddr;
465  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size << ", Posted: " << (posted ? "T" : "F");
466  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid << ", Payload: 0x"
467  << std::hex;
468  str << std::setfill('0');
469  for ( std::vector<uint8_t>::iterator it = data.begin(); it != data.end(); it++ ) {
470  str << std::setw(2) << static_cast<unsigned>(*it);
471  }
472  return str.str();
473  }
474 
475  /* Data members */
476  Addr pAddr; /* Physical address */
477  Addr vAddr; /* Virtual address */
478  uint64_t size; /* Number of bytes to write */
479  std::vector<uint8_t> data; /* Written data */
480  bool posted; /* Whether write is posted (requires no response) */
481  Addr iPtr; /* Instruction pointer - optional metadata */
482  uint32_t tid; /* Thread ID */
483 
484  /* Serialization */
485  Write() :
486  Request(0, 0)
487  {}
488 
489  void serialize_order(SST::Core::Serialization::serializer& ser) override
490  {
491  StandardMem::Request::serialize_order(ser);
492  SST_SER(pAddr);
493  SST_SER(vAddr);
494  SST_SER(size);
495  SST_SER(data);
496  SST_SER(posted);
497  SST_SER(iPtr);
498  SST_SER(tid);
499  }
500 
501  ImplementSerializable(SST::Interfaces::StandardMem::Write);
502  };
503 
504  /** Response to a Write */
505  class WriteResp : public Request
506  {
507  public:
508  /** Manually construct a write response */
509  WriteResp(id_t id, Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0,
510  uint32_t tid = 0) :
511  Request(id, flags),
512  pAddr(physAddr),
513  vAddr(virtAddr),
514  size(size),
515  iPtr(instPtr),
516  tid(tid)
517  {}
518  /** Automatically construct a write response from a Write */
519  explicit WriteResp(Write* wr) :
520  Request(wr->getID(), wr->getAllFlags()),
521  pAddr(wr->pAddr),
522  vAddr(wr->vAddr),
523  size(wr->size),
524  iPtr(wr->iPtr),
525  tid(wr->tid)
526  {}
527  /** Destructor */
528  virtual ~WriteResp() {}
529 
530  virtual Request* makeResponse() override { return nullptr; }
531 
532  virtual bool needsResponse() override { return false; }
533 
534  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
535 
536  void handle(RequestHandler* handler) override { return handler->handle(this); }
537 
538  std::string getString() override
539  {
540  std::ostringstream str;
541  str << "ID: " << id << ", Type: WriteResp, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
542  << pAddr;
543  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size << ", InstPtr: 0x" << std::hex << iPtr;
544  str << ", ThreadID: " << std::dec << tid;
545  return str.str();
546  }
547 
548  /* Data members */
549  Addr pAddr; /* Physical address */
550  Addr vAddr; /* Virtual address */
551  uint64_t size; /* Number of bytes to read */
552  Addr iPtr; /* Instruction pointer - optional metadata */
553  uint32_t tid; /* Thread ID */
554 
555  /* Serialization */
556  WriteResp() :
557  Request(0, 0)
558  {}
559 
560  void serialize_order(SST::Core::Serialization::serializer& ser) override
561  {
562  StandardMem::Request::serialize_order(ser);
563  SST_SER(pAddr);
564  SST_SER(vAddr);
565  SST_SER(size);
566  SST_SER(iPtr);
567  SST_SER(tid);
568  }
569 
570  ImplementSerializable(SST::Interfaces::StandardMem::WriteResp);
571  };
572 
573  /* Flush an address from cache
574  * Response type is FlushResp
575  * inv = false: Write back dirty data to memory, leave clean data in cache
576  * inv = true: Write back dirty data to memory, invalidate data in cache
577  */
578  class FlushAddr : public Request
579  {
580  public:
581  FlushAddr(Addr physAddr, uint64_t size, bool inv, uint32_t depth, flags_t flags = 0, Addr virtAddr = 0,
582  Addr instPtr = 0, uint32_t tid = 0) :
583  Request(flags),
584  pAddr(physAddr),
585  vAddr(virtAddr),
586  size(size),
587  inv(inv),
588  depth(depth),
589  iPtr(instPtr),
590  tid(tid)
591  {}
592  virtual ~FlushAddr() {}
593 
594  virtual Request* makeResponse() override { return new FlushResp(this); }
595 
596  virtual bool needsResponse() override { return true; }
597 
598  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
599 
600  void handle(RequestHandler* handler) override { return handler->handle(this); }
601 
602  std::string getString() override
603  {
604  std::ostringstream str;
605  str << "ID: " << id << ", Type: FlushAddr, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
606  << pAddr;
607  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size << ", Inv: " << (inv ? "T" : "F");
608  str << ", Depth: " << depth << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
609  return str.str();
610  }
611 
612  Addr pAddr; /* Physical address */
613  Addr vAddr; /* Virtual address */
614  uint64_t size; /* Number of bytes to invalidate */
615  bool inv; /* Whether flush should also invalidate line */
616  uint32_t depth; /* How many levels down the memory hierarchy this flush should propogate. E.g., 1 = L1 only, 2 =
617  L1 + L2, etc. */
618  Addr iPtr; /* Instruction pointer */
619  uint32_t tid; /* Thread ID */
620 
621  /* Serialization */
622  FlushAddr() :
623  Request(0, 0)
624  {}
625 
626  void serialize_order(SST::Core::Serialization::serializer& ser) override
627  {
628  StandardMem::Request::serialize_order(ser);
629  SST_SER(pAddr);
630  SST_SER(vAddr);
631  SST_SER(size);
632  SST_SER(inv);
633  SST_SER(depth);
634  SST_SER(iPtr);
635  SST_SER(tid);
636  }
637 
638  ImplementSerializable(SST::Interfaces::StandardMem::FlushAddr);
639  };
640 
641  /* Flush an entire cache
642  * Write back dirty data to memory, invalidate data in cache
643  * Response type is FlushResp
644  */
645  class FlushCache : public Request
646  {
647  public:
648  explicit FlushCache(uint32_t depth = std::numeric_limits<uint32_t>::max(), flags_t flags = 0, Addr instPtr = 0,
649  uint32_t tid = 0) :
650  Request(flags),
651  depth(depth),
652  iPtr(instPtr),
653  tid(tid)
654  {}
655  virtual ~FlushCache() {}
656 
657  virtual Request* makeResponse() override { return new FlushResp(this); }
658 
659  virtual bool needsResponse() override { return true; }
660 
661  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
662 
663  void handle(RequestHandler* handler) override { return handler->handle(this); }
664 
665  std::string getString() override
666  {
667  std::ostringstream str;
668  str << "ID: " << id << ", Type: FlushCache, Flags: [" << getFlagString() << "], ";
669  str << "Depth: " << std::dec << depth << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec
670  << tid;
671  return str.str();
672  }
673 
674  uint32_t depth; /* How many levels down the memory hierarchy this flush should propagate. E.g., 1 = L1 only, 2 =
675  L1 + L2, etc. */
676  Addr iPtr; /* Instruction pointer */
677  uint32_t tid; /* Thread ID */
678 
679  /* Serialization */
680  void serialize_order(SST::Core::Serialization::serializer& ser) override
681  {
682  StandardMem::Request::serialize_order(ser);
683  SST_SER(depth);
684  SST_SER(iPtr);
685  SST_SER(tid);
686  }
687 
688  ImplementSerializable(SST::Interfaces::StandardMem::FlushCache);
689  };
690 
691  /** Response to a flush request.
692  * Flushes can occasionally fail, check getSuccess() to determine success.
693  */
694  class FlushResp : public Request
695  {
696  public:
697  FlushResp(id_t id, Addr physAddr, uint64_t size, flags_t flags = 0, Addr vAddr = 0, Addr instPtr = 0,
698  uint32_t tid = 0) :
699  Request(id, flags),
700  pAddr(physAddr),
701  vAddr(vAddr),
702  size(size),
703  iPtr(instPtr),
704  tid(tid)
705  {}
706  explicit FlushResp(FlushAddr* fl, flags_t newFlags = 0) :
707  Request(fl->getID(), fl->getAllFlags() | newFlags),
708  pAddr(fl->pAddr),
709  vAddr(fl->vAddr),
710  size(fl->size),
711  iPtr(fl->iPtr),
712  tid(fl->tid)
713  {}
714  explicit FlushResp(FlushCache* fc, flags_t newFlags = 0) :
715  Request(fc->getID(), fc->getAllFlags() | newFlags),
716  pAddr(0),
717  vAddr(0),
718  size(0),
719  iPtr(fc->iPtr),
720  tid(fc->tid)
721  {}
722  virtual ~FlushResp() {}
723 
724  virtual Request* makeResponse() override { return nullptr; }
725 
726  virtual bool needsResponse() override { return false; }
727 
728  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
729 
730  void handle(RequestHandler* handler) override { return handler->handle(this); }
731 
732  std::string getString() override
733  {
734  std::ostringstream str;
735  str << "ID: " << id << ", Type: FlushResp, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
736  << pAddr;
737  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size;
738  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
739  return str.str();
740  }
741 
742  Addr pAddr; /* Physical address */
743  Addr vAddr; /* Virtual address */
744  uint64_t size; /* Number of bytes to invalidate */
745  Addr iPtr; /* Instruction pointer */
746  uint32_t tid; /* Thread ID */
747 
748  /* Serialization */
749  FlushResp() :
750  Request(0, 0)
751  {}
752 
753  void serialize_order(SST::Core::Serialization::serializer& ser) override
754  {
755  StandardMem::Request::serialize_order(ser);
756  SST_SER(pAddr);
757  SST_SER(vAddr);
758  SST_SER(size);
759  SST_SER(iPtr);
760  SST_SER(tid);
761  }
762 
763  ImplementSerializable(SST::Interfaces::StandardMem::FlushResp);
764  };
765 
766  /**
767  * Locked atomic update -> guaranteed success
768  * A ReadLock **must** be followed by a WriteUnlock
769  */
770 
771  /** ReadLock acquires and locks an address
772  * Returns a ReadResp with the current data value
773  */
774  class ReadLock : public Request
775  {
776  public:
777  ReadLock(
778  Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
779  Request(flags),
780  pAddr(physAddr),
781  vAddr(virtAddr),
782  size(size),
783  iPtr(instPtr),
784  tid(tid)
785  {}
786  virtual ~ReadLock() {}
787 
788  Request* makeResponse() override
789  {
790  std::vector<uint8_t> datavec(size, 0); /* This is a placeholder. If actual data values are used in
791  simulation, the model should update this */
792  return new ReadResp(id, pAddr, size, datavec, flags, vAddr, iPtr, tid);
793  }
794 
795  bool needsResponse() override { return true; }
796 
797  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
798 
799  void handle(RequestHandler* handler) override { return handler->handle(this); }
800 
801  std::string getString() override
802  {
803  std::ostringstream str;
804  str << "ID: " << id << ", Type: ReadLock, Flags: [" << getFlagString() << "] PhysAddr: 0x" << std::hex
805  << pAddr << ", VirtAddr: 0x" << vAddr;
806  str << ", Size: " << std::dec << size << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec
807  << tid;
808  return str.str();
809  }
810 
811  /* Data members */
812  Addr pAddr; /* Physical address */
813  Addr vAddr; /* Virtual address */
814  uint64_t size; /* Number of bytes to read */
815  Addr iPtr; /* Instruction pointer - optional metadata */
816  uint32_t tid; /* Thread ID */
817 
818  /* Serialization */
819  ReadLock() :
820  Request(0, 0)
821  {}
822 
823  void serialize_order(SST::Core::Serialization::serializer& ser) override
824  {
825  StandardMem::Request::serialize_order(ser);
826  SST_SER(pAddr);
827  SST_SER(vAddr);
828  SST_SER(size);
829  SST_SER(iPtr);
830  SST_SER(tid);
831  }
832 
833  ImplementSerializable(SST::Interfaces::StandardMem::ReadLock);
834  };
835 
836  /* WriteUnlock writes a locked address
837  * WriteUnlock will fatally error if lock is not acquired first
838  * Returns a WriteResp
839  */
840  class WriteUnlock : public Request
841  {
842  public:
843  WriteUnlock(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, bool posted = false, flags_t flags = 0,
844  Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
845  Request(flags),
846  pAddr(physAddr),
847  vAddr(virtAddr),
848  size(size),
849  data(wData),
850  posted(posted),
851  iPtr(instPtr),
852  tid(tid)
853  {}
854 
855  virtual ~WriteUnlock() {}
856 
857  virtual Request* makeResponse() override { return new WriteResp(id, pAddr, size, flags, vAddr = 0, iPtr, tid); }
858 
859  virtual bool needsResponse() override { return !posted; }
860 
861  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
862 
863  void handle(RequestHandler* handler) override { return handler->handle(this); }
864 
865  std::string getString() override
866  {
867  std::ostringstream str;
868  str << "ID: " << id << ", Type: WriteUnlock, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
869  << pAddr;
870  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size << ", Posted: " << (posted ? "T" : "F");
871  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid << ", Payload: 0x"
872  << std::hex;
873  str << std::setfill('0');
874  for ( std::vector<uint8_t>::iterator it = data.begin(); it != data.end(); it++ ) {
875  str << std::setw(2) << static_cast<unsigned>(*it);
876  }
877  return str.str();
878  }
879 
880  /* Data members */
881  Addr pAddr; /* Physical address */
882  Addr vAddr; /* Virtual address */
883  uint64_t size; /* Number of bytes to write */
884  std::vector<uint8_t> data; /* Written data */
885  bool posted; /* Whether write is posted (requires no response) */
886  Addr iPtr; /* Instruction pointer - optional metadata */
887  uint32_t tid; /* Thread ID */
888 
889  /* Serialization */
890  WriteUnlock() :
891  Request(0, 0)
892  {}
893 
894  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
895  {
896  StandardMem::Request::serialize_order(ser);
897  SST_SER(pAddr);
898  SST_SER(vAddr);
899  SST_SER(size);
900  SST_SER(data);
901  SST_SER(posted);
902  SST_SER(iPtr);
903  SST_SER(tid);
904  }
905 
906  ImplementSerializable(SST::Interfaces::StandardMem::WriteUnlock);
907  };
908 
909  /**
910  * Conditional atomic update. Can fail.
911  * A LoadLink should be followed by a StoreConditional
912  */
913 
914  /* LoadLink loads an address and tracks it for atomicity
915  * Returns a ReadResp
916  */
917  class LoadLink : public Request
918  {
919  public:
920  LoadLink(
921  Addr physAddr, uint64_t size, flags_t flags = 0, Addr virtAddr = 0, Addr instPtr = 0, uint32_t tid = 0) :
922  Request(flags),
923  pAddr(physAddr),
924  vAddr(virtAddr),
925  size(size),
926  iPtr(instPtr),
927  tid(tid)
928  {}
929  virtual ~LoadLink() {}
930 
931  Request* makeResponse() override
932  {
933  std::vector<uint8_t> datavec(size, 0); /* This is a placeholder. If actual data values are used in
934  simulation, the model should update this */
935  return new ReadResp(id, pAddr, size, datavec, flags, vAddr, iPtr, tid);
936  }
937 
938  bool needsResponse() override { return true; }
939 
940  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
941 
942  void handle(RequestHandler* handler) override { return handler->handle(this); }
943 
944  std::string getString() override
945  {
946  std::ostringstream str;
947  str << "ID: " << id << ", Type: LoadLink, Flags: [" << getFlagString() << "] PhysAddr: 0x" << std::hex
948  << pAddr << ", VirtAddr: 0x" << vAddr;
949  str << ", Size: " << std::dec << size << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec
950  << tid;
951  return str.str();
952  }
953 
954  /* Data members */
955  Addr pAddr; /* Physical address */
956  Addr vAddr; /* Virtual address */
957  uint64_t size; /* Number of bytes to read */
958  Addr iPtr; /* Instruction pointer - optional metadata */
959  uint32_t tid; /* Thread ID */
960 
961  /* Serialization */
962  LoadLink() :
963  Request(0, 0)
964  {}
965 
966  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
967  {
968  StandardMem::Request::serialize_order(ser);
969  SST_SER(pAddr);
970  SST_SER(vAddr);
971  SST_SER(size);
972  SST_SER(iPtr);
973  SST_SER(tid);
974  }
975 
976  ImplementSerializable(SST::Interfaces::StandardMem::LoadLink);
977  };
978 
979  /* StoreConditional checks if a write to a prior LoadLink address will be atomic,
980  * if so, writes the address and returns a WriteResp with getSuccess() == true
981  * if not, does not write the address and returns a WriteResp with getSuccess() == false
982  */
983  class StoreConditional : public Request
984  {
985  public:
986  StoreConditional(Addr physAddr, uint64_t size, std::vector<uint8_t> wData, flags_t flags = 0, Addr virtAddr = 0,
987  Addr instPtr = 0, uint32_t tid = 0) :
988  Request(flags),
989  pAddr(physAddr),
990  vAddr(virtAddr),
991  size(size),
992  data(wData),
993  iPtr(instPtr),
994  tid(tid)
995  {}
996 
997  virtual ~StoreConditional() {}
998 
999  /* Model must also call setFail() on response if LLSC failed */
1000  virtual Request* makeResponse() override { return new WriteResp(id, pAddr, size, flags, vAddr, iPtr, tid); }
1001 
1002  virtual bool needsResponse() override { return true; }
1003 
1004  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
1005 
1006  void handle(RequestHandler* handler) override { return handler->handle(this); }
1007 
1008  std::string getString() override
1009  {
1010  std::ostringstream str;
1011  str << "ID: " << id << ", Type: StoreConditional, Flags: [" << getFlagString() << "], PhysAddr: 0x"
1012  << std::hex << pAddr;
1013  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size;
1014  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid << ", Payload: 0x"
1015  << std::hex;
1016  str << std::setfill('0');
1017  for ( std::vector<uint8_t>::iterator it = data.begin(); it != data.end(); it++ ) {
1018  str << std::setw(2) << static_cast<unsigned>(*it);
1019  }
1020  return str.str();
1021  }
1022 
1023  /* Data members */
1024  Addr pAddr; /* Physical address */
1025  Addr vAddr; /* Virtual address */
1026  uint64_t size; /* Number of bytes to write */
1027  std::vector<uint8_t> data; /* Written data */
1028  Addr iPtr; /* Instruction pointer - optional metadata */
1029  uint32_t tid; /* Thread ID */
1030 
1031  /* Serialization */
1032  StoreConditional() :
1033  Request(0, 0)
1034  {}
1035 
1036  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
1037  {
1038  StandardMem::Request::serialize_order(ser);
1039  SST_SER(pAddr);
1040  SST_SER(vAddr);
1041  SST_SER(size);
1042  SST_SER(data);
1043  SST_SER(iPtr);
1044  SST_SER(tid);
1045  }
1046 
1047  ImplementSerializable(SST::Interfaces::StandardMem::StoreConditional);
1048  };
1049 
1050  /* Explicit data movement */
1051  /** Move: move data from one address to another
1052  * Returns a WriteResp
1053  */
1054  class MoveData : public Request
1055  {
1056  public:
1057  MoveData(Addr pSrc, Addr pDst, uint64_t size, bool posted = false, flags_t flags = 0, Addr vSrc = 0,
1058  Addr vDst = 0, Addr iPtr = 0, uint32_t tid = 0) :
1059  Request(flags),
1060  pSrc(pSrc),
1061  vSrc(vSrc),
1062  pDst(pDst),
1063  vDst(vDst),
1064  size(size),
1065  posted(posted),
1066  iPtr(iPtr),
1067  tid(tid)
1068  {}
1069  virtual ~MoveData() {}
1070 
1071  virtual Request* makeResponse() override { return new WriteResp(id, pDst, size, flags, vDst, iPtr, tid); }
1072 
1073  virtual bool needsResponse() override { return !posted; }
1074 
1075  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
1076 
1077  void handle(RequestHandler* handler) override { return handler->handle(this); }
1078 
1079  std::string getString() override
1080  {
1081  std::ostringstream str;
1082  str << "ID: " << id << ", Type: MoveData, Flags: [" << getFlagString() << "], SrcPhysAddr: 0x" << std::hex
1083  << pSrc;
1084  str << ", SrcVirtAddr: 0x" << vSrc << ", DstPhysAddr: 0x" << pDst << ", DstVirtAddr: 0x" << vDst;
1085  str << ", Size: " << std::dec << size << ", Posted: " << (posted ? "T" : "F");
1086  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
1087  return str.str();
1088  }
1089 
1090  /* Data members */
1091  Addr pSrc; /* Physical address of source */
1092  Addr vSrc; /* Virtual address of source */
1093  Addr pDst; /* Physical address of destination */
1094  Addr vDst; /* Virtual address of destination */
1095  uint64_t size; /* Number of bytes to move */
1096  bool posted; /* True if a response is needed */
1097  Addr iPtr; /* Instruction pointer */
1098  uint32_t tid; /* Thread ID */
1099 
1100  /* Serialization */
1101  MoveData() :
1102  Request(0, 0)
1103  {}
1104 
1105  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
1106  {
1107  StandardMem::Request::serialize_order(ser);
1108  SST_SER(pSrc);
1109  SST_SER(vSrc);
1110  SST_SER(pDst);
1111  SST_SER(vDst);
1112  SST_SER(size);
1113  SST_SER(posted);
1114  SST_SER(iPtr);
1115  SST_SER(tid);
1116  }
1117 
1118  ImplementSerializable(SST::Interfaces::StandardMem::MoveData);
1119  };
1120 
1121  /** Notifies endpoint that an address has been invalidated from the L1.
1122  */
1123  class InvNotify : public Request
1124  {
1125  public:
1126  InvNotify(Addr pAddr, uint64_t size, flags_t flags = 0, Addr vAddr = 0, Addr iPtr = 0, uint32_t tid = 0) :
1127  Request(flags),
1128  pAddr(pAddr),
1129  vAddr(vAddr),
1130  size(size),
1131  iPtr(iPtr),
1132  tid(tid)
1133  {}
1134  virtual ~InvNotify() {}
1135 
1136  virtual Request* makeResponse() override { return nullptr; }
1137 
1138  virtual bool needsResponse() override { return false; }
1139 
1140  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
1141 
1142  void handle(RequestHandler* handler) override { return handler->handle(this); }
1143 
1144  std::string getString() override
1145  {
1146  std::ostringstream str;
1147  str << "ID: " << id << ", Type: InvNotify, Flags: [" << getFlagString() << "], PhysAddr: 0x" << std::hex
1148  << pAddr;
1149  str << ", VirtAddr: 0x" << vAddr << ", Size: " << std::dec << size;
1150  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
1151  return str.str();
1152  }
1153 
1154  Addr pAddr; /* Physical address */
1155  Addr vAddr; /* Virtual address */
1156  uint64_t size; /* Number of bytes invalidated */
1157  Addr iPtr; /* Instruction pointer */
1158  uint32_t tid; /* Thread ID */
1159 
1160  /* Serialization */
1161  InvNotify() :
1162  Request(0, 0)
1163  {}
1164 
1165  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
1166  {
1167  StandardMem::Request::serialize_order(ser);
1168  SST_SER(pAddr);
1169  SST_SER(vAddr);
1170  SST_SER(size);
1171  SST_SER(iPtr);
1172  SST_SER(tid);
1173  }
1174 
1175  ImplementSerializable(SST::Interfaces::StandardMem::InvNotify);
1176  };
1177 
1178  /* This class can be inherited to create custom events that can be handled in a limited fashion by existing
1179  * interfaces Child class must be serializable
1180  */
1182  {
1183  public:
1184  CustomData() {}
1185  virtual ~CustomData() {}
1186  virtual Addr getRoutingAddress() = 0; /* Return address to use for routing this event to its destination */
1187  virtual uint64_t getSize() = 0; /* Return size to use when accounting for bandwidth used is needed */
1188  virtual CustomData* makeResponse() = 0; /* Return a CustomData* object formatted as a response */
1189  virtual bool needsResponse() = 0; /* Return whether a response is needed */
1190  virtual std::string getString() = 0; /* String representation for debug/output/etc. */
1191 
1192  /* This needs to be serializable so that we can use it in events in parallel simulations */
1193  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override = 0;
1194  // ImplementSerializable(SST::Interfaces::StandardMem::CustomData);
1195  ImplementVirtualSerializable(CustomData);
1196  };
1197 
1198  class CustomReq : public Request
1199  {
1200  public:
1201  explicit CustomReq(CustomData* data, flags_t flags = 0, Addr iPtr = 0, uint32_t tid = 0) :
1202  Request(flags),
1203  data(data),
1204  iPtr(iPtr),
1205  tid(tid)
1206  {}
1207  virtual ~CustomReq() {}
1208 
1209  virtual Request* makeResponse() override { return new CustomResp(this); }
1210 
1211  virtual bool needsResponse() override { return data->needsResponse(); }
1212 
1213  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
1214 
1215  void handle(RequestHandler* handler) override { return handler->handle(this); }
1216 
1217  std::string getString() override
1218  {
1219  std::ostringstream str;
1220  str << "ID: " << id << ", Type: CustomReq, Flags: [" << getFlagString() << "], " << data->getString();
1221  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
1222  return str.str();
1223  }
1224 
1225  /**
1226  * Get the CustomData object associated with this request.
1227  * Ownership of the CustomData object is retained by this request.
1228  */
1229  CustomData& getData() { return *data; }
1230 
1231  /**
1232  * Get the CustomData object associated with this request.
1233  * Ownership of the CustomData object is retained by this request.
1234  * The returned data cannot be modified.
1235  */
1236  const CustomData& getData() const { return *data; }
1237 
1238  /**
1239  * Set the CustomData object associated with this request to a new
1240  * value.
1241  * This request takes ownership of the CustomData object.
1242  * The previous CustomData object is deleted.
1243  */
1245  {
1246  delete data;
1247  data = d;
1248  }
1249 
1250  /**
1251  * Reset the CustomData object associated with this request to a new
1252  * value.
1253  * The previous CustomData object is returned and ownership is
1254  * transferred to the caller.
1255  * This request assumes ownership of the passed in CustomData object.
1256  * If no CustomData object is passed in, the data member is set to nullptr.
1257  */
1258  CustomData* resetData(CustomData* d = nullptr) { return std::exchange(data, d); }
1259 
1260  /**
1261  * Obtain the CustomData object associated with this request.
1262  * Ownership of the CustomData object is transferred to the caller.
1263  * The data member of this request is set to nullptr.
1264  */
1266 
1267  CustomData* data; /* Custom class that holds data for this event */
1268  Addr iPtr; /* Instruction pointer */
1269  uint32_t tid; /* Thread ID */
1270 
1271  /* Serialization */
1272  CustomReq() :
1273  Request(0, 0)
1274  {}
1275 
1276  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
1277  {
1278  StandardMem::Request::serialize_order(ser);
1279  SST_SER(data);
1280  SST_SER(iPtr);
1281  SST_SER(tid);
1282  }
1283 
1284  ImplementSerializable(SST::Interfaces::StandardMem::CustomReq);
1285  };
1286 
1287  class CustomResp : public Request
1288  {
1289  public:
1290  CustomResp(id_t id, CustomData* data, flags_t flags = 0, Addr iPtr = 0, uint32_t tid = 0) :
1291  Request(id, flags),
1292  data(data),
1293  iPtr(iPtr),
1294  tid(tid)
1295  {}
1296  explicit CustomResp(CustomReq* req) :
1297  Request(req->getID(), req->getAllFlags()),
1298  data(req->getData().makeResponse()),
1299  iPtr(req->iPtr),
1300  tid(req->tid)
1301  {}
1302  virtual ~CustomResp() {}
1303 
1304  virtual Request* makeResponse() override { return nullptr; }
1305 
1306  virtual bool needsResponse() override { return false; }
1307 
1308  SST::Event* convert(RequestConverter* converter) override { return converter->convert(this); }
1309 
1310  void handle(RequestHandler* handler) override { return handler->handle(this); }
1311 
1312  std::string getString() override
1313  {
1314  std::ostringstream str;
1315  str << "ID: " << id << ", Type: CustomResp, Flags: [" << getFlagString() << "], " << data->getString();
1316  str << ", InstPtr: 0x" << std::hex << iPtr << ", ThreadID: " << std::dec << tid;
1317  return str.str();
1318  }
1319 
1320  /**
1321  * Get the CustomData object associated with this response.
1322  * Ownership of the CustomData object is retained by this response.
1323  */
1324  CustomData& getData() { return *data; }
1325 
1326  /**
1327  * Get the CustomData object associated with this response.
1328  * Ownership of the CustomData object is retained by this response.
1329  * The returned data cannot be modified.
1330  */
1331  const CustomData& getData() const { return *data; }
1332 
1333  /**
1334  * Set the CustomData object associated with this response to a new
1335  * value.
1336  * This response takes ownership of the CustomData object.
1337  * The previous CustomData object is deleted.
1338  */
1340  {
1341  delete data;
1342  data = d;
1343  }
1344 
1345  /**
1346  * Reset the CustomData object associated with this response to a new
1347  * value.
1348  * The previous CustomData object is returned and ownership is
1349  * transferred to the caller.
1350  * This response assumes ownership of the passed in CustomData object.
1351  * If no CustomData object is passed in, the data member is set to nullptr.
1352  */
1353  CustomData* resetData(CustomData* d = nullptr) { return std::exchange(data, d); }
1354 
1355  /**
1356  * Obtain the CustomData object associated with this response.
1357  * Ownership of the CustomData object is transferred to the caller.
1358  * The data member of this response is set to nullptr.
1359  */
1361 
1362  CustomData* data; /* Custom class that holds data for this event */
1363  Addr iPtr; /* Instruction pointer */
1364  uint32_t tid; /* Thread ID */
1365 
1366  /* Serialization */
1367  CustomResp() :
1368  Request(0, 0)
1369  {}
1370 
1371  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override
1372  {
1373  StandardMem::Request::serialize_order(ser);
1374  SST_SER(data);
1375  SST_SER(iPtr);
1376  SST_SER(tid);
1377  }
1378 
1379  ImplementSerializable(SST::Interfaces::StandardMem::CustomResp);
1380  };
1381 
1382  /* Class for implementation-specific converter functions */
1384  {
1385  public:
1386  RequestConverter() {}
1387  virtual ~RequestConverter() {}
1388 
1389  /* Built in command converters */
1390  virtual SST::Event* convert(Read* request) = 0;
1391  virtual SST::Event* convert(ReadResp* request) = 0;
1392  virtual SST::Event* convert(Write* request) = 0;
1393  virtual SST::Event* convert(WriteResp* request) = 0;
1394  virtual SST::Event* convert(FlushAddr* request) = 0;
1395  /* convert(FlushCache) temporarily has a default implementation for backward compatibility
1396  * It will transition to pure virtual in SST 16
1397  */
1398  virtual SST::Event* convert(FlushCache* UNUSED(request))
1399  {
1400  Output out("", 0, 0, Output::STDERR);
1401  out.fatal(CALL_INFO, -1, "Error: Event converter for FlushCache requests is not implemented.\n");
1402  }
1403  virtual SST::Event* convert(FlushResp* request) = 0;
1404  virtual SST::Event* convert(ReadLock* request) = 0;
1405  virtual SST::Event* convert(WriteUnlock* request) = 0;
1406  virtual SST::Event* convert(LoadLink* request) = 0;
1407  virtual SST::Event* convert(StoreConditional* request) = 0;
1408  virtual SST::Event* convert(MoveData* request) = 0;
1409  virtual SST::Event* convert(CustomReq* request) = 0;
1410  virtual SST::Event* convert(CustomResp* request) = 0;
1411  virtual SST::Event* convert(InvNotify* request) = 0;
1412 
1413  /* Serialization */
1414  virtual void serialize_order(SST::Core::Serialization::serializer& UNUSED(ser)) override {}
1415  ImplementVirtualSerializable(RequestConverter);
1416  };
1417 
1418  /* Class for implementation-specific handler functions */
1420  {
1421  public:
1422  RequestHandler() = default;
1423  explicit RequestHandler(SST::Output* o) :
1424  out(o)
1425  {}
1426  virtual ~RequestHandler() = default;
1427 
1428  /* Built in command handlers */
1429  virtual void handle(Read* UNUSED(request))
1430  {
1431  out->fatal(CALL_INFO, -1, "Error: RequestHandler for Read requests is not implemented\n");
1432  }
1433  virtual void handle(ReadResp* UNUSED(request))
1434  {
1435  out->fatal(CALL_INFO, -1, "Error: RequestHandler for ReadResp requests is not implemented\n");
1436  }
1437  virtual void handle(Write* UNUSED(request))
1438  {
1439  out->fatal(CALL_INFO, -1, "Error: RequestHandler for Write requests is not implemented\n");
1440  }
1441  virtual void handle(WriteResp* UNUSED(request))
1442  {
1443  out->fatal(CALL_INFO, -1, "Error: RequestHandler for WriteResp requests is not implemented\n");
1444  }
1445  virtual void handle(FlushAddr* UNUSED(request))
1446  {
1447  out->fatal(CALL_INFO, -1, "Error: RequestHandler for FlushAddr requests is not implemented\n");
1448  }
1449  virtual void handle(FlushCache* UNUSED(request))
1450  {
1451  out->fatal(CALL_INFO, -1, "Error: RequestHandler for FlushCache requests is not implemented\n");
1452  }
1453  virtual void handle(FlushResp* UNUSED(request))
1454  {
1455  out->fatal(CALL_INFO, -1, "Error: RequestHandler for FlushResp requests is not implemented\n");
1456  }
1457  virtual void handle(ReadLock* UNUSED(request))
1458  {
1459  out->fatal(CALL_INFO, -1, "Error: RequestHandler for ReadLock requests is not implemented\n");
1460  }
1461  virtual void handle(WriteUnlock* UNUSED(request))
1462  {
1463  out->fatal(CALL_INFO, -1, "Error: RequestHandler for WriteUnlock requests is not implemented\n");
1464  }
1465  virtual void handle(LoadLink* UNUSED(request))
1466  {
1467  out->fatal(CALL_INFO, -1, "Error: RequestHandler for LoadLink requests is not implemented\n");
1468  }
1469  virtual void handle(StoreConditional* UNUSED(request))
1470  {
1471  out->fatal(CALL_INFO, -1, "Error: RequestHandler for StoreConditional requests is not implemented\n");
1472  }
1473  virtual void handle(MoveData* UNUSED(request))
1474  {
1475  out->fatal(CALL_INFO, -1, "Error: RequestHandler for MoveData requests is not implemented\n");
1476  }
1477  virtual void handle(CustomReq* UNUSED(request))
1478  {
1479  out->fatal(CALL_INFO, -1, "Error: RequestHandler for CustomReq requests is not implemented\n");
1480  }
1481  virtual void handle(CustomResp* UNUSED(request))
1482  {
1483  out->fatal(CALL_INFO, -1, "Error: RequestHandler for CustomResp requests is not implemented\n");
1484  }
1485  virtual void handle(InvNotify* UNUSED(request))
1486  {
1487  out->fatal(CALL_INFO, -1, "Error: RequestHandler for InvNotify requests is not implemented\n");
1488  }
1489 
1490  SST::Output* out;
1491 
1492  /* Serialization */
1493  virtual void serialize_order(SST::Core::Serialization::serializer& ser) override { SST_SER(out); }
1494  ImplementSerializable(RequestHandler);
1495  };
1496 
1497  /** Constructor, designed to be used via 'loadUserSubComponent' and 'loadAnonymousSubComponent'.
1498  *
1499  * @param id Component ID assigned to this subcomponent
1500  * @param params Parameters passed to this subcomponent
1501  * @param time TimeConverter indicating the time base (e.g., clock period) associated with this endpoint
1502  * @param handler Callback function to use for event receives
1503  */
1505  SST::ComponentId_t id, Params& UNUSED(params), TimeConverter*& UNUSED(time), HandlerBase*& UNUSED(handler)) :
1506  SubComponent(id)
1507  {}
1508 
1509  /** Default constructor, used for serialization ONLY */
1511  SubComponent()
1512  {}
1513 
1514  /**
1515  * Sends a memory-based request during the init()/complete() phases
1516  * @param req Request to send
1517  */
1518  virtual void sendUntimedData(Request* req) = 0;
1519 
1520  /**
1521  * Receive any data during the init()/complete() phases.
1522  * @see SST::Link::recvInitData()
1523  * Handler is not used during init()/complete(), parent must
1524  * poll this interface to get received events.
1525  *
1526  * @return Event if one was received, otherwise nullptr
1527  */
1528  virtual Request* recvUntimedData() = 0;
1529 
1530  /**
1531  * Send a Request through the interface
1532  *
1533  * @param req Request to send
1534  */
1535  virtual void send(Request* req) = 0;
1536 
1537  /**
1538  * Receive a Request response from the side of the link.
1539  *
1540  * Use this method for polling-based applications.
1541  * Register a handler for push-based notification of responses.
1542  *
1543  * @return nullptr if nothing is available.
1544  * @return Pointer to a Request response
1545  * Upon receipt, the receiver takes responsibility for deleting the event
1546  */
1547  virtual Request* poll() = 0;
1548 
1549  /**
1550  * Get cache/memory line size (in bytes) from the memory system
1551  *
1552  * The memory system should provide this and it should be
1553  * valid after the init() phase is complete, so processors
1554  * can safely call this function during setup().
1555  *
1556  * @return 0 if the interface does not provide this capability or not relevant
1557  * @return line size of the memory system
1558  */
1559  virtual Addr getLineSize() = 0;
1560 
1561  /**
1562  * Sets the physical memory address(es), if any, that are mapped
1563  * to this endpoint. Not required for endpoints that are not mapped
1564  * into the memory address space.
1565  *
1566  * Components loading this subcomponent as an MMIO device must call this
1567  * function prior to SST's init() phase.
1568  *
1569  * @param start Base address of the region mapped to this endpoint
1570  * @param size Size, in bytes, of the region mapped to this endpoint
1571  */
1572  virtual void setMemoryMappedAddressRegion(Addr start, Addr size) = 0;
1573 
1574  /**
1575  * Serialization function
1576  */
1578  {
1579  SST::SubComponent::serialize_order(ser);
1580  }
1581 };
1582 
1583 } // namespace SST::Interfaces
1584 
1585 #endif // SST_CORE_INTERFACES_STANDARDMEM_H
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:57
void setData(CustomData *d)
Set the CustomData object associated with this response to a new value.
Definition: stdMem.h:1339
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
CustomData * releaseData()
Obtain the CustomData object associated with this response.
Definition: stdMem.h:1360
Base template for handlers which take a class defined argument.
Definition: ssthandler.h:109
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:156
Request * makeResponse() override
Create read response.
Definition: stdMem.h:310
Response to a Write.
Definition: stdMem.h:505
Base template for the class.
Definition: ssthandler.h:1273
Handler class with user-data argument.
Definition: ssthandler.h:1136
virtual Request * poll()=0
Receive a Request response from the side of the link.
A class to convert between a component&#39;s view of time and the core&#39;s view of time.
Definition: timeConverter.h:27
CustomData & getData()
Get the CustomData object associated with this response.
Definition: stdMem.h:1324
const CustomData & getData() const
Get the CustomData object associated with this response.
Definition: stdMem.h:1331
const CustomData & getData() const
Get the CustomData object associated with this request.
Definition: stdMem.h:1236
Definition: simpleNetwork.cc:18
Base class for StandardMem commands.
Definition: stdMem.h:140
Response to a Read.
Definition: stdMem.h:356
Definition: action.cc:18
virtual ~WriteResp()
Destructor.
Definition: stdMem.h:528
Move: move data from one address to another Returns a WriteResp.
Definition: stdMem.h:1054
Generic interface to Memory models.
Definition: stdMem.h:75
Definition: serializable.h:23
CustomData & getData()
Get the CustomData object associated with this request.
Definition: stdMem.h:1229
CustomData * resetData(CustomData *d=nullptr)
Reset the CustomData object associated with this response to a new value.
Definition: stdMem.h:1353
virtual void setMemoryMappedAddressRegion(Addr start, Addr size)=0
Sets the physical memory address(es), if any, that are mapped to this endpoint.
void serialize_order(SST::Core::Serialization::serializer &ser) override
Serialization function.
Definition: stdMem.h:1577
StandardMem()
Default constructor, used for serialization ONLY.
Definition: stdMem.h:1510
Locked atomic update -> guaranteed success A ReadLock must be followed by a WriteUnlock.
Definition: stdMem.h:774
virtual Request * recvUntimedData()=0
Receive any data during the init()/complete() phases.
Response to a flush request.
Definition: stdMem.h:694
Flag
Flags that modify requests.
Definition: stdMem.h:151
Definition: output.h:65
Read request.
Definition: stdMem.h:290
CustomData * resetData(CustomData *d=nullptr)
Reset the CustomData object associated with this request to a new value.
Definition: stdMem.h:1258
Notifies endpoint that an address has been invalidated from the L1.
Definition: stdMem.h:1123
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:509
Parameter store.
Definition: params.h:63
void setData(CustomData *d)
Set the CustomData object associated with this request to a new value.
Definition: stdMem.h:1244
virtual Addr getLineSize()=0
Get cache/memory line size (in bytes) from the memory system.
virtual void send(Request *req)=0
Send a Request through the interface.
virtual void sendUntimedData(Request *req)=0
Sends a memory-based request during the init()/complete() phases.
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:1504
uint64_t Addr
All Addresses can be 64-bit.
Definition: stdMem.h:134
CustomData * releaseData()
Obtain the CustomData object associated with this request.
Definition: stdMem.h:1265
Base class for Events - Items sent across links to communicate between components.
Definition: event.h:40
SubComponent is a class loadable through the factory which allows dynamic functionality to be added t...
Definition: subcomponent.h:28
Request to write data.
Definition: stdMem.h:434
WriteResp(Write *wr)
Automatically construct a write response from a Write.
Definition: stdMem.h:519