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