1#include "mem/hmc_controller.hh"
2
3#include "base/random.hh"
4#include "debug/HMCController.hh"
5
6HMCController::HMCController(const HMCControllerParams* p) :
7    NoncoherentXBar(p),
8    n_master_ports(p->port_master_connection_count),
9    rr_counter(0)
10{
11    assert(p->port_slave_connection_count == 1);
12}
13
14HMCController*
15HMCControllerParams::create()
16{
17    return new HMCController(this);
18}
19
20// Since this module is a load distributor, all its master ports have the same
21//  range so we should keep only one of the ranges and ignore the others
22void HMCController::recvRangeChange(PortID master_port_id)
23{
24    if (master_port_id == 0)
25    {
26       gotAllAddrRanges = true;
27       BaseXBar::recvRangeChange(master_port_id);
28    }
29    else
30        gotAddrRanges[master_port_id] = true;
31}
32
33int HMCController::rotate_counter()
34{
35    int current_value = rr_counter;
36    rr_counter++;
37    if (rr_counter == n_master_ports)
38        rr_counter = 0;
39    return current_value;
40}
41
42bool HMCController::recvTimingReq(PacketPtr pkt, PortID slave_port_id)
43{
44    // determine the source port based on the id
45    SlavePort *src_port = slavePorts[slave_port_id];
46
47    // we should never see express snoops on a non-coherent component
48    assert(!pkt->isExpressSnoop());
49
50    // For now, this is a simple round robin counter, for distribution the
51    //  load among the serial links
52    PortID master_port_id = rotate_counter();
53
54    // test if the layer should be considered occupied for the current
55    // port
56    if (!reqLayers[master_port_id]->tryTiming(src_port)) {
57        DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x BUSY\n",
58                src_port->name(), pkt->cmdString(), pkt->getAddr());
59        return false;
60    }
61
62    DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x\n",
63            src_port->name(), pkt->cmdString(), pkt->getAddr());
64
65    // store size and command as they might be modified when
66    // forwarding the packet
67    unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
68    unsigned int pkt_cmd = pkt->cmdToIndex();
69
70    // store the old header delay so we can restore it if needed
71    Tick old_header_delay = pkt->headerDelay;
72
73    // a request sees the frontend and forward latency
74    Tick xbar_delay = (frontendLatency + forwardLatency) * clockPeriod();
75
76    // set the packet header and payload delay
77    calcPacketTiming(pkt, xbar_delay);
78
79    // determine how long to be layer is busy
80    Tick packetFinishTime = clockEdge(Cycles(1)) + pkt->payloadDelay;
81
82    // before forwarding the packet (and possibly altering it),
83    // remember if we are expecting a response
84    const bool expect_response = pkt->needsResponse() &&
85        !pkt->cacheResponding();
86
87    // since it is a normal request, attempt to send the packet
88    bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
89
90    if (!success)  {
91        DPRINTF(HMCController, "recvTimingReq: src %s %s 0x%x RETRY\n",
92                src_port->name(), pkt->cmdString(), pkt->getAddr());
93
94        // restore the header delay as it is additive
95        pkt->headerDelay = old_header_delay;
96
97        // occupy until the header is sent
98        reqLayers[master_port_id]->failedTiming(src_port,
99                                                clockEdge(Cycles(1)));
100
101        return false;
102    }
103
104    // remember where to route the response to
105    if (expect_response) {
106        assert(routeTo.find(pkt->req) == routeTo.end());
107        routeTo[pkt->req] = slave_port_id;
108    }
109
110    reqLayers[master_port_id]->succeededTiming(packetFinishTime);
111
112    // stats updates
113    pktCount[slave_port_id][master_port_id]++;
114    pktSize[slave_port_id][master_port_id] += pkt_size;
115    transDist[pkt_cmd]++;
116
117    return true;
118}
119