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