1 #include "mem/hmc_controller.hh"
3 #include "base/random.hh"
4 #include "base/trace.hh"
5 #include "debug/HMCController.hh"
7 HMCController::HMCController(const HMCControllerParams
* p
) :
9 n_master_ports(p
->port_master_connection_count
),
12 assert(p
->port_slave_connection_count
== 1);
16 HMCControllerParams::create()
18 return new HMCController(this);
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
)
25 if (master_port_id
== 0)
27 gotAllAddrRanges
= true;
28 BaseXBar::recvRangeChange(master_port_id
);
31 gotAddrRanges
[master_port_id
] = true;
34 int HMCController::rotate_counter()
36 int current_value
= rr_counter
;
38 if (rr_counter
== n_master_ports
)
43 bool HMCController::recvTimingReq(PacketPtr pkt
, PortID slave_port_id
)
45 // determine the source port based on the id
46 ResponsePort
*src_port
= slavePorts
[slave_port_id
];
48 // we should never see express snoops on a non-coherent component
49 assert(!pkt
->isExpressSnoop());
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();
55 // test if the layer should be considered occupied for the current
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());
63 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x\n",
64 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
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();
71 // store the old header delay so we can restore it if needed
72 Tick old_header_delay
= pkt
->headerDelay
;
74 // a request sees the frontend and forward latency
75 Tick xbar_delay
= (frontendLatency
+ forwardLatency
) * clockPeriod();
77 // set the packet header and payload delay
78 calcPacketTiming(pkt
, xbar_delay
);
80 // determine how long to be layer is busy
81 Tick packetFinishTime
= clockEdge(Cycles(1)) + pkt
->payloadDelay
;
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();
88 // since it is a normal request, attempt to send the packet
89 bool success
= masterPorts
[master_port_id
]->sendTimingReq(pkt
);
92 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x RETRY\n",
93 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
95 // restore the header delay as it is additive
96 pkt
->headerDelay
= old_header_delay
;
98 // occupy until the header is sent
99 reqLayers
[master_port_id
]->failedTiming(src_port
,
100 clockEdge(Cycles(1)));
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
;
111 reqLayers
[master_port_id
]->succeededTiming(packetFinishTime
);
114 pktCount
[slave_port_id
][master_port_id
]++;
115 pktSize
[slave_port_id
][master_port_id
] += pkt_size
;
116 transDist
[pkt_cmd
]++;