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