hmc_controller.cc revision 11184:07b0dacf27d6
1#include "base/random.hh" 2#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->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} 121