| /* | |
| * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood | |
| * Copyright (c) 2012 Advanced Micro Devices, Inc. | |
| * 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. | |
| */ | |
| #ifndef __MEM_RUBY_STRUCTURES_MEMORY_CONTROL_HH__ | |
| #define __MEM_RUBY_STRUCTURES_MEMORY_CONTROL_HH__ | |
| #include <iostream> | |
| #include <list> | |
| #include <string> | |
| #include "mem/abstract_mem.hh" | |
| #include "mem/protocol/MemoryMsg.hh" | |
| #include "mem/ruby/common/Address.hh" | |
| #include "mem/ruby/common/Global.hh" | |
| #include "mem/ruby/profiler/MemCntrlProfiler.hh" | |
| #include "mem/ruby/structures/MemoryNode.hh" | |
| #include "mem/ruby/system/System.hh" | |
| #include "params/RubyMemoryControl.hh" | |
| // This constant is part of the definition of tFAW; see | |
| // the comments in header to RubyMemoryControl.cc | |
| #define ACTIVATE_PER_TFAW 4 | |
| ////////////////////////////////////////////////////////////////////////////// | |
| class RubyMemoryControl : public AbstractMemory, public Consumer | |
| { | |
| public: | |
| typedef RubyMemoryControlParams Params; | |
| RubyMemoryControl(const Params *p); | |
| void init(); | |
| void reset(); | |
| ~RubyMemoryControl(); | |
| virtual BaseSlavePort& getSlavePort(const std::string& if_name, | |
| PortID idx = InvalidPortID); | |
| unsigned int drain(DrainManager *dm); | |
| void wakeup(); | |
| void setDescription(const std::string& name) { m_description = name; }; | |
| std::string getDescription() { return m_description; }; | |
| // Called from the directory: | |
| bool recvTimingReq(PacketPtr pkt); | |
| void recvFunctional(PacketPtr pkt); | |
| void enqueueMemRef(MemoryNode *memRef); | |
| bool areNSlotsAvailable(int n) { return true; }; // infinite queue length | |
| void print(std::ostream& out) const; | |
| void regStats(); | |
| const int getBank(const physical_address_t addr) const; | |
| const int getRank(const physical_address_t addr) const; | |
| // not used in Ruby memory controller | |
| const int getChannel(const physical_address_t addr) const; | |
| const int getRow(const physical_address_t addr) const; | |
| //added by SS | |
| int getBanksPerRank() { return m_banks_per_rank; }; | |
| int getRanksPerDimm() { return m_ranks_per_dimm; }; | |
| int getDimmsPerChannel() { return m_dimms_per_channel; } | |
| bool functionalRead(Packet *pkt); | |
| uint32_t functionalWrite(Packet *pkt); | |
| private: | |
| void enqueueToDirectory(MemoryNode *req, Cycles latency); | |
| const int getRank(int bank) const; | |
| bool queueReady(int bank); | |
| void issueRequest(int bank); | |
| bool issueRefresh(int bank); | |
| void markTfaw(int rank); | |
| void executeCycle(); | |
| // Private copy constructor and assignment operator | |
| RubyMemoryControl (const RubyMemoryControl& obj); | |
| RubyMemoryControl& operator=(const RubyMemoryControl& obj); | |
| private: | |
| // For now, make use of a queued slave port to avoid dealing with | |
| // flow control for the responses being sent back | |
| class MemoryPort : public QueuedSlavePort | |
| { | |
| SlavePacketQueue queue; | |
| RubyMemoryControl& memory; | |
| public: | |
| MemoryPort(const std::string& name, RubyMemoryControl& _memory); | |
| protected: | |
| Tick recvAtomic(PacketPtr pkt); | |
| void recvFunctional(PacketPtr pkt); | |
| bool recvTimingReq(PacketPtr); | |
| virtual AddrRangeList getAddrRanges() const; | |
| }; | |
| /** | |
| * Our incoming port, for a multi-ported controller add a crossbar | |
| * in front of it | |
| */ | |
| MemoryPort port; | |
| // data members | |
| std::string m_description; | |
| int m_msg_counter; | |
| int m_banks_per_rank; | |
| int m_ranks_per_dimm; | |
| int m_dimms_per_channel; | |
| int m_bank_bit_0; | |
| int m_rank_bit_0; | |
| int m_dimm_bit_0; | |
| unsigned int m_bank_queue_size; | |
| int m_bank_busy_time; | |
| int m_rank_rank_delay; | |
| int m_read_write_delay; | |
| int m_basic_bus_busy_time; | |
| Cycles m_mem_ctl_latency; | |
| int m_refresh_period; | |
| int m_mem_random_arbitrate; | |
| int m_tFaw; | |
| Cycles m_mem_fixed_delay; | |
| int m_total_banks; | |
| int m_total_ranks; | |
| int m_refresh_period_system; | |
| // queues where memory requests live | |
| std::list<MemoryNode *> m_response_queue; | |
| std::list<MemoryNode *> m_input_queue; | |
| std::list<MemoryNode *>* m_bankQueues; | |
| // Each entry indicates number of address-bus cycles until bank | |
| // is reschedulable: | |
| int* m_bankBusyCounter; | |
| int* m_oldRequest; | |
| uint64* m_tfaw_shift; | |
| int* m_tfaw_count; | |
| // Each of these indicates number of address-bus cycles until | |
| // we can issue a new request of the corresponding type: | |
| int m_busBusyCounter_Write; | |
| int m_busBusyCounter_ReadNewRank; | |
| int m_busBusyCounter_Basic; | |
| int m_busBusy_WhichRank; // which rank last granted | |
| int m_roundRobin; // which bank queue was last granted | |
| int m_refresh_count; // cycles until next refresh | |
| int m_need_refresh; // set whenever m_refresh_count goes to zero | |
| int m_refresh_bank; // which bank to refresh next | |
| int m_ageCounter; // age of old requests; to detect starvation | |
| int m_idleCount; // watchdog timer for shutting down | |
| MemCntrlProfiler* m_profiler_ptr; | |
| class MemCntrlEvent : public Event | |
| { | |
| public: | |
| MemCntrlEvent(RubyMemoryControl* _mem_cntrl) | |
| { | |
| mem_cntrl = _mem_cntrl; | |
| } | |
| private: | |
| void process() { mem_cntrl->wakeup(); } | |
| RubyMemoryControl* mem_cntrl; | |
| }; | |
| MemCntrlEvent m_event; | |
| }; | |
| std::ostream& operator<<(std::ostream& out, const RubyMemoryControl& obj); | |
| #endif // __MEM_RUBY_STRUCTURES_MEMORY_CONTROL_HH__ |