Merge ktlim@zizzer:/bk/m5
[gem5.git] / src / cpu / ozone / cpu.hh
1 /*
2 * Copyright (c) 2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef __CPU_OZONE_CPU_HH__
30 #define __CPU_OZONE_CPU_HH__
31
32 #include <set>
33
34 #include "base/statistics.hh"
35 #include "base/timebuf.hh"
36 #include "config/full_system.hh"
37 #include "cpu/base.hh"
38 #include "cpu/exec_context.hh"
39 #include "cpu/inst_seq.hh"
40 #include "cpu/ozone/rename_table.hh"
41 #include "cpu/ozone/thread_state.hh"
42 #include "cpu/pc_event.hh"
43 #include "cpu/static_inst.hh"
44 #include "mem/mem_interface.hh"
45 #include "sim/eventq.hh"
46
47 // forward declarations
48 #if FULL_SYSTEM
49 #include "arch/alpha/tlb.hh"
50
51 class AlphaITB;
52 class AlphaDTB;
53 class PhysicalMemory;
54 class MemoryController;
55
56 class Sampler;
57 class RemoteGDB;
58 class GDBListener;
59
60 namespace Kernel {
61 class Statistics;
62 };
63
64 #else
65
66 class Process;
67
68 #endif // FULL_SYSTEM
69
70 class Checkpoint;
71 class EndQuiesceEvent;
72 class MemInterface;
73
74 namespace Trace {
75 class InstRecord;
76 }
77
78 template <class>
79 class Checker;
80
81 /**
82 * Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with
83 * simple out-of-order capabilities added to it. It is still a 1 CPI machine
84 * (?), but is capable of handling cache misses. Basically it models having
85 * a ROB/IQ by only allowing a certain amount of instructions to execute while
86 * the cache miss is outstanding.
87 */
88
89 template <class Impl>
90 class OzoneCPU : public BaseCPU
91 {
92 private:
93 typedef typename Impl::FrontEnd FrontEnd;
94 typedef typename Impl::BackEnd BackEnd;
95 typedef typename Impl::DynInst DynInst;
96 typedef typename Impl::DynInstPtr DynInstPtr;
97
98 typedef TheISA::MiscReg MiscReg;
99
100 public:
101 class OzoneXC : public ExecContext {
102 public:
103 OzoneCPU<Impl> *cpu;
104
105 OzoneThreadState<Impl> *thread;
106
107 BaseCPU *getCpuPtr();
108
109 void setCpuId(int id);
110
111 int readCpuId() { return thread->cpuId; }
112
113 FunctionalMemory *getMemPtr() { return thread->mem; }
114
115 #if FULL_SYSTEM
116 System *getSystemPtr() { return cpu->system; }
117
118 PhysicalMemory *getPhysMemPtr() { return cpu->physmem; }
119
120 AlphaITB *getITBPtr() { return cpu->itb; }
121
122 AlphaDTB * getDTBPtr() { return cpu->dtb; }
123
124 Kernel::Statistics *getKernelStats() { return thread->kernelStats; }
125 #else
126 Process *getProcessPtr() { return thread->process; }
127 #endif
128
129 Status status() const { return thread->_status; }
130
131 void setStatus(Status new_status);
132
133 /// Set the status to Active. Optional delay indicates number of
134 /// cycles to wait before beginning execution.
135 void activate(int delay = 1);
136
137 /// Set the status to Suspended.
138 void suspend();
139
140 /// Set the status to Unallocated.
141 void deallocate();
142
143 /// Set the status to Halted.
144 void halt();
145
146 #if FULL_SYSTEM
147 void dumpFuncProfile();
148 #endif
149
150 void takeOverFrom(ExecContext *old_context);
151
152 void regStats(const std::string &name);
153
154 void serialize(std::ostream &os);
155 void unserialize(Checkpoint *cp, const std::string &section);
156
157 #if FULL_SYSTEM
158 EndQuiesceEvent *getQuiesceEvent();
159
160 Tick readLastActivate();
161 Tick readLastSuspend();
162
163 void profileClear();
164 void profileSample();
165 #endif
166
167 int getThreadNum();
168
169 // Also somewhat obnoxious. Really only used for the TLB fault.
170 TheISA::MachInst getInst();
171
172 void copyArchRegs(ExecContext *xc);
173
174 void clearArchRegs();
175
176 uint64_t readIntReg(int reg_idx);
177
178 float readFloatRegSingle(int reg_idx);
179
180 double readFloatRegDouble(int reg_idx);
181
182 uint64_t readFloatRegInt(int reg_idx);
183
184 void setIntReg(int reg_idx, uint64_t val);
185
186 void setFloatRegSingle(int reg_idx, float val);
187
188 void setFloatRegDouble(int reg_idx, double val);
189
190 void setFloatRegInt(int reg_idx, uint64_t val);
191
192 uint64_t readPC() { return thread->PC; }
193 void setPC(Addr val);
194
195 uint64_t readNextPC() { return thread->nextPC; }
196 void setNextPC(Addr val);
197
198 public:
199 // ISA stuff:
200 MiscReg readMiscReg(int misc_reg);
201
202 MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault);
203
204 Fault setMiscReg(int misc_reg, const MiscReg &val);
205
206 Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val);
207
208 unsigned readStCondFailures()
209 { return thread->storeCondFailures; }
210
211 void setStCondFailures(unsigned sc_failures)
212 { thread->storeCondFailures = sc_failures; }
213
214 #if FULL_SYSTEM
215 bool inPalMode() { return cpu->inPalMode(); }
216 #endif
217
218 bool misspeculating() { return false; }
219
220 #if !FULL_SYSTEM
221 TheISA::IntReg getSyscallArg(int i)
222 { return thread->renameTable[TheISA::ArgumentReg0 + i]->readIntResult(); }
223
224 // used to shift args for indirect syscall
225 void setSyscallArg(int i, TheISA::IntReg val)
226 { thread->renameTable[TheISA::ArgumentReg0 + i]->setIntResult(i); }
227
228 void setSyscallReturn(SyscallReturn return_value)
229 { cpu->setSyscallReturn(return_value, thread->tid); }
230
231 Counter readFuncExeInst() { return thread->funcExeInst; }
232
233 void setFuncExeInst(Counter new_val)
234 { thread->funcExeInst = new_val; }
235 #endif
236 };
237
238 // execution context proxy
239 OzoneXC ozoneXC;
240 ExecContext *xcProxy;
241 ExecContext *checkerXC;
242
243 typedef OzoneThreadState<Impl> ImplState;
244
245 private:
246 OzoneThreadState<Impl> thread;
247
248 public:
249 // main simulation loop (one cycle)
250 void tick();
251
252 std::set<InstSeqNum> snList;
253 std::set<Addr> lockAddrList;
254 private:
255 struct TickEvent : public Event
256 {
257 OzoneCPU *cpu;
258 int width;
259
260 TickEvent(OzoneCPU *c, int w);
261 void process();
262 const char *description();
263 };
264
265 TickEvent tickEvent;
266
267 /// Schedule tick event, regardless of its current state.
268 void scheduleTickEvent(int delay)
269 {
270 if (tickEvent.squashed())
271 tickEvent.reschedule(curTick + cycles(delay));
272 else if (!tickEvent.scheduled())
273 tickEvent.schedule(curTick + cycles(delay));
274 }
275
276 /// Unschedule tick event, regardless of its current state.
277 void unscheduleTickEvent()
278 {
279 if (tickEvent.scheduled())
280 tickEvent.squash();
281 }
282
283 private:
284 Trace::InstRecord *traceData;
285
286 template<typename T>
287 void trace_data(T data);
288
289 public:
290 enum Status {
291 Running,
292 Idle,
293 SwitchedOut
294 };
295
296 Status _status;
297
298 public:
299 bool checkInterrupts;
300
301 void post_interrupt(int int_num, int index);
302
303 void zero_fill_64(Addr addr) {
304 static int warned = 0;
305 if (!warned) {
306 warn ("WH64 is not implemented");
307 warned = 1;
308 }
309 };
310
311 typedef typename Impl::Params Params;
312
313 OzoneCPU(Params *params);
314
315 virtual ~OzoneCPU();
316
317 void init();
318
319 public:
320 BaseCPU *getCpuPtr() { return this; }
321
322 void setCpuId(int id) { cpuId = id; }
323
324 int readCpuId() { return cpuId; }
325
326 int cpuId;
327
328 void switchOut(Sampler *sampler);
329 void signalSwitched();
330 void takeOverFrom(BaseCPU *oldCPU);
331
332 Sampler *sampler;
333
334 int switchCount;
335
336 #if FULL_SYSTEM
337 Addr dbg_vtophys(Addr addr);
338
339 bool interval_stats;
340
341 AlphaITB *itb;
342 AlphaDTB *dtb;
343 System *system;
344
345 // the following two fields are redundant, since we can always
346 // look them up through the system pointer, but we'll leave them
347 // here for now for convenience
348 MemoryController *memctrl;
349 PhysicalMemory *physmem;
350 #endif
351
352 // L1 instruction cache
353 MemInterface *icacheInterface;
354
355 // L1 data cache
356 MemInterface *dcacheInterface;
357
358 /** Pointer to memory. */
359 FunctionalMemory *mem;
360
361 FrontEnd *frontEnd;
362
363 BackEnd *backEnd;
364 private:
365 Status status() const { return _status; }
366 void setStatus(Status new_status) { _status = new_status; }
367
368 virtual void activateContext(int thread_num, int delay);
369 virtual void suspendContext(int thread_num);
370 virtual void deallocateContext(int thread_num);
371 virtual void haltContext(int thread_num);
372
373 // statistics
374 virtual void regStats();
375 virtual void resetStats();
376
377 // number of simulated instructions
378 public:
379 Counter numInst;
380 Counter startNumInst;
381
382 virtual Counter totalInstructions() const
383 {
384 return numInst - startNumInst;
385 }
386
387 private:
388 // number of simulated loads
389 Counter numLoad;
390 Counter startNumLoad;
391
392 // number of idle cycles
393 Stats::Average<> notIdleFraction;
394 Stats::Formula idleFraction;
395 public:
396
397 virtual void serialize(std::ostream &os);
398 virtual void unserialize(Checkpoint *cp, const std::string &section);
399
400
401 #if FULL_SYSTEM
402 bool validInstAddr(Addr addr) { return true; }
403 bool validDataAddr(Addr addr) { return true; }
404
405 Fault translateInstReq(MemReqPtr &req)
406 {
407 return itb->translate(req);
408 }
409
410 Fault translateDataReadReq(MemReqPtr &req)
411 {
412 return dtb->translate(req, false);
413 }
414
415 Fault translateDataWriteReq(MemReqPtr &req)
416 {
417 return dtb->translate(req, true);
418 }
419
420 #else
421 bool validInstAddr(Addr addr)
422 { return true; }
423
424 bool validDataAddr(Addr addr)
425 { return true; }
426
427 int getInstAsid() { return thread.asid; }
428 int getDataAsid() { return thread.asid; }
429
430 Fault dummyTranslation(MemReqPtr &req)
431 {
432 #if 0
433 assert((req->vaddr >> 48 & 0xffff) == 0);
434 #endif
435
436 // put the asid in the upper 16 bits of the paddr
437 req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
438 req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
439 return NoFault;
440 }
441
442 /** Translates instruction requestion in syscall emulation mode. */
443 Fault translateInstReq(MemReqPtr &req)
444 {
445 return dummyTranslation(req);
446 }
447
448 /** Translates data read request in syscall emulation mode. */
449 Fault translateDataReadReq(MemReqPtr &req)
450 {
451 return dummyTranslation(req);
452 }
453
454 /** Translates data write request in syscall emulation mode. */
455 Fault translateDataWriteReq(MemReqPtr &req)
456 {
457 return dummyTranslation(req);
458 }
459 #endif
460
461 /** Old CPU read from memory function. No longer used. */
462 template <class T>
463 Fault read(MemReqPtr &req, T &data)
464 {
465 #if 0
466 #if FULL_SYSTEM && defined(TARGET_ALPHA)
467 if (req->flags & LOCKED) {
468 req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
469 req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
470 }
471 #endif
472 #endif
473 Fault error;
474 if (req->flags & LOCKED) {
475 lockAddrList.insert(req->paddr);
476 lockFlag = true;
477 }
478
479 error = this->mem->read(req, data);
480 data = gtoh(data);
481 return error;
482 }
483
484
485 /** CPU read function, forwards read to LSQ. */
486 template <class T>
487 Fault read(MemReqPtr &req, T &data, int load_idx)
488 {
489 return backEnd->read(req, data, load_idx);
490 }
491
492 /** Old CPU write to memory function. No longer used. */
493 template <class T>
494 Fault write(MemReqPtr &req, T &data)
495 {
496 #if 0
497 #if FULL_SYSTEM && defined(TARGET_ALPHA)
498 ExecContext *xc;
499
500 // If this is a store conditional, act appropriately
501 if (req->flags & LOCKED) {
502 xc = req->xc;
503
504 if (req->flags & UNCACHEABLE) {
505 // Don't update result register (see stq_c in isa_desc)
506 req->result = 2;
507 xc->setStCondFailures(0);//Needed? [RGD]
508 } else {
509 bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
510 Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
511 req->result = lock_flag;
512 if (!lock_flag ||
513 ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
514 xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
515 xc->setStCondFailures(xc->readStCondFailures() + 1);
516 if (((xc->readStCondFailures()) % 100000) == 0) {
517 std::cerr << "Warning: "
518 << xc->readStCondFailures()
519 << " consecutive store conditional failures "
520 << "on cpu " << req->xc->readCpuId()
521 << std::endl;
522 }
523 return NoFault;
524 }
525 else xc->setStCondFailures(0);
526 }
527 }
528
529 // Need to clear any locked flags on other proccessors for
530 // this address. Only do this for succsful Store Conditionals
531 // and all other stores (WH64?). Unsuccessful Store
532 // Conditionals would have returned above, and wouldn't fall
533 // through.
534 for (int i = 0; i < this->system->execContexts.size(); i++){
535 xc = this->system->execContexts[i];
536 if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
537 (req->paddr & ~0xf)) {
538 xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
539 }
540 }
541
542 #endif
543 #endif
544
545 if (req->flags & LOCKED) {
546 if (req->flags & UNCACHEABLE) {
547 req->result = 2;
548 } else {
549 if (this->lockFlag) {
550 if (lockAddrList.find(req->paddr) !=
551 lockAddrList.end()) {
552 req->result = 1;
553 } else {
554 req->result = 0;
555 return NoFault;
556 }
557 } else {
558 req->result = 0;
559 return NoFault;
560 }
561 }
562 }
563
564 return this->mem->write(req, (T)htog(data));
565 }
566
567 /** CPU write function, forwards write to LSQ. */
568 template <class T>
569 Fault write(MemReqPtr &req, T &data, int store_idx)
570 {
571 return backEnd->write(req, data, store_idx);
572 }
573
574 void prefetch(Addr addr, unsigned flags)
575 {
576 // need to do this...
577 }
578
579 void writeHint(Addr addr, int size, unsigned flags)
580 {
581 // need to do this...
582 }
583
584 Fault copySrcTranslate(Addr src);
585
586 Fault copy(Addr dest);
587
588 InstSeqNum globalSeqNum;
589
590 public:
591 void squashFromXC();
592
593 // @todo: This can be a useful debug function. Implement it.
594 void dumpInsts() { frontEnd->dumpInsts(); }
595
596 #if FULL_SYSTEM
597 Fault hwrei();
598 int readIntrFlag() { return thread.regs.intrflag; }
599 void setIntrFlag(int val) { thread.regs.intrflag = val; }
600 bool inPalMode() { return AlphaISA::PcPAL(thread.PC); }
601 bool inPalMode(Addr pc) { return AlphaISA::PcPAL(pc); }
602 bool simPalCheck(int palFunc);
603 void processInterrupts();
604 #else
605 void syscall();
606 void setSyscallReturn(SyscallReturn return_value, int tid);
607 #endif
608
609 ExecContext *xcBase() { return xcProxy; }
610
611 bool decoupledFrontEnd;
612 struct CommStruct {
613 InstSeqNum doneSeqNum;
614 InstSeqNum nonSpecSeqNum;
615 bool uncached;
616 unsigned lqIdx;
617
618 bool stall;
619 };
620 TimeBuffer<CommStruct> comm;
621
622 bool lockFlag;
623
624 Stats::Scalar<> quiesceCycles;
625
626 Checker<DynInstPtr> *checker;
627 };
628
629 #endif // __CPU_OZONE_CPU_HH__