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