timing.hh revision 9523
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 void verifyMemoryMode() const; 265 266 virtual void activateContext(ThreadID thread_num, Cycles delay); 267 virtual void suspendContext(ThreadID thread_num); 268 269 Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags); 270 271 Fault writeMem(uint8_t *data, unsigned size, 272 Addr addr, unsigned flags, uint64_t *res); 273 274 void fetch(); 275 void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc); 276 void completeIfetch(PacketPtr ); 277 void completeDataAccess(PacketPtr pkt); 278 void advanceInst(Fault fault); 279 280 /** This function is used by the page table walker to determine if it could 281 * translate the a pending request or if the underlying request has been 282 * squashed. This always returns false for the simple timing CPU as it never 283 * executes any instructions speculatively. 284 * @ return Is the current instruction squashed? 285 */ 286 bool isSquashed() const { return false; } 287 288 /** 289 * Print state of address in memory system via PrintReq (for 290 * debugging). 291 */ 292 void printAddr(Addr a); 293 294 /** 295 * Finish a DTB translation. 296 * @param state The DTB translation state. 297 */ 298 void finishTranslation(WholeTranslationState *state); 299 300 private: 301 302 typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent; 303 FetchEvent fetchEvent; 304 305 struct IprEvent : Event { 306 Packet *pkt; 307 TimingSimpleCPU *cpu; 308 IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t); 309 virtual void process(); 310 virtual const char *description() const; 311 }; 312 313 /** 314 * Check if a system is in a drained state. 315 * 316 * We need to drain if: 317 * <ul> 318 * <li>We are in the middle of a microcode sequence as some CPUs 319 * (e.g., HW accelerated CPUs) can't be started in the middle 320 * of a gem5 microcode sequence. 321 * 322 * <li>Stay at PC is true. 323 * </ul> 324 */ 325 bool isDrained() { 326 return microPC() == 0 && 327 !stayAtPC; 328 } 329 330 /** 331 * Try to complete a drain request. 332 * 333 * @returns true if the CPU is drained, false otherwise. 334 */ 335 bool tryCompleteDrain(); 336 337 /** 338 * Drain manager to use when signaling drain completion 339 * 340 * This pointer is non-NULL when draining and NULL otherwise. 341 */ 342 DrainManager *drainManager; 343}; 344 345#endif // __CPU_SIMPLE_TIMING_HH__ 346