hmc_controller.cc revision 11284
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->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} 118