SST 16.0.0
Structural Simulation Toolkit
stdMem.h
1// -*- mode: c++ -*-
2// Copyright 2009-2026 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-2026, 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
35namespace SST {
36class Component;
37class Event;
38} // namespace SST
39
40namespace 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 */
75class StandardMem : public SubComponent
76{
77public:
78 class Request; // Needed for HandlerBase definition
79 /**
80 Base handler for request handling.
81 */
83
84 /**
85 Used to create checkpointable handlers for request handling.
86 The callback 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, &classname::function_name>(this)
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, &classname::function_name, dataT>(this, data)
101 */
102 template <typename classT, auto funcT, typename dataT = void>
104
105 /**
106 Used to create checkpointable handlers for request handling.
107 The callback function is expected to be in the form of:
108
109 void func(Request* event)
110
111 In which case, the class is created with:
112
113 new StdMem::Handler<classname, &classname::function_name>(this)
114
115 Or, to add static data, the callback function is:
116
117 void func(Request* event, dataT data)
118
119 and the class is created with:
120
121 new stdMem::Handler<classname, &classname::function_name, dataT>(this, data)
122 */
123 template <typename classT, auto funcT, typename dataT = void>
124 using Handler2 [[deprecated(
125 "The name Handler2 has been deprecated and will be removed in SST 17. Please rename Handler2 to Handler.")]]
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
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 */
1383 class RequestConverter : public SST::Core::Serialization::serializable
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 */
1419 class RequestHandler : public SST::Core::Serialization::serializable
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
Main component object for the simulation.
Definition component.h:32
Definition serializable.h:25
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:43
Base class for Events - Items sent across links to communicate between components.
Definition event.h:41
CustomData * releaseData()
Obtain the CustomData object associated with this request.
Definition stdMem.h:1265
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 request to a new value.
Definition stdMem.h:1258
void setData(CustomData *d)
Set the CustomData object associated with this request to a new value.
Definition stdMem.h:1244
const CustomData & getData() const
Get the CustomData object associated with this request.
Definition stdMem.h:1236
void setData(CustomData *d)
Set the CustomData object associated with this response to a new value.
Definition stdMem.h:1339
CustomData * releaseData()
Obtain the CustomData object associated with this response.
Definition stdMem.h:1360
CustomData * resetData(CustomData *d=nullptr)
Reset the CustomData object associated with this response to a new value.
Definition stdMem.h:1353
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
Response to a flush request.
Definition stdMem.h:695
Notifies endpoint that an address has been invalidated from the L1.
Definition stdMem.h:1124
Move: move data from one address to another Returns a WriteResp.
Definition stdMem.h:1055
Locked atomic update -> guaranteed success A ReadLock must be followed by a WriteUnlock.
Definition stdMem.h:775
Response to a Read.
Definition stdMem.h:357
Read request.
Definition stdMem.h:291
Request * makeResponse() override
Create read response.
Definition stdMem.h:310
Base class for StandardMem commands.
Definition stdMem.h:141
Flag
Flags that modify requests.
Definition stdMem.h:151
Response to a Write.
Definition stdMem.h:506
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
WriteResp(Write *wr)
Automatically construct a write response from a Write.
Definition stdMem.h:519
virtual ~WriteResp()
Destructor.
Definition stdMem.h:528
Request to write data.
Definition stdMem.h:435
Generic interface to Memory models.
Definition stdMem.h:76
SSTHandlerBase< void, Request * > HandlerBase
Base handler for request handling.
Definition stdMem.h:82
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.
virtual Addr getLineSize()=0
Get cache/memory line size (in bytes) from the memory system.
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:1504
uint64_t Addr
All Addresses can be 64-bit.
Definition stdMem.h:134
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
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.
SSTHandler< void, Request *, classT, dataT, funcT > Handler
Used to create checkpointable handlers for request handling.
Definition stdMem.h:103
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:58
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
@ STDERR
Definition output.h:65
Parameter store.
Definition params.h:65
Base template for handlers which take a class defined argument.
Definition ssthandler.h:79
Base template for the class.
Definition ssthandler.h:1102
A class to convert between a component's view of time and the core's view of time.
Definition timeConverter.h:31