# HG changeset patch # Parent 8fb939c5d7e893c2e46e47a6110e145b4e7d6d41 hmc controller diff -r 8fb939c5d7e8 src/mem/HMCController.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/HMCController.py Wed Jul 08 16:19:47 2015 +0200 @@ -0,0 +1,6 @@ +from m5.params import * +from XBar import * + +class HMCController(NoncoherentXBar): + type = 'HMCController' + cxx_header = "mem/hmc_controller.hh" diff -r 8fb939c5d7e8 src/mem/hmc_controller.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/hmc_controller.hh Wed Jul 08 16:19:47 2015 +0200 @@ -0,0 +1,31 @@ +#ifndef __HMC_CONTROLLER__ +#define __HMC_CONTROLLER__ + +#include "mem/noncoherent_xbar.hh" +#include "mem/port.hh" +#include "params/HMCController.hh" + +using namespace std; + +class HMCController : public NoncoherentXBar +{ +public: + + HMCController(const HMCControllerParams *p); + +private: + + // Receive range change only on one of the ports (because they all have the same range) + virtual void recvRangeChange(PortID master_port_id); + + // Receive a request and distribute it among slave ports + // Simply forwards the packet to the next serial link based on a + // Round-robin counter + virtual bool recvTimingReq(PacketPtr pkt, PortID slave_port_id); + + int n_master_ports; + int rr_counter; + int rotate_counter(); +}; + +#endif //__HMC_CONTROLLER__ diff -r 8fb939c5d7e8 src/mem/hmc_controller.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mem/hmc_controller.cc Wed Jul 08 16:19:47 2015 +0200 @@ -0,0 +1,120 @@ +#include "base/random.hh" +#include "debug/HMCController.hh" +#include "mem/hmc_controller.hh" + +HMCController::HMCController(const HMCControllerParams* p) : + NoncoherentXBar(p), + n_master_ports(p->port_master_connection_count), + rr_counter(0) +{ + assert(p->port_slave_connection_count == 1); +} + +HMCController* +HMCControllerParams::create() +{ + return new HMCController(this); +} + +// Since this module is a load distributor, all its master ports have the same range +// so we should keep only one of the ranges and ignore the others +void HMCController::recvRangeChange(PortID master_port_id) +{ + if ( master_port_id == 0 ) + { + gotAllAddrRanges = true; + BaseXBar::recvRangeChange(master_port_id); + } + else + gotAddrRanges[master_port_id] = true; +} + +int HMCController::rotate_counter() +{ + int current_value = rr_counter; + rr_counter++; + if ( rr_counter == n_master_ports ) + rr_counter = 0; + return current_value; +} + +bool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id) +{ + // determine the source port based on the id + SlavePort *src_port = slavePorts[slave_port_id]; + + // we should never see express snoops on a non-coherent component + assert(!pkt->isExpressSnoop()); + + // For now, this is a simple round robin counter, for distribution the + // load among the serial links + PortID master_port_id = rotate_counter(); + + // test if the layer should be considered occupied for the current + // port + if (!reqLayers[master_port_id]->tryTiming(src_port)) { + DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + return false; + } + + DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // store size and command as they might be modified when + // forwarding the packet + unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0; + unsigned int pkt_cmd = pkt->cmdToIndex(); + + // store the old header delay so we can restore it if needed + Tick old_header_delay = pkt->headerDelay; + + // a request sees the frontend and forward latency + Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod(); + + // set the packet header and payload delay + calcPacketTiming(pkt, xbar_delay); + + // determine how long to be layer is busy + Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay; + + // before forwarding the packet (and possibly altering it), + // remember if we are expecting a response + const bool expect_response = pkt->needsResponse() && + !pkt->memInhibitAsserted(); + + // since it is a normal request, attempt to send the packet + bool success = masterPorts[master_port_id]->sendTimingReq(pkt); + + if (!success) { + // inhibited packets should never be forced to retry + assert(!pkt->memInhibitAsserted()); + + DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n", + src_port->name(), pkt->cmdString(), pkt->getAddr()); + + // restore the header delay as it is additive + pkt->headerDelay = old_header_delay; + + // occupy until the header is sent + reqLayers[master_port_id]->failedTiming(src_port, + clockEdge(Cycles(1))); + + return false; + } + + // remember where to route the response to + if (expect_response) { + assert(routeTo.find(pkt->req) == routeTo.end()); + routeTo[pkt->req] = slave_port_id; + } + + reqLayers[master_port_id]->succeededTiming(packetFinishTime); + + // stats updates + pktCount[slave_port_id][master_port_id]++; + pktSize[slave_port_id][master_port_id] += pkt_size; + transDist[pkt_cmd]++; + + return true; +}