Large update of several parts of my code. The most notable change is the inclusion of a full-fledged load/store queue. At the moment it still has some issues running, but most of the code is hopefully close to the final version.

SConscript:
arch/isa_parser.py:
cpu/base_dyn_inst.cc:
    Remove OOO CPU stuff.
arch/alpha/faults.hh:
    Add fake memory fault.  This will be removed eventually.
arch/alpha/isa_desc:
    Change EA comp and Mem accessor to be const StaticInstPtrs.
cpu/base_dyn_inst.hh:
    Update read/write calls to use load queue and store queue indices.
cpu/beta_cpu/alpha_dyn_inst.hh:
    Change to const StaticInst in the register accessors.
cpu/beta_cpu/alpha_dyn_inst_impl.hh:
    Update syscall code with thread numbers.
cpu/beta_cpu/alpha_full_cpu.hh:
    Alter some of the full system code so it will compile without errors.
cpu/beta_cpu/alpha_full_cpu_builder.cc:
    Created a DerivAlphaFullCPU class so I can instantiate different CPUs that have different template parameters.
cpu/beta_cpu/alpha_full_cpu_impl.hh:
    Update some of the full system code so it compiles.
cpu/beta_cpu/alpha_params.hh:
cpu/beta_cpu/fetch_impl.hh:
    Remove asid.
cpu/beta_cpu/comm.hh:
    Remove global history field.
cpu/beta_cpu/commit.hh:
    Comment out rename map.
cpu/beta_cpu/commit_impl.hh:
    Update some of the full system code so it compiles.  Also change it so that it handles memory instructions properly.
cpu/beta_cpu/cpu_policy.hh:
    Removed IQ from the IEW template parameter to make it more uniform.
cpu/beta_cpu/decode.hh:
    Add debug function.
cpu/beta_cpu/decode_impl.hh:
    Slight updates for decode in the case where it causes a squash.
cpu/beta_cpu/fetch.hh:
cpu/beta_cpu/rob.hh:
    Comment out unneccessary code.
cpu/beta_cpu/full_cpu.cc:
    Changed some of the full system code so it compiles.  Updated exec contexts and so forth to hopefully make multithreading easier.
cpu/beta_cpu/full_cpu.hh:
    Updated some of the full system code to make it compile.
cpu/beta_cpu/iew.cc:
    Removed IQ from template parameter to IEW.
cpu/beta_cpu/iew.hh:
    Removed IQ from template parameter to IEW. Updated IEW to recognize the Load/Store queue.
cpu/beta_cpu/iew_impl.hh:
    New handling of memory instructions through the Load/Store queue.
cpu/beta_cpu/inst_queue.hh:
    Updated comment.
cpu/beta_cpu/inst_queue_impl.hh:
    Slightly different handling of memory instructions due to Load/Store queue.
cpu/beta_cpu/regfile.hh:
    Updated full system code so it compiles.
cpu/beta_cpu/rob_impl.hh:
    Moved some code around; no major functional changes.
cpu/ooo_cpu/ooo_cpu.hh:
    Slight updates to OOO CPU; still does not work.
cpu/static_inst.hh:
    Remove OOO CPU stuff.  Change ea comp and mem acc to return const StaticInst.
kern/kernel_stats.hh:
    Extra forward declares added due to compile error.

--HG--
extra : convert_revision : 594a7cdbe57f6c2bda7d08856fcd864604a6238e
This commit is contained in:
Kevin Lim 2005-05-03 10:56:47 -04:00
parent 6191d3e444
commit 61d95de4c8
34 changed files with 838 additions and 927 deletions

View file

@ -52,7 +52,6 @@ base_sources = Split('''
arch/alpha/full_cpu_exec.cc arch/alpha/full_cpu_exec.cc
arch/alpha/faults.cc arch/alpha/faults.cc
arch/alpha/isa_traits.cc arch/alpha/isa_traits.cc
arch/alpha/ooo_cpu_exec.cc
base/circlebuf.cc base/circlebuf.cc
base/copyright.cc base/copyright.cc
@ -157,10 +156,6 @@ base_sources = Split('''
cpu/full_cpu/iq/seznec/iq_seznec.cc cpu/full_cpu/iq/seznec/iq_seznec.cc
cpu/full_cpu/iq/standard/iq_standard.cc cpu/full_cpu/iq/standard/iq_standard.cc
cpu/inorder_cpu/inorder_cpu.cc cpu/inorder_cpu/inorder_cpu.cc
cpu/ooo_cpu/ea_list.cc
cpu/ooo_cpu/ooo_cpu.cc
cpu/ooo_cpu/ooo_dyn_inst.cc
cpu/ooo_cpu/ooo_sim_obj.cc
cpu/sampling_cpu/sampling_cpu.cc cpu/sampling_cpu/sampling_cpu.cc
cpu/simple_cpu/simple_cpu.cc cpu/simple_cpu/simple_cpu.cc
cpu/trace/reader/mem_trace_reader.cc cpu/trace/reader/mem_trace_reader.cc
@ -402,8 +397,7 @@ env.Command(Split('''arch/alpha/decoder.cc
arch/alpha/fast_cpu_exec.cc arch/alpha/fast_cpu_exec.cc
arch/alpha/simple_cpu_exec.cc arch/alpha/simple_cpu_exec.cc
arch/alpha/inorder_cpu_exec.cc arch/alpha/inorder_cpu_exec.cc
arch/alpha/full_cpu_exec.cc arch/alpha/full_cpu_exec.cc'''),
arch/alpha/ooo_cpu_exec.cc'''),
Split('''arch/alpha/isa_desc Split('''arch/alpha/isa_desc
arch/isa_parser.py'''), arch/isa_parser.py'''),
'$SRCDIR/arch/isa_parser.py $SOURCE $TARGET.dir arch/alpha') '$SRCDIR/arch/isa_parser.py $SOURCE $TARGET.dir arch/alpha')

View file

@ -47,6 +47,7 @@ enum Fault {
Fen_Fault, // FP not-enabled fault Fen_Fault, // FP not-enabled fault
Pal_Fault, // call_pal S/W interrupt Pal_Fault, // call_pal S/W interrupt
Integer_Overflow_Fault, Integer_Overflow_Fault,
Fake_Mem_Fault,
Num_Faults // number of faults Num_Faults // number of faults
}; };

View file

@ -744,9 +744,9 @@ output header {{
/// Memory request flags. See mem_req_base.hh. /// Memory request flags. See mem_req_base.hh.
unsigned memAccessFlags; unsigned memAccessFlags;
/// Pointer to EAComp object. /// Pointer to EAComp object.
StaticInstPtr<AlphaISA> eaCompPtr; const StaticInstPtr<AlphaISA> eaCompPtr;
/// Pointer to MemAcc object. /// Pointer to MemAcc object.
StaticInstPtr<AlphaISA> memAccPtr; const StaticInstPtr<AlphaISA> memAccPtr;
/// Constructor /// Constructor
Memory(const char *mnem, MachInst _machInst, OpClass __opClass, Memory(const char *mnem, MachInst _machInst, OpClass __opClass,
@ -762,8 +762,8 @@ output header {{
public: public:
StaticInstPtr<AlphaISA> &eaCompInst() { return eaCompPtr; } const StaticInstPtr<AlphaISA> &eaCompInst() const { return eaCompPtr; }
StaticInstPtr<AlphaISA> &memAccInst() { return memAccPtr; } const StaticInstPtr<AlphaISA> &memAccInst() const { return memAccPtr; }
}; };
/** /**
@ -2539,9 +2539,9 @@ decode OPCODE default Unknown::unknown() {
xc->syscall(); xc->syscall();
}}, IsNonSpeculative); }}, IsNonSpeculative);
// Read uniq reg into ABI return value register (r0) // Read uniq reg into ABI return value register (r0)
0x9e: rduniq({{ R0 = Runiq; }}, IsNonSpeculative); 0x9e: rduniq({{ R0 = Runiq; }});
// Write uniq reg with value from ABI arg register (r16) // Write uniq reg with value from ABI arg register (r16)
0x9f: wruniq({{ Runiq = R16; }}, IsNonSpeculative); 0x9f: wruniq({{ Runiq = R16; }});
} }
} }
#endif #endif

View file

@ -642,9 +642,6 @@ CpuModel('FullCPU', 'full_cpu_exec.cc',
CpuModel('AlphaFullCPU', 'alpha_full_cpu_exec.cc', CpuModel('AlphaFullCPU', 'alpha_full_cpu_exec.cc',
'#include "cpu/beta_cpu/alpha_dyn_inst.hh"', '#include "cpu/beta_cpu/alpha_dyn_inst.hh"',
{ 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' })
CpuModel('OoOCPU', 'ooo_cpu_exec.cc',
'#include "cpu/ooo_cpu/ooo_dyn_inst.hh"',
{ 'CPU_exec_context': 'OoODynInst<OoOImpl>' })
# Expand template with CPU-specific references into a dictionary with # Expand template with CPU-specific references into a dictionary with
# an entry for each CPU model name. The entry key is the model name # an entry for each CPU model name. The entry key is the model name

View file

@ -43,8 +43,6 @@
#include "cpu/base_dyn_inst.hh" #include "cpu/base_dyn_inst.hh"
#include "cpu/beta_cpu/alpha_impl.hh" #include "cpu/beta_cpu/alpha_impl.hh"
#include "cpu/beta_cpu/alpha_full_cpu.hh" #include "cpu/beta_cpu/alpha_full_cpu.hh"
#include "cpu/ooo_cpu/ooo_impl.hh"
#include "cpu/ooo_cpu/ooo_cpu.hh"
using namespace std; using namespace std;
@ -384,14 +382,9 @@ BaseDynInst<Impl>::eaSrcsReady()
// Forward declaration... // Forward declaration...
template class BaseDynInst<AlphaSimpleImpl>; template class BaseDynInst<AlphaSimpleImpl>;
template class BaseDynInst<OoOImpl>;
template <> template <>
int int
BaseDynInst<AlphaSimpleImpl>::instcount = 0; BaseDynInst<AlphaSimpleImpl>::instcount = 0;
template <>
int
BaseDynInst<OoOImpl>::instcount = 0;
#endif // __CPU_BASE_DYN_INST_CC__ #endif // __CPU_BASE_DYN_INST_CC__

View file

@ -404,6 +404,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
const Addr &getEA() const { return instEffAddr; } const Addr &getEA() const { return instEffAddr; }
bool doneEACalc() { return eaCalcDone; } bool doneEACalc() { return eaCalcDone; }
bool eaSrcsReady(); bool eaSrcsReady();
public:
int16_t lqIdx;
int16_t sqIdx;
}; };
template<class Impl> template<class Impl>
@ -419,6 +423,7 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
// Record key MemReq parameters so we can generate another one // Record key MemReq parameters so we can generate another one
// just like it for the timing access without calling translate() // just like it for the timing access without calling translate()
// again (which might mess up the TLB). // again (which might mess up the TLB).
// Do I ever really need this? -KTL 3/05
effAddr = req->vaddr; effAddr = req->vaddr;
physEffAddr = req->paddr; physEffAddr = req->paddr;
memReqFlags = req->flags; memReqFlags = req->flags;
@ -433,7 +438,7 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
#endif #endif
if (fault == No_Fault) { if (fault == No_Fault) {
fault = cpu->read(req, data); fault = cpu->read(req, data, lqIdx);
} }
else { else {
// Return a fixed value to keep simulation deterministic even // Return a fixed value to keep simulation deterministic even
@ -459,8 +464,8 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
traceData->setData(data); traceData->setData(data);
} }
storeSize = sizeof(T); // storeSize = sizeof(T);
storeData = data; // storeData = data;
MemReqPtr req = new MemReq(addr, xc, sizeof(T), flags); MemReqPtr req = new MemReq(addr, xc, sizeof(T), flags);
@ -485,7 +490,7 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
#endif #endif
if (fault == No_Fault) { if (fault == No_Fault) {
fault = cpu->write(req, data); fault = cpu->write(req, data, sqIdx);
} }
if (res) { if (res) {

View file

@ -47,11 +47,10 @@ class AlphaDynInst : public BaseDynInst<Impl>
/** BaseDynInst constructor given a static inst pointer. */ /** BaseDynInst constructor given a static inst pointer. */
AlphaDynInst(StaticInstPtr<AlphaISA> &_staticInst); AlphaDynInst(StaticInstPtr<AlphaISA> &_staticInst);
/** Executes the instruction. Why the hell did I put this here? */ /** Executes the instruction.*/
Fault execute() Fault execute()
{ {
this->fault = this->staticInst->execute(this, this->traceData); return this->fault = this->staticInst->execute(this, this->traceData);
return this->fault;
} }
public: public:
@ -105,47 +104,47 @@ class AlphaDynInst : public BaseDynInst<Impl>
// storage (which is pretty hard to imagine they would have reason // storage (which is pretty hard to imagine they would have reason
// to do). // to do).
uint64_t readIntReg(StaticInst<ISA> *si, int idx) uint64_t readIntReg(const StaticInst<ISA> *si, int idx)
{ {
return this->cpu->readIntReg(_srcRegIdx[idx]); return this->cpu->readIntReg(_srcRegIdx[idx]);
} }
float readFloatRegSingle(StaticInst<ISA> *si, int idx) float readFloatRegSingle(const StaticInst<ISA> *si, int idx)
{ {
return this->cpu->readFloatRegSingle(_srcRegIdx[idx]); return this->cpu->readFloatRegSingle(_srcRegIdx[idx]);
} }
double readFloatRegDouble(StaticInst<ISA> *si, int idx) double readFloatRegDouble(const StaticInst<ISA> *si, int idx)
{ {
return this->cpu->readFloatRegDouble(_srcRegIdx[idx]); return this->cpu->readFloatRegDouble(_srcRegIdx[idx]);
} }
uint64_t readFloatRegInt(StaticInst<ISA> *si, int idx) uint64_t readFloatRegInt(const StaticInst<ISA> *si, int idx)
{ {
return this->cpu->readFloatRegInt(_srcRegIdx[idx]); return this->cpu->readFloatRegInt(_srcRegIdx[idx]);
} }
/** @todo: Make results into arrays so they can handle multiple dest /** @todo: Make results into arrays so they can handle multiple dest
* registers. * registers.
*/ */
void setIntReg(StaticInst<ISA> *si, int idx, uint64_t val) void setIntReg(const StaticInst<ISA> *si, int idx, uint64_t val)
{ {
this->cpu->setIntReg(_destRegIdx[idx], val); this->cpu->setIntReg(_destRegIdx[idx], val);
this->instResult.integer = val; this->instResult.integer = val;
} }
void setFloatRegSingle(StaticInst<ISA> *si, int idx, float val) void setFloatRegSingle(const StaticInst<ISA> *si, int idx, float val)
{ {
this->cpu->setFloatRegSingle(_destRegIdx[idx], val); this->cpu->setFloatRegSingle(_destRegIdx[idx], val);
this->instResult.fp = val; this->instResult.fp = val;
} }
void setFloatRegDouble(StaticInst<ISA> *si, int idx, double val) void setFloatRegDouble(const StaticInst<ISA> *si, int idx, double val)
{ {
this->cpu->setFloatRegDouble(_destRegIdx[idx], val); this->cpu->setFloatRegDouble(_destRegIdx[idx], val);
this->instResult.dbl = val; this->instResult.dbl = val;
} }
void setFloatRegInt(StaticInst<ISA> *si, int idx, uint64_t val) void setFloatRegInt(const StaticInst<ISA> *si, int idx, uint64_t val)
{ {
this->cpu->setFloatRegInt(_destRegIdx[idx], val); this->cpu->setFloatRegInt(_destRegIdx[idx], val);
this->instResult.integer = val; this->instResult.integer = val;

View file

@ -129,7 +129,8 @@ template <class Impl>
void void
AlphaDynInst<Impl>::syscall() AlphaDynInst<Impl>::syscall()
{ {
this->cpu->syscall(); this->cpu->syscall(this->threadNumber);
// this->cpu->syscall();
} }
#endif #endif

View file

@ -28,8 +28,6 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
void regStats(); void regStats();
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
bool inPalMode();
//Note that the interrupt stuff from the base CPU might be somewhat //Note that the interrupt stuff from the base CPU might be somewhat
//ISA specific (ie NumInterruptLevels). These functions might not //ISA specific (ie NumInterruptLevels). These functions might not
//be needed in FullCPU though. //be needed in FullCPU though.
@ -106,13 +104,16 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
} }
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
uint64_t *getIPR(); uint64_t *getIpr();
uint64_t readIpr(int idx, Fault &fault); uint64_t readIpr(int idx, Fault &fault);
Fault setIpr(int idx, uint64_t val); Fault setIpr(int idx, uint64_t val);
int readIntrFlag(); int readIntrFlag();
void setIntrFlag(int val); void setIntrFlag(int val);
Fault hwrei(); Fault hwrei();
bool inPalMode(); bool inPalMode() { return AlphaISA::PcPAL(this->regFile.readPC()); }
bool inPalMode(uint64_t PC)
{ return AlphaISA::PcPAL(PC); }
void trap(Fault fault); void trap(Fault fault);
bool simPalCheck(int palFunc); bool simPalCheck(int palFunc);
@ -153,7 +154,7 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
} }
} }
void syscall(); void syscall(short thread_num);
void squashStages(); void squashStages();
#endif #endif
@ -168,11 +169,13 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
// Not sure this is used anywhere. // Not sure this is used anywhere.
void intr_post(RegFile *regs, Fault fault, Addr pc); void intr_post(RegFile *regs, Fault fault, Addr pc);
// Actually used within exec files. Implement properly. // Actually used within exec files. Implement properly.
void swap_palshadow(RegFile *regs, bool use_shadow); void swapPALShadow(bool use_shadow);
// Called by CPU constructor. Can implement as I please. // Called by CPU constructor. Can implement as I please.
void initCPU(RegFile *regs); void initCPU(RegFile *regs);
// Called by initCPU. Implement as I please. // Called by initCPU. Implement as I please.
void initIPRs(RegFile *regs); void initIPRs(RegFile *regs);
void halt() { panic("Halt not implemented!\n"); }
#endif #endif
@ -193,6 +196,11 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
return error; return error;
} }
template <class T>
Fault read(MemReqPtr &req, T &data, int load_idx)
{
return this->iew.ldstQueue.read(req, data, load_idx);
}
template <class T> template <class T>
Fault write(MemReqPtr &req, T &data) Fault write(MemReqPtr &req, T &data)
@ -218,7 +226,7 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
std::cerr << "Warning: " std::cerr << "Warning: "
<< req->xc->storeCondFailures << req->xc->storeCondFailures
<< " consecutive store conditional failures " << " consecutive store conditional failures "
<< "on cpu " << cpu_id << "on cpu " << this->cpu_id
<< std::endl; << std::endl;
} }
return No_Fault; return No_Fault;
@ -232,8 +240,8 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
// and all other stores (WH64?). Unsuccessful Store // and all other stores (WH64?). Unsuccessful Store
// Conditionals would have returned above, and wouldn't fall // Conditionals would have returned above, and wouldn't fall
// through. // through.
for (int i = 0; i < system->execContexts.size(); i++){ for (int i = 0; i < this->system->execContexts.size(); i++){
cregs = &system->execContexts[i]->regs.miscRegs; cregs = &this->system->execContexts[i]->regs.miscRegs;
if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) { if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
cregs->lock_flag = false; cregs->lock_flag = false;
} }
@ -244,6 +252,12 @@ class AlphaFullCPU : public FullBetaCPU<Impl>
return this->mem->write(req, (T)htoa(data)); return this->mem->write(req, (T)htoa(data));
} }
template <class T>
Fault write(MemReqPtr &req, T &data, int store_idx)
{
return this->iew.ldstQueue.write(req, data, store_idx);
}
}; };
#endif // __CPU_BETA_CPU_ALPHA_FULL_CPU_HH__ #endif // __CPU_BETA_CPU_ALPHA_FULL_CPU_HH__

View file

@ -33,8 +33,17 @@
#include "mem/functional_mem/functional_memory.hh" #include "mem/functional_mem/functional_memory.hh"
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
BEGIN_DECLARE_SIM_OBJECT_PARAMS(BaseFullCPU) class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl>
{
public:
DerivAlphaFullCPU(AlphaSimpleParams p)
: AlphaFullCPU<AlphaSimpleImpl>(p)
{ }
};
BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
Param<int> cycle_time;
Param<int> numThreads; Param<int> numThreads;
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
@ -44,8 +53,6 @@ SimObjectParam<AlphaDTB *> dtb;
Param<int> mult; Param<int> mult;
#else #else
SimObjectVectorParam<Process *> workload; SimObjectVectorParam<Process *> workload;
SimObjectParam<Process *> process;
Param<short> asid;
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
SimObjectParam<FunctionalMemory *> mem; SimObjectParam<FunctionalMemory *> mem;
@ -120,23 +127,25 @@ Param<unsigned> numROBEntries;
Param<unsigned> instShiftAmt; Param<unsigned> instShiftAmt;
Param<bool> defReg; Param<bool> defer_registration;
END_DECLARE_SIM_OBJECT_PARAMS(BaseFullCPU) Param<bool> function_trace;
Param<Tick> function_trace_start;
BEGIN_INIT_SIM_OBJECT_PARAMS(BaseFullCPU) END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
INIT_PARAM(cycle_time, "cpu cycle time"),
INIT_PARAM(numThreads, "number of HW thread contexts"), INIT_PARAM(numThreads, "number of HW thread contexts"),
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
INIT_PARAM(system, "System object"), INIT_PARAM(system, "System object"),
INIT_PARAM(itb, "Instruction translation buffer"), INIT_PARAM(itb, "Instruction translation buffer"),
INIT_PARAM(dtb, "Data translation buffer"), INIT_PARAM(dtb, "Data translation buffer"),
INIT_PARAM_DFLT(mult, "System clock multiplier", 1), INIT_PARAM(mult, "System clock multiplier"),
#else #else
INIT_PARAM(workload, "Processes to run"), INIT_PARAM(workload, "Processes to run"),
INIT_PARAM_DFLT(process, "Process to run", NULL),
INIT_PARAM(asid, "Address space ID"),
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
INIT_PARAM_DFLT(mem, "Memory", NULL), INIT_PARAM_DFLT(mem, "Memory", NULL),
@ -230,14 +239,16 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(BaseFullCPU)
INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), INIT_PARAM(numROBEntries, "Number of reorder buffer entries"),
INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"),
INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
INIT_PARAM(defReg, "Defer registration") INIT_PARAM(function_trace, "Enable function trace"),
INIT_PARAM(function_trace_start, "Cycle to start function trace")
END_INIT_SIM_OBJECT_PARAMS(BaseFullCPU) END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
CREATE_SIM_OBJECT(BaseFullCPU) CREATE_SIM_OBJECT(DerivAlphaFullCPU)
{ {
AlphaFullCPU<AlphaSimpleImpl> *cpu; DerivAlphaFullCPU *cpu;
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
if (mult != 1) if (mult != 1)
@ -255,30 +266,21 @@ CREATE_SIM_OBJECT(BaseFullCPU)
fatal("Must specify at least one workload!"); fatal("Must specify at least one workload!");
} }
Process *actual_process;
if (process == NULL) {
actual_process = workload[0];
} else {
actual_process = process;
}
#endif #endif
AlphaSimpleParams params; AlphaSimpleParams params;
params.cycleTime = cycle_time;
params.name = getInstanceName(); params.name = getInstanceName();
params.numberOfThreads = actual_num_threads; params.numberOfThreads = actual_num_threads;
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
params._system = system; params.system = system;
params.itb = itb; params.itb = itb;
params.dtb = dtb; params.dtb = dtb;
params.freq = ticksPerSecond * mult;
#else #else
params.workload = workload; params.workload = workload;
params.process = actual_process;
params.asid = asid;
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
params.mem = mem; params.mem = mem;
@ -356,12 +358,15 @@ CREATE_SIM_OBJECT(BaseFullCPU)
params.instShiftAmt = 2; params.instShiftAmt = 2;
params.defReg = defReg; params.defReg = defer_registration;
cpu = new AlphaFullCPU<AlphaSimpleImpl>(params); params.functionTrace = function_trace;
params.functionTraceStart = function_trace_start;
cpu = new DerivAlphaFullCPU(params);
return cpu; return cpu;
} }
REGISTER_SIM_OBJECT("AlphaFullCPU", BaseFullCPU) REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU)

View file

@ -12,6 +12,14 @@
#include "cpu/beta_cpu/alpha_params.hh" #include "cpu/beta_cpu/alpha_params.hh"
#include "cpu/beta_cpu/comm.hh" #include "cpu/beta_cpu/comm.hh"
#ifdef FULL_SYSTEM
#include "arch/alpha/osfpal.hh"
#include "arch/alpha/isa_traits.hh"
//#include "arch/alpha/ev5.hh"
//using namespace EV5;
#endif
template <class Impl> template <class Impl>
AlphaFullCPU<Impl>::AlphaFullCPU(Params &params) AlphaFullCPU<Impl>::AlphaFullCPU(Params &params)
: FullBetaCPU<Impl>(params) : FullBetaCPU<Impl>(params)
@ -42,9 +50,12 @@ AlphaFullCPU<Impl>::regStats()
#ifndef FULL_SYSTEM #ifndef FULL_SYSTEM
// Will probably need to know which thread is calling syscall
// Will need to pass that information in to the DynInst when it is constructed,
// so that this call can be made with the proper thread number.
template <class Impl> template <class Impl>
void void
AlphaFullCPU<Impl>::syscall() AlphaFullCPU<Impl>::syscall(short thread_num)
{ {
DPRINTF(FullCPU, "AlphaFullCPU: Syscall() called.\n\n"); DPRINTF(FullCPU, "AlphaFullCPU: Syscall() called.\n\n");
@ -60,7 +71,8 @@ AlphaFullCPU<Impl>::syscall()
// Copy over all important state to xc once all the unrolling is done. // Copy over all important state to xc once all the unrolling is done.
copyToXC(); copyToXC();
this->process->syscall(this->xc); this->thread[0]->syscall();
// this->thread[thread_num]->syscall();
// Copy over all important state back to CPU. // Copy over all important state back to CPU.
copyFromXC(); copyFromXC();
@ -102,6 +114,8 @@ AlphaFullCPU<Impl>::squashStages()
this->iew.squash(); this->iew.squash();
this->iewQueue.advance(); this->iewQueue.advance();
this->iewQueue.advance(); this->iewQueue.advance();
// Needs to tell the LSQ to write back all of its data
this->iew.lsqWriteback();
this->rob.squash(rob_head); this->rob.squash(rob_head);
this->commit.setSquashing(); this->commit.setSquashing();
@ -203,390 +217,35 @@ template <class Impl>
uint64_t * uint64_t *
AlphaFullCPU<Impl>::getIpr() AlphaFullCPU<Impl>::getIpr()
{ {
return regFile.getIpr(); return this->regFile.getIpr();
} }
template <class Impl> template <class Impl>
uint64_t uint64_t
AlphaFullCPU<Impl>::readIpr(int idx, Fault &fault) AlphaFullCPU<Impl>::readIpr(int idx, Fault &fault)
{ {
uint64_t *ipr = getIpr(); return this->regFile.readIpr(idx, fault);
uint64_t retval = 0; // return value, default 0
switch (idx) {
case AlphaISA::IPR_PALtemp0:
case AlphaISA::IPR_PALtemp1:
case AlphaISA::IPR_PALtemp2:
case AlphaISA::IPR_PALtemp3:
case AlphaISA::IPR_PALtemp4:
case AlphaISA::IPR_PALtemp5:
case AlphaISA::IPR_PALtemp6:
case AlphaISA::IPR_PALtemp7:
case AlphaISA::IPR_PALtemp8:
case AlphaISA::IPR_PALtemp9:
case AlphaISA::IPR_PALtemp10:
case AlphaISA::IPR_PALtemp11:
case AlphaISA::IPR_PALtemp12:
case AlphaISA::IPR_PALtemp13:
case AlphaISA::IPR_PALtemp14:
case AlphaISA::IPR_PALtemp15:
case AlphaISA::IPR_PALtemp16:
case AlphaISA::IPR_PALtemp17:
case AlphaISA::IPR_PALtemp18:
case AlphaISA::IPR_PALtemp19:
case AlphaISA::IPR_PALtemp20:
case AlphaISA::IPR_PALtemp21:
case AlphaISA::IPR_PALtemp22:
case AlphaISA::IPR_PALtemp23:
case AlphaISA::IPR_PAL_BASE:
case AlphaISA::IPR_IVPTBR:
case AlphaISA::IPR_DC_MODE:
case AlphaISA::IPR_MAF_MODE:
case AlphaISA::IPR_ISR:
case AlphaISA::IPR_EXC_ADDR:
case AlphaISA::IPR_IC_PERR_STAT:
case AlphaISA::IPR_DC_PERR_STAT:
case AlphaISA::IPR_MCSR:
case AlphaISA::IPR_ASTRR:
case AlphaISA::IPR_ASTER:
case AlphaISA::IPR_SIRR:
case AlphaISA::IPR_ICSR:
case AlphaISA::IPR_ICM:
case AlphaISA::IPR_DTB_CM:
case AlphaISA::IPR_IPLR:
case AlphaISA::IPR_INTID:
case AlphaISA::IPR_PMCTR:
// no side-effect
retval = ipr[idx];
break;
case AlphaISA::IPR_CC:
retval |= ipr[idx] & ULL(0xffffffff00000000);
retval |= curTick & ULL(0x00000000ffffffff);
break;
case AlphaISA::IPR_VA:
retval = ipr[idx];
break;
case AlphaISA::IPR_VA_FORM:
case AlphaISA::IPR_MM_STAT:
case AlphaISA::IPR_IFAULT_VA_FORM:
case AlphaISA::IPR_EXC_MASK:
case AlphaISA::IPR_EXC_SUM:
retval = ipr[idx];
break;
case AlphaISA::IPR_DTB_PTE:
{
AlphaISA::PTE &pte = dtb->index(!misspeculating());
retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32;
retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8;
retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12;
retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1;
retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2;
retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4;
retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57;
}
break;
// write only registers
case AlphaISA::IPR_HWINT_CLR:
case AlphaISA::IPR_SL_XMIT:
case AlphaISA::IPR_DC_FLUSH:
case AlphaISA::IPR_IC_FLUSH:
case AlphaISA::IPR_ALT_MODE:
case AlphaISA::IPR_DTB_IA:
case AlphaISA::IPR_DTB_IAP:
case AlphaISA::IPR_ITB_IA:
case AlphaISA::IPR_ITB_IAP:
fault = Unimplemented_Opcode_Fault;
break;
default:
// invalid IPR
fault = Unimplemented_Opcode_Fault;
break;
}
return retval;
} }
template <class Impl> template <class Impl>
Fault Fault
AlphaFullCPU<Impl>::setIpr(int idx, uint64_t val) AlphaFullCPU<Impl>::setIpr(int idx, uint64_t val)
{ {
uint64_t *ipr = getIpr(); return this->regFile.setIpr(idx, val);
uint64_t old;
if (misspeculating())
return No_Fault;
switch (idx) {
case AlphaISA::IPR_PALtemp0:
case AlphaISA::IPR_PALtemp1:
case AlphaISA::IPR_PALtemp2:
case AlphaISA::IPR_PALtemp3:
case AlphaISA::IPR_PALtemp4:
case AlphaISA::IPR_PALtemp5:
case AlphaISA::IPR_PALtemp6:
case AlphaISA::IPR_PALtemp7:
case AlphaISA::IPR_PALtemp8:
case AlphaISA::IPR_PALtemp9:
case AlphaISA::IPR_PALtemp10:
case AlphaISA::IPR_PALtemp11:
case AlphaISA::IPR_PALtemp12:
case AlphaISA::IPR_PALtemp13:
case AlphaISA::IPR_PALtemp14:
case AlphaISA::IPR_PALtemp15:
case AlphaISA::IPR_PALtemp16:
case AlphaISA::IPR_PALtemp17:
case AlphaISA::IPR_PALtemp18:
case AlphaISA::IPR_PALtemp19:
case AlphaISA::IPR_PALtemp20:
case AlphaISA::IPR_PALtemp21:
case AlphaISA::IPR_PALtemp22:
case AlphaISA::IPR_PAL_BASE:
case AlphaISA::IPR_IC_PERR_STAT:
case AlphaISA::IPR_DC_PERR_STAT:
case AlphaISA::IPR_PMCTR:
// write entire quad w/ no side-effect
ipr[idx] = val;
break;
case AlphaISA::IPR_CC_CTL:
// This IPR resets the cycle counter. We assume this only
// happens once... let's verify that.
assert(ipr[idx] == 0);
ipr[idx] = 1;
break;
case AlphaISA::IPR_CC:
// This IPR only writes the upper 64 bits. It's ok to write
// all 64 here since we mask out the lower 32 in rpcc (see
// isa_desc).
ipr[idx] = val;
break;
case AlphaISA::IPR_PALtemp23:
// write entire quad w/ no side-effect
old = ipr[idx];
ipr[idx] = val;
kernelStats.context(old, val);
break;
case AlphaISA::IPR_DTB_PTE:
// write entire quad w/ no side-effect, tag is forthcoming
ipr[idx] = val;
break;
case AlphaISA::IPR_EXC_ADDR:
// second least significant bit in PC is always zero
ipr[idx] = val & ~2;
break;
case AlphaISA::IPR_ASTRR:
case AlphaISA::IPR_ASTER:
// only write least significant four bits - privilege mask
ipr[idx] = val & 0xf;
break;
case AlphaISA::IPR_IPLR:
#ifdef DEBUG
if (break_ipl != -1 && break_ipl == (val & 0x1f))
debug_break();
#endif
// only write least significant five bits - interrupt level
ipr[idx] = val & 0x1f;
kernelStats.swpipl(ipr[idx]);
break;
case AlphaISA::IPR_DTB_CM:
kernelStats.mode((val & 0x18) != 0);
case AlphaISA::IPR_ICM:
// only write two mode bits - processor mode
ipr[idx] = val & 0x18;
break;
case AlphaISA::IPR_ALT_MODE:
// only write two mode bits - processor mode
ipr[idx] = val & 0x18;
break;
case AlphaISA::IPR_MCSR:
// more here after optimization...
ipr[idx] = val;
break;
case AlphaISA::IPR_SIRR:
// only write software interrupt mask
ipr[idx] = val & 0x7fff0;
break;
case AlphaISA::IPR_ICSR:
ipr[idx] = val & ULL(0xffffff0300);
break;
case AlphaISA::IPR_IVPTBR:
case AlphaISA::IPR_MVPTBR:
ipr[idx] = val & ULL(0xffffffffc0000000);
break;
case AlphaISA::IPR_DC_TEST_CTL:
ipr[idx] = val & 0x1ffb;
break;
case AlphaISA::IPR_DC_MODE:
case AlphaISA::IPR_MAF_MODE:
ipr[idx] = val & 0x3f;
break;
case AlphaISA::IPR_ITB_ASN:
ipr[idx] = val & 0x7f0;
break;
case AlphaISA::IPR_DTB_ASN:
ipr[idx] = val & ULL(0xfe00000000000000);
break;
case AlphaISA::IPR_EXC_SUM:
case AlphaISA::IPR_EXC_MASK:
// any write to this register clears it
ipr[idx] = 0;
break;
case AlphaISA::IPR_INTID:
case AlphaISA::IPR_SL_RCV:
case AlphaISA::IPR_MM_STAT:
case AlphaISA::IPR_ITB_PTE_TEMP:
case AlphaISA::IPR_DTB_PTE_TEMP:
// read-only registers
return Unimplemented_Opcode_Fault;
case AlphaISA::IPR_HWINT_CLR:
case AlphaISA::IPR_SL_XMIT:
case AlphaISA::IPR_DC_FLUSH:
case AlphaISA::IPR_IC_FLUSH:
// the following are write only
ipr[idx] = val;
break;
case AlphaISA::IPR_DTB_IA:
// really a control write
ipr[idx] = 0;
dtb->flushAll();
break;
case AlphaISA::IPR_DTB_IAP:
// really a control write
ipr[idx] = 0;
dtb->flushProcesses();
break;
case AlphaISA::IPR_DTB_IS:
// really a control write
ipr[idx] = val;
dtb->flushAddr(val, DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
break;
case AlphaISA::IPR_DTB_TAG: {
struct AlphaISA::PTE pte;
// FIXME: granularity hints NYI...
if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0)
panic("PTE GH field != 0");
// write entire quad
ipr[idx] = val;
// construct PTE for new entry
pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]);
pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]);
pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]);
pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]);
pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]);
pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]);
pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]);
// insert new TAG/PTE value into data TLB
dtb->insert(val, pte);
}
break;
case AlphaISA::IPR_ITB_PTE: {
struct AlphaISA::PTE pte;
// FIXME: granularity hints NYI...
if (ITB_PTE_GH(val) != 0)
panic("PTE GH field != 0");
// write entire quad
ipr[idx] = val;
// construct PTE for new entry
pte.ppn = ITB_PTE_PPN(val);
pte.xre = ITB_PTE_XRE(val);
pte.xwe = 0;
pte.fonr = ITB_PTE_FONR(val);
pte.fonw = ITB_PTE_FONW(val);
pte.asma = ITB_PTE_ASMA(val);
pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]);
// insert new TAG/PTE value into data TLB
itb->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
}
break;
case AlphaISA::IPR_ITB_IA:
// really a control write
ipr[idx] = 0;
itb->flushAll();
break;
case AlphaISA::IPR_ITB_IAP:
// really a control write
ipr[idx] = 0;
itb->flushProcesses();
break;
case AlphaISA::IPR_ITB_IS:
// really a control write
ipr[idx] = val;
itb->flushAddr(val, ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
break;
default:
// invalid IPR
return Unimplemented_Opcode_Fault;
}
// no error...
return No_Fault;
} }
template <class Impl> template <class Impl>
int int
AlphaFullCPU<Impl>::readIntrFlag() AlphaFullCPU<Impl>::readIntrFlag()
{ {
return regs.intrflag; return this->regFile.readIntrFlag();
} }
template <class Impl> template <class Impl>
void void
AlphaFullCPU<Impl>::setIntrFlag(int val) AlphaFullCPU<Impl>::setIntrFlag(int val)
{ {
regs.intrflag = val; this->regFile.setIntrFlag(val);
} }
// Can force commit stage to squash and stuff. // Can force commit stage to squash and stuff.
@ -596,36 +255,27 @@ AlphaFullCPU<Impl>::hwrei()
{ {
uint64_t *ipr = getIpr(); uint64_t *ipr = getIpr();
if (!PC_PAL(regs.pc)) if (!inPalMode())
return Unimplemented_Opcode_Fault; return Unimplemented_Opcode_Fault;
setNextPC(ipr[AlphaISA::IPR_EXC_ADDR]); setNextPC(ipr[AlphaISA::IPR_EXC_ADDR]);
if (!misspeculating()) { // kernelStats.hwrei();
kernelStats.hwrei();
if ((ipr[AlphaISA::IPR_EXC_ADDR] & 1) == 0) if ((ipr[AlphaISA::IPR_EXC_ADDR] & 1) == 0)
AlphaISA::swap_palshadow(&regs, false); // AlphaISA::swap_palshadow(&regs, false);
AlphaISA::check_interrupts = true; this->checkInterrupts = true;
}
// FIXME: XXX check for interrupts? XXX // FIXME: XXX check for interrupts? XXX
return No_Fault; return No_Fault;
} }
template <class Impl>
bool
AlphaFullCPU<Impl>::inPalMode()
{
return PC_PAL(readPC());
}
template <class Impl> template <class Impl>
bool bool
AlphaFullCPU<Impl>::simPalCheck(int palFunc) AlphaFullCPU<Impl>::simPalCheck(int palFunc)
{ {
kernelStats.callpal(palFunc); // kernelStats.callpal(palFunc);
switch (palFunc) { switch (palFunc) {
case PAL::halt: case PAL::halt:
@ -636,7 +286,7 @@ AlphaFullCPU<Impl>::simPalCheck(int palFunc)
case PAL::bpt: case PAL::bpt:
case PAL::bugchk: case PAL::bugchk:
if (system->breakpoint()) if (this->system->breakpoint())
return false; return false;
break; break;
} }
@ -651,21 +301,22 @@ template <class Impl>
void void
AlphaFullCPU<Impl>::trap(Fault fault) AlphaFullCPU<Impl>::trap(Fault fault)
{ {
uint64_t PC = commit.readPC(); // Keep in mind that a trap may be initiated by fetch if there's a TLB
// miss
uint64_t PC = this->commit.readCommitPC();
DPRINTF(Fault, "Fault %s\n", FaultName(fault)); DPRINTF(Fault, "Fault %s\n", FaultName(fault));
Stats::recordEvent(csprintf("Fault %s", FaultName(fault))); this->recordEvent(csprintf("Fault %s", FaultName(fault)));
assert(!misspeculating()); // kernelStats.fault(fault);
kernelStats.fault(fault);
if (fault == Arithmetic_Fault) if (fault == Arithmetic_Fault)
panic("Arithmetic traps are unimplemented!"); panic("Arithmetic traps are unimplemented!");
AlphaISA::InternalProcReg *ipr = getIpr(); typename AlphaISA::InternalProcReg *ipr = getIpr();
// exception restart address - Get the commit PC // exception restart address - Get the commit PC
if (fault != Interrupt_Fault || !PC_PAL(PC)) if (fault != Interrupt_Fault || !inPalMode(PC))
ipr[AlphaISA::IPR_EXC_ADDR] = PC; ipr[AlphaISA::IPR_EXC_ADDR] = PC;
if (fault == Pal_Fault || fault == Arithmetic_Fault /* || if (fault == Pal_Fault || fault == Arithmetic_Fault /* ||
@ -674,11 +325,12 @@ AlphaFullCPU<Impl>::trap(Fault fault)
ipr[AlphaISA::IPR_EXC_ADDR] += 4; ipr[AlphaISA::IPR_EXC_ADDR] += 4;
} }
if (!PC_PAL(PC)) if (!inPalMode(PC))
AlphaISA::swap_palshadow(&regs, true); swapPALShadow(true);
setPC( ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault] ); this->regFile.setPC( ipr[AlphaISA::IPR_PAL_BASE] +
setNextPC(PC + sizeof(MachInst)); AlphaISA::fault_addr[fault] );
this->regFile.setNextPC(PC + sizeof(MachInst));
} }
template <class Impl> template <class Impl>
@ -694,7 +346,7 @@ AlphaFullCPU<Impl>::processInterrupts()
// same logical index. // same logical index.
template <class Impl> template <class Impl>
void void
AlphaFullCPU<Impl>::swap_palshadow(RegFile *regs, bool use_shadow) AlphaFullCPU<Impl>::swapPALShadow(bool use_shadow)
{ {
if (palShadowEnabled == use_shadow) if (palShadowEnabled == use_shadow)
panic("swap_palshadow: wrong PAL shadow state"); panic("swap_palshadow: wrong PAL shadow state");
@ -703,6 +355,7 @@ AlphaFullCPU<Impl>::swap_palshadow(RegFile *regs, bool use_shadow)
// Will have to lookup in rename map to get physical registers, then // Will have to lookup in rename map to get physical registers, then
// swap. // swap.
/*
for (int i = 0; i < AlphaISA::NumIntRegs; i++) { for (int i = 0; i < AlphaISA::NumIntRegs; i++) {
if (reg_redir[i]) { if (reg_redir[i]) {
AlphaISA::IntReg temp = regs->intRegFile[i]; AlphaISA::IntReg temp = regs->intRegFile[i];
@ -710,6 +363,7 @@ AlphaFullCPU<Impl>::swap_palshadow(RegFile *regs, bool use_shadow)
regs->palregs[i] = temp; regs->palregs[i] = temp;
} }
} }
*/
} }
#endif // FULL_SYSTEM #endif // FULL_SYSTEM

View file

@ -20,12 +20,12 @@ class MemInterface;
class AlphaSimpleParams : public BaseFullCPU::Params class AlphaSimpleParams : public BaseFullCPU::Params
{ {
public: public:
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
AlphaITB *itb; AlphaDTB *dtb; AlphaITB *itb; AlphaDTB *dtb;
#else #else
std::vector<Process *> workload; std::vector<Process *> workload;
Process *process; Process *process;
short asid;
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
FunctionalMemory *mem; FunctionalMemory *mem;

View file

@ -50,7 +50,6 @@ struct SimpleIEWSimpleCommit {
bool branchTaken; bool branchTaken;
uint64_t mispredPC; uint64_t mispredPC;
uint64_t nextPC; uint64_t nextPC;
unsigned globalHist;
InstSeqNum squashedSeqNum; InstSeqNum squashedSeqNum;
}; };
@ -78,7 +77,6 @@ struct TimeBufStruct {
bool branchTaken; bool branchTaken;
uint64_t mispredPC; uint64_t mispredPC;
uint64_t nextPC; uint64_t nextPC;
unsigned globalHist;
}; };
decodeComm decodeInfo; decodeComm decodeInfo;
@ -113,12 +111,11 @@ struct TimeBufStruct {
bool branchTaken; bool branchTaken;
uint64_t mispredPC; uint64_t mispredPC;
uint64_t nextPC; uint64_t nextPC;
unsigned globalHist;
// Think of better names here. // Think of better names here.
// Will need to be a variety of sizes... // Will need to be a variety of sizes...
// Maybe make it a vector, that way only need one object. // Maybe make it a vector, that way only need one object.
std::vector<PhysRegIndex> freeRegs; // std::vector<PhysRegIndex> freeRegs;
bool robSquashing; bool robSquashing;
@ -129,7 +126,7 @@ struct TimeBufStruct {
// Extra bits of information so that the LDSTQ only updates when it // Extra bits of information so that the LDSTQ only updates when it
// needs to. // needs to.
bool commitIsStore; // bool commitIsStore;
bool commitIsLoad; bool commitIsLoad;
// Communication specifically to the IQ to tell the IQ that it can // Communication specifically to the IQ to tell the IQ that it can

View file

@ -113,9 +113,6 @@ class SimpleCommit
/** Pointer to FullCPU. */ /** Pointer to FullCPU. */
FullCPU *cpu; FullCPU *cpu;
/** Pointer to the rename map. DO NOT USE if possible. */
// typename Impl::CPUPol::RenameMap *renameMap;
//Store buffer interface? Will need to move committed stores to the //Store buffer interface? Will need to move committed stores to the
//store buffer //store buffer

View file

@ -166,9 +166,9 @@ SimpleCommit<Impl>::commit()
// hwrei() is what resets the PC to the place where instruction execution // hwrei() is what resets the PC to the place where instruction execution
// beings again. // beings again.
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
if (ISA::check_interrupts && if (//checkInterrupts &&
cpu->check_interrupts() && cpu->check_interrupts() &&
!xc->inPalMode()) { !cpu->inPalMode(readCommitPC())) {
// Will need to squash all instructions currently in flight and have // Will need to squash all instructions currently in flight and have
// the interrupt handler restart at the last non-committed inst. // the interrupt handler restart at the last non-committed inst.
// Most of that can be handled through the trap() function. The // Most of that can be handled through the trap() function. The
@ -215,8 +215,6 @@ SimpleCommit<Impl>::commit()
toIEW->commitInfo.mispredPC = fromIEW->mispredPC; toIEW->commitInfo.mispredPC = fromIEW->mispredPC;
toIEW->commitInfo.globalHist = fromIEW->globalHist;
if (toIEW->commitInfo.branchMispredict) { if (toIEW->commitInfo.branchMispredict) {
++branchMispredicts; ++branchMispredicts;
} }
@ -257,6 +255,9 @@ SimpleCommit<Impl>::commitInsts()
// Can't commit and squash things at the same time... // Can't commit and squash things at the same time...
//////////////////////////////////// ////////////////////////////////////
if (rob->isEmpty())
return;
DynInstPtr head_inst = rob->readHeadInst(); DynInstPtr head_inst = rob->readHeadInst();
unsigned num_committed = 0; unsigned num_committed = 0;
@ -275,9 +276,11 @@ SimpleCommit<Impl>::commitInsts()
if (head_inst->isSquashed()) { if (head_inst->isSquashed()) {
// Hack to avoid the instruction being retired (and deleted) if // Hack to avoid the instruction being retired (and deleted) if
// it hasn't been through the IEW stage yet. // it hasn't been through the IEW stage yet.
/*
if (!head_inst->isExecuted()) { if (!head_inst->isExecuted()) {
break; break;
} }
*/
DPRINTF(Commit, "Commit: Retiring squashed instruction from " DPRINTF(Commit, "Commit: Retiring squashed instruction from "
"ROB.\n"); "ROB.\n");
@ -341,7 +344,7 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
// and committed this instruction. // and committed this instruction.
cpu->funcExeInst--; cpu->funcExeInst--;
if (head_inst->isStore() || head_inst->isNonSpeculative()) { if (head_inst->isNonSpeculative()) {
DPRINTF(Commit, "Commit: Encountered a store or non-speculative " DPRINTF(Commit, "Commit: Encountered a store or non-speculative "
"instruction at the head of the ROB, PC %#x.\n", "instruction at the head of the ROB, PC %#x.\n",
head_inst->readPC()); head_inst->readPC());
@ -376,12 +379,14 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
} }
// Check if the instruction caused a fault. If so, trap. // Check if the instruction caused a fault. If so, trap.
if (head_inst->getFault() != No_Fault) { Fault inst_fault = head_inst->getFault();
if (inst_fault != No_Fault && inst_fault != Fake_Mem_Fault) {
if (!head_inst->isNop()) { if (!head_inst->isNop()) {
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
cpu->trap(fault); cpu->trap(inst_fault);
#else // !FULL_SYSTEM #else // !FULL_SYSTEM
panic("fault (%d) detected @ PC %08p", head_inst->getFault(), panic("fault (%d) detected @ PC %08p", inst_fault,
head_inst->PC); head_inst->PC);
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
} }
@ -390,7 +395,7 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
// Check if we're really ready to commit. If not then return false. // Check if we're really ready to commit. If not then return false.
// I'm pretty sure all instructions should be able to commit if they've // I'm pretty sure all instructions should be able to commit if they've
// reached this far. For now leave this in as a check. // reached this far. For now leave this in as a check.
if(!rob->isHeadReady()) { if (!rob->isHeadReady()) {
panic("Commit: Unable to commit head instruction!\n"); panic("Commit: Unable to commit head instruction!\n");
return false; return false;
} }
@ -413,17 +418,7 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
++commitCommittedBranches; ++commitCommittedBranches;
} }
#if 0 #if 0
// Check if the instruction has a destination register.
// If so add the previous physical register of its logical register's
// destination to the free list through the time buffer.
for (int i = 0; i < head_inst->numDestRegs(); i++)
{
toIEW->commitInfo.freeRegs.push_back(head_inst->prevDestRegIdx(i));
}
#endif
// Explicit communication back to the LDSTQ that a load has been committed // Explicit communication back to the LDSTQ that a load has been committed
// and can be removed from the LDSTQ. Stores don't need this because // and can be removed from the LDSTQ. Stores don't need this because
// the LDSTQ will already have been told that a store has reached the head // the LDSTQ will already have been told that a store has reached the head
@ -436,6 +431,7 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
++commitCommittedLoads; ++commitCommittedLoads;
} }
} }
#endif
// Now that the instruction is going to be committed, finalize its // Now that the instruction is going to be committed, finalize its
// trace data. // trace data.
@ -487,7 +483,7 @@ SimpleCommit<Impl>::markCompletedInsts()
// Grab completed insts out of the IEW instruction queue, and mark // Grab completed insts out of the IEW instruction queue, and mark
// instructions completed within the ROB. // instructions completed within the ROB.
for (int inst_num = 0; for (int inst_num = 0;
inst_num < iewWidth && fromIEW->insts[inst_num]; inst_num < fromIEW->size && fromIEW->insts[inst_num];
++inst_num) ++inst_num)
{ {
DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n", DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n",

View file

@ -34,7 +34,7 @@ struct SimpleCPUPolicy
typedef SimpleFetch<Impl> Fetch; typedef SimpleFetch<Impl> Fetch;
typedef SimpleDecode<Impl> Decode; typedef SimpleDecode<Impl> Decode;
typedef SimpleRename<Impl> Rename; typedef SimpleRename<Impl> Rename;
typedef SimpleIEW<Impl, IQ> IEW; typedef SimpleIEW<Impl> IEW;
typedef SimpleCommit<Impl> Commit; typedef SimpleCommit<Impl> Commit;
/** The struct for communication between fetch and decode. */ /** The struct for communication between fetch and decode. */

View file

@ -68,12 +68,16 @@ class SimpleDecode
void squash(); void squash();
private: private:
inline bool fetchInstsValid();
void block(); void block();
inline void unblock(); inline void unblock();
void squash(DynInstPtr &inst); void squash(DynInstPtr &inst);
void dumpFetchQueue();
// Interfaces to objects outside of decode. // Interfaces to objects outside of decode.
/** CPU interface. */ /** CPU interface. */
FullCPU *cpu; FullCPU *cpu;

View file

@ -98,6 +98,13 @@ SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
} }
template<class Impl>
inline bool
SimpleDecode<Impl>::fetchInstsValid()
{
return fromFetch->size > 0;
}
template<class Impl> template<class Impl>
void void
SimpleDecode<Impl>::block() SimpleDecode<Impl>::block()
@ -156,14 +163,14 @@ SimpleDecode<Impl>::squash(DynInstPtr &inst)
// Set status to squashing. // Set status to squashing.
_status = Squashing; _status = Squashing;
// Maybe advance the time buffer? Not sure what to do in the normal
// case.
// Clear the skid buffer in case it has any data in it. // Clear the skid buffer in case it has any data in it.
while (!skidBuffer.empty()) while (!skidBuffer.empty()) {
{
skidBuffer.pop(); skidBuffer.pop();
} }
// Squash instructions up until this one
// Slightly unrealistic!
cpu->removeInstsUntil(inst->seqNum);
} }
template<class Impl> template<class Impl>
@ -205,7 +212,7 @@ SimpleDecode<Impl>::tick()
if (_status == Unblocking) { if (_status == Unblocking) {
++decodeUnblockCycles; ++decodeUnblockCycles;
if (fromFetch->size > 0) { if (fetchInstsValid()) {
// Add the current inputs to the skid buffer so they can be // Add the current inputs to the skid buffer so they can be
// reprocessed when this stage unblocks. // reprocessed when this stage unblocks.
skidBuffer.push(*fromFetch); skidBuffer.push(*fromFetch);
@ -216,7 +223,7 @@ SimpleDecode<Impl>::tick()
} else if (_status == Blocked) { } else if (_status == Blocked) {
++decodeBlockedCycles; ++decodeBlockedCycles;
if (fromFetch->size > 0) { if (fetchInstsValid()) {
block(); block();
} }
@ -240,12 +247,12 @@ SimpleDecode<Impl>::tick()
squash(); squash();
} }
} else if (_status == Squashing) { } else if (_status == Squashing) {
++decodeSquashCycles;
if (!fromCommit->commitInfo.squash && if (!fromCommit->commitInfo.squash &&
!fromCommit->commitInfo.robSquashing) { !fromCommit->commitInfo.robSquashing) {
_status = Running; _status = Running;
} else if (fromCommit->commitInfo.squash) { } else if (fromCommit->commitInfo.squash) {
++decodeSquashCycles;
squash(); squash();
} }
} }
@ -264,8 +271,7 @@ SimpleDecode<Impl>::decode()
// Check time buffer if being told to stall. // Check time buffer if being told to stall.
if (fromRename->renameInfo.stall || if (fromRename->renameInfo.stall ||
fromIEW->iewInfo.stall || fromIEW->iewInfo.stall ||
fromCommit->commitInfo.stall) fromCommit->commitInfo.stall) {
{
block(); block();
return; return;
} }
@ -273,7 +279,7 @@ SimpleDecode<Impl>::decode()
// Check fetch queue to see if instructions are available. // Check fetch queue to see if instructions are available.
// If no available instructions, do nothing, unless this stage is // If no available instructions, do nothing, unless this stage is
// currently unblocking. // currently unblocking.
if (fromFetch->size == 0 && _status != Unblocking) { if (!fetchInstsValid() && _status != Unblocking) {
DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n"); DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
// Should I change the status to idle? // Should I change the status to idle?
++decodeIdleCycles; ++decodeIdleCycles;
@ -286,7 +292,7 @@ SimpleDecode<Impl>::decode()
unsigned to_rename_index = 0; unsigned to_rename_index = 0;
int insts_available = _status == Unblocking ? int insts_available = _status == Unblocking ?
skidBuffer.front().size : skidBuffer.front().size - numInst :
fromFetch->size; fromFetch->size;
// Debug block... // Debug block...
@ -308,8 +314,8 @@ SimpleDecode<Impl>::decode()
} }
#endif #endif
while (insts_available > 0) while (insts_available > 0)
{ {
DPRINTF(Decode, "Decode: Sending instruction to rename.\n"); DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
inst = _status == Unblocking ? skidBuffer.front().insts[numInst] : inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
@ -331,6 +337,16 @@ SimpleDecode<Impl>::decode()
continue; continue;
} }
// Also check if instructions have no source registers. Mark
// them as ready to issue at any time. Not sure if this check
// should exist here or at a later stage; however it doesn't matter
// too much for function correctness.
// Isn't this handled by the inst queue?
if (inst->numSrcRegs() == 0) {
inst->setCanIssue();
}
// This current instruction is valid, so add it into the decode // This current instruction is valid, so add it into the decode
// queue. The next instruction may not be valid, so check to // queue. The next instruction may not be valid, so check to
// see if branches were predicted correctly. // see if branches were predicted correctly.
@ -369,16 +385,6 @@ SimpleDecode<Impl>::decode()
// addr (either the immediate, or the branch PC + 4) and redirect // addr (either the immediate, or the branch PC + 4) and redirect
// fetch if it's incorrect. // fetch if it's incorrect.
// Also check if instructions have no source registers. Mark
// them as ready to issue at any time. Not sure if this check
// should exist here or at a later stage; however it doesn't matter
// too much for function correctness.
// Isn't this handled by the inst queue?
if (inst->numSrcRegs() == 0) {
inst->setCanIssue();
}
// Increment which instruction we're looking at. // Increment which instruction we're looking at.
++numInst; ++numInst;
++to_rename_index; ++to_rename_index;

View file

@ -74,7 +74,6 @@ class SimpleFetch
void processCacheCompletion(); void processCacheCompletion();
// private:
// Figure out PC vs next PC and how it should be updated // Figure out PC vs next PC and how it should be updated
void squash(const Addr &new_PC); void squash(const Addr &new_PC);
@ -93,9 +92,6 @@ class SimpleFetch
*/ */
bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC); bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC);
// Might not want this function...
// inline void recordGlobalHist(DynInstPtr &inst);
/** /**
* Fetches the cache line that contains fetch_PC. Returns any * Fetches the cache line that contains fetch_PC. Returns any
* fault that happened. Puts the data into the class variable * fault that happened. Puts the data into the class variable
@ -184,9 +180,6 @@ class SimpleFetch
/** Mask to get a cache block's address. */ /** Mask to get a cache block's address. */
Addr cacheBlkMask; Addr cacheBlkMask;
/** The instruction being fetched. */
// MachInst inst;
/** The cache line being fetched. */ /** The cache line being fetched. */
uint8_t *cacheData; uint8_t *cacheData;

View file

@ -44,6 +44,8 @@ SimpleFetch<Impl>::SimpleFetch(Params &params)
commitToFetchDelay(params.commitToFetchDelay), commitToFetchDelay(params.commitToFetchDelay),
fetchWidth(params.fetchWidth) fetchWidth(params.fetchWidth)
{ {
DPRINTF(Fetch, "Fetch: Fetch constructor called\n");
// Set status to idle. // Set status to idle.
_status = Idle; _status = Idle;
@ -52,7 +54,7 @@ SimpleFetch<Impl>::SimpleFetch(Params &params)
// Not sure of this parameter. I think it should be based on the // Not sure of this parameter. I think it should be based on the
// thread number. // thread number.
#ifndef FULL_SYSTEM #ifndef FULL_SYSTEM
memReq->asid = params.asid; memReq->asid = 0;
#else #else
memReq->asid = 0; memReq->asid = 0;
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
@ -163,21 +165,10 @@ SimpleFetch<Impl>::processCacheCompletion()
// to return. // to return.
// Can keep track of how many cache accesses go unused due to // Can keep track of how many cache accesses go unused due to
// misspeculation here. // misspeculation here.
// How to handle an outstanding miss which gets cancelled due to squash,
// then a new icache miss gets scheduled?
if (_status == IcacheMissStall) if (_status == IcacheMissStall)
_status = IcacheMissComplete; _status = IcacheMissComplete;
} }
#if 0
template <class Impl>
inline void
SimpleFetch<Impl>::recordGlobalHist(DynInstPtr &inst)
{
inst->setGlobalHist(branchPred.BPReadGlobalHist());
}
#endif
template <class Impl> template <class Impl>
bool bool
SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC) SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
@ -311,7 +302,6 @@ SimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,
// Tell the CPU to remove any instructions that are in flight between // Tell the CPU to remove any instructions that are in flight between
// fetch and decode. // fetch and decode.
cpu->removeInstsUntil(seq_num); cpu->removeInstsUntil(seq_num);
} }
template <class Impl> template <class Impl>
@ -428,7 +418,9 @@ SimpleFetch<Impl>::tick()
// Switch status to running // Switch status to running
_status = Running; _status = Running;
++fetchSquashCycles; ++fetchCycles;
fetch();
} else if (_status != IcacheMissStall) { } else if (_status != IcacheMissStall) {
DPRINTF(Fetch, "Fetch: Running stage.\n"); DPRINTF(Fetch, "Fetch: Running stage.\n");

View file

@ -16,7 +16,7 @@
using namespace std; using namespace std;
BaseFullCPU::BaseFullCPU(Params &params) BaseFullCPU::BaseFullCPU(Params &params)
: BaseCPU(&params) : BaseCPU(&params), cpu_id(0)
{ {
} }
@ -82,15 +82,14 @@ FullBetaCPU<Impl>::FullBetaCPU(Params &params)
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
system(params.system), system(params.system),
memCtrl(system->memCtrl), memCtrl(system->memctrl),
physmem(system->physmem), physmem(system->physmem),
itb(params.itb), itb(params.itb),
dtb(params.dtb), dtb(params.dtb),
mem(params.mem), mem(params.mem),
#else #else
process(params.process), // Hardcoded for a single thread!!
asid(params.asid), mem(params.workload[0]->getMemory()),
mem(process->getMemory()),
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
icacheInterface(params.icacheInterface), icacheInterface(params.icacheInterface),
@ -100,20 +99,40 @@ FullBetaCPU<Impl>::FullBetaCPU(Params &params)
funcExeInst(0) funcExeInst(0)
{ {
_status = Idle; _status = Idle;
#ifndef FULL_SYSTEM
thread.resize(this->number_of_threads);
#endif
for (int i = 0; i < this->number_of_threads; ++i) {
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
xc = new ExecContext(this, 0, system, itb, dtb, mem); assert(i == 0);
system->execContexts[i] =
new ExecContext(this, i, system, itb, dtb, mem);
// initialize CPU, including PC // initialize CPU, including PC
TheISA::initCPU(&xc->regs); TheISA::initCPU(&system->execContexts[i]->regs);
execContexts.push_back(system->execContexts[i]);
#else #else
DPRINTF(FullCPU, "FullCPU: Process's starting PC is %#x, process is %#x", if (i < params.workload.size()) {
process->prog_entry, process); DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, "
xc = new ExecContext(this, /* thread_num */ 0, process, /* asid */ 0); "process is %#x",
i, params.workload[i]->prog_entry, thread[i]);
assert(process->getMemory() != NULL); thread[i] = new ExecContext(this, i, params.workload[i], i);
assert(mem != NULL); }
assert(params.workload[i]->getMemory() != NULL);
assert(mem != NULL);
execContexts.push_back(thread[i]);
#endif // !FULL_SYSTEM #endif // !FULL_SYSTEM
execContexts.push_back(xc); }
// Note that this is a hack so that my code which still uses xc-> will
// still work. I should remove this eventually
#ifdef FULL_SYSTEM
xc = system->execContexts[0];
#else
xc = thread[0];
#endif
// The stages also need their CPU pointer setup. However this must be // The stages also need their CPU pointer setup. However this must be
// done at the upper level CPU because they have pointers to the upper // done at the upper level CPU because they have pointers to the upper
@ -202,29 +221,33 @@ FullBetaCPU<Impl>::init()
// Need to do a copy of the xc->regs into the CPU's regfile so // Need to do a copy of the xc->regs into the CPU's regfile so
// that it can start properly. // that it can start properly.
#ifdef FULL_SYSTEM
ExecContext *src_xc = system->execContexts[0];
#else
ExecContext *src_xc = thread[0];
#endif
// First loop through the integer registers. // First loop through the integer registers.
for (int i = 0; i < Impl::ISA::NumIntRegs; ++i) for (int i = 0; i < Impl::ISA::NumIntRegs; ++i)
{ {
regFile.intRegFile[i] = xc->regs.intRegFile[i]; regFile.intRegFile[i] = src_xc->regs.intRegFile[i];
} }
// Then loop through the floating point registers. // Then loop through the floating point registers.
for (int i = 0; i < Impl::ISA::NumFloatRegs; ++i) for (int i = 0; i < Impl::ISA::NumFloatRegs; ++i)
{ {
regFile.floatRegFile[i].d = xc->regs.floatRegFile.d[i]; regFile.floatRegFile[i].d = src_xc->regs.floatRegFile.d[i];
regFile.floatRegFile[i].q = xc->regs.floatRegFile.q[i]; regFile.floatRegFile[i].q = src_xc->regs.floatRegFile.q[i];
} }
// Then loop through the misc registers. // Then loop through the misc registers.
regFile.miscRegs.fpcr = xc->regs.miscRegs.fpcr; regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
regFile.miscRegs.uniq = xc->regs.miscRegs.uniq; regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
regFile.miscRegs.lock_flag = xc->regs.miscRegs.lock_flag; regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
regFile.miscRegs.lock_addr = xc->regs.miscRegs.lock_addr; regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
// Then finally set the PC and the next PC. // Then finally set the PC and the next PC.
regFile.pc = xc->regs.pc; regFile.pc = src_xc->regs.pc;
regFile.npc = xc->regs.npc; regFile.npc = src_xc->regs.npc;
} }
} }
@ -277,13 +300,13 @@ FullBetaCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
// Set all status's to active, schedule the // Set all status's to active, schedule the
// CPU's tick event. // CPU's tick event.
tickEvent.schedule(curTick);
for (int i = 0; i < execContexts.size(); ++i) { for (int i = 0; i < execContexts.size(); ++i) {
execContexts[i]->activate(); ExecContext *xc = execContexts[i];
if (xc->status() == ExecContext::Active && _status != Running) {
_status = Running;
tickEvent.schedule(curTick);
}
} }
// Switch out the other CPU.
oldCPU->switchOut();
} }
template <class Impl> template <class Impl>
@ -463,6 +486,7 @@ FullBetaCPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
inst_to_delete->seqNum, inst_to_delete->readPC()); inst_to_delete->seqNum, inst_to_delete->readPC());
// Remove the instruction from the list. // Remove the instruction from the list.
instList.back() = NULL;
instList.pop_back(); instList.pop_back();
// Mark it as squashed. // Mark it as squashed.

View file

@ -5,11 +5,12 @@
//itself properly. Constructor. Derived alpha class. Threads! //itself properly. Constructor. Derived alpha class. Threads!
// Avoid running stages and advancing queues if idle/stalled. // Avoid running stages and advancing queues if idle/stalled.
#ifndef __SIMPLE_FULL_CPU_HH__ #ifndef __CPU_BETA_CPU_FULL_CPU_HH__
#define __SIMPLE_FULL_CPU_HH__ #define __CPU_BETA_CPU_FULL_CPU_HH__
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <vector>
#include "cpu/beta_cpu/comm.hh" #include "cpu/beta_cpu/comm.hh"
@ -20,6 +21,11 @@
#include "cpu/beta_cpu/cpu_policy.hh" #include "cpu/beta_cpu/cpu_policy.hh"
#include "sim/process.hh" #include "sim/process.hh"
#ifdef FULL_SYSTEM
#include "arch/alpha/ev5.hh"
using namespace EV5;
#endif
class FunctionalMemory; class FunctionalMemory;
class Process; class Process;
@ -34,6 +40,9 @@ class BaseFullCPU : public BaseCPU
#else #else
BaseFullCPU(Params &params); BaseFullCPU(Params &params);
#endif // FULL_SYSTEM #endif // FULL_SYSTEM
private:
int cpu_id;
}; };
template <class Impl> template <class Impl>
@ -41,6 +50,7 @@ class FullBetaCPU : public BaseFullCPU
{ {
public: public:
//Put typedefs from the Impl here. //Put typedefs from the Impl here.
typedef typename Impl::ISA ISA;
typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::CPUPol CPUPolicy;
typedef typename Impl::Params Params; typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr; typedef typename Impl::DynInstPtr DynInstPtr;
@ -114,19 +124,21 @@ class FullBetaCPU : public BaseFullCPU
bool validDataAddr(Addr addr) { return true; } bool validDataAddr(Addr addr) { return true; }
/** Get instruction asid. */ /** Get instruction asid. */
int getInstAsid() { return ITB_ASN_ASN(regs.ipr[ISA::IPR_ITB_ASN]); } int getInstAsid()
{ return ITB_ASN_ASN(regFile.getIpr()[ISA::IPR_ITB_ASN]); }
/** Get data asid. */ /** Get data asid. */
int getDataAsid() { return DTB_ASN_ASN(regs.ipr[ISA::IPR_DTB_ASN]); } int getDataAsid()
{ return DTB_ASN_ASN(regFile.getIpr()[ISA::IPR_DTB_ASN]); }
#else #else
bool validInstAddr(Addr addr) bool validInstAddr(Addr addr)
{ return process->validInstAddr(addr); } { return thread[0]->validInstAddr(addr); }
bool validDataAddr(Addr addr) bool validDataAddr(Addr addr)
{ return process->validDataAddr(addr); } { return thread[0]->validDataAddr(addr); }
int getInstAsid() { return asid; } int getInstAsid() { return thread[0]->asid; }
int getDataAsid() { return asid; } int getDataAsid() { return thread[0]->asid; }
#endif #endif
@ -284,7 +296,14 @@ class FullBetaCPU : public BaseFullCPU
ExecContext *xc; ExecContext *xc;
/** Temporary function to get pointer to exec context. */ /** Temporary function to get pointer to exec context. */
ExecContext *xcBase() { return xc; } ExecContext *xcBase()
{
#ifdef FULL_SYSTEM
return system->execContexts[0];
#else
return thread[0];
#endif
}
InstSeqNum globalSeqNum; InstSeqNum globalSeqNum;
@ -299,12 +318,7 @@ class FullBetaCPU : public BaseFullCPU
// SWContext *swCtx; // SWContext *swCtx;
#else #else
Process *process; std::vector<ExecContext *> thread;
// Address space ID. Note that this is used for TIMING cache
// simulation only; all functional memory accesses should use
// one of the FunctionalMemory pointers above.
short asid;
#endif #endif
FunctionalMemory *mem; FunctionalMemory *mem;

View file

@ -4,4 +4,4 @@
#include "cpu/beta_cpu/iew_impl.hh" #include "cpu/beta_cpu/iew_impl.hh"
#include "cpu/beta_cpu/inst_queue.hh" #include "cpu/beta_cpu/inst_queue.hh"
template class SimpleIEW<AlphaSimpleImpl, AlphaSimpleImpl::CPUPol::IQ>; template class SimpleIEW<AlphaSimpleImpl>;

View file

@ -14,7 +14,7 @@
//Can IEW even stall? Space should be available/allocated already...maybe //Can IEW even stall? Space should be available/allocated already...maybe
//if there's not enough write ports on the ROB or waiting for CDB //if there's not enough write ports on the ROB or waiting for CDB
//arbitration. //arbitration.
template<class Impl, class IQ> template<class Impl>
class SimpleIEW class SimpleIEW
{ {
private: private:
@ -25,6 +25,7 @@ class SimpleIEW
typedef typename Impl::FullCPU FullCPU; typedef typename Impl::FullCPU FullCPU;
typedef typename Impl::Params Params; typedef typename Impl::Params Params;
typedef typename CPUPol::IQ IQ;
typedef typename CPUPol::RenameMap RenameMap; typedef typename CPUPol::RenameMap RenameMap;
typedef typename CPUPol::LDSTQ LDSTQ; typedef typename CPUPol::LDSTQ LDSTQ;
@ -33,6 +34,7 @@ class SimpleIEW
typedef typename CPUPol::RenameStruct RenameStruct; typedef typename CPUPol::RenameStruct RenameStruct;
typedef typename CPUPol::IssueStruct IssueStruct; typedef typename CPUPol::IssueStruct IssueStruct;
friend class Impl::FullCPU;
public: public:
enum Status { enum Status {
Running, Running,
@ -49,15 +51,17 @@ class SimpleIEW
Status _wbStatus; Status _wbStatus;
public: public:
void squash(); class WritebackEvent : public Event {
private:
DynInstPtr inst;
SimpleIEW<Impl> *iewStage;
void squashDueToBranch(DynInstPtr &inst); public:
WritebackEvent(DynInstPtr &_inst, SimpleIEW<Impl> *_iew);
void squashDueToMem(DynInstPtr &inst); virtual void process();
virtual const char *description();
void block(); };
inline void unblock();
public: public:
SimpleIEW(Params &params); SimpleIEW(Params &params);
@ -74,17 +78,30 @@ class SimpleIEW
void setRenameMap(RenameMap *rm_ptr); void setRenameMap(RenameMap *rm_ptr);
void squash();
void squashDueToBranch(DynInstPtr &inst);
void squashDueToMem(DynInstPtr &inst);
void block();
inline void unblock();
void wakeDependents(DynInstPtr &inst); void wakeDependents(DynInstPtr &inst);
void tick(); void instToCommit(DynInstPtr &inst);
void iew();
private: private:
void dispatchInsts(); void dispatchInsts();
void executeInsts(); void executeInsts();
public:
void tick();
void iew();
//Interfaces to objects inside and outside of IEW. //Interfaces to objects inside and outside of IEW.
/** Time buffer interface. */ /** Time buffer interface. */
TimeBuffer<TimeStruct> *timeBuffer; TimeBuffer<TimeStruct> *timeBuffer;
@ -121,11 +138,18 @@ class SimpleIEW
/** Skid buffer between rename and IEW. */ /** Skid buffer between rename and IEW. */
std::queue<RenameStruct> skidBuffer; std::queue<RenameStruct> skidBuffer;
protected:
/** Instruction queue. */ /** Instruction queue. */
IQ instQueue; IQ instQueue;
LDSTQ ldstQueue; LDSTQ ldstQueue;
#ifndef FULL_SYSTEM
public:
void lsqWriteback();
#endif
private:
/** Pointer to rename map. Might not want this stage to directly /** Pointer to rename map. Might not want this stage to directly
* access this though... * access this though...
*/ */

View file

@ -12,8 +12,36 @@
#include "base/timebuf.hh" #include "base/timebuf.hh"
#include "cpu/beta_cpu/iew.hh" #include "cpu/beta_cpu/iew.hh"
template<class Impl, class IQ> template<class Impl>
SimpleIEW<Impl, IQ>::SimpleIEW(Params &params) SimpleIEW<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst,
SimpleIEW<Impl> *_iew)
: Event(&mainEventQueue, CPU_Tick_Pri), inst(_inst), iewStage(_iew)
{
this->setFlags(Event::AutoDelete);
}
template<class Impl>
void
SimpleIEW<Impl>::WritebackEvent::process()
{
DPRINTF(IEW, "IEW: WRITEBACK EVENT!!!!\n");
// Need to insert instruction into queue to commit
iewStage->instToCommit(inst);
// Need to execute second half of the instruction, do actual writing to
// registers and such
inst->execute();
}
template<class Impl>
const char *
SimpleIEW<Impl>::WritebackEvent::description()
{
return "LSQ writeback event";
}
template<class Impl>
SimpleIEW<Impl>::SimpleIEW(Params &params)
: // Just make this time buffer really big for now : // Just make this time buffer really big for now
issueToExecQueue(5, 5), issueToExecQueue(5, 5),
instQueue(params), instQueue(params),
@ -36,11 +64,13 @@ SimpleIEW<Impl, IQ>::SimpleIEW(Params &params)
// Instruction queue needs the queue between issue and execute. // Instruction queue needs the queue between issue and execute.
instQueue.setIssueToExecuteQueue(&issueToExecQueue); instQueue.setIssueToExecuteQueue(&issueToExecQueue);
ldstQueue.setIEW(this);
} }
template <class Impl, class IQ> template <class Impl>
void void
SimpleIEW<Impl, IQ>::regStats() SimpleIEW<Impl>::regStats()
{ {
instQueue.regStats(); instQueue.regStats();
@ -111,9 +141,9 @@ SimpleIEW<Impl, IQ>::regStats()
.desc("Number of branches that were predicted taken incorrectly"); .desc("Number of branches that were predicted taken incorrectly");
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::setCPU(FullCPU *cpu_ptr) SimpleIEW<Impl>::setCPU(FullCPU *cpu_ptr)
{ {
DPRINTF(IEW, "IEW: Setting CPU pointer.\n"); DPRINTF(IEW, "IEW: Setting CPU pointer.\n");
cpu = cpu_ptr; cpu = cpu_ptr;
@ -122,9 +152,9 @@ SimpleIEW<Impl, IQ>::setCPU(FullCPU *cpu_ptr)
ldstQueue.setCPU(cpu_ptr); ldstQueue.setCPU(cpu_ptr);
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{ {
DPRINTF(IEW, "IEW: Setting time buffer pointer.\n"); DPRINTF(IEW, "IEW: Setting time buffer pointer.\n");
timeBuffer = tb_ptr; timeBuffer = tb_ptr;
@ -139,9 +169,9 @@ SimpleIEW<Impl, IQ>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
instQueue.setTimeBuffer(tb_ptr); instQueue.setTimeBuffer(tb_ptr);
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
{ {
DPRINTF(IEW, "IEW: Setting rename queue pointer.\n"); DPRINTF(IEW, "IEW: Setting rename queue pointer.\n");
renameQueue = rq_ptr; renameQueue = rq_ptr;
@ -150,9 +180,9 @@ SimpleIEW<Impl, IQ>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
fromRename = renameQueue->getWire(-renameToIEWDelay); fromRename = renameQueue->getWire(-renameToIEWDelay);
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
{ {
DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n"); DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n");
iewQueue = iq_ptr; iewQueue = iq_ptr;
@ -161,63 +191,17 @@ SimpleIEW<Impl, IQ>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
toCommit = iewQueue->getWire(0); toCommit = iewQueue->getWire(0);
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::setRenameMap(RenameMap *rm_ptr) SimpleIEW<Impl>::setRenameMap(RenameMap *rm_ptr)
{ {
DPRINTF(IEW, "IEW: Setting rename map pointer.\n"); DPRINTF(IEW, "IEW: Setting rename map pointer.\n");
renameMap = rm_ptr; renameMap = rm_ptr;
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::wakeDependents(DynInstPtr &inst) SimpleIEW<Impl>::squash()
{
instQueue.wakeDependents(inst);
}
template<class Impl, class IQ>
void
SimpleIEW<Impl, IQ>::block()
{
DPRINTF(IEW, "IEW: Blocking.\n");
// Set the status to Blocked.
_status = Blocked;
// Add the current inputs to the skid buffer so they can be
// reprocessed when this stage unblocks.
skidBuffer.push(*fromRename);
// Note that this stage only signals previous stages to stall when
// it is the cause of the stall originates at this stage. Otherwise
// the previous stages are expected to check all possible stall signals.
}
template<class Impl, class IQ>
inline void
SimpleIEW<Impl, IQ>::unblock()
{
// Check if there's information in the skid buffer. If there is, then
// set status to unblocking, otherwise set it directly to running.
DPRINTF(IEW, "IEW: Reading instructions out of the skid "
"buffer.\n");
// Remove the now processed instructions from the skid buffer.
skidBuffer.pop();
// If there's still information in the skid buffer, then
// continue to tell previous stages to stall. They will be
// able to restart once the skid buffer is empty.
if (!skidBuffer.empty()) {
toRename->iewInfo.stall = true;
} else {
DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
_status = Running;
}
}
template<class Impl, class IQ>
void
SimpleIEW<Impl, IQ>::squash()
{ {
DPRINTF(IEW, "IEW: Squashing all instructions.\n"); DPRINTF(IEW, "IEW: Squashing all instructions.\n");
_status = Squashing; _status = Squashing;
@ -229,9 +213,9 @@ SimpleIEW<Impl, IQ>::squash()
ldstQueue.squash(fromCommit->commitInfo.doneSeqNum); ldstQueue.squash(fromCommit->commitInfo.doneSeqNum);
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::squashDueToBranch(DynInstPtr &inst) SimpleIEW<Impl>::squashDueToBranch(DynInstPtr &inst)
{ {
DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
inst->PC); inst->PC);
@ -251,9 +235,9 @@ SimpleIEW<Impl, IQ>::squashDueToBranch(DynInstPtr &inst)
(inst->readPC() + sizeof(MachInst)); (inst->readPC() + sizeof(MachInst));
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::squashDueToMem(DynInstPtr &inst) SimpleIEW<Impl>::squashDueToMem(DynInstPtr &inst)
{ {
DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n", DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
inst->PC); inst->PC);
@ -268,9 +252,63 @@ SimpleIEW<Impl, IQ>::squashDueToMem(DynInstPtr &inst)
toCommit->nextPC = inst->readNextPC(); toCommit->nextPC = inst->readNextPC();
} }
template <class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::dispatchInsts() SimpleIEW<Impl>::block()
{
DPRINTF(IEW, "IEW: Blocking.\n");
// Set the status to Blocked.
_status = Blocked;
// Add the current inputs to the skid buffer so they can be
// reprocessed when this stage unblocks.
skidBuffer.push(*fromRename);
// Note that this stage only signals previous stages to stall when
// it is the cause of the stall originates at this stage. Otherwise
// the previous stages are expected to check all possible stall signals.
}
template<class Impl>
inline void
SimpleIEW<Impl>::unblock()
{
// Check if there's information in the skid buffer. If there is, then
// set status to unblocking, otherwise set it directly to running.
DPRINTF(IEW, "IEW: Reading instructions out of the skid "
"buffer.\n");
// Remove the now processed instructions from the skid buffer.
skidBuffer.pop();
// If there's still information in the skid buffer, then
// continue to tell previous stages to stall. They will be
// able to restart once the skid buffer is empty.
if (!skidBuffer.empty()) {
toRename->iewInfo.stall = true;
} else {
DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
_status = Running;
}
}
template<class Impl>
void
SimpleIEW<Impl>::wakeDependents(DynInstPtr &inst)
{
instQueue.wakeDependents(inst);
}
template<class Impl>
void
SimpleIEW<Impl>::instToCommit(DynInstPtr &inst)
{
}
template <class Impl>
void
SimpleIEW<Impl>::dispatchInsts()
{ {
//////////////////////////////////////// ////////////////////////////////////////
// DISPATCH/ISSUE stage // DISPATCH/ISSUE stage
@ -329,14 +367,14 @@ SimpleIEW<Impl, IQ>::dispatchInsts()
// a signal to this stage to issue and execute that // a signal to this stage to issue and execute that
// store. Change to be a bit that says the instruction // store. Change to be a bit that says the instruction
// has extra work to do at commit. // has extra work to do at commit.
inst->setCanCommit(); // inst->setCanCommit();
instQueue.insertNonSpec(inst); // instQueue.insertNonSpec(inst);
++iewDispStoreInsts; ++iewDispStoreInsts;
++iewDispNonSpecInsts; // ++iewDispNonSpecInsts;
continue; // continue;
} else if (inst->isNonSpeculative()) { } else if (inst->isNonSpeculative()) {
DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction " DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "
"encountered, skipping.\n"); "encountered, skipping.\n");
@ -385,9 +423,9 @@ SimpleIEW<Impl, IQ>::dispatchInsts()
} }
} }
template <class Impl, class IQ> template <class Impl>
void void
SimpleIEW<Impl, IQ>::executeInsts() SimpleIEW<Impl>::executeInsts()
{ {
//////////////////////////////////////// ////////////////////////////////////////
//EXECUTE/WRITEBACK stage //EXECUTE/WRITEBACK stage
@ -403,6 +441,8 @@ SimpleIEW<Impl, IQ>::executeInsts()
int fu_usage = 0; int fu_usage = 0;
bool fetch_redirect = false; bool fetch_redirect = false;
int inst_slot = 0;
int time_slot = 0;
// Execute/writeback any instructions that are available. // Execute/writeback any instructions that are available.
for (int inst_num = 0; for (int inst_num = 0;
@ -452,7 +492,7 @@ SimpleIEW<Impl, IQ>::executeInsts()
++iewExecLoadInsts; ++iewExecLoadInsts;
} else if (inst->isStore()) { } else if (inst->isStore()) {
ldstQueue.executeStore(); ldstQueue.executeStore(inst);
++iewExecStoreInsts; ++iewExecStoreInsts;
} else { } else {
@ -473,9 +513,23 @@ SimpleIEW<Impl, IQ>::executeInsts()
// For now naively assume that all instructions take one cycle. // For now naively assume that all instructions take one cycle.
// Otherwise would have to look into the time buffer based on the // Otherwise would have to look into the time buffer based on the
// latency of the instruction. // latency of the instruction.
(*iewQueue)[time_slot].insts[inst_slot];
while ((*iewQueue)[time_slot].insts[inst_slot]) {
if (inst_slot < issueWidth) {
++inst_slot;
} else {
++time_slot;
inst_slot = 0;
}
assert(time_slot < 5);
}
// May actually have to work this out, especially with loads and stores
// Add finished instruction to queue to commit. // Add finished instruction to queue to commit.
toCommit->insts[inst_num] = inst; (*iewQueue)[time_slot].insts[inst_slot] = inst;
(*iewQueue)[time_slot].size++;
// Check if branch was correct. This check happens after the // Check if branch was correct. This check happens after the
// instruction is added to the queue because even if the branch // instruction is added to the queue because even if the branch
@ -518,9 +572,9 @@ SimpleIEW<Impl, IQ>::executeInsts()
} }
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::tick() SimpleIEW<Impl>::tick()
{ {
// Considering putting all the state-determining stuff in this section. // Considering putting all the state-determining stuff in this section.
@ -594,14 +648,20 @@ SimpleIEW<Impl, IQ>::tick()
// Write back number of free IQ entries here. // Write back number of free IQ entries here.
toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries(); toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries();
ldstQueue.writebackStores();
// Check the committed load/store signals to see if there's a load // Check the committed load/store signals to see if there's a load
// or store to commit. Also check if it's being told to execute a // or store to commit. Also check if it's being told to execute a
// nonspeculative instruction. // nonspeculative instruction.
if (fromCommit->commitInfo.commitIsStore) { // This is pretty inefficient...
// if (0/*fromCommit->commitInfo.commitIsStore*/) {
if (!fromCommit->commitInfo.squash &&
!fromCommit->commitInfo.robSquashing) {
ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum); ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum);
} else if (fromCommit->commitInfo.commitIsLoad) { // } else if (fromCommit->commitInfo.commitIsLoad) {
ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum); ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum);
} }
// }
if (fromCommit->commitInfo.nonSpecSeqNum != 0) { if (fromCommit->commitInfo.nonSpecSeqNum != 0) {
instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum); instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum);
@ -611,9 +671,9 @@ SimpleIEW<Impl, IQ>::tick()
instQueue.numFreeEntries()); instQueue.numFreeEntries());
} }
template<class Impl, class IQ> template<class Impl>
void void
SimpleIEW<Impl, IQ>::iew() SimpleIEW<Impl>::iew()
{ {
// Might want to put all state checks in the tick() function. // Might want to put all state checks in the tick() function.
// Check if being told to stall from commit. // Check if being told to stall from commit.
@ -663,3 +723,12 @@ SimpleIEW<Impl, IQ>::iew()
// Not the best place for it, but this works (hopefully). // Not the best place for it, but this works (hopefully).
issueToExecQueue.advance(); issueToExecQueue.advance();
} }
#ifndef FULL_SYSTEM
template<class Impl>
void
SimpleIEW<Impl>::lsqWriteback()
{
ldstQueue.writebackAllInsts();
}
#endif

View file

@ -174,7 +174,7 @@ class InstructionQueue
* once the IQ gets a signal from commit. While it's redundant to * once the IQ gets a signal from commit. While it's redundant to
* have the key be a part of the value (the sequence number is stored * have the key be a part of the value (the sequence number is stored
* inside of DynInst), when these instructions are woken up only * inside of DynInst), when these instructions are woken up only
* the sequence number will be available. Thus it is necessary to be * the sequence number will be available. Thus it is most efficient to be
* able to search by the sequence number alone. * able to search by the sequence number alone.
*/ */
std::map<InstSeqNum, DynInstPtr> nonSpecInsts; std::map<InstSeqNum, DynInstPtr> nonSpecInsts;

View file

@ -31,8 +31,6 @@ InstructionQueue<Impl>::InstructionQueue(Params &params)
numPhysFloatRegs(params.numPhysFloatRegs), numPhysFloatRegs(params.numPhysFloatRegs),
commitToIEWDelay(params.commitToIEWDelay) commitToIEWDelay(params.commitToIEWDelay)
{ {
DPRINTF(IQ, "IQ: Int width is %i.\n", params.executeIntWidth);
// Initialize the number of free IQ entries. // Initialize the number of free IQ entries.
freeEntries = numEntries; freeEntries = numEntries;
@ -291,10 +289,6 @@ InstructionQueue<Impl>::insertNonSpec(DynInstPtr &inst)
// Decrease the number of free entries. // Decrease the number of free entries.
--freeEntries; --freeEntries;
// Look through its source registers (physical regs), and mark any
// dependencies.
// addToDependents(inst);
// Have this instruction set itself as the producer of its destination // Have this instruction set itself as the producer of its destination
// register(s). // register(s).
createDependency(inst); createDependency(inst);
@ -568,15 +562,20 @@ InstructionQueue<Impl>::scheduleReadyInsts()
break; break;
case Squashed: case Squashed:
issuing_inst = squashed_head_inst; // issuing_inst = squashed_head_inst;
assert(0 && "Squashed insts should not issue any more!");
squashedInsts.pop(); squashedInsts.pop();
// Set the squashed instruction as able to commit so that commit
// can just drop it from the ROB. This is a bit faked.
++squashed_issued; ++squashed_issued;
++freeEntries;
DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n", DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n",
issuing_inst->readPC()); squashed_head_inst->readPC());
break; break;
} }
if (list_with_oldest != None) { if (list_with_oldest != None && list_with_oldest != Squashed) {
i2e_info->insts[total_issued] = issuing_inst; i2e_info->insts[total_issued] = issuing_inst;
i2e_info->size++; i2e_info->size++;
@ -641,8 +640,10 @@ InstructionQueue<Impl>::squash()
// Setup the squash iterator to point to the tail. // Setup the squash iterator to point to the tail.
squashIt = tail; squashIt = tail;
// Call doSquash. // Call doSquash if there are insts in the IQ
doSquash(); if (freeEntries != numEntries) {
doSquash();
}
// Also tell the memory dependence unit to squash. // Also tell the memory dependence unit to squash.
memDepUnit.squash(squashedSeqNum); memDepUnit.squash(squashedSeqNum);
@ -672,12 +673,12 @@ InstructionQueue<Impl>::doSquash()
// Remove the instruction from the dependency list. // Remove the instruction from the dependency list.
// Hack for now: These below don't add themselves to the // Hack for now: These below don't add themselves to the
// dependency list, so don't try to remove them. // dependency list, so don't try to remove them.
if (!squashed_inst->isNonSpeculative() && if (!squashed_inst->isNonSpeculative()/* &&
!squashed_inst->isStore()) { !squashed_inst->isStore()*/
int8_t total_src_regs = squashed_inst->numSrcRegs(); ) {
for (int src_reg_idx = 0; for (int src_reg_idx = 0;
src_reg_idx < total_src_regs; src_reg_idx < squashed_inst->numSrcRegs();
src_reg_idx++) src_reg_idx++)
{ {
PhysRegIndex src_reg = PhysRegIndex src_reg =
@ -699,6 +700,8 @@ InstructionQueue<Impl>::doSquash()
// Might want to remove producers as well. // Might want to remove producers as well.
} else { } else {
nonSpecInsts[squashed_inst->seqNum] = NULL;
nonSpecInsts.erase(squashed_inst->seqNum); nonSpecInsts.erase(squashed_inst->seqNum);
++iqSquashedNonSpecRemoved; ++iqSquashedNonSpecRemoved;
@ -709,7 +712,11 @@ InstructionQueue<Impl>::doSquash()
// Mark it as squashed within the IQ. // Mark it as squashed within the IQ.
squashed_inst->setSquashedInIQ(); squashed_inst->setSquashedInIQ();
squashedInsts.push(squashed_inst); // squashedInsts.push(squashed_inst);
squashed_inst->setIssued();
squashed_inst->setCanCommit();
++freeEntries;
DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n", DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
squashed_inst->readPC()); squashed_inst->readPC());
@ -718,6 +725,13 @@ InstructionQueue<Impl>::doSquash()
--squashIt; --squashIt;
++iqSquashedInstsExamined; ++iqSquashedInstsExamined;
} }
assert(freeEntries <= numEntries);
if (freeEntries == numEntries) {
tail = cpu->instList.end();
}
} }
template <class Impl> template <class Impl>
@ -739,8 +753,6 @@ InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
//Look at the physical destination register of the DynInst //Look at the physical destination register of the DynInst
//and look it up on the dependency graph. Then mark as ready //and look it up on the dependency graph. Then mark as ready
//any instructions within the instruction queue. //any instructions within the instruction queue.
int8_t total_dest_regs = completed_inst->numDestRegs();
DependencyEntry *curr; DependencyEntry *curr;
// Tell the memory dependence unit to wake any dependents on this // Tell the memory dependence unit to wake any dependents on this
@ -751,7 +763,7 @@ InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
} }
for (int dest_reg_idx = 0; for (int dest_reg_idx = 0;
dest_reg_idx < total_dest_regs; dest_reg_idx < completed_inst->numDestRegs();
dest_reg_idx++) dest_reg_idx++)
{ {
PhysRegIndex dest_reg = PhysRegIndex dest_reg =
@ -759,7 +771,7 @@ InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
// Special case of uniq or control registers. They are not // Special case of uniq or control registers. They are not
// handled by the IQ and thus have no dependency graph entry. // handled by the IQ and thus have no dependency graph entry.
// @todo Figure out a cleaner way to handle thie. // @todo Figure out a cleaner way to handle this.
if (dest_reg >= numPhysRegs) { if (dest_reg >= numPhysRegs) {
continue; continue;
} }
@ -789,6 +801,8 @@ InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
DependencyEntry::mem_alloc_counter--; DependencyEntry::mem_alloc_counter--;
curr->inst = NULL;
delete curr; delete curr;
} }
@ -874,7 +888,10 @@ InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
dependGraph[dest_reg].inst = new_inst; dependGraph[dest_reg].inst = new_inst;
assert(!dependGraph[dest_reg].next); if (dependGraph[dest_reg].next) {
dumpDependGraph();
panic("IQ: Dependency graph not empty!");
}
// Mark the scoreboard to say it's not yet ready. // Mark the scoreboard to say it's not yet ready.
regScoreboard[dest_reg] = false; regScoreboard[dest_reg] = false;
@ -929,36 +946,12 @@ InstructionQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove)
--mem_alloc_counter; --mem_alloc_counter;
// Could push this off to the destructor of DependencyEntry
curr->inst = NULL;
delete curr; delete curr;
} }
template <class Impl>
void
InstructionQueue<Impl>::dumpDependGraph()
{
DependencyEntry *curr;
for (int i = 0; i < numPhysRegs; ++i)
{
curr = &dependGraph[i];
if (curr->inst) {
cprintf("dependGraph[%i]: producer: %#x consumer: ", i,
curr->inst->readPC());
} else {
cprintf("dependGraph[%i]: No producer. consumer: ", i);
}
while (curr->next != NULL) {
curr = curr->next;
cprintf("%#x ", curr->inst->readPC());
}
cprintf("\n");
}
}
template <class Impl> template <class Impl>
void void
InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) InstructionQueue<Impl>::addIfReady(DynInstPtr &inst)
@ -1024,6 +1017,12 @@ InstructionQueue<Impl>::addIfReady(DynInstPtr &inst)
} }
} }
/*
* Caution, this function must not be called prior to tail being updated at
* least once, otherwise it will fail the assertion. This is because
* instList.begin() actually changes upon the insertion of an element into the
* list when the list is empty.
*/
template <class Impl> template <class Impl>
int int
InstructionQueue<Impl>::countInsts() InstructionQueue<Impl>::countInsts()
@ -1031,6 +1030,9 @@ InstructionQueue<Impl>::countInsts()
ListIt count_it = cpu->instList.begin(); ListIt count_it = cpu->instList.begin();
int total_insts = 0; int total_insts = 0;
if (tail == cpu->instList.end())
return 0;
while (count_it != tail) { while (count_it != tail) {
if (!(*count_it)->isIssued()) { if (!(*count_it)->isIssued()) {
++total_insts; ++total_insts;
@ -1051,6 +1053,33 @@ InstructionQueue<Impl>::countInsts()
return total_insts; return total_insts;
} }
template <class Impl>
void
InstructionQueue<Impl>::dumpDependGraph()
{
DependencyEntry *curr;
for (int i = 0; i < numPhysRegs; ++i)
{
curr = &dependGraph[i];
if (curr->inst) {
cprintf("dependGraph[%i]: producer: %#x consumer: ", i,
curr->inst->readPC());
} else {
cprintf("dependGraph[%i]: No producer. consumer: ", i);
}
while (curr->next != NULL) {
curr = curr->next;
cprintf("%#x ", curr->inst->readPC());
}
cprintf("\n");
}
}
template <class Impl> template <class Impl>
void void
InstructionQueue<Impl>::dumpLists() InstructionQueue<Impl>::dumpLists()

View file

@ -1,18 +1,26 @@
#ifndef __REGFILE_HH__ #ifndef __CPU_BETA_CPU_REGFILE_HH__
#define __REGFILE_HH__ #define __CPU_BETA_CPU_REGFILE_HH__
// @todo: Destructor // @todo: Destructor
#include "arch/alpha/isa_traits.hh" #include "arch/alpha/isa_traits.hh"
#include "base/trace.hh"
#include "cpu/beta_cpu/comm.hh" #include "cpu/beta_cpu/comm.hh"
#include "base/trace.hh" #ifdef FULL_SYSTEM
#include "kern/kernel_stats.hh"
#include "arch/alpha/ev5.hh"
using namespace EV5;
#endif
// This really only depends on the ISA, and not the Impl. It might be nicer // This really only depends on the ISA, and not the Impl. It might be nicer
// to see if I can make it depend on nothing... // to see if I can make it depend on nothing...
// Things that are in the ifdef FULL_SYSTEM are pretty dependent on the ISA, // Things that are in the ifdef FULL_SYSTEM are pretty dependent on the ISA,
// and should go in the AlphaFullCPU. // and should go in the AlphaFullCPU.
extern void debug_break();
template <class Impl> template <class Impl>
class PhysRegFile class PhysRegFile
{ {
@ -27,6 +35,7 @@ class PhysRegFile
//be private eventually with some accessor functions. //be private eventually with some accessor functions.
public: public:
typedef typename Impl::ISA ISA; typedef typename Impl::ISA ISA;
typedef typename Impl::FullCPU FullCPU;
PhysRegFile(unsigned _numPhysicalIntRegs, PhysRegFile(unsigned _numPhysicalIntRegs,
unsigned _numPhysicalFloatRegs); unsigned _numPhysicalFloatRegs);
@ -177,6 +186,7 @@ class PhysRegFile
#ifdef FULL_SYSTEM #ifdef FULL_SYSTEM
uint64_t readIpr(int idx, Fault &fault); uint64_t readIpr(int idx, Fault &fault);
Fault setIpr(int idx, uint64_t val); Fault setIpr(int idx, uint64_t val);
InternalProcReg *getIpr() { return ipr; }
int readIntrFlag() { return intrflag; } int readIntrFlag() { return intrflag; }
void setIntrFlag(int val) { intrflag = val; } void setIntrFlag(int val) { intrflag = val; }
#endif #endif
@ -196,7 +206,21 @@ class PhysRegFile
Addr pc; // program counter Addr pc; // program counter
Addr npc; // next-cycle program counter Addr npc; // next-cycle program counter
#ifdef FULL_SYSTEM
private: private:
// This is ISA specifc stuff; remove it eventually once ISAImpl is used
IntReg palregs[NumIntRegs]; // PAL shadow registers
InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs
int intrflag; // interrupt flag
bool pal_shadow; // using pal_shadow registers
#endif
private:
FullCPU *cpu;
public:
void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; }
unsigned numPhysicalIntRegs; unsigned numPhysicalIntRegs;
unsigned numPhysicalFloatRegs; unsigned numPhysicalFloatRegs;
}; };
@ -269,46 +293,42 @@ PhysRegFile<Impl>::readIpr(int idx, Fault &fault)
case ISA::IPR_IPLR: case ISA::IPR_IPLR:
case ISA::IPR_INTID: case ISA::IPR_INTID:
case ISA::IPR_PMCTR: case ISA::IPR_PMCTR:
// no side-effect // no side-effect
retval = ipr[idx]; retval = ipr[idx];
break; break;
case ISA::IPR_CC: case ISA::IPR_CC:
retval |= ipr[idx] & ULL(0xffffffff00000000); retval |= ipr[idx] & ULL(0xffffffff00000000);
retval |= curTick & ULL(0x00000000ffffffff); retval |= curTick & ULL(0x00000000ffffffff);
break; break;
case ISA::IPR_VA: case ISA::IPR_VA:
// SFX: unlocks interrupt status registers retval = ipr[idx];
retval = ipr[idx]; break;
if (!misspeculating())
regs.intrlock = false;
break;
case ISA::IPR_VA_FORM: case ISA::IPR_VA_FORM:
case ISA::IPR_MM_STAT: case ISA::IPR_MM_STAT:
case ISA::IPR_IFAULT_VA_FORM: case ISA::IPR_IFAULT_VA_FORM:
case ISA::IPR_EXC_MASK: case ISA::IPR_EXC_MASK:
case ISA::IPR_EXC_SUM: case ISA::IPR_EXC_SUM:
retval = ipr[idx]; retval = ipr[idx];
break; break;
case ISA::IPR_DTB_PTE: case ISA::IPR_DTB_PTE:
{ {
ISA::PTE &pte = dtb->index(!misspeculating()); typename ISA::PTE &pte = cpu->dtb->index(1);
retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32;
retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8;
retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12;
retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1;
retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2;
retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4;
retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57;
} }
break; break;
// write only registers // write only registers
case ISA::IPR_HWINT_CLR: case ISA::IPR_HWINT_CLR:
case ISA::IPR_SL_XMIT: case ISA::IPR_SL_XMIT:
case ISA::IPR_DC_FLUSH: case ISA::IPR_DC_FLUSH:
@ -318,22 +338,19 @@ PhysRegFile<Impl>::readIpr(int idx, Fault &fault)
case ISA::IPR_DTB_IAP: case ISA::IPR_DTB_IAP:
case ISA::IPR_ITB_IA: case ISA::IPR_ITB_IA:
case ISA::IPR_ITB_IAP: case ISA::IPR_ITB_IAP:
fault = Unimplemented_Opcode_Fault; fault = Unimplemented_Opcode_Fault;
break; break;
default: default:
// invalid IPR // invalid IPR
fault = Unimplemented_Opcode_Fault; fault = Unimplemented_Opcode_Fault;
break; break;
} }
return retval; return retval;
} }
#ifdef DEBUG extern int break_ipl;
// Cause the simulator to break when changing to the following IPL
int break_ipl = -1;
#endif
template <class Impl> template <class Impl>
Fault Fault
@ -341,9 +358,6 @@ PhysRegFile<Impl>::setIpr(int idx, uint64_t val)
{ {
uint64_t old; uint64_t old;
if (misspeculating())
return No_Fault;
switch (idx) { switch (idx) {
case ISA::IPR_PALtemp0: case ISA::IPR_PALtemp0:
case ISA::IPR_PALtemp1: case ISA::IPR_PALtemp1:
@ -372,222 +386,225 @@ PhysRegFile<Impl>::setIpr(int idx, uint64_t val)
case ISA::IPR_IC_PERR_STAT: case ISA::IPR_IC_PERR_STAT:
case ISA::IPR_DC_PERR_STAT: case ISA::IPR_DC_PERR_STAT:
case ISA::IPR_PMCTR: case ISA::IPR_PMCTR:
// write entire quad w/ no side-effect // write entire quad w/ no side-effect
ipr[idx] = val; ipr[idx] = val;
break; break;
case ISA::IPR_CC_CTL: case ISA::IPR_CC_CTL:
// This IPR resets the cycle counter. We assume this only // This IPR resets the cycle counter. We assume this only
// happens once... let's verify that. // happens once... let's verify that.
assert(ipr[idx] == 0); assert(ipr[idx] == 0);
ipr[idx] = 1; ipr[idx] = 1;
break; break;
case ISA::IPR_CC: case ISA::IPR_CC:
// This IPR only writes the upper 64 bits. It's ok to write // This IPR only writes the upper 64 bits. It's ok to write
// all 64 here since we mask out the lower 32 in rpcc (see // all 64 here since we mask out the lower 32 in rpcc (see
// isa_desc). // isa_desc).
ipr[idx] = val; ipr[idx] = val;
break; break;
case ISA::IPR_PALtemp23: case ISA::IPR_PALtemp23:
// write entire quad w/ no side-effect // write entire quad w/ no side-effect
old = ipr[idx]; old = ipr[idx];
ipr[idx] = val; ipr[idx] = val;
kernelStats.context(old, val); // kernelStats.context(old, val);
break; break;
case ISA::IPR_DTB_PTE: case ISA::IPR_DTB_PTE:
// write entire quad w/ no side-effect, tag is forthcoming // write entire quad w/ no side-effect, tag is forthcoming
ipr[idx] = val; ipr[idx] = val;
break; break;
case ISA::IPR_EXC_ADDR: case ISA::IPR_EXC_ADDR:
// second least significant bit in PC is always zero // second least significant bit in PC is always zero
ipr[idx] = val & ~2; ipr[idx] = val & ~2;
break; break;
case ISA::IPR_ASTRR: case ISA::IPR_ASTRR:
case ISA::IPR_ASTER: case ISA::IPR_ASTER:
// only write least significant four bits - privilege mask // only write least significant four bits - privilege mask
ipr[idx] = val & 0xf; ipr[idx] = val & 0xf;
break; break;
case ISA::IPR_IPLR: case ISA::IPR_IPLR:
#ifdef DEBUG #ifdef DEBUG
if (break_ipl != -1 && break_ipl == (val & 0x1f)) if (break_ipl != -1 && break_ipl == (val & 0x1f))
debug_break(); debug_break();
#endif #endif
// only write least significant five bits - interrupt level // only write least significant five bits - interrupt level
ipr[idx] = val & 0x1f; ipr[idx] = val & 0x1f;
kernelStats.swpipl(ipr[idx]); // kernelStats.swpipl(ipr[idx]);
break; break;
case ISA::IPR_DTB_CM: case ISA::IPR_DTB_CM:
kernelStats.mode((val & 0x18) != 0); // if (val & 0x18)
// kernelStats->mode(Kernel::user);
// else
// kernelStats->mode(Kernel::kernel);
case ISA::IPR_ICM: case ISA::IPR_ICM:
// only write two mode bits - processor mode // only write two mode bits - processor mode
ipr[idx] = val & 0x18; ipr[idx] = val & 0x18;
break; break;
case ISA::IPR_ALT_MODE: case ISA::IPR_ALT_MODE:
// only write two mode bits - processor mode // only write two mode bits - processor mode
ipr[idx] = val & 0x18; ipr[idx] = val & 0x18;
break; break;
case ISA::IPR_MCSR: case ISA::IPR_MCSR:
// more here after optimization... // more here after optimization...
ipr[idx] = val; ipr[idx] = val;
break; break;
case ISA::IPR_SIRR: case ISA::IPR_SIRR:
// only write software interrupt mask // only write software interrupt mask
ipr[idx] = val & 0x7fff0; ipr[idx] = val & 0x7fff0;
break; break;
case ISA::IPR_ICSR: case ISA::IPR_ICSR:
ipr[idx] = val & ULL(0xffffff0300); ipr[idx] = val & ULL(0xffffff0300);
break; break;
case ISA::IPR_IVPTBR: case ISA::IPR_IVPTBR:
case ISA::IPR_MVPTBR: case ISA::IPR_MVPTBR:
ipr[idx] = val & ULL(0xffffffffc0000000); ipr[idx] = val & ULL(0xffffffffc0000000);
break; break;
case ISA::IPR_DC_TEST_CTL: case ISA::IPR_DC_TEST_CTL:
ipr[idx] = val & 0x1ffb; ipr[idx] = val & 0x1ffb;
break; break;
case ISA::IPR_DC_MODE: case ISA::IPR_DC_MODE:
case ISA::IPR_MAF_MODE: case ISA::IPR_MAF_MODE:
ipr[idx] = val & 0x3f; ipr[idx] = val & 0x3f;
break; break;
case ISA::IPR_ITB_ASN: case ISA::IPR_ITB_ASN:
ipr[idx] = val & 0x7f0; ipr[idx] = val & 0x7f0;
break; break;
case ISA::IPR_DTB_ASN: case ISA::IPR_DTB_ASN:
ipr[idx] = val & ULL(0xfe00000000000000); ipr[idx] = val & ULL(0xfe00000000000000);
break; break;
case ISA::IPR_EXC_SUM: case ISA::IPR_EXC_SUM:
case ISA::IPR_EXC_MASK: case ISA::IPR_EXC_MASK:
// any write to this register clears it // any write to this register clears it
ipr[idx] = 0; ipr[idx] = 0;
break; break;
case ISA::IPR_INTID: case ISA::IPR_INTID:
case ISA::IPR_SL_RCV: case ISA::IPR_SL_RCV:
case ISA::IPR_MM_STAT: case ISA::IPR_MM_STAT:
case ISA::IPR_ITB_PTE_TEMP: case ISA::IPR_ITB_PTE_TEMP:
case ISA::IPR_DTB_PTE_TEMP: case ISA::IPR_DTB_PTE_TEMP:
// read-only registers // read-only registers
return Unimplemented_Opcode_Fault; return Unimplemented_Opcode_Fault;
case ISA::IPR_HWINT_CLR: case ISA::IPR_HWINT_CLR:
case ISA::IPR_SL_XMIT: case ISA::IPR_SL_XMIT:
case ISA::IPR_DC_FLUSH: case ISA::IPR_DC_FLUSH:
case ISA::IPR_IC_FLUSH: case ISA::IPR_IC_FLUSH:
// the following are write only // the following are write only
ipr[idx] = val; ipr[idx] = val;
break; break;
case ISA::IPR_DTB_IA: case ISA::IPR_DTB_IA:
// really a control write // really a control write
ipr[idx] = 0; ipr[idx] = 0;
dtb->flushAll(); cpu->dtb->flushAll();
break; break;
case ISA::IPR_DTB_IAP: case ISA::IPR_DTB_IAP:
// really a control write // really a control write
ipr[idx] = 0; ipr[idx] = 0;
dtb->flushProcesses(); cpu->dtb->flushProcesses();
break; break;
case ISA::IPR_DTB_IS: case ISA::IPR_DTB_IS:
// really a control write // really a control write
ipr[idx] = val; ipr[idx] = val;
dtb->flushAddr(val, DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN])); cpu->dtb->flushAddr(val, DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN]));
break; break;
case ISA::IPR_DTB_TAG: { case ISA::IPR_DTB_TAG: {
struct ISA::PTE pte; struct ISA::PTE pte;
// FIXME: granularity hints NYI... // FIXME: granularity hints NYI...
if (DTB_PTE_GH(ipr[ISA::IPR_DTB_PTE]) != 0) if (DTB_PTE_GH(ipr[ISA::IPR_DTB_PTE]) != 0)
panic("PTE GH field != 0"); panic("PTE GH field != 0");
// write entire quad // write entire quad
ipr[idx] = val; ipr[idx] = val;
// construct PTE for new entry // construct PTE for new entry
pte.ppn = DTB_PTE_PPN(ipr[ISA::IPR_DTB_PTE]); pte.ppn = DTB_PTE_PPN(ipr[ISA::IPR_DTB_PTE]);
pte.xre = DTB_PTE_XRE(ipr[ISA::IPR_DTB_PTE]); pte.xre = DTB_PTE_XRE(ipr[ISA::IPR_DTB_PTE]);
pte.xwe = DTB_PTE_XWE(ipr[ISA::IPR_DTB_PTE]); pte.xwe = DTB_PTE_XWE(ipr[ISA::IPR_DTB_PTE]);
pte.fonr = DTB_PTE_FONR(ipr[ISA::IPR_DTB_PTE]); pte.fonr = DTB_PTE_FONR(ipr[ISA::IPR_DTB_PTE]);
pte.fonw = DTB_PTE_FONW(ipr[ISA::IPR_DTB_PTE]); pte.fonw = DTB_PTE_FONW(ipr[ISA::IPR_DTB_PTE]);
pte.asma = DTB_PTE_ASMA(ipr[ISA::IPR_DTB_PTE]); pte.asma = DTB_PTE_ASMA(ipr[ISA::IPR_DTB_PTE]);
pte.asn = DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN]); pte.asn = DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN]);
// insert new TAG/PTE value into data TLB // insert new TAG/PTE value into data TLB
dtb->insert(val, pte); cpu->dtb->insert(val, pte);
} }
break; break;
case ISA::IPR_ITB_PTE: { case ISA::IPR_ITB_PTE: {
struct ISA::PTE pte; struct ISA::PTE pte;
// FIXME: granularity hints NYI... // FIXME: granularity hints NYI...
if (ITB_PTE_GH(val) != 0) if (ITB_PTE_GH(val) != 0)
panic("PTE GH field != 0"); panic("PTE GH field != 0");
// write entire quad // write entire quad
ipr[idx] = val; ipr[idx] = val;
// construct PTE for new entry // construct PTE for new entry
pte.ppn = ITB_PTE_PPN(val); pte.ppn = ITB_PTE_PPN(val);
pte.xre = ITB_PTE_XRE(val); pte.xre = ITB_PTE_XRE(val);
pte.xwe = 0; pte.xwe = 0;
pte.fonr = ITB_PTE_FONR(val); pte.fonr = ITB_PTE_FONR(val);
pte.fonw = ITB_PTE_FONW(val); pte.fonw = ITB_PTE_FONW(val);
pte.asma = ITB_PTE_ASMA(val); pte.asma = ITB_PTE_ASMA(val);
pte.asn = ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN]); pte.asn = ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN]);
// insert new TAG/PTE value into data TLB // insert new TAG/PTE value into data TLB
itb->insert(ipr[ISA::IPR_ITB_TAG], pte); cpu->itb->insert(ipr[ISA::IPR_ITB_TAG], pte);
} }
break; break;
case ISA::IPR_ITB_IA: case ISA::IPR_ITB_IA:
// really a control write // really a control write
ipr[idx] = 0; ipr[idx] = 0;
itb->flushAll(); cpu->itb->flushAll();
break; break;
case ISA::IPR_ITB_IAP: case ISA::IPR_ITB_IAP:
// really a control write // really a control write
ipr[idx] = 0; ipr[idx] = 0;
itb->flushProcesses(); cpu->itb->flushProcesses();
break; break;
case ISA::IPR_ITB_IS: case ISA::IPR_ITB_IS:
// really a control write // really a control write
ipr[idx] = val; ipr[idx] = val;
itb->flushAddr(val, ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN])); cpu->itb->flushAddr(val, ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN]));
break; break;
default: default:
// invalid IPR // invalid IPR
return Unimplemented_Opcode_Fault; return Unimplemented_Opcode_Fault;
} }
// no error... // no error...
@ -596,4 +613,4 @@ PhysRegFile<Impl>::setIpr(int idx, uint64_t val)
#endif // #ifdef FULL_SYSTEM #endif // #ifdef FULL_SYSTEM
#endif // __REGFILE_HH__ #endif // __CPU_BETA_CPU_REGFILE_HH__

View file

@ -10,8 +10,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
//#include "arch/alpha/isa_traits.hh"
/** /**
* ROB class. Uses the instruction list that exists within the CPU to * ROB class. Uses the instruction list that exists within the CPU to
* represent the ROB. This class doesn't contain that list, but instead * represent the ROB. This class doesn't contain that list, but instead

View file

@ -1,5 +1,5 @@
#ifndef __ROB_IMPL_HH__ #ifndef __CPU_BETA_CPU_ROB_IMPL_HH__
#define __ROB_IMPL_HH__ #define __CPU_BETA_CPU_ROB_IMPL_HH__
#include "cpu/beta_cpu/rob.hh" #include "cpu/beta_cpu/rob.hh"
@ -107,10 +107,8 @@ ROB<Impl>::retireHead()
assert(numInstsInROB == countInsts()); assert(numInstsInROB == countInsts());
assert(numInstsInROB > 0); assert(numInstsInROB > 0);
DynInstPtr head_inst;
// Get the head ROB instruction. // Get the head ROB instruction.
head_inst = cpu->instList.front(); DynInstPtr head_inst = cpu->instList.front();
// Make certain this can retire. // Make certain this can retire.
assert(head_inst->readyToCommit()); assert(head_inst->readyToCommit());
@ -126,11 +124,10 @@ ROB<Impl>::retireHead()
// A special case is needed if the instruction being retired is the // A special case is needed if the instruction being retired is the
// only instruction in the ROB; otherwise the tail iterator will become // only instruction in the ROB; otherwise the tail iterator will become
// invalidated. // invalidated.
if (tail == cpu->instList.begin()) { cpu->removeFrontInst(head_inst);
cpu->removeFrontInst(head_inst);
if (numInstsInROB == 0) {
tail = cpu->instList.end(); tail = cpu->instList.end();
} else {
cpu->removeFrontInst(head_inst);
} }
} }
@ -283,4 +280,4 @@ ROB<Impl>::readTailSeqNum()
return (*tail)->seqNum; return (*tail)->seqNum;
} }
#endif // __ROB_IMPL_HH__ #endif // __CPU_BETA_CPU_ROB_IMPL_HH__

View file

@ -122,7 +122,7 @@ class OoOCPU : public BaseCPU
enum Status { enum Status {
Running, Running,
Idle, Idle,
IcacheMissStall, IcacheMiss,
IcacheMissComplete, IcacheMissComplete,
DcacheMissStall, DcacheMissStall,
SwitchedOut SwitchedOut
@ -161,6 +161,8 @@ class OoOCPU : public BaseCPU
virtual ~OoOCPU(); virtual ~OoOCPU();
void init();
private: private:
void copyFromXC(); void copyFromXC();
@ -203,14 +205,21 @@ class OoOCPU : public BaseCPU
// Will need to create a cache completion event upon any memory miss. // Will need to create a cache completion event upon any memory miss.
ICacheCompletionEvent iCacheCompletionEvent; ICacheCompletionEvent iCacheCompletionEvent;
class DCacheCompletionEvent;
typedef typename
std::list<DCacheCompletionEvent>::iterator DCacheCompEventIt;
class DCacheCompletionEvent : public Event class DCacheCompletionEvent : public Event
{ {
private: private:
OoOCPU *cpu; OoOCPU *cpu;
DynInstPtr inst; DynInstPtr inst;
DCacheCompEventIt dcceIt;
public: public:
DCacheCompletionEvent(OoOCPU *_cpu, DynInstPtr &_inst); DCacheCompletionEvent(OoOCPU *_cpu, DynInstPtr &_inst,
DCacheCompEventIt &_dcceIt);
virtual void process(); virtual void process();
virtual const char *description(); virtual const char *description();
@ -218,6 +227,11 @@ class OoOCPU : public BaseCPU
friend class DCacheCompletionEvent; friend class DCacheCompletionEvent;
protected:
std::list<DCacheCompletionEvent> dCacheCompList;
DCacheCompEventIt dcceIt;
private:
Status status() const { return _status; } Status status() const { return _status; }
virtual void activateContext(int thread_num, int delay); virtual void activateContext(int thread_num, int delay);
@ -260,6 +274,8 @@ class OoOCPU : public BaseCPU
void processICacheCompletion(); void processICacheCompletion();
public:
virtual void serialize(std::ostream &os); virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section); virtual void unserialize(Checkpoint *cp, const std::string &section);
@ -350,7 +366,7 @@ class OoOCPU : public BaseCPU
void commitHeadInst(); void commitHeadInst();
bool grabInst(); bool getOneInst();
Fault fetchCacheLine(); Fault fetchCacheLine();
@ -471,6 +487,7 @@ class OoOCPU : public BaseCPU
// ROB tracking stuff. // ROB tracking stuff.
DynInstPtr robHeadPtr; DynInstPtr robHeadPtr;
DynInstPtr robTailPtr; DynInstPtr robTailPtr;
unsigned robSize;
unsigned robInsts; unsigned robInsts;
// List of outstanding EA instructions. // List of outstanding EA instructions.
@ -545,10 +562,8 @@ OoOCPU<Impl>::read(Addr addr, T &data, unsigned flags, DynInstPtr inst)
/*MemAccessResult result = */dcacheInterface->access(readReq); /*MemAccessResult result = */dcacheInterface->access(readReq);
if (dcacheInterface->doEvents()) { if (dcacheInterface->doEvents()) {
readReq->completionEvent = new DCacheCompletionEvent(this, inst); readReq->completionEvent = new DCacheCompletionEvent(this, inst,
lastDcacheStall = curTick; dcceIt);
unscheduleTickEvent();
_status = DcacheMissStall;
} }
} }
@ -579,7 +594,7 @@ OoOCPU<Impl>::write(T data, Addr addr, unsigned flags,
writeReq->reset(addr, sizeof(T), flags); writeReq->reset(addr, sizeof(T), flags);
// translate to physical address // translate to physical address
Fault fault = xc->translateDataWriteReq(writeReq); Fault fault = translateDataWriteReq(writeReq);
// do functional access // do functional access
if (fault == No_Fault) if (fault == No_Fault)
@ -593,10 +608,8 @@ OoOCPU<Impl>::write(T data, Addr addr, unsigned flags,
/*MemAccessResult result = */dcacheInterface->access(writeReq); /*MemAccessResult result = */dcacheInterface->access(writeReq);
if (dcacheInterface->doEvents()) { if (dcacheInterface->doEvents()) {
writeReq->completionEvent = new DCacheCompletionEvent(this, inst); writeReq->completionEvent = new DCacheCompletionEvent(this, inst,
lastDcacheStall = curTick; dcceIt);
unscheduleTickEvent();
_status = DcacheMissStall;
} }
} }

View file

@ -41,16 +41,12 @@
// forward declarations // forward declarations
struct AlphaSimpleImpl; struct AlphaSimpleImpl;
struct OoOImpl;
class ExecContext; class ExecContext;
class DynInst; class DynInst;
template <class Impl> template <class Impl>
class AlphaDynInst; class AlphaDynInst;
template <class Impl>
class OoODynInst;
class FastCPU; class FastCPU;
class SimpleCPU; class SimpleCPU;
class InorderCPU; class InorderCPU;
@ -260,7 +256,7 @@ class StaticInst : public StaticInstBase
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
* just the EA computation. * just the EA computation.
*/ */
virtual virtual const
StaticInstPtr<ISA> &eaCompInst() const { return nullStaticInstPtr; } StaticInstPtr<ISA> &eaCompInst() const { return nullStaticInstPtr; }
/** /**
@ -269,7 +265,7 @@ class StaticInst : public StaticInstBase
* obtain the dependence info (numSrcRegs and srcRegIdx[]) for * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
* just the memory access (not the EA computation). * just the memory access (not the EA computation).
*/ */
virtual virtual const
StaticInstPtr<ISA> &memAccInst() const { return nullStaticInstPtr; } StaticInstPtr<ISA> &memAccInst() const { return nullStaticInstPtr; }
/// The binary machine instruction. /// The binary machine instruction.

View file

@ -41,6 +41,9 @@
class BaseCPU; class BaseCPU;
class ExecContext; class ExecContext;
class FnEvent; class FnEvent;
// What does kernel stats expect is included?
class StaticInstBase;
class System;
enum Fault; enum Fault;
namespace Kernel { namespace Kernel {

View file

@ -0,0 +1,79 @@
from BaseCPU import BaseCPU
simobj DerivAlphaFullCPU(BaseCPU):
type = 'DerivAlphaFullCPU'
numThreads = Param.Unsigned("number of HW thread contexts")
if not build_env['FULL_SYSTEM']:
mem = Param.FunctionalMemory(NULL, "memory")
decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch "
"delay")
commitToFetchDelay = Param.Unsigned("Commit to fetch delay")
fetchWidth = Param.Unsigned("Fetch width")
renameToDecodeDelay = Param.Unsigned("Rename to decode delay")
iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode "
"delay")
commitToDecodeDelay = Param.Unsigned("Commit to decode delay")
fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay")
decodeWidth = Param.Unsigned("Decode width")
iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename "
"delay")
commitToRenameDelay = Param.Unsigned("Commit to rename delay")
decodeToRenameDelay = Param.Unsigned("Decode to rename delay")
renameWidth = Param.Unsigned("Rename width")
commitToIEWDelay = Param.Unsigned("Commit to "
"Issue/Execute/Writeback delay")
renameToIEWDelay = Param.Unsigned("Rename to "
"Issue/Execute/Writeback delay")
issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal "
"to the IEW stage)")
issueWidth = Param.Unsigned("Issue width")
executeWidth = Param.Unsigned("Execute width")
executeIntWidth = Param.Unsigned("Integer execute width")
executeFloatWidth = Param.Unsigned("Floating point execute width")
executeBranchWidth = Param.Unsigned("Branch execute width")
executeMemoryWidth = Param.Unsigned("Memory execute width")
iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit "
"delay")
renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay")
commitWidth = Param.Unsigned("Commit width")
squashWidth = Param.Unsigned("Squash width")
local_predictor_size = Param.Unsigned("Size of local predictor")
local_ctr_bits = Param.Unsigned("Bits per counter")
local_history_table_size = Param.Unsigned("Size of local history table")
local_history_bits = Param.Unsigned("Bits for the local history")
global_predictor_size = Param.Unsigned("Size of global predictor")
global_ctr_bits = Param.Unsigned("Bits per counter")
global_history_bits = Param.Unsigned("Bits of history")
choice_predictor_size = Param.Unsigned("Size of choice predictor")
choice_ctr_bits = Param.Unsigned("Bits of choice counters")
BTBEntries = Param.Unsigned("Number of BTB entries")
BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits")
RASSize = Param.Unsigned("RAS size")
LQEntries = Param.Unsigned("Number of load queue entries")
SQEntries = Param.Unsigned("Number of store queue entries")
LFSTSize = Param.Unsigned("Last fetched store table size")
SSITSize = Param.Unsigned("Store set ID table size")
numPhysIntRegs = Param.Unsigned("Number of physical integer registers")
numPhysFloatRegs = Param.Unsigned("Number of physical floating point "
"registers")
numIQEntries = Param.Unsigned("Number of instruction queue entries")
numROBEntries = Param.Unsigned("Number of reorder buffer entries")
instShiftAmt = Param.Unsigned("Number of bits to shift instructions by")
function_trace = Param.Bool(False, "Enable function trace")
function_trace_start = Param.Tick(0, "Cycle to start function trace")