Merge ktlim@zizzer:/bk/m5
[gem5.git] / src / cpu / base_dyn_inst.cc
1 /*
2 * Copyright (c) 2004-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 #include <iostream>
30 #include <set>
31 #include <string>
32 #include <sstream>
33
34 #include "base/cprintf.hh"
35 #include "base/trace.hh"
36
37 #include "arch/faults.hh"
38 #include "cpu/exetrace.hh"
39 #include "mem/mem_req.hh"
40
41 #include "cpu/base_dyn_inst.hh"
42 #include "cpu/o3/alpha_impl.hh"
43 #include "cpu/o3/alpha_cpu.hh"
44 #include "cpu/ozone/simple_impl.hh"
45 #include "cpu/ozone/ozone_impl.hh"
46
47 using namespace std;
48 using namespace TheISA;
49
50 #define NOHASH
51 #ifndef NOHASH
52
53 #include "base/hashmap.hh"
54
55 unsigned int MyHashFunc(const BaseDynInst *addr)
56 {
57 unsigned a = (unsigned)addr;
58 unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
59
60 return hash;
61 }
62
63 typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc>
64 my_hash_t;
65
66 my_hash_t thishash;
67 #endif
68
69 template <class Impl>
70 BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC,
71 Addr pred_PC, InstSeqNum seq_num,
72 FullCPU *cpu)
73 : staticInst(machInst), traceData(NULL), cpu(cpu)/*, xc(cpu->xcBase())*/
74 {
75 seqNum = seq_num;
76
77 PC = inst_PC;
78 nextPC = PC + sizeof(MachInst);
79 predPC = pred_PC;
80
81 initVars();
82 }
83
84 template <class Impl>
85 BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst)
86 : staticInst(_staticInst), traceData(NULL)
87 {
88 seqNum = 0;
89 initVars();
90 }
91
92 template <class Impl>
93 void
94 BaseDynInst<Impl>::initVars()
95 {
96 req = NULL;
97 effAddr = MemReq::inval_addr;
98 physEffAddr = MemReq::inval_addr;
99 storeSize = 0;
100
101 readyRegs = 0;
102
103 completed = false;
104 resultReady = false;
105 canIssue = false;
106 issued = false;
107 executed = false;
108 canCommit = false;
109 committed = false;
110 squashed = false;
111 squashedInIQ = false;
112 squashedInLSQ = false;
113 squashedInROB = false;
114 eaCalcDone = false;
115 memOpDone = false;
116 lqIdx = -1;
117 sqIdx = -1;
118 reachedCommit = false;
119
120 blockingInst = false;
121 recoverInst = false;
122
123 iqEntry = false;
124 robEntry = false;
125
126 serializeBefore = false;
127 serializeAfter = false;
128 serializeHandled = false;
129
130 // Eventually make this a parameter.
131 threadNumber = 0;
132
133 // Also make this a parameter, or perhaps get it from xc or cpu.
134 asid = 0;
135
136 // Initialize the fault to be unimplemented opcode.
137 // fault = new UnimplementedOpcodeFault;
138 fault = NoFault;
139
140 ++instcount;
141
142 if (instcount > 1500) {
143 cpu->dumpInsts();
144 #ifdef DEBUG
145 dumpSNList();
146 #endif
147 assert(instcount <= 1500);
148 }
149
150 DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n",
151 seqNum, instcount);
152
153 #ifdef DEBUG
154 cpu->snList.insert(seqNum);
155 #endif
156 }
157
158 template <class Impl>
159 BaseDynInst<Impl>::~BaseDynInst()
160 {
161 if (req) {
162 req = NULL;
163 }
164
165 if (traceData) {
166 delete traceData;
167 }
168
169 --instcount;
170
171 DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n",
172 seqNum, instcount);
173 #ifdef DEBUG
174 cpu->snList.erase(seqNum);
175 #endif
176 }
177
178 #ifdef DEBUG
179 template <class Impl>
180 void
181 BaseDynInst<Impl>::dumpSNList()
182 {
183 std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin();
184
185 int count = 0;
186 while (sn_it != cpu->snList.end()) {
187 cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it));
188 count++;
189 sn_it++;
190 }
191 }
192 #endif
193
194 template <class Impl>
195 void
196 BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags)
197 {
198 // This is the "functional" implementation of prefetch. Not much
199 // happens here since prefetches don't affect the architectural
200 // state.
201
202 // Generate a MemReq so we can translate the effective address.
203 MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags);
204 req->asid = asid;
205
206 // Prefetches never cause faults.
207 fault = NoFault;
208
209 // note this is a local, not BaseDynInst::fault
210 Fault trans_fault = cpu->translateDataReadReq(req);
211
212 if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
213 // It's a valid address to cacheable space. Record key MemReq
214 // parameters so we can generate another one just like it for
215 // the timing access without calling translate() again (which
216 // might mess up the TLB).
217 effAddr = req->vaddr;
218 physEffAddr = req->paddr;
219 memReqFlags = req->flags;
220 } else {
221 // Bogus address (invalid or uncacheable space). Mark it by
222 // setting the eff_addr to InvalidAddr.
223 effAddr = physEffAddr = MemReq::inval_addr;
224 }
225
226 if (traceData) {
227 traceData->setAddr(addr);
228 }
229 }
230
231 template <class Impl>
232 void
233 BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags)
234 {
235 // Need to create a MemReq here so we can do a translation. This
236 // will casue a TLB miss trap if necessary... not sure whether
237 // that's the best thing to do or not. We don't really need the
238 // MemReq otherwise, since wh64 has no functional effect.
239 MemReqPtr req = new MemReq(addr, thread->getXCProxy(), size, flags);
240 req->asid = asid;
241
242 fault = cpu->translateDataWriteReq(req);
243
244 if (fault == NoFault && !(req->flags & UNCACHEABLE)) {
245 // Record key MemReq parameters so we can generate another one
246 // just like it for the timing access without calling translate()
247 // again (which might mess up the TLB).
248 effAddr = req->vaddr;
249 physEffAddr = req->paddr;
250 memReqFlags = req->flags;
251 } else {
252 // ignore faults & accesses to uncacheable space... treat as no-op
253 effAddr = physEffAddr = MemReq::inval_addr;
254 }
255
256 storeSize = size;
257 storeData = 0;
258 }
259
260 /**
261 * @todo Need to find a way to get the cache block size here.
262 */
263 template <class Impl>
264 Fault
265 BaseDynInst<Impl>::copySrcTranslate(Addr src)
266 {
267 MemReqPtr req = new MemReq(src, thread->getXCProxy(), 64);
268 req->asid = asid;
269
270 // translate to physical address
271 Fault fault = cpu->translateDataReadReq(req);
272
273 if (fault == NoFault) {
274 thread->copySrcAddr = src;
275 thread->copySrcPhysAddr = req->paddr;
276 } else {
277 thread->copySrcAddr = 0;
278 thread->copySrcPhysAddr = 0;
279 }
280 return fault;
281 }
282
283 /**
284 * @todo Need to find a way to get the cache block size here.
285 */
286 template <class Impl>
287 Fault
288 BaseDynInst<Impl>::copy(Addr dest)
289 {
290 uint8_t data[64];
291 FunctionalMemory *mem = thread->mem;
292 assert(thread->copySrcPhysAddr || thread->misspeculating());
293 MemReqPtr req = new MemReq(dest, thread->getXCProxy(), 64);
294 req->asid = asid;
295
296 // translate to physical address
297 Fault fault = cpu->translateDataWriteReq(req);
298
299 if (fault == NoFault) {
300 Addr dest_addr = req->paddr;
301 // Need to read straight from memory since we have more than 8 bytes.
302 req->paddr = thread->copySrcPhysAddr;
303 mem->read(req, data);
304 req->paddr = dest_addr;
305 mem->write(req, data);
306 }
307 return fault;
308 }
309
310 template <class Impl>
311 void
312 BaseDynInst<Impl>::dump()
313 {
314 cprintf("T%d : %#08d `", threadNumber, PC);
315 cout << staticInst->disassemble(PC);
316 cprintf("'\n");
317 }
318
319 template <class Impl>
320 void
321 BaseDynInst<Impl>::dump(std::string &outstring)
322 {
323 std::ostringstream s;
324 s << "T" << threadNumber << " : 0x" << PC << " "
325 << staticInst->disassemble(PC);
326
327 outstring = s.str();
328 }
329
330 #if 0
331 template <class Impl>
332 Fault
333 BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes)
334 {
335 Fault fault;
336
337 // check alignments, even speculative this test should always pass
338 if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) {
339 for (int i = 0; i < nbytes; i++)
340 ((char *) p)[i] = 0;
341
342 // I added the following because according to the comment above,
343 // we should never get here. The comment lies
344 #if 0
345 panic("unaligned access. Cycle = %n", curTick);
346 #endif
347 return NoFault;
348 }
349
350 MemReqPtr req = new MemReq(addr, thread, nbytes);
351 switch(cmd) {
352 case Read:
353 fault = spec_mem->read(req, (uint8_t *)p);
354 break;
355
356 case Write:
357 fault = spec_mem->write(req, (uint8_t *)p);
358 if (fault != NoFault)
359 break;
360
361 specMemWrite = true;
362 storeSize = nbytes;
363 switch(nbytes) {
364 case sizeof(uint8_t):
365 *(uint8_t)&storeData = (uint8_t *)p;
366 break;
367 case sizeof(uint16_t):
368 *(uint16_t)&storeData = (uint16_t *)p;
369 break;
370 case sizeof(uint32_t):
371 *(uint32_t)&storeData = (uint32_t *)p;
372 break;
373 case sizeof(uint64_t):
374 *(uint64_t)&storeData = (uint64_t *)p;
375 break;
376 }
377 break;
378
379 default:
380 fault = genMachineCheckFault();
381 break;
382 }
383
384 trace_mem(fault, cmd, addr, p, nbytes);
385
386 return fault;
387 }
388
389 #endif
390
391 template <class Impl>
392 void
393 BaseDynInst<Impl>::markSrcRegReady()
394 {
395 if (++readyRegs == numSrcRegs()) {
396 canIssue = true;
397 }
398 }
399
400 template <class Impl>
401 void
402 BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx)
403 {
404 ++readyRegs;
405
406 _readySrcRegIdx[src_idx] = true;
407
408 if (readyRegs == numSrcRegs()) {
409 canIssue = true;
410 }
411 }
412
413 template <class Impl>
414 bool
415 BaseDynInst<Impl>::eaSrcsReady()
416 {
417 // For now I am assuming that src registers 1..n-1 are the ones that the
418 // EA calc depends on. (i.e. src reg 0 is the source of the data to be
419 // stored)
420
421 for (int i = 1; i < numSrcRegs(); ++i) {
422 if (!_readySrcRegIdx[i])
423 return false;
424 }
425
426 return true;
427 }
428
429 // Forward declaration
430 template class BaseDynInst<AlphaSimpleImpl>;
431
432 template <>
433 int
434 BaseDynInst<AlphaSimpleImpl>::instcount = 0;
435
436 // Forward declaration
437 template class BaseDynInst<SimpleImpl>;
438
439 template <>
440 int
441 BaseDynInst<SimpleImpl>::instcount = 0;
442
443 // Forward declaration
444 template class BaseDynInst<OzoneImpl>;
445
446 template <>
447 int
448 BaseDynInst<OzoneImpl>::instcount = 0;