32 #include "debug/DRAM.hh"
33 #include "debug/Drain.hh"
34 #include "debug/MemCtrl.hh"
35 #include "debug/QOS.hh"
48 retryRdReqPC1(false), retryWrReqPC1(false),
52 respondEventPC1([
this] {processRespondEvent(pc1Int, respQueuePC1,
53 respondEventPC1, retryRdReqPC1); },
name()),
55 partitionedQ(
p.partitioned_q)
57 DPRINTF(MemCtrl,
"Setting up HBM controller\n");
59 pc0Int =
dynamic_cast<DRAMInterface*
>(dram);
61 assert(
dynamic_cast<DRAMInterface*
>(
p.dram_2) !=
nullptr);
63 readBufferSize = pc0Int->readBufferSize + pc1Int->readBufferSize;
64 writeBufferSize = pc0Int->writeBufferSize + pc1Int->writeBufferSize;
66 fatal_if(!pc0Int,
"Memory controller must have pc0 interface");
67 fatal_if(!pc1Int,
"Memory controller must have pc1 interface");
69 pc0Int->setCtrl(
this, commandWindow, 0);
70 pc1Int->setCtrl(
this, commandWindow, 1);
73 writeHighThreshold = (writeBufferSize * (
p.write_high_thresh_perc/2)
75 writeLowThreshold = (writeBufferSize * (
p.write_low_thresh_perc/2)
78 writeHighThreshold = (writeBufferSize *
p.write_high_thresh_perc
80 writeLowThreshold = (writeBufferSize *
p.write_low_thresh_perc
116 panic(
"Can't handle address range for packet %s\n", pkt->
print());
132 panic(
"Can't handle address range for packet %s\n", pkt->
print());
147 panic(
"Can't handle address range for packet %s\n",
157 "Write queue limit %d, PC0 size %d, entries needed %d\n",
168 "Write queue limit %d, PC1 size %d, entries needed %d\n",
179 "Read queue limit %d, PC0 size %d, entries needed %d\n",
192 "Read queue limit %d, PC1 size %d, entries needed %d\n",
205 "HBMCtrl: Read queue limit %d, entries needed %d\n",
224 "Should only see read and writes at memory controller\n");
246 unsigned size = pkt->
getSize();
338 auto current_it = it++;
351 auto current_it = it++;
370 Tick cmd_at = cmd_tick;
379 while (
rowBurstTicks.count(burst_tick) >= max_cmds_per_burst) {
390 while (
colBurstTicks.count(burst_tick) >= max_cmds_per_burst) {
405 Tick max_multi_cmd_split)
409 Tick cmd_at = cmd_tick;
419 Tick burst_offset = 0;
421 while (max_multi_cmd_split > (first_cmd_offset + burst_offset)) {
426 Tick first_cmd_tick = burst_tick - std::min(burst_offset, burst_tick);
429 bool first_can_issue =
false;
430 bool second_can_issue =
false;
432 while (!first_can_issue || !second_can_issue) {
433 bool same_burst = (burst_tick == first_cmd_tick);
435 auto second_cmd_count = same_burst ?
438 first_can_issue = first_cmd_count < max_cmds_per_burst;
439 second_can_issue = second_cmd_count < max_cmds_per_burst;
441 if (!second_can_issue) {
442 DPRINTF(
MemCtrl,
"Contention (cmd2) found on command bus at %d\n",
451 bool gap_violated = !same_burst &&
452 ((burst_tick - first_cmd_tick) > max_multi_cmd_split);
454 if (!first_can_issue || (!second_can_issue && gap_violated)) {
455 DPRINTF(
MemCtrl,
"Contention (cmd1) found on command bus at %d\n",
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void print(std::ostream &o, int verbosity=0, const std::string &prefix="") const
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
bool cacheResponding() const
bool isTimingMode() const
Is the system in timing mode?
void getBackdoor(MemBackdoorPtr &bd_ptr)
AddrRange getAddrRange() const
Get the address range.
Tick commandOffset() const override
void drainRanks() override
Iterate through dram ranks to exit self-refresh in order to drain.
void startup() override
Iterate through dram ranks and instantiate per rank startup routine.
bool readQueueFullPC1(unsigned int pkt_count) const
uint64_t readQueueSizePC1
virtual void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
AddrRangeList getAddrRanges() override
uint64_t readQueueSizePC0
Following counters are used to keep track of the entries in read/write queue for each pseudo channel ...
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override
bool retryRdReqPC1
Remember if we have to retry a request for second pseudo channel.
void recvFunctional(PacketPtr pkt) override
virtual void drainResume() override
Resume execution after a successful drain.
EventFunctionWrapper respondEventPC1
uint64_t writeQueueSizePC1
bool recvTimingReq(PacketPtr pkt) override
bool writeQueueFullPC1(unsigned int pkt_count) const
bool partitionedQ
This indicates if the R/W queues will be partitioned among pseudo channels.
uint64_t writeQueueSizePC0
void pruneBurstTick() override
Remove commands that have already issued from rowBurstTicks and colBurstTicks.
virtual void startup() override
startup() is the final initialization call before simulation.
std::unordered_multiset< Tick > colBurstTicks
This is used to ensure that the column command bandwidth does not exceed the allowable media constrai...
bool readQueueFullPC0(unsigned int pkt_count) const
Check if the read queue partition of both pseudo channels has room for more entries.
std::unordered_multiset< Tick > rowBurstTicks
Holds count of row commands issued in burst window starting at defined Tick.
Tick recvAtomic(PacketPtr pkt) override
bool readQueueFull(unsigned int pkt_count) const
EventFunctionWrapper nextReqEventPC1
NextReq and Respond events for second pseudo channel.
HBMCtrl(const HBMCtrlParams &p)
Tick verifyMultiCmd(Tick cmd_tick, Tick max_cmds_per_burst, Tick max_multi_cmd_split=0) override
Check for command bus contention for multi-cycle (2 currently) command.
std::deque< MemPacket * > respQueuePC1
Response queue for pkts sent to second pseudo channel The first pseudo channel uses MemCtrl::respQueu...
DRAMInterface * pc0Int
Pointers to interfaces of the two pseudo channels pc0Int is same as MemCtrl::dram (it will be pointin...
Tick verifySingleCmd(Tick cmd_tick, Tick max_cmds_per_burst, bool row_cmd) override
Check for command bus contention for single cycle command.
bool writeQueueFullPC0(unsigned int pkt_count) const
Check if the write queue partition of both pseudo channels has room for more entries.
The memory controller is a single-channel memory controller capturing the most important timing const...
bool recvFunctionalLogic(PacketPtr pkt, MemInterface *mem_intr)
virtual void startup() override
startup() is the final initialization call before simulation.
void addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, MemInterface *mem_intr)
Decode the incoming pkt, create a mem_pkt and push to the back of the write queue.
Tick recvAtomicLogic(PacketPtr pkt, MemInterface *mem_intr)
std::deque< MemPacket * > respQueue
Response queue where read packets wait after we're done working with them, but it's not time to send ...
std::vector< MemPacketQueue > writeQueue
virtual void processNextReqEvent(MemInterface *mem_intr, MemPacketQueue &resp_queue, EventFunctionWrapper &resp_event, EventFunctionWrapper &next_req_event, bool &retry_wr_req)
Bunch of things requires to setup "events" in gem5 When event "respondEvent" occurs for example,...
bool addToReadQueue(PacketPtr pkt, unsigned int pkt_count, MemInterface *mem_intr)
When a new read comes in, first check if the write q has a pending request to the same address....
bool writeQueueFull(unsigned int pkt_count) const
Check if the write queue has room for more entries.
virtual void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
uint32_t readBufferSize
The following are basic design parameters of the memory controller, and are initialized based on para...
EventFunctionWrapper nextReqEvent
std::vector< MemPacketQueue > readQueue
The controller's main read and write queues, with support for QoS reordering.
bool isTimingMode
Remember if the memory system is in timing mode.
Tick getBurstWindow(Tick cmd_tick)
Calculate burst window aligned tick.
virtual void drainResume() override
Resume execution after a successful drain.
const Tick commandWindow
Length of a command window, used to check command bandwidth.
Tick nextBurstAt
Till when the controller must wait before issuing next RD/WR burst?
uint32_t bytesPerBurst() const
uint8_t qosSchedule(std::initializer_list< Queues * > queues_ptr, uint64_t queue_entry_size, const PacketPtr pkt)
Assign priority to a packet by executing the configured QoS policy.
System * system() const
read the system pointer
uint64_t totalReadQueueSize
Total read request packets queue length in #packets.
uint8_t schedule(RequestorID id, uint64_t data)
DRAMInterface declaration.
bool contains(const Addr &a) const
Determine if the range contains an address.
static constexpr T divCeil(const T &a, const U &b)
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
bool scheduled() const
Determine if the current event is scheduled.
#define panic(...)
This implements a cprintf based panic() function.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
MemInterface declaration.
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
uint64_t Tick
Tick count type.
statistics::Scalar writeReqs
statistics::Scalar readReqs
statistics::Scalar numWrRetry
statistics::Scalar totGap
statistics::Scalar numRdRetry
statistics::Scalar bytesReadSys
statistics::Scalar bytesWrittenSys
const std::string & name()