mem: Update port terminology
[gem5.git] / src / mem / hmc_controller.cc
1 #include "mem/hmc_controller.hh"
2
3 #include "base/random.hh"
4 #include "base/trace.hh"
5 #include "debug/HMCController.hh"
6
7 HMCController::HMCController(const HMCControllerParams* p) :
8 NoncoherentXBar(p),
9 n_master_ports(p->port_master_connection_count),
10 rr_counter(0)
11 {
12 assert(p->port_slave_connection_count == 1);
13 }
14
15 HMCController*
16 HMCControllerParams::create()
17 {
18 return new HMCController(this);
19 }
20
21 // Since this module is a load distributor, all its master ports have the same
22 // range so we should keep only one of the ranges and ignore the others
23 void HMCController::recvRangeChange(PortID master_port_id)
24 {
25 if (master_port_id == 0)
26 {
27 gotAllAddrRanges = true;
28 BaseXBar::recvRangeChange(master_port_id);
29 }
30 else
31 gotAddrRanges[master_port_id] = true;
32 }
33
34 int HMCController::rotate_counter()
35 {
36 int current_value = rr_counter;
37 rr_counter++;
38 if (rr_counter == n_master_ports)
39 rr_counter = 0;
40 return current_value;
41 }
42
43 bool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
44 {
45 // determine the source port based on the id
46 ResponsePort *src_port = slavePorts[slave_port_id];
47
48 // we should never see express snoops on a non-coherent component
49 assert(!pkt->isExpressSnoop());
50
51 // For now, this is a simple round robin counter, for distribution the
52 // load among the serial links
53 PortID master_port_id = rotate_counter();
54
55 // test if the layer should be considered occupied for the current
56 // port
57 if (!reqLayers[master_port_id]->tryTiming(src_port)) {
58 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n",
59 src_port->name(), pkt->cmdString(), pkt->getAddr());
60 return false;
61 }
62
63 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n",
64 src_port->name(), pkt->cmdString(), pkt->getAddr());
65
66 // store size and command as they might be modified when
67 // forwarding the packet
68 unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
69 unsigned int pkt_cmd = pkt->cmdToIndex();
70
71 // store the old header delay so we can restore it if needed
72 Tick old_header_delay = pkt->headerDelay;
73
74 // a request sees the frontend and forward latency
75 Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod();
76
77 // set the packet header and payload delay
78 calcPacketTiming(pkt, xbar_delay);
79
80 // determine how long to be layer is busy
81 Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay;
82
83 // before forwarding the packet (and possibly altering it),
84 // remember if we are expecting a response
85 const bool expect_response = pkt->needsResponse() &&
86 !pkt->cacheResponding();
87
88 // since it is a normal request, attempt to send the packet
89 bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
90
91 if (!success) {
92 DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n",
93 src_port->name(), pkt->cmdString(), pkt->getAddr());
94
95 // restore the header delay as it is additive
96 pkt->headerDelay = old_header_delay;
97
98 // occupy until the header is sent
99 reqLayers[master_port_id]->failedTiming(src_port,
100 clockEdge(Cycles(1)));
101
102 return false;
103 }
104
105 // remember where to route the response to
106 if (expect_response) {
107 assert(routeTo.find(pkt->req) == routeTo.end());
108 routeTo[pkt->req] = slave_port_id;
109 }
110
111 reqLayers[master_port_id]->succeededTiming(packetFinishTime);
112
113 // stats updates
114 pktCount[slave_port_id][master_port_id]++;
115 pktSize[slave_port_id][master_port_id] += pkt_size;
116 transDist[pkt_cmd]++;
117
118 return true;
119 }