1 #include "mem/hmc_controller.hh"
3 #include "base/random.hh"
4 #include "base/trace.hh"
5 #include "debug/HMCController.hh"
7 HMCController::HMCController(const HMCControllerParams
&p
) :
9 numMemSidePorts(p
.port_mem_side_ports_connection_count
),
12 assert(p
.port_cpu_side_ports_connection_count
== 1);
15 // Since this module is a load distributor, all its request ports have the same
16 // range so we should keep only one of the ranges and ignore the others
17 void HMCController::recvRangeChange(PortID mem_side_port_id
)
19 if (mem_side_port_id
== 0)
21 gotAllAddrRanges
= true;
22 BaseXBar::recvRangeChange(mem_side_port_id
);
25 gotAddrRanges
[mem_side_port_id
] = true;
28 int HMCController::rotate_counter()
30 int current_value
= rr_counter
;
32 if (rr_counter
== numMemSidePorts
)
37 bool HMCController::recvTimingReq(PacketPtr pkt
, PortID cpu_side_port_id
)
39 // determine the source port based on the id
40 ResponsePort
*src_port
= cpuSidePorts
[cpu_side_port_id
];
42 // we should never see express snoops on a non-coherent component
43 assert(!pkt
->isExpressSnoop());
45 // For now, this is a simple round robin counter, for distribution the
46 // load among the serial links
47 PortID mem_side_port_id
= rotate_counter();
49 // test if the layer should be considered occupied for the current
51 if (!reqLayers
[mem_side_port_id
]->tryTiming(src_port
)) {
52 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x BUSY\n",
53 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
57 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x\n",
58 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
60 // store size and command as they might be modified when
61 // forwarding the packet
62 unsigned int pkt_size
= pkt
->hasData() ? pkt
->getSize() : 0;
63 unsigned int pkt_cmd
= pkt
->cmdToIndex();
65 // store the old header delay so we can restore it if needed
66 Tick old_header_delay
= pkt
->headerDelay
;
68 // a request sees the frontend and forward latency
69 Tick xbar_delay
= (frontendLatency
+ forwardLatency
) * clockPeriod();
71 // set the packet header and payload delay
72 calcPacketTiming(pkt
, xbar_delay
);
74 // determine how long to be layer is busy
75 Tick packetFinishTime
= clockEdge(Cycles(1)) + pkt
->payloadDelay
;
77 // before forwarding the packet (and possibly altering it),
78 // remember if we are expecting a response
79 const bool expect_response
= pkt
->needsResponse() &&
80 !pkt
->cacheResponding();
82 // since it is a normal request, attempt to send the packet
83 bool success
= memSidePorts
[mem_side_port_id
]->sendTimingReq(pkt
);
86 DPRINTF(HMCController
, "recvTimingReq: src %s %s 0x%x RETRY\n",
87 src_port
->name(), pkt
->cmdString(), pkt
->getAddr());
89 // restore the header delay as it is additive
90 pkt
->headerDelay
= old_header_delay
;
92 // occupy until the header is sent
93 reqLayers
[mem_side_port_id
]->failedTiming(src_port
,
94 clockEdge(Cycles(1)));
99 // remember where to route the response to
100 if (expect_response
) {
101 assert(routeTo
.find(pkt
->req
) == routeTo
.end());
102 routeTo
[pkt
->req
] = cpu_side_port_id
;
105 reqLayers
[mem_side_port_id
]->succeededTiming(packetFinishTime
);
108 pktCount
[cpu_side_port_id
][mem_side_port_id
]++;
109 pktSize
[cpu_side_port_id
][mem_side_port_id
] += pkt_size
;
110 transDist
[pkt_cmd
]++;