1#include "mem/hmc_controller.hh" 2 3#include "base/random.hh" 4#include "debug/HMCController.hh" 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} 119