51#include "debug/AddrRanges.hh"
52#include "debug/CoherentXBar.hh"
60 snoopResponseLatency(
p.snoop_response_latency),
61 maxOutstandingSnoopCheck(
p.max_outstanding_snoops),
62 maxRoutingTableSizeCheck(
p.max_routing_table_size),
63 pointOfCoherency(
p.point_of_coherency),
64 pointOfUnification(
p.point_of_unification),
66 ADD_STAT(snoops, statistics::units::Count::get(),
"Total snoops"),
67 ADD_STAT(snoopTraffic, statistics::units::Byte::get(),
"Total snoop traffic"),
68 ADD_STAT(snoopFanout, statistics::units::Count::get(),
69 "Request fanout histogram")
74 for (
int i = 0;
i <
p.port_mem_side_ports_connection_count; ++
i) {
75 std::string portName =
csprintf(
"%s.mem_side_port[%d]",
name(),
i);
86 if (
p.port_default_connection_count) {
88 std::string portName =
name() +
".default";
100 for (
int i = 0;
i <
p.port_cpu_side_ports_connection_count; ++
i) {
101 std::string portName =
csprintf(
"%s.cpu_side_port[%d]",
name(),
i);
132 if (
p->isSnooping()) {
133 DPRINTF(AddrRanges,
"Adding snooping requestor %s\n",
140 warn(
"CoherentXBar %s has no snooping ports attached!\n",
name());
159 assert(is_express_snoop == cache_responding);
166 if (!is_express_snoop &&
167 !
reqLayers[mem_side_port_id]->tryTiming(src_port)) {
204 if (pkt->
isClean() && !is_destination) {
213 reqLayers[mem_side_port_id]->failedTiming(src_port,
230 __func__, src_port->
name(), pkt->
print(),
231 sf_res.first.size(), sf_res.second);
239 if (!sf_res.first.empty())
259 const bool expect_snoop_resp = !cache_responding && pkt->
cacheResponding();
265 bool respond_directly =
false;
288 if (pkt->
isWrite() && is_destination) {
293 success =
memSidePorts[mem_side_port_id]->sendTimingReq(pkt);
299 respond_directly =
true;
300 assert(!expect_snoop_resp);
301 expect_response =
false;
313 assert(!is_express_snoop);
322 reqLayers[mem_side_port_id]->failedTiming(src_port,
326 if (!is_express_snoop) {
329 if (expect_snoop_resp) {
337 "%s: Outstanding snoop requests exceeded %d\n",
342 if (expect_response || expect_snoop_resp) {
347 "%s: Routing table exceeds %d packets\n",
352 reqLayers[mem_side_port_id]->succeededTiming(packetFinishTime);
356 pktCount[cpu_side_port_id][mem_side_port_id]++;
357 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
360 if (is_express_snoop) {
372 PortID rsp_port_id = cpu_side_port_id;
392 respond_directly =
true;
394 rsp_pkt = cmo_lookup->second;
398 const auto route_lookup =
routeTo.find(rsp_pkt->
req);
399 assert(route_lookup !=
routeTo.end());
400 rsp_port_id = route_lookup->second;
408 respond_directly =
false;
415 "%s: Routing table exceeds %d packets\n",
422 if (respond_directly) {
440 cpuSidePorts[rsp_port_id]->schedTimingResp(rsp_pkt, response_time);
453 const auto route_lookup =
routeTo.find(pkt->
req);
454 assert(route_lookup !=
routeTo.end());
455 const PortID cpu_side_port_id = route_lookup->second;
461 if (!
respLayers[cpu_side_port_id]->tryTiming(src_port)) {
499 respLayers[cpu_side_port_id]->succeededTiming(packetFinishTime);
502 pktCount[cpu_side_port_id][mem_side_port_id]++;
503 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
543 pkt->
print(), sf_res.first.size(), sf_res.second);
566 assert(
findPort(pkt) == mem_side_port_id);
576 const auto route_lookup =
routeTo.find(pkt->
req);
577 assert(route_lookup !=
routeTo.end());
578 const PortID dest_port_id = route_lookup->second;
592 if (forwardAsSnoop) {
594 if (!
snoopLayers[dest_port_id]->tryTiming(src_port)) {
603 if (!
respLayers[dest_port_id]->tryTiming(snoop_port)) {
634 if (forwardAsSnoop) {
646 [[maybe_unused]]
bool success =
648 pktCount[cpu_side_port_id][dest_port_id]++;
649 pktSize[cpu_side_port_id][dest_port_id] += pkt_size;
652 snoopLayers[dest_port_id]->succeededTiming(packetFinishTime);
663 assert(cpu_side_port_id != dest_port_id);
684 respLayers[dest_port_id]->succeededTiming(packetFinishTime);
710 for (
const auto&
p: dests) {
716 p->getId() != exclude_cpu_side_port_id) {
718 p->sendTimingSnoopReq(pkt);
733 reqLayers[mem_side_port_id]->recvRetry();
747 Tick snoop_response_latency = 0;
765 snoop_response_latency += sf_res.second *
clockPeriod();
768 pkt->
print(), sf_res.first.size(), sf_res.second);
782 if (!sf_res.first.empty())
791 snoop_response_cmd = snoop_result.first;
792 snoop_response_latency += snoop_result.second;
796 Tick response_latency = 0;
812 if (pkt->
isWrite() && is_destination) {
818 response_latency = backdoor ?
819 mem_side_port->sendAtomicBackdoor(pkt, *backdoor) :
820 mem_side_port->sendAtomic(pkt);
830 pktCount[cpu_side_port_id][mem_side_port_id]++;
831 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
844 pkt->
cmd = snoop_response_cmd;
845 response_latency = snoop_response_latency;
878 pktCount[cpu_side_port_id][mem_side_port_id]++;
879 pktSize[cpu_side_port_id][mem_side_port_id] += pkt_size;
885 return response_latency;
901 Tick snoop_response_latency = 0;
904 snoop_response_latency += sf_res.second *
clockPeriod();
907 pkt->
print(), sf_res.first.size(), sf_res.second);
913 MemCmd snoop_response_cmd = snoop_result.first;
914 snoop_response_latency += snoop_result.second;
917 pkt->
cmd = snoop_response_cmd;
926 return snoop_response_latency;
931 PortID source_mem_side_port_id,
939 Tick snoop_response_latency = 0;
946 for (
const auto&
p: dests) {
952 p->getId() == exclude_cpu_side_port_id)
955 Tick latency =
p->sendAtomicSnoop(pkt);
965 assert(pkt->
cmd != orig_cmd);
970 snoop_response_cmd = pkt->
cmd;
971 snoop_response_latency = latency;
997 return std::make_pair(snoop_response_cmd, snoop_response_latency);
1005 memSidePorts[dest_id]->sendMemBackdoorReq(req, backdoor);
1031 if (
p->trySatisfyFunctional(pkt)) {
1054 if (
p->trySatisfyFunctional(pkt)) {
1077 p->getId() != exclude_cpu_side_port_id)
1078 p->sendFunctionalSnoop(pkt);
The base crossbar contains the common elements of the non-coherent and coherent crossbar.
PortID defaultPortID
Port that handles requests that don't match any of the interfaces.
std::vector< RequestPort * > memSidePorts
const Cycles headerLatency
Cycles the layer is occupied processing the packet header.
const Cycles frontendLatency
Cycles of front-end pipeline including the delay to accept the request and to decode the address.
PortID findPort(AddrRange addr_range, PacketPtr pkt=nullptr)
Find which port connected to this crossbar (if any) should be given a packet with this address range.
statistics::Vector transDist
Stats for transaction distribution and data passing through the crossbar.
std::unordered_map< RequestPtr, PortID > routeTo
Remember where request packets came from so that we can route responses to the appropriate port.
statistics::Vector2d pktCount
std::vector< QueuedResponsePort * > cpuSidePorts
The memory-side ports and CPU-side ports of the crossbar.
void regStats() override
Callback to set stat parameters.
const Cycles forwardLatency
statistics::Vector2d pktSize
void calcPacketTiming(PacketPtr pkt, Tick header_delay)
Calculate the timing parameters for the packet.
const Cycles responseLatency
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Declaration of the coherent crossbar memory-side port type, one will be instantiated for each of the ...
Declaration of the coherent crossbar CPU-side port type, one will be instantiated for each of the mem...
Internal class to bridge between an incoming snoop response from a CPU-side port and forwarding it th...
A coherent crossbar connects a number of (potentially) snooping requestors and responders,...
std::vector< RespLayer * > respLayers
void recvReqRetry(PortID mem_side_port_id)
bool recvTimingResp(PacketPtr pkt, PortID mem_side_port_id)
bool sinkPacket(const PacketPtr pkt) const
Determine if the crossbar should sink the packet, as opposed to forwarding it, or responding.
std::vector< SnoopRespLayer * > snoopLayers
bool recvTimingSnoopResp(PacketPtr pkt, PortID cpu_side_port_id)
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &backdoor)
Function called by the port when the crossbar receives a request for a memory backdoor.
std::unordered_map< PacketId, PacketPtr > outstandingCMO
Store the outstanding cache maintenance that we are expecting snoop responses from so we can determin...
std::vector< SnoopRespPort * > snoopRespPorts
Tick recvAtomicSnoop(PacketPtr pkt, PortID mem_side_port_id)
bool recvTimingReq(PacketPtr pkt, PortID cpu_side_port_id)
System * system
Keep a pointer to the system to be allow to querying memory system properties.
std::vector< ReqLayer * > reqLayers
Declare the layers of this crossbar, one vector for requests, one for responses, and one for snoop re...
std::vector< QueuedResponsePort * > snoopPorts
std::unordered_set< RequestPtr > outstandingSnoop
Store the outstanding requests that we are expecting snoop responses from so we can determine which s...
void forwardTiming(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward a timing packet to our snoopers, potentially excluding one of the connected coherent requesto...
void recvTimingSnoopReq(PacketPtr pkt, PortID mem_side_port_id)
const Cycles snoopResponseLatency
Cycles of snoop response latency.
void recvFunctional(PacketPtr pkt, PortID cpu_side_port_id)
Function called by the port when the crossbar is receiving a Functional transaction.
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
CoherentXBar(const CoherentXBarParams &p)
virtual void regStats()
Callback to set stat parameters.
void forwardFunctional(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward a functional packet to our snoopers, potentially excluding one of the connected coherent requ...
std::pair< MemCmd, Tick > forwardAtomic(PacketPtr pkt, PortID exclude_cpu_side_port_id)
Forward an atomic packet to our snoopers, potentially excluding one of the connected coherent request...
statistics::Scalar snoopTraffic
statistics::Scalar snoops
SnoopFilter * snoopFilter
A snoop filter that tracks cache line residency and can restrict the broadcast needed for probes.
bool isDestination(const PacketPtr pkt) const
Determine if the packet's destination is the memory below.
void recvFunctionalSnoop(PacketPtr pkt, PortID mem_side_port_id)
Function called by the port when the crossbar is receiving a functional snoop transaction.
const unsigned int maxOutstandingSnoopCheck
Maximum number of outstading snoops sanity check.
statistics::Distribution snoopFanout
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
bool forwardPacket(const PacketPtr pkt)
Determine if the crossbar should forward the packet, as opposed to responding to it.
const unsigned int maxRoutingTableSizeCheck
Maximum routing table size sanity check.
const bool pointOfCoherency
Is this crossbar the point of coherency?
Tick recvAtomicBackdoor(PacketPtr pkt, PortID cpu_side_port_id, MemBackdoorPtr *backdoor=nullptr)
Cycles is a wrapper class for representing cycle counts, i.e.
const AddrRange & range() const
virtual std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void setExpressSnoop()
The express snoop flag is used for two purposes.
bool responderHadWritable() const
uint32_t snoopDelay
Keep track of the extra delay incurred by snooping upwards before sending a request down the memory s...
bool needsWritable() const
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
bool isCleanEviction() const
Is this packet a clean eviction, including both actual clean evict packets, but also clean writebacks...
bool needsResponse() const
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
int cmdToIndex() const
Return the index of this command.
RequestPtr req
A pointer to the original request.
bool isExpressSnoop() const
bool cacheResponding() const
MemCmd cmd
The command field of the packet.
bool isBlockCached() const
const std::string name() const
Return port name (for DPRINTF).
A queued port is a port that has an infinite queue for outgoing packets and thus decouples the module...
A RequestPort is a specialisation of a Port, which implements the default protocol for the three diff...
A ResponsePort is a specialization of a port.
void finishRequest(bool will_retry, Addr addr, bool is_secure)
For an un-successful request, revert the change to the snoop filter.
void setCPUSidePorts(const SnoopList &_cpu_side_ports)
Init a new snoop filter and tell it about all the cpu_sideports of the enclosing bus.
void updateSnoopForward(const Packet *cpkt, const ResponsePort &rsp_port, const RequestPort &req_port)
Pass snoop responses that travel downward through the snoop filter and let them update the snoop filt...
void updateResponse(const Packet *cpkt, const ResponsePort &cpu_side_port)
Update the snoop filter with a response from below (outer / other cache, or memory) and update the tr...
std::pair< SnoopList, Cycles > lookupSnoop(const Packet *cpkt)
Handle an incoming snoop from below (the memory-side port).
void updateSnoopResponse(const Packet *cpkt, const ResponsePort &rsp_port, const ResponsePort &req_port)
Let the snoop filter see any snoop responses that turn into request responses and indicate cache to c...
std::pair< SnoopList, Cycles > lookupRequest(const Packet *cpkt, const ResponsePort &cpu_side_port)
Lookup a request (from a CPU-side port) in the snoop filter and return a list of other CPU-side ports...
bool bypassCaches() const
Should caches be bypassed?
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
Declaration of a coherent crossbar.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
const PortID InvalidPortID
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.
uint64_t Tick
Tick count type.
std::string csprintf(const char *format, const Args &...args)