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