46#include "debug/Config.hh"
47#include "debug/Drain.hh"
48#include "debug/Ruby.hh"
49#include "mem/ruby/protocol/AccessPermission.hh"
69 p.ruby_system->getAccessBackingStore(), -1,
77 for (
size_t i = 0;
i <
p.port_in_ports_connection_count; ++
i) {
79 (
"%s.response_ports%d",
name(),
i), *
this,
80 p.ruby_system->getAccessBackingStore(),
81 i,
p.no_retry_on_stall));
85 for (
size_t i = 0;
i <
p.port_interrupt_out_port_connection_count; ++
i) {
87 "%s.request_ports%d",
name(),
i), *
this));
97 response_port->sendRangeChange();
106 if (if_name ==
"mem_request_port") {
108 }
else if (if_name ==
"pio_request_port") {
110 }
else if (if_name ==
"mem_response_port") {
112 }
else if (if_name ==
"pio_response_port") {
114 }
else if (if_name ==
"interrupt_out_port") {
118 panic(
"%s: unknown %s index (%d)\n", __func__, if_name, idx);
122 }
else if (if_name ==
"in_ports") {
126 panic(
"%s: unknown %s index (%d)\n", __func__, if_name, idx);
165 bool _access_backing_store,
PortID id,
166 bool _no_retry_on_stall):
183 owner.pioResponsePort.schedTimingResp(
198 assert(port != NULL);
216 for (
size_t i = 0;
i <
owner.request_ports.size(); ++
i) {
218 for (
auto it =
l.begin(); it !=
l.end(); ++it) {
219 if (it->contains(pkt->
getAddr())) {
222 [[maybe_unused]]
bool success =
223 owner.request_ports[
i]->sendTimingReq(pkt);
229 panic(
"Should never reach here!\n");
236 if (!
owner.system->bypassCaches()) {
237 panic(
"Ruby supports atomic accesses only in noncaching mode\n");
240 for (
size_t i = 0;
i <
owner.request_ports.size(); ++
i) {
242 for (
auto it =
l.begin(); it !=
l.end(); ++it) {
243 if (it->contains(pkt->
getAddr())) {
244 return owner.request_ports[
i]->sendAtomic(pkt);
248 panic(
"Could not find address in Ruby PIO address ranges!\n");
258 panic(
"RubyPort should never see request with the "
259 "cacheResponding flag set\n");
266 RequestPtr req = std::make_shared<Request>(pkt->
req->getPaddr(),
268 pkt->
req->getFlags(),
269 pkt->
req->requestorId());
279 if (pkt->
req->isCacheMaintenance()) {
280 warn_once(
"Cache maintenance operations are not supported in Ruby.\n");
289 assert(
owner.memRequestPort.isConnected());
291 "pio address\n", pkt->
getAddr());
299 owner.memRequestPort.schedTimingReq(pkt,
310 RequestStatus requestStatus =
owner.makeRequest(pkt);
315 if (requestStatus == RequestStatus_Issued) {
319 assert(
pf !=
nullptr);
335 "Request %s for address %#x did not issue because %s\n",
337 RequestStatus_to_string(requestStatus));
349 if (!
owner.system->bypassCaches()) {
350 panic(
"Ruby supports atomic accesses only in noncaching mode\n");
359 assert(
owner.memRequestPort.isConnected());
361 "pio address\n", pkt->
getAddr());
368 Tick req_ticks =
owner.memRequestPort.sendAtomic(pkt);
369 return owner.ticksToCycles(req_ticks);
373 rs->getBlockSizeBytes());
377 static int mem_interface_type = -1;
378 if (mem_interface_type == -1) {
379 if (
rs->m_abstract_controls[MachineType_Directory].size() != 0) {
380 mem_interface_type = MachineType_Directory;
382 else if (
rs->m_abstract_controls[MachineType_Memory].size() != 0) {
383 mem_interface_type = MachineType_Memory;
386 panic(
"Can't find the memory controller interface\n");
392 pkt->
getAddr(), (MachineType)mem_interface_type);
394 rs->m_abstract_controls[mem_interface_type][
id.getNum()];
397 rs->getPhysMem()->access(pkt);
411 owner.addToRetryList(
this);
431 assert(
owner.pioRequestPort.isConnected());
432 owner.pioRequestPort.sendFunctional(pkt);
439 if (pkt->
req->getGPUFuncAccess()) {
440 pkt->
req->requestorId(
owner.m_controller->getRequestorId());
448 rs->getPhysMem()->functionalAccess(pkt);
450 bool accessSucceeded =
false;
455 accessSucceeded =
rs->functionalRead(pkt);
457 accessSucceeded =
rs->functionalWrite(pkt);
465 fatal(
"Ruby functional %s failed for address %#x\n",
481 accessSucceeded ?
"successful":
"failed");
494 system->isDeviceMemAddr(pkt) ||
495 pkt->
req->hasNoAddr());
502 assert(port != NULL);
521 assert(port != NULL);
537 auto request = std::make_shared<Request>(
541 request->setExtraData(txnId);
551 if (port->isSnooping()) {
553 port->sendTimingSnoopReq(&pkt);
575 for (
auto i = curRetryList.begin();
i != curRetryList.end(); ++
i) {
577 "Sequencer may now be free. SendRetry to port %s\n",
579 (*i)->sendRetryReq();
590 DPRINTF(Drain,
"Drain count: %u\n", drainCount);
591 if (drainCount == 0) {
592 DPRINTF(Drain,
"RubyPort done draining, signaling drain done\n");
611 DPRINTF(Drain,
"RubyPort not drained\n");
629 if (pkt->
req->getExtraData() != 0) {
639 accessPhysMem =
false;
653 accessPhysMem =
false;
656 if (pkt->
req->isKernel()) {
657 accessPhysMem =
false;
658 needsResponse =
true;
667 if (
owner.system->isDeviceMemAddr(pkt)) {
668 auto dmem =
owner.system->getDeviceMemory(pkt);
671 rs->getPhysMem()->access(pkt);
673 panic(
"Packet is in neither device nor system memory!");
675 }
else if (needsResponse) {
699 for (
size_t i = 0;
i <
owner.request_ports.size(); ++
i) {
700 ranges.splice(ranges.begin(),
701 owner.request_ports[
i]->getAddrRanges());
703 for ([[maybe_unused]]
const auto &
r : ranges)
713 for (
auto it = ranges.begin(); it != ranges.end(); ++it) {
714 if (it->contains(
addr)) {
727 ||
owner.system->isDeviceMemAddr(pkt);
737 auto request = std::make_shared<Request>(
747 if ((*p)->isSnooping()) {
749 (*p)->sendTimingSnoopReq(&pkt);
760 r.pioResponsePort.sendRangeChange();
769 if (port->trySatisfyFunctional(func_pkt)) {
ClockedObject(const ClockedObjectParams &p)
bool isSWPrefetch() const
virtual std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
bool needsResponse() const
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
bool matchAddr(const Addr addr, const bool is_secure) const
Check if packet corresponds to a given address and address space.
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
void convertScToWrite()
It has been determined that the SC packet should successfully update memory.
RequestPtr req
A pointer to the original request.
void setFunctionalResponseStatus(bool success)
void convertLlToRead()
When ruby is in use, Ruby will monitor the cache line and the phys memory should treat LL ops as norm...
bool cacheResponding() const
MemCmd cmd
The command field of the packet.
bool suppressFuncError() const
bool htmTransactionFailedInCache() const
Returns whether or not this packet/request has returned from the cache hierarchy in a failed transact...
void allocate()
Allocate memory for the packet.
Ports are used to interface objects to each other.
const PortID id
A numeric identifier to distinguish ports in a vector, and set to InvalidPortID in case this port is ...
const std::string name() const
Return port name (for DPRINTF).
QueuedRequestPort(const std::string &name, ReqPacketQueue &req_queue, SnoopRespPacketQueue &snoop_resp_queue, PortID id=InvalidPortID)
Create a QueuedPort with a given name, and a supplied implementation of two packet queues.
QueuedResponsePort(const std::string &name, RespPacketQueue &resp_queue, PortID id=InvalidPortID)
Create a QueuedPort with a given name, owner, and a supplied implementation of a packet queue.
void schedTimingResp(PacketPtr pkt, Tick when)
Schedule the sending of a timing response.
@ TLBI_EXT_SYNC
The Request tells the CPU model that a remote TLB Sync has been requested.
@ funcRequestorId
This requestor id is used for functional requests that don't come from a particular device.
Tick recvAtomic(PacketPtr pkt)
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
SnoopRespPacketQueue snoopRespQueue
MemRequestPort(const std::string &_name, RubyPort &_port)
bool isShadowRomAddress(Addr addr) const
bool access_backing_store
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
MemResponsePort(const std::string &_name, RubyPort &_port, bool _access_backing_store, PortID id, bool _no_retry_on_stall)
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
bool isPhysMemAddress(PacketPtr pkt) const
void hitCallback(PacketPtr pkt)
void recvRangeChange()
Called to receive an address range change from the peer response port.
SnoopRespPacketQueue snoopRespQueue
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
PioRequestPort(const std::string &_name, RubyPort &_port)
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
AddrRangeList getAddrRanges() const
Get a list of the non-overlapping address ranges the owner is responsible for.
PioResponsePort(const std::string &_name, RubyPort &_port)
void ruby_hit_callback(PacketPtr pkt)
std::vector< MemResponsePort * > response_ports
Addr makeLineAddress(Addr addr) const
void ruby_unaddressed_callback(PacketPtr pkt)
virtual int outstandingCount() const =0
void ruby_stale_translation_callback(Addr txnId)
virtual void descheduleDeadlockEvent()=0
std::string printAddress(Addr addr) const
std::vector< MemResponsePort * > retryList
RubySystem * m_ruby_system
MemResponsePort memResponsePort
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
PioResponsePort pioResponsePort
PioRequestPort pioRequestPort
RubyPort(const Params &p)
virtual bool isDeadlockEventScheduled() const =0
virtual int functionalWrite(Packet *func_pkt)
unsigned int gotAddrRanges
void addToRetryList(MemResponsePort *port)
MemRequestPort memRequestPort
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
AbstractController * m_controller
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
void ruby_eviction_callback(Addr address)
MessageBuffer * m_mandatory_q_ptr
std::vector< PioRequestPort * > request_ports
Addr getOffset(Addr addr) const
std::vector< MemResponsePort * >::iterator CpuPortIter
Vector of M5 Ports attached to this Ruby port.
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
void signalDrainDone() const
Signal that an object is drained.
DrainState drainState() const
Return the current drain state of an object.
DrainState
Object drain/handover states.
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
#define panic(...)
This implements a cprintf based panic() function.
#define fatal(...)
This implements a cprintf based fatal() function.
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Addr makeLineAddress(Addr addr, int cacheLineBits)
std::string printAddress(Addr addr, int cacheLineBits)
Addr getOffset(Addr addr, int cacheLineBits)
Copyright (c) 2024 Arm Limited All rights reserved.
T safe_cast(U &&ref_or_ptr)
std::shared_ptr< Request > RequestPtr
Tick curTick()
The universal simulation clock.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
uint64_t Tick
Tick count type.
RubyTester::SenderState SenderState
std::string csprintf(const char *format, const Args &...args)
SimpleMemory declaration.