diff options
author | Erfan Azarkhish <erfan.azarkhish@unibo.it> | 2015-11-03 12:17:56 -0600 |
---|---|---|
committer | Erfan Azarkhish <erfan.azarkhish@unibo.it> | 2015-11-03 12:17:56 -0600 |
commit | 1530e1a690a7d3c1b028e59d2fa37c88df8e47df (patch) | |
tree | 7b8c62718c14e44e5636ccf4debe1d6180a3f4a9 /src/mem/hmc_controller.cc | |
parent | 100cbc9cf63af46697f129c9c10f0cc80ff7db9d (diff) | |
download | gem5-1530e1a690a7d3c1b028e59d2fa37c88df8e47df.tar.xz |
mem: hmc: adds controller
This patch models a simple HMC Controller. It simply schedules the incoming
packets to HMC Serial Links using a round robin mechanism. This patch should
be applied in series with other patches modeling a complete HMC device.
Committed by: Nilay Vaish <nilay@cs.wisc.edu>
Diffstat (limited to 'src/mem/hmc_controller.cc')
-rw-r--r-- | src/mem/hmc_controller.cc | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/mem/hmc_controller.cc b/src/mem/hmc_controller.cc new file mode 100644 index 000000000..c6fd36206 --- /dev/null +++ b/src/mem/hmc_controller.cc @@ -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; +} |