46 #include "debug/Config.hh"
47 #include "debug/Drain.hh"
48 #include "debug/Ruby.hh"
49 #include "mem/ruby/protocol/AccessPermission.hh"
63 m_controller(NULL), m_mandatory_q_ptr(NULL),
65 pioRequestPort(
csprintf(
"%s.pio-request-port",
name()), this),
66 pioResponsePort(
csprintf(
"%s.pio-response-port",
name()), this),
67 memRequestPort(
csprintf(
"%s.mem-request-port",
name()), this),
68 memResponsePort(
csprintf(
"%s-mem-response-port",
name()), this,
69 p.ruby_system->getAccessBackingStore(), -1,
71 gotAddrRanges(
p.port_interrupt_out_port_connection_count),
72 m_isCPUSequencer(
p.is_cpu_sequencer)
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);
139 reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
154 reqQueue(*_port, *this), snoopRespQueue(*_port, *this)
161 bool _access_backing_store,
PortID id,
162 bool _no_retry_on_stall)
164 access_backing_store(_access_backing_store),
165 no_retry_on_stall(_no_retry_on_stall)
193 assert(port != NULL);
215 for (
auto it =
l.begin(); it !=
l.end(); ++it) {
216 if (it->contains(pkt->
getAddr())) {
219 [[maybe_unused]]
bool success =
226 panic(
"Should never reach here!\n");
235 panic(
"Ruby supports atomic accesses only in noncaching mode\n");
240 for (
auto it =
l.begin(); it !=
l.end(); ++it) {
241 if (it->contains(pkt->
getAddr())) {
246 panic(
"Could not find address in Ruby PIO address ranges!\n");
257 panic(
"RubyPort should never see request with the "
258 "cacheResponding flag set\n");
262 if (pkt->
req->isCacheMaintenance()) {
263 warn_once(
"Cache maintenance operations are not supported in Ruby.\n");
265 schedTimingResp(pkt,
curTick());
271 if (!pkt->
req->isMemMgmt() && !isPhysMemAddress(pkt)) {
274 "pio address\n", pkt->
getAddr());
293 RequestStatus requestStatus = ruby_port->
makeRequest(pkt);
298 if (requestStatus == RequestStatus_Issued) {
310 "Request %s for address %#x did not issue because %s\n",
312 RequestStatus_to_string(requestStatus));
326 panic(
"Ruby supports atomic accesses only in noncaching mode\n");
332 if (!isPhysMemAddress(pkt)) {
335 "pio address\n", pkt->
getAddr());
352 static int mem_interface_type = -1;
353 if (mem_interface_type == -1) {
354 if (
rs->m_abstract_controls[MachineType_Directory].size() != 0) {
355 mem_interface_type = MachineType_Directory;
357 else if (
rs->m_abstract_controls[MachineType_Memory].size() != 0) {
358 mem_interface_type = MachineType_Memory;
361 panic(
"Can't find the memory controller interface\n");
367 pkt->
getAddr(), (MachineType)mem_interface_type);
369 rs->m_abstract_controls[mem_interface_type][
id.getNum()];
371 if (access_backing_store)
372 rs->getPhysMem()->access(pkt);
386 if (!no_retry_on_stall && !ruby_port->
onRetryList(
this)) {
401 if (!isPhysMemAddress(pkt)) {
411 if (access_backing_store) {
416 rs->getPhysMem()->functionalAccess(pkt);
418 bool accessSucceeded =
false;
423 accessSucceeded =
rs->functionalRead(pkt);
425 accessSucceeded =
rs->functionalWrite(pkt);
433 fatal(
"Ruby functional %s failed for address %#x\n",
449 accessSucceeded ?
"successful":
"failed");
468 assert(port != NULL);
487 assert(port != NULL);
503 auto request = std::make_shared<Request>(
507 request->setExtraData(txnId);
517 if (port->isSnooping()) {
519 port->sendTimingSnoopReq(&pkt);
541 for (
auto i = curRetryList.begin();
i != curRetryList.end(); ++
i) {
543 "Sequencer may now be free. SendRetry to port %s\n",
545 (*i)->sendRetryReq();
556 DPRINTF(Drain,
"Drain count: %u\n", drainCount);
557 if (drainCount == 0) {
558 DPRINTF(Drain,
"RubyPort done draining, signaling drain done\n");
577 DPRINTF(Drain,
"RubyPort not drained\n");
591 bool accessPhysMem = access_backing_store;
595 if (pkt->
req->getExtraData() != 0) {
605 accessPhysMem =
false;
619 accessPhysMem =
false;
622 if (pkt->
req->isKernel()) {
623 accessPhysMem =
false;
624 needsResponse =
true;
638 rs->getPhysMem()->access(pkt);
640 panic(
"Packet is in neither device nor system memory!");
642 }
else if (needsResponse) {
652 schedTimingResp(pkt,
curTick());
668 ranges.splice(ranges.begin(),
671 for ([[maybe_unused]]
const auto &
r : ranges)
682 for (
auto it = ranges.begin(); it != ranges.end(); ++it) {
683 if (it->contains(
addr)) {
707 auto request = std::make_shared<Request>(
717 if ((*p)->isSnooping()) {
719 (*p)->sendTimingSnoopReq(&pkt);
730 r.pioResponsePort.sendRangeChange();
739 if (port->trySatisfyFunctional(func_pkt)) {
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Cycles ticksToCycles(Tick t) const
virtual std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
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...
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.
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
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...
Ports are used to interface objects to each other.
bool isConnected() const
Is this port currently connected to a peer?
const std::string name() const
Return port name (for DPRINTF).
The QueuedRequestPort combines two queues, a request queue and a snoop response queue,...
void schedTimingReq(PacketPtr pkt, Tick when)
Schedule the sending of a timing request.
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
void schedTimingResp(PacketPtr pkt, Tick when)
Schedule the sending of a timing response.
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
@ 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.
void sendRangeChange() const
Called by the owner to send a range change.
AddrRangeList getShadowRomRanges() const
bool isMemAddr(Addr addr) const
Check if a physical address is within a range of a memory that is part of the global address map.
bool isDeviceMemAddr(const PacketPtr &pkt) const
Similar to isMemAddr but for devices.
bool bypassCaches() const
Should caches be bypassed?
memory::AbstractMemory * getDeviceMemory(const PacketPtr &pkt) const
Return a pointer to the device memory.
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
virtual MessageBuffer * getMandatoryQueue() const =0
Tick recvAtomic(PacketPtr pkt)
MachineID mapAddressToMachine(Addr addr, MachineType mtype) const
Map an address to the correct MachineID.
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
MemRequestPort(const std::string &_name, RubyPort *_port)
bool isShadowRomAddress(Addr addr) const
Tick recvAtomic(PacketPtr pkt)
Receive an atomic request packet from the peer.
void recvFunctional(PacketPtr pkt)
Receive a functional request packet from the peer.
bool recvTimingReq(PacketPtr pkt)
Receive a timing request from the peer.
MemResponsePort(const std::string &_name, RubyPort *_port, bool _access_backing_store, PortID id, bool _no_retry_on_stall)
bool isPhysMemAddress(PacketPtr pkt) const
void hitCallback(PacketPtr pkt)
void recvRangeChange()
Called to receive an address range change from the peer response port.
bool recvTimingResp(PacketPtr pkt)
Receive a timing response from the peer.
PioRequestPort(const std::string &_name, RubyPort *_port)
PioResponsePort(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.
void ruby_hit_callback(PacketPtr pkt)
std::vector< MemResponsePort * > response_ports
virtual RequestStatus makeRequest(PacketPtr pkt)=0
void ruby_unaddressed_callback(PacketPtr pkt)
virtual int outstandingCount() const =0
std::vector< MemResponsePort * >::iterator CpuPortIter
Vector of M5 Ports attached to this Ruby port.
void ruby_stale_translation_callback(Addr txnId)
virtual void descheduleDeadlockEvent()=0
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
bool onRetryList(MemResponsePort *port)
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
static uint32_t getBlockSizeBytes()
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)
Addr getOffset(Addr addr)
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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.
const std::string & name()