1 #include "mem/hmc_controller.hh"
3 #include "base/random.hh"
4 #include "debug/HMCController.hh"
6 HMCController::HMCController(const HMCControllerParams
* p
) :
8 n_master_ports(p
->port_master_connection_count
),
11 assert(p
->port_slave_connection_count
== 1);
15 HMCControllerParams::create()
17 return new HMCController(this);
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
22 void HMCController::recvRangeChange(PortID master_port_id
)
24 if (master_port_id
== 0)
26 gotAllAddrRanges
= true;
27 BaseXBar::recvRangeChange(master_port_id
);
30 gotAddrRanges
[master_port_id
] = true;
33 int HMCController::rotate_counter()
35 int current_value
= rr_counter
;
37 if (rr_counter
== n_master_ports
)
42 bool HMCController::recvTimingReq(PacketPtr pkt
, PortID slave_port_id
)
44 // determine the source port based on the id
45 SlavePort
*src_port
= slavePorts
[slave_port_id
];
47 // we should never see express snoops on a non-coherent component
48 assert(!pkt
->isExpressSnoop());
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();
54 // test if the layer should be considered occupied for the current
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());
62 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x\n",
63 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
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();
70 // store the old header delay so we can restore it if needed
71 Tick old_header_delay
= pkt
->headerDelay
;
73 // a request sees the frontend and forward latency
74 Tick xbar_delay
= (frontendLatency
+ forwardLatency
) * clockPeriod();
76 // set the packet header and payload delay
77 calcPacketTiming(pkt
, xbar_delay
);
79 // determine how long to be layer is busy
80 Tick packetFinishTime
= clockEdge(Cycles(1)) + pkt
->payloadDelay
;
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();
87 // since it is a normal request, attempt to send the packet
88 bool success
= masterPorts
[master_port_id
]->sendTimingReq(pkt
);
91 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x RETRY\n",
92 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
94 // restore the header delay as it is additive
95 pkt
->headerDelay
= old_header_delay
;
97 // occupy until the header is sent
98 reqLayers
[master_port_id
]->failedTiming(src_port
,
99 clockEdge(Cycles(1)));
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
;
110 reqLayers
[master_port_id
]->succeededTiming(packetFinishTime
);
113 pktCount
[slave_port_id
][master_port_id
]++;
114 pktSize
[slave_port_id
][master_port_id
] += pkt_size
;
115 transDist
[pkt_cmd
]++;