111793Sbrandon.potter@amd.com#include "mem/hmc_controller.hh" 211793Sbrandon.potter@amd.com 311184Serfan.azarkhish@unibo.it#include "base/random.hh" 411184Serfan.azarkhish@unibo.it#include "debug/HMCController.hh" 511184Serfan.azarkhish@unibo.it 611184Serfan.azarkhish@unibo.itHMCController::HMCController(const HMCControllerParams* p) : 711184Serfan.azarkhish@unibo.it NoncoherentXBar(p), 811184Serfan.azarkhish@unibo.it n_master_ports(p->port_master_connection_count), 911184Serfan.azarkhish@unibo.it rr_counter(0) 1011184Serfan.azarkhish@unibo.it{ 1111184Serfan.azarkhish@unibo.it assert(p->port_slave_connection_count == 1); 1211184Serfan.azarkhish@unibo.it} 1311184Serfan.azarkhish@unibo.it 1411184Serfan.azarkhish@unibo.itHMCController* 1511184Serfan.azarkhish@unibo.itHMCControllerParams::create() 1611184Serfan.azarkhish@unibo.it{ 1711184Serfan.azarkhish@unibo.it return new HMCController(this); 1811184Serfan.azarkhish@unibo.it} 1911184Serfan.azarkhish@unibo.it 2011184Serfan.azarkhish@unibo.it// Since this module is a load distributor, all its master ports have the same 2111184Serfan.azarkhish@unibo.it// range so we should keep only one of the ranges and ignore the others 2211184Serfan.azarkhish@unibo.itvoid HMCController::recvRangeChange(PortID master_port_id) 2311184Serfan.azarkhish@unibo.it{ 2411184Serfan.azarkhish@unibo.it if (master_port_id == 0) 2511184Serfan.azarkhish@unibo.it { 2611184Serfan.azarkhish@unibo.it gotAllAddrRanges = true; 2711184Serfan.azarkhish@unibo.it BaseXBar::recvRangeChange(master_port_id); 2811184Serfan.azarkhish@unibo.it } 2911184Serfan.azarkhish@unibo.it else 3011184Serfan.azarkhish@unibo.it gotAddrRanges[master_port_id] = true; 3111184Serfan.azarkhish@unibo.it} 3211184Serfan.azarkhish@unibo.it 3311184Serfan.azarkhish@unibo.itint HMCController::rotate_counter() 3411184Serfan.azarkhish@unibo.it{ 3511184Serfan.azarkhish@unibo.it int current_value = rr_counter; 3611184Serfan.azarkhish@unibo.it rr_counter++; 3711184Serfan.azarkhish@unibo.it if (rr_counter == n_master_ports) 3811184Serfan.azarkhish@unibo.it rr_counter = 0; 3911184Serfan.azarkhish@unibo.it return current_value; 4011184Serfan.azarkhish@unibo.it} 4111184Serfan.azarkhish@unibo.it 4211184Serfan.azarkhish@unibo.itbool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id) 4311184Serfan.azarkhish@unibo.it{ 4411184Serfan.azarkhish@unibo.it // determine the source port based on the id 4511184Serfan.azarkhish@unibo.it SlavePort *src_port = slavePorts[slave_port_id]; 4611184Serfan.azarkhish@unibo.it 4711184Serfan.azarkhish@unibo.it // we should never see express snoops on a non-coherent component 4811184Serfan.azarkhish@unibo.it assert(!pkt->isExpressSnoop()); 4911184Serfan.azarkhish@unibo.it 5011184Serfan.azarkhish@unibo.it // For now, this is a simple round robin counter, for distribution the 5111184Serfan.azarkhish@unibo.it // load among the serial links 5211184Serfan.azarkhish@unibo.it PortID master_port_id = rotate_counter(); 5311184Serfan.azarkhish@unibo.it 5411184Serfan.azarkhish@unibo.it // test if the layer should be considered occupied for the current 5511184Serfan.azarkhish@unibo.it // port 5611184Serfan.azarkhish@unibo.it if (!reqLayers[master_port_id]->tryTiming(src_port)) { 5711184Serfan.azarkhish@unibo.it DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n", 5811184Serfan.azarkhish@unibo.it src_port->name(), pkt->cmdString(), pkt->getAddr()); 5911184Serfan.azarkhish@unibo.it return false; 6011184Serfan.azarkhish@unibo.it } 6111184Serfan.azarkhish@unibo.it 6211184Serfan.azarkhish@unibo.it DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n", 6311184Serfan.azarkhish@unibo.it src_port->name(), pkt->cmdString(), pkt->getAddr()); 6411184Serfan.azarkhish@unibo.it 6511184Serfan.azarkhish@unibo.it // store size and command as they might be modified when 6611184Serfan.azarkhish@unibo.it // forwarding the packet 6711184Serfan.azarkhish@unibo.it unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; 6811184Serfan.azarkhish@unibo.it unsigned int pkt_cmd = pkt->cmdToIndex(); 6911184Serfan.azarkhish@unibo.it 7011184Serfan.azarkhish@unibo.it // store the old header delay so we can restore it if needed 7111184Serfan.azarkhish@unibo.it Tick old_header_delay = pkt->headerDelay; 7211184Serfan.azarkhish@unibo.it 7311184Serfan.azarkhish@unibo.it // a request sees the frontend and forward latency 7411184Serfan.azarkhish@unibo.it Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod(); 7511184Serfan.azarkhish@unibo.it 7611184Serfan.azarkhish@unibo.it // set the packet header and payload delay 7711184Serfan.azarkhish@unibo.it calcPacketTiming(pkt, xbar_delay); 7811184Serfan.azarkhish@unibo.it 7911184Serfan.azarkhish@unibo.it // determine how long to be layer is busy 8011184Serfan.azarkhish@unibo.it Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay; 8111184Serfan.azarkhish@unibo.it 8211184Serfan.azarkhish@unibo.it // before forwarding the packet (and possibly altering it), 8311184Serfan.azarkhish@unibo.it // remember if we are expecting a response 8411184Serfan.azarkhish@unibo.it const bool expect_response = pkt->needsResponse() && 8511284Sandreas.hansson@arm.com !pkt->cacheResponding(); 8611184Serfan.azarkhish@unibo.it 8711184Serfan.azarkhish@unibo.it // since it is a normal request, attempt to send the packet 8811184Serfan.azarkhish@unibo.it bool success = masterPorts[master_port_id]->sendTimingReq(pkt); 8911184Serfan.azarkhish@unibo.it 9011184Serfan.azarkhish@unibo.it if (!success) { 9111184Serfan.azarkhish@unibo.it DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n", 9211184Serfan.azarkhish@unibo.it src_port->name(), pkt->cmdString(), pkt->getAddr()); 9311184Serfan.azarkhish@unibo.it 9411184Serfan.azarkhish@unibo.it // restore the header delay as it is additive 9511184Serfan.azarkhish@unibo.it pkt->headerDelay = old_header_delay; 9611184Serfan.azarkhish@unibo.it 9711184Serfan.azarkhish@unibo.it // occupy until the header is sent 9811184Serfan.azarkhish@unibo.it reqLayers[master_port_id]->failedTiming(src_port, 9911184Serfan.azarkhish@unibo.it clockEdge(Cycles(1))); 10011184Serfan.azarkhish@unibo.it 10111184Serfan.azarkhish@unibo.it return false; 10211184Serfan.azarkhish@unibo.it } 10311184Serfan.azarkhish@unibo.it 10411184Serfan.azarkhish@unibo.it // remember where to route the response to 10511184Serfan.azarkhish@unibo.it if (expect_response) { 10611184Serfan.azarkhish@unibo.it assert(routeTo.find(pkt->req) == routeTo.end()); 10711184Serfan.azarkhish@unibo.it routeTo[pkt->req] = slave_port_id; 10811184Serfan.azarkhish@unibo.it } 10911184Serfan.azarkhish@unibo.it 11011184Serfan.azarkhish@unibo.it reqLayers[master_port_id]->succeededTiming(packetFinishTime); 11111184Serfan.azarkhish@unibo.it 11211184Serfan.azarkhish@unibo.it // stats updates 11311184Serfan.azarkhish@unibo.it pktCount[slave_port_id][master_port_id]++; 11411184Serfan.azarkhish@unibo.it pktSize[slave_port_id][master_port_id] += pkt_size; 11511184Serfan.azarkhish@unibo.it transDist[pkt_cmd]++; 11611184Serfan.azarkhish@unibo.it 11711184Serfan.azarkhish@unibo.it return true; 11811184Serfan.azarkhish@unibo.it} 119