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