timing.hh revision 9442:36967173340c
1/* 2 * Copyright (c) 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) 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(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(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 CpuPort 156 { 157 public: 158 159 TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu) 160 : CpuPort(_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 222 protected: 223 224 virtual bool recvTimingResp(PacketPtr pkt); 225 226 virtual void recvRetry(); 227 228 struct DTickEvent : public TickEvent 229 { 230 DTickEvent(TimingSimpleCPU *_cpu) 231 : TickEvent(_cpu) {} 232 void process(); 233 const char *description() const { return "Timing CPU dcache tick"; } 234 }; 235 236 DTickEvent tickEvent; 237 238 }; 239 240 IcachePort icachePort; 241 DcachePort dcachePort; 242 243 PacketPtr ifetch_pkt; 244 PacketPtr dcache_pkt; 245 246 Tick previousCycle; 247 248 protected: 249 250 /** Return a reference to the data port. */ 251 virtual CpuPort &getDataPort() { return dcachePort; } 252 253 /** Return a reference to the instruction port. */ 254 virtual CpuPort &getInstPort() { return icachePort; } 255 256 public: 257 258 unsigned int drain(DrainManager *drain_manager); 259 void drainResume(); 260 261 void switchOut(); 262 void takeOverFrom(BaseCPU *oldCPU); 263 264 virtual void activateContext(ThreadID thread_num, Cycles delay); 265 virtual void suspendContext(ThreadID thread_num); 266 267 Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); 268 269 Fault writeMem(uint8_t *data, unsigned size, 270 Addr addr, unsigned flags, uint64_t *res); 271 272 void fetch(); 273 void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); 274 void completeIfetch(PacketPtr ); 275 void completeDataAccess(PacketPtr pkt); 276 void advanceInst(Fault fault); 277 278 /** This function is used by the page table walker to determine if it could 279 * translate the a pending request or if the underlying request has been 280 * squashed. This always returns false for the simple timing CPU as it never 281 * executes any instructions speculatively. 282 * @ return Is the current instruction squashed? 283 */ 284 bool isSquashed() const { return false; } 285 286 /** 287 * Print state of address in memory system via PrintReq (for 288 * debugging). 289 */ 290 void printAddr(Addr a); 291 292 /** 293 * Finish a DTB translation. 294 * @param state The DTB translation state. 295 */ 296 void finishTranslation(WholeTranslationState *state); 297 298 private: 299 300 typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; 301 FetchEvent fetchEvent; 302 303 struct IprEvent : Event { 304 Packet *pkt; 305 TimingSimpleCPU *cpu; 306 IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t); 307 virtual void process(); 308 virtual const char *description() const; 309 }; 310 311 /** 312 * Check if a system is in a drained state. 313 * 314 * We need to drain if: 315 * <ul> 316 * <li>We are in the middle of a microcode sequence as some CPUs 317 * (e.g., HW accelerated CPUs) can't be started in the middle 318 * of a gem5 microcode sequence. 319 * 320 * <li>Stay at PC is true. 321 * </ul> 322 */ 323 bool isDrained() { 324 return microPC() == 0 && 325 !stayAtPC; 326 } 327 328 /** 329 * Try to complete a drain request. 330 * 331 * @returns true if the CPU is drained, false otherwise. 332 */ 333 bool tryCompleteDrain(); 334 335 /** 336 * Drain manager to use when signaling drain completion 337 * 338 * This pointer is non-NULL when draining and NULL otherwise. 339 */ 340 DrainManager *drainManager; 341}; 342 343#endif // __CPU_SIMPLE_TIMING_HH__ 344