simple_mem.cc revision 9228:bbdca4088834
1/* 2 * Copyright (c) 2010-2012 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2001-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ron Dreslinski 41 * Ali Saidi 42 * Andreas Hansson 43 */ 44 45#include "base/random.hh" 46#include "mem/simple_mem.hh" 47 48using namespace std; 49 50SimpleMemory::SimpleMemory(const SimpleMemoryParams* p) : 51 AbstractMemory(p), 52 port(name() + ".port", *this), lat(p->latency), 53 lat_var(p->latency_var), bandwidth(p->bandwidth), 54 isBusy(false), retryReq(false), releaseEvent(this) 55{ 56} 57 58void 59SimpleMemory::init() 60{ 61 // allow unconnected memories as this is used in several ruby 62 // systems at the moment 63 if (port.isConnected()) { 64 port.sendRangeChange(); 65 } 66} 67 68Tick 69SimpleMemory::calculateLatency(PacketPtr pkt) 70{ 71 if (pkt->memInhibitAsserted()) { 72 return 0; 73 } else { 74 Tick latency = lat; 75 if (lat_var != 0) 76 latency += random_mt.random<Tick>(0, lat_var); 77 return latency; 78 } 79} 80 81Tick 82SimpleMemory::doAtomicAccess(PacketPtr pkt) 83{ 84 access(pkt); 85 return calculateLatency(pkt); 86} 87 88void 89SimpleMemory::doFunctionalAccess(PacketPtr pkt) 90{ 91 functionalAccess(pkt); 92} 93 94bool 95SimpleMemory::recvTimingReq(PacketPtr pkt) 96{ 97 if (pkt->memInhibitAsserted()) { 98 // snooper will supply based on copy of packet 99 // still target's responsibility to delete packet 100 delete pkt; 101 return true; 102 } 103 104 // we should never get a new request after committing to retry the 105 // current one, the bus violates the rule as it simply sends a 106 // retry to the next one waiting on the retry list, so simply 107 // ignore it 108 if (retryReq) 109 return false; 110 111 // if we are busy with a read or write, remember that we have to 112 // retry 113 if (isBusy) { 114 retryReq = true; 115 return false; 116 } 117 118 // update the release time according to the bandwidth limit, and 119 // do so with respect to the time it takes to finish this request 120 // rather than long term as it is the short term data rate that is 121 // limited for any real memory 122 123 // only look at reads and writes when determining if we are busy, 124 // and for how long, as it is not clear what to regulate for the 125 // other types of commands 126 if (pkt->isRead() || pkt->isWrite()) { 127 // calculate an appropriate tick to release to not exceed 128 // the bandwidth limit 129 Tick duration = pkt->getSize() * bandwidth; 130 131 // only consider ourselves busy if there is any need to wait 132 // to avoid extra events being scheduled for (infinitely) fast 133 // memories 134 if (duration != 0) { 135 schedule(releaseEvent, curTick() + duration); 136 isBusy = true; 137 } 138 } 139 140 // go ahead and deal with the packet and put the response in the 141 // queue if there is one 142 bool needsResponse = pkt->needsResponse(); 143 Tick latency = doAtomicAccess(pkt); 144 // turn packet around to go back to requester if response expected 145 if (needsResponse) { 146 // doAtomicAccess() should already have turned packet into 147 // atomic response 148 assert(pkt->isResponse()); 149 port.schedTimingResp(pkt, curTick() + latency); 150 } else { 151 delete pkt; 152 } 153 154 return true; 155} 156 157void 158SimpleMemory::release() 159{ 160 assert(isBusy); 161 isBusy = false; 162 if (retryReq) { 163 retryReq = false; 164 port.sendRetry(); 165 } 166} 167 168SlavePort & 169SimpleMemory::getSlavePort(const std::string &if_name, int idx) 170{ 171 if (if_name != "port") { 172 return MemObject::getSlavePort(if_name, idx); 173 } else { 174 return port; 175 } 176} 177 178unsigned int 179SimpleMemory::drain(Event *de) 180{ 181 int count = port.drain(de); 182 183 if (count) 184 changeState(Draining); 185 else 186 changeState(Drained); 187 return count; 188} 189 190SimpleMemory::MemoryPort::MemoryPort(const std::string& _name, 191 SimpleMemory& _memory) 192 : QueuedSlavePort(_name, &_memory, queueImpl), 193 queueImpl(_memory, *this), memory(_memory) 194{ } 195 196AddrRangeList 197SimpleMemory::MemoryPort::getAddrRanges() const 198{ 199 AddrRangeList ranges; 200 ranges.push_back(memory.getAddrRange()); 201 return ranges; 202} 203 204Tick 205SimpleMemory::MemoryPort::recvAtomic(PacketPtr pkt) 206{ 207 return memory.doAtomicAccess(pkt); 208} 209 210void 211SimpleMemory::MemoryPort::recvFunctional(PacketPtr pkt) 212{ 213 pkt->pushLabel(memory.name()); 214 215 if (!queue.checkFunctional(pkt)) { 216 // Default implementation of SimpleTimingPort::recvFunctional() 217 // calls recvAtomic() and throws away the latency; we can save a 218 // little here by just not calculating the latency. 219 memory.doFunctionalAccess(pkt); 220 } 221 222 pkt->popLabel(); 223} 224 225bool 226SimpleMemory::MemoryPort::recvTimingReq(PacketPtr pkt) 227{ 228 return memory.recvTimingReq(pkt); 229} 230 231SimpleMemory* 232SimpleMemoryParams::create() 233{ 234 return new SimpleMemory(this); 235} 236