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