timing.hh revision 10407
1/* 2 * Copyright (c) 2012-2013 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) 2002-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: Steve Reinhardt 41 */ 42 43#ifndef __CPU_SIMPLE_TIMING_HH__ 44#define __CPU_SIMPLE_TIMING_HH__ 45 46#include "cpu/simple/base.hh" 47#include "cpu/translation.hh" 48#include "params/TimingSimpleCPU.hh" 49 50class TimingSimpleCPU : public BaseSimpleCPU 51{ 52 public: 53 54 TimingSimpleCPU(TimingSimpleCPUParams * params); 55 virtual ~TimingSimpleCPU(); 56 57 virtual void init(); 58 59 private: 60 61 /* 62 * If an access needs to be broken into fragments, currently at most two, 63 * the the following two classes are used as the sender state of the 64 * packets so the CPU can keep track of everything. In the main packet 65 * sender state, there's an array with a spot for each fragment. If a 66 * fragment has already been accepted by the CPU, aka isn't waiting for 67 * a retry, it's pointer is NULL. After each fragment has successfully 68 * been processed, the "outstanding" counter is decremented. Once the 69 * count is zero, the entire larger access is complete. 70 */ 71 class SplitMainSenderState : public Packet::SenderState 72 { 73 public: 74 int outstanding; 75 PacketPtr fragments[2]; 76 77 int 78 getPendingFragment() 79 { 80 if (fragments[0]) { 81 return 0; 82 } else if (fragments[1]) { 83 return 1; 84 } else { 85 return -1; 86 } 87 } 88 }; 89 90 class SplitFragmentSenderState : public Packet::SenderState 91 { 92 public: 93 SplitFragmentSenderState(PacketPtr _bigPkt, int _index) : 94 bigPkt(_bigPkt), index(_index) 95 {} 96 PacketPtr bigPkt; 97 int index; 98 99 void 100 clearFromParent() 101 { 102 SplitMainSenderState * main_send_state = 103 dynamic_cast<SplitMainSenderState *>(bigPkt->senderState); 104 main_send_state->fragments[index] = NULL; 105 } 106 }; 107 108 class FetchTranslation : public BaseTLB::Translation 109 { 110 protected: 111 TimingSimpleCPU *cpu; 112 113 public: 114 FetchTranslation(TimingSimpleCPU *_cpu) 115 : cpu(_cpu) 116 {} 117 118 void 119 markDelayed() 120 { 121 assert(cpu->_status == BaseSimpleCPU::Running); 122 cpu->_status = ITBWaitResponse; 123 } 124 125 void 126 finish(const Fault &fault, RequestPtr req, ThreadContext *tc, 127 BaseTLB::Mode mode) 128 { 129 cpu->sendFetch(fault, req, tc); 130 } 131 }; 132 FetchTranslation fetchTranslation; 133 134 void sendData(RequestPtr req, uint8_t *data, uint64_t *res, bool read); 135 void sendSplitData(RequestPtr req1, RequestPtr req2, RequestPtr req, 136 uint8_t *data, bool read); 137 138 void translationFault(const Fault &fault); 139 140 void buildPacket(PacketPtr &pkt, RequestPtr req, bool read); 141 void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, 142 RequestPtr req1, RequestPtr req2, RequestPtr req, 143 uint8_t *data, bool read); 144 145 bool handleReadPacket(PacketPtr pkt); 146 // This function always implicitly uses dcache_pkt. 147 bool handleWritePacket(); 148 149 /** 150 * A TimingCPUPort overrides the default behaviour of the 151 * recvTiming and recvRetry and implements events for the 152 * scheduling of handling of incoming packets in the following 153 * cycle. 154 */ 155 class TimingCPUPort : public MasterPort 156 { 157 public: 158 159 TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu) 160 : MasterPort(_name, _cpu), cpu(_cpu), retryEvent(this) 161 { } 162 163 protected: 164 165 /** 166 * Snooping a coherence request, do nothing. 167 */ 168 virtual void recvTimingSnoopReq(PacketPtr pkt) {} 169 170 TimingSimpleCPU* cpu; 171 172 struct TickEvent : public Event 173 { 174 PacketPtr pkt; 175 TimingSimpleCPU *cpu; 176 177 TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {} 178 const char *description() const { return "Timing CPU tick"; } 179 void schedule(PacketPtr _pkt, Tick t); 180 }; 181 182 EventWrapper<MasterPort, &MasterPort::sendRetry> retryEvent; 183 }; 184 185 class IcachePort : public TimingCPUPort 186 { 187 public: 188 189 IcachePort(TimingSimpleCPU *_cpu) 190 : TimingCPUPort(_cpu->name() + ".icache_port", _cpu), 191 tickEvent(_cpu) 192 { } 193 194 protected: 195 196 virtual bool recvTimingResp(PacketPtr pkt); 197 198 virtual void recvRetry(); 199 200 struct ITickEvent : public TickEvent 201 { 202 203 ITickEvent(TimingSimpleCPU *_cpu) 204 : TickEvent(_cpu) {} 205 void process(); 206 const char *description() const { return "Timing CPU icache tick"; } 207 }; 208 209 ITickEvent tickEvent; 210 211 }; 212 213 class DcachePort : public TimingCPUPort 214 { 215 public: 216 217 DcachePort(TimingSimpleCPU *_cpu) 218 : TimingCPUPort(_cpu->name() + ".dcache_port", _cpu), 219 tickEvent(_cpu) 220 { 221 cacheBlockMask = ~(cpu->cacheLineSize() - 1); 222 } 223 224 Addr cacheBlockMask; 225 protected: 226 227 /** Snoop a coherence request, we need to check if this causes 228 * a wakeup event on a cpu that is monitoring an address 229 */ 230 virtual void recvTimingSnoopReq(PacketPtr pkt); 231 232 virtual bool recvTimingResp(PacketPtr pkt); 233 234 virtual void recvRetry(); 235 236 struct DTickEvent : public TickEvent 237 { 238 DTickEvent(TimingSimpleCPU *_cpu) 239 : TickEvent(_cpu) {} 240 void process(); 241 const char *description() const { return "Timing CPU dcache tick"; } 242 }; 243 244 DTickEvent tickEvent; 245 246 }; 247 248 IcachePort icachePort; 249 DcachePort dcachePort; 250 251 PacketPtr ifetch_pkt; 252 PacketPtr dcache_pkt; 253 254 Tick previousCycle; 255 256 protected: 257 258 /** Return a reference to the data port. */ 259 virtual MasterPort &getDataPort() { return dcachePort; } 260 261 /** Return a reference to the instruction port. */ 262 virtual MasterPort &getInstPort() { return icachePort; } 263 264 public: 265 266 unsigned int drain(DrainManager *drain_manager); 267 void drainResume(); 268 269 void switchOut(); 270 void takeOverFrom(BaseCPU *oldCPU); 271 272 void verifyMemoryMode() const; 273 274 virtual void activateContext(ThreadID thread_num); 275 virtual void suspendContext(ThreadID thread_num); 276 277 Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); 278 279 Fault writeMem(uint8_t *data, unsigned size, 280 Addr addr, unsigned flags, uint64_t *res); 281 282 void fetch(); 283 void sendFetch(const Fault &fault, RequestPtr req, ThreadContext *tc); 284 void completeIfetch(PacketPtr ); 285 void completeDataAccess(PacketPtr pkt); 286 void advanceInst(const Fault &fault); 287 288 /** This function is used by the page table walker to determine if it could 289 * translate the a pending request or if the underlying request has been 290 * squashed. This always returns false for the simple timing CPU as it never 291 * executes any instructions speculatively. 292 * @ return Is the current instruction squashed? 293 */ 294 bool isSquashed() const { return false; } 295 296 /** 297 * Print state of address in memory system via PrintReq (for 298 * debugging). 299 */ 300 void printAddr(Addr a); 301 302 /** 303 * Finish a DTB translation. 304 * @param state The DTB translation state. 305 */ 306 void finishTranslation(WholeTranslationState *state); 307 308 private: 309 310 typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; 311 FetchEvent fetchEvent; 312 313 struct IprEvent : Event { 314 Packet *pkt; 315 TimingSimpleCPU *cpu; 316 IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t); 317 virtual void process(); 318 virtual const char *description() const; 319 }; 320 321 /** 322 * Check if a system is in a drained state. 323 * 324 * We need to drain if: 325 * <ul> 326 * <li>We are in the middle of a microcode sequence as some CPUs 327 * (e.g., HW accelerated CPUs) can't be started in the middle 328 * of a gem5 microcode sequence. 329 * 330 * <li>Stay at PC is true. 331 * 332 * <li>A fetch event is scheduled. Normally this would never be the 333 * case with microPC() == 0, but right after a context is 334 * activated it can happen. 335 * </ul> 336 */ 337 bool isDrained() { 338 return microPC() == 0 && !stayAtPC && !fetchEvent.scheduled(); 339 } 340 341 /** 342 * Try to complete a drain request. 343 * 344 * @returns true if the CPU is drained, false otherwise. 345 */ 346 bool tryCompleteDrain(); 347 348 /** 349 * Drain manager to use when signaling drain completion 350 * 351 * This pointer is non-NULL when draining and NULL otherwise. 352 */ 353 DrainManager *drainManager; 354}; 355 356#endif // __CPU_SIMPLE_TIMING_HH__ 357