This change updates the HBMCtrl such that both pseudo channels can be in separate states (read or write) at the same time. In addition, the controller queues are now always split in two halves for both pseudo channels. Change-Id: Ifb599e611ad99f6c511baaf245bad2b5c9210a86 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/65491 Reviewed-by: Jason Lowe-Power <power.jg@gmail.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
271 lines
8.6 KiB
C++
271 lines
8.6 KiB
C++
/*
|
|
* Copyright (c) 2022 The Regents of the University of California
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* HBMCtrl declaration
|
|
*/
|
|
|
|
#ifndef __HBM_CTRL_HH__
|
|
#define __HBM_CTRL_HH__
|
|
|
|
#include <deque>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "mem/mem_ctrl.hh"
|
|
#include "params/HBMCtrl.hh"
|
|
|
|
namespace gem5
|
|
{
|
|
|
|
namespace memory
|
|
{
|
|
|
|
class MemInterface;
|
|
class DRAMInterface;
|
|
|
|
|
|
/**
|
|
* HBM2 is divided into two pseudo channels which have independent data buses
|
|
* but share a command bus (separate row and column command bus). Therefore,
|
|
* the HBM memory controller should be able to control both pseudo channels.
|
|
* This HBM memory controller inherits from gem5's default
|
|
* memory controller (pseudo channel 0) and manages the additional HBM pseudo
|
|
* channel (pseudo channel 1).
|
|
*/
|
|
class HBMCtrl : public MemCtrl
|
|
{
|
|
|
|
protected:
|
|
|
|
bool respQEmpty() override
|
|
{
|
|
return (respQueue.empty() && respQueuePC1.empty());
|
|
}
|
|
|
|
private:
|
|
|
|
/**
|
|
* Remember if we have to retry a request for second pseudo channel.
|
|
*/
|
|
bool retryRdReqPC1;
|
|
bool retryWrReqPC1;
|
|
|
|
/**
|
|
* Remove commands that have already issued from rowBurstTicks
|
|
* and colBurstTicks
|
|
*/
|
|
void pruneBurstTick() override;
|
|
|
|
AddrRangeList getAddrRanges() override;
|
|
|
|
public:
|
|
HBMCtrl(const HBMCtrlParams &p);
|
|
|
|
void pruneRowBurstTick();
|
|
void pruneColBurstTick();
|
|
|
|
/**
|
|
* Check for command bus contention for single cycle command.
|
|
* If there is contention, shift command to next burst.
|
|
* Check verifies that the commands issued per burst is less
|
|
* than a defined max number, maxCommandsPerWindow.
|
|
* Therefore, contention per cycle is not verified and instead
|
|
* is done based on a burst window.
|
|
*
|
|
* @param cmd_tick Initial tick of command, to be verified
|
|
* @param max_cmds_per_burst Number of commands that can issue
|
|
* in a burst window
|
|
* @return tick for command issue without contention
|
|
*/
|
|
Tick verifySingleCmd(Tick cmd_tick, Tick max_cmds_per_burst,
|
|
bool row_cmd) override;
|
|
|
|
/**
|
|
* Check for command bus contention for multi-cycle (2 currently)
|
|
* command. If there is contention, shift command(s) to next burst.
|
|
* Check verifies that the commands issued per burst is less
|
|
* than a defined max number, maxCommandsPerWindow.
|
|
* Therefore, contention per cycle is not verified and instead
|
|
* is done based on a burst window.
|
|
* For HBM2, only row cmds (activate) can be multi-cycle
|
|
*
|
|
* @param cmd_tick Initial tick of command, to be verified
|
|
* @param max_multi_cmd_split Maximum delay between commands
|
|
* @param max_cmds_per_burst Number of commands that can issue
|
|
* in a burst window
|
|
* @return tick for command issue without contention
|
|
*/
|
|
Tick verifyMultiCmd(Tick cmd_tick, Tick max_cmds_per_burst,
|
|
Tick max_multi_cmd_split = 0) override;
|
|
|
|
/**
|
|
* NextReq and Respond events for second pseudo channel
|
|
*
|
|
*/
|
|
EventFunctionWrapper nextReqEventPC1;
|
|
EventFunctionWrapper respondEventPC1;
|
|
|
|
/**
|
|
* Check if the read queue partition of both pseudo
|
|
* channels has room for more entries. This is used when the HBM ctrl
|
|
* is run with partitioned queues
|
|
*
|
|
* @param pkt_count The number of entries needed in the read queue
|
|
* @return true if read queue partition is full, false otherwise
|
|
*/
|
|
bool readQueueFullPC0(unsigned int pkt_count) const;
|
|
bool readQueueFullPC1(unsigned int pkt_count) const;
|
|
|
|
/**
|
|
* Check if the write queue partition of both pseudo
|
|
* channels has room for more entries. This is used when the HBM ctrl
|
|
* is run with partitioned queues
|
|
*
|
|
* @param pkt_count The number of entries needed in the write queue
|
|
* @return true if write queue is full, false otherwise
|
|
*/
|
|
bool writeQueueFullPC0(unsigned int pkt_count) const;
|
|
bool writeQueueFullPC1(unsigned int pkt_count) const;
|
|
|
|
/**
|
|
* Following counters are used to keep track of the entries in read/write
|
|
* queue for each pseudo channel (useful when the partitioned queues are
|
|
* used)
|
|
*/
|
|
uint64_t readQueueSizePC0 = 0;
|
|
uint64_t readQueueSizePC1 = 0;
|
|
uint64_t writeQueueSizePC0 = 0;
|
|
uint64_t writeQueueSizePC1 = 0;
|
|
|
|
/**
|
|
* Response queue for pkts sent to second pseudo channel
|
|
* The first pseudo channel uses MemCtrl::respQueue
|
|
*/
|
|
std::deque<MemPacket*> respQueuePC1;
|
|
|
|
/**
|
|
* Holds count of row commands issued in burst window starting at
|
|
* defined Tick. This is used to ensure that the row command bandwidth
|
|
* does not exceed the allowable media constraints.
|
|
*/
|
|
std::unordered_multiset<Tick> rowBurstTicks;
|
|
|
|
/**
|
|
* This is used to ensure that the column command bandwidth
|
|
* does not exceed the allowable media constraints. HBM2 has separate
|
|
* command bus for row and column commands
|
|
*/
|
|
std::unordered_multiset<Tick> colBurstTicks;
|
|
|
|
/**
|
|
* Pointers to interfaces of the two pseudo channels
|
|
* pc0Int is same as MemCtrl::dram (it will be pointing to
|
|
* the DRAM interface defined in base MemCtrl)
|
|
*/
|
|
DRAMInterface* pc0Int;
|
|
DRAMInterface* pc1Int;
|
|
|
|
/**
|
|
* This indicates if the R/W queues will be partitioned among
|
|
* pseudo channels
|
|
*/
|
|
bool partitionedQ;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Is there a respondEvent scheduled?
|
|
*
|
|
* @return true if event is scheduled
|
|
*/
|
|
bool respondEventScheduled(uint8_t pseudo_channel) const override
|
|
{
|
|
if (pseudo_channel == 0) {
|
|
return MemCtrl::respondEventScheduled(pseudo_channel);
|
|
} else {
|
|
assert(pseudo_channel == 1);
|
|
return respondEventPC1.scheduled();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Is there a read/write burst Event scheduled?
|
|
*
|
|
* @return true if event is scheduled
|
|
*/
|
|
bool requestEventScheduled(uint8_t pseudo_channel) const override
|
|
{
|
|
if (pseudo_channel == 0) {
|
|
return MemCtrl::requestEventScheduled(pseudo_channel);
|
|
} else {
|
|
assert(pseudo_channel == 1);
|
|
return nextReqEventPC1.scheduled();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* restart the controller scheduler
|
|
*
|
|
* @param Tick to schedule next event
|
|
* @param pseudo_channel pseudo channel number for which scheduler
|
|
* needs to restart
|
|
*/
|
|
void restartScheduler(Tick tick, uint8_t pseudo_channel) override
|
|
{
|
|
if (pseudo_channel == 0) {
|
|
MemCtrl::restartScheduler(tick);
|
|
} else {
|
|
schedule(nextReqEventPC1, tick);
|
|
}
|
|
}
|
|
|
|
|
|
virtual void init() override;
|
|
virtual void startup() override;
|
|
virtual void drainResume() override;
|
|
|
|
|
|
protected:
|
|
Tick recvAtomic(PacketPtr pkt) override;
|
|
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override;
|
|
void recvFunctional(PacketPtr pkt) override;
|
|
void recvMemBackdoorReq(const MemBackdoorReq &req,
|
|
MemBackdoorPtr &_backdoor) override;
|
|
bool recvTimingReq(PacketPtr pkt) override;
|
|
|
|
};
|
|
|
|
} // namespace memory
|
|
} // namespace gem5
|
|
|
|
#endif //__HBM_CTRL_HH__
|