summaryrefslogtreecommitdiff
path: root/src/mem/hmc_controller.cc
diff options
context:
space:
mode:
authorErfan Azarkhish <erfan.azarkhish@unibo.it>2015-11-03 12:17:56 -0600
committerErfan Azarkhish <erfan.azarkhish@unibo.it>2015-11-03 12:17:56 -0600
commit1530e1a690a7d3c1b028e59d2fa37c88df8e47df (patch)
tree7b8c62718c14e44e5636ccf4debe1d6180a3f4a9 /src/mem/hmc_controller.cc
parent100cbc9cf63af46697f129c9c10f0cc80ff7db9d (diff)
downloadgem5-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.cc120
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;
+}