Merge ktlim@zizzer:/bk/newmem
into zamp.eecs.umich.edu:/z/ktlim2/clean/newmem --HG-- extra : convert_revision : c565fd7cebaa4058ba510b3db50a9c76bf301228
This commit is contained in:
commit
0b0cb2bca7
69 changed files with 1141 additions and 619 deletions
|
@ -1,14 +1,14 @@
|
|||
import optparse, os, sys
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
import os,optparse,sys
|
||||
from SysPaths import *
|
||||
|
||||
parser = optparse.OptionParser(option_list=m5.standardOptions)
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
parser.add_option("-t", "--timing", action="store_true")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
m5.setStandardOptions(options)
|
||||
|
||||
if args:
|
||||
print "Error: script doesn't take any positional arguments"
|
||||
|
@ -190,6 +190,8 @@ class MyLinuxAlphaSystem(LinuxAlphaSystem):
|
|||
else:
|
||||
cpu = AtomicSimpleCPU()
|
||||
cpu.mem = magicbus2
|
||||
cpu.icache_port = magicbus2.port
|
||||
cpu.dcache_port = magicbus2.port
|
||||
cpu.itb = AlphaITB()
|
||||
cpu.dtb = AlphaDTB()
|
||||
sim_console = SimConsole(listener=ConsoleListener(port=3456))
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
# MIPS: "m5 test.py -a Mips -c hello_mips"
|
||||
|
||||
import os, optparse, sys
|
||||
|
||||
import m5
|
||||
from m5.objects import *
|
||||
from FullO3Config import *
|
||||
|
||||
# parse command-line arguments
|
||||
parser = optparse.OptionParser(option_list=m5.standardOptions)
|
||||
parser = optparse.OptionParser()
|
||||
|
||||
parser.add_option("-c", "--cmd", default="hello",
|
||||
help="The binary to run in syscall emulation mode.")
|
||||
help="The binary to run in syscall emulation mode.")
|
||||
parser.add_option("-o", "--options", default="",
|
||||
help="The options to pass to the binary, use \" \" around the entire\
|
||||
string.")
|
||||
|
@ -26,7 +27,6 @@ parser.add_option("-m", "--maxtick", type="int",
|
|||
help="Set the maximum number of ticks to run for")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
m5.setStandardOptions(options)
|
||||
|
||||
if args:
|
||||
print "Error: script doesn't take any positional arguments"
|
||||
|
@ -75,6 +75,8 @@ else:
|
|||
cpu = AtomicSimpleCPU()
|
||||
cpu.workload = process
|
||||
cpu.mem = magicbus
|
||||
cpu.icache_port=magicbus.port
|
||||
cpu.dcache_port=magicbus.port
|
||||
|
||||
system = System(physmem = mem, cpu = cpu)
|
||||
mem.port = magicbus.port
|
||||
|
|
|
@ -112,6 +112,10 @@ namespace AlphaISA
|
|||
lock_flag = 0;
|
||||
lock_addr = 0;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
#if FULL_SYSTEM
|
||||
protected:
|
||||
typedef uint64_t InternalProcReg;
|
||||
|
|
|
@ -215,6 +215,11 @@ class TimeBuffer
|
|||
{
|
||||
return wire(this, 0);
|
||||
}
|
||||
|
||||
int getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __BASE_TIMEBUF_HH__
|
||||
|
|
|
@ -188,9 +188,10 @@ if env['USE_CHECKER']:
|
|||
if i in env['CPU_MODELS']:
|
||||
checker_supports = True
|
||||
if not checker_supports:
|
||||
print "Checker only supports CPU models %s, please " \
|
||||
"set USE_CHECKER=False or use one of those CPU models" \
|
||||
% CheckerSupportedCPUList
|
||||
print "Checker only supports CPU models",
|
||||
for i in CheckerSupportedCPUList:
|
||||
print i,
|
||||
print ", please set USE_CHECKER=False or use one of those CPU models"
|
||||
Exit(1)
|
||||
|
||||
|
||||
|
|
|
@ -59,11 +59,11 @@ int maxThreadsPerCPU = 1;
|
|||
|
||||
#if FULL_SYSTEM
|
||||
BaseCPU::BaseCPU(Params *p)
|
||||
: SimObject(p->name), clock(p->clock), checkInterrupts(true),
|
||||
: MemObject(p->name), clock(p->clock), checkInterrupts(true),
|
||||
params(p), number_of_threads(p->numberOfThreads), system(p->system)
|
||||
#else
|
||||
BaseCPU::BaseCPU(Params *p)
|
||||
: SimObject(p->name), clock(p->clock), params(p),
|
||||
: MemObject(p->name), clock(p->clock), params(p),
|
||||
number_of_threads(p->numberOfThreads), system(p->system)
|
||||
#endif
|
||||
{
|
||||
|
|
|
@ -37,15 +37,16 @@
|
|||
#include "base/statistics.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
|
||||
class BranchPred;
|
||||
class CheckerCPU;
|
||||
class ThreadContext;
|
||||
class System;
|
||||
class Port;
|
||||
|
||||
class BaseCPU : public SimObject
|
||||
class BaseCPU : public MemObject
|
||||
{
|
||||
protected:
|
||||
// CPU's clock period in terms of the number of ticks of curTime.
|
||||
|
|
|
@ -127,6 +127,12 @@ class CheckerCPU : public BaseCPU
|
|||
|
||||
Port *dcachePort;
|
||||
|
||||
virtual Port *getPort(const std::string &name, int idx)
|
||||
{
|
||||
panic("Not supported on checker!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
// Primary thread being run.
|
||||
SimpleThread *thread;
|
||||
|
|
|
@ -120,7 +120,7 @@ class CheckerThreadContext : public ThreadContext
|
|||
void suspend() { actualTC->suspend(); }
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
void deallocate() { actualTC->deallocate(); }
|
||||
void deallocate(int delay = 0) { actualTC->deallocate(delay); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt() { actualTC->halt(); }
|
||||
|
|
|
@ -102,7 +102,9 @@ Param<unsigned> renameToROBDelay;
|
|||
Param<unsigned> commitWidth;
|
||||
Param<unsigned> squashWidth;
|
||||
Param<Tick> trapLatency;
|
||||
Param<Tick> fetchTrapLatency;
|
||||
|
||||
Param<unsigned> backComSize;
|
||||
Param<unsigned> forwardComSize;
|
||||
|
||||
Param<std::string> predType;
|
||||
Param<unsigned> localPredictorSize;
|
||||
|
@ -222,7 +224,9 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU)
|
|||
INIT_PARAM(commitWidth, "Commit width"),
|
||||
INIT_PARAM(squashWidth, "Squash width"),
|
||||
INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6),
|
||||
INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12),
|
||||
|
||||
INIT_PARAM(backComSize, "Time buffer size for backwards communication"),
|
||||
INIT_PARAM(forwardComSize, "Time buffer size for forward communication"),
|
||||
|
||||
INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"),
|
||||
INIT_PARAM(localPredictorSize, "Size of local predictor"),
|
||||
|
@ -350,7 +354,9 @@ CREATE_SIM_OBJECT(DerivO3CPU)
|
|||
params->commitWidth = commitWidth;
|
||||
params->squashWidth = squashWidth;
|
||||
params->trapLatency = trapLatency;
|
||||
params->fetchTrapLatency = fetchTrapLatency;
|
||||
|
||||
params->backComSize = backComSize;
|
||||
params->forwardComSize = forwardComSize;
|
||||
|
||||
params->predType = predType;
|
||||
params->localPredictorSize = localPredictorSize;
|
||||
|
|
|
@ -70,18 +70,19 @@ class AlphaTC : public O3ThreadContext<Impl>
|
|||
{ panic("Not supported on Alpha!"); }
|
||||
|
||||
|
||||
// This function exits the thread context in the CPU and returns
|
||||
// 1 if the CPU has no more active threads (meaning it's OK to exit);
|
||||
// Used in syscall-emulation mode when a thread executes the 'exit'
|
||||
// syscall.
|
||||
/** This function exits the thread context in the CPU and returns
|
||||
* 1 if the CPU has no more active threads (meaning it's OK to exit);
|
||||
* Used in syscall-emulation mode when a thread executes the 'exit'
|
||||
* syscall.
|
||||
*/
|
||||
virtual int exit()
|
||||
{
|
||||
this->cpu->deallocateContext(this->thread->readTid());
|
||||
this->deallocate();
|
||||
|
||||
// If there are still threads executing in the system
|
||||
if (this->cpu->numActiveThreads())
|
||||
return 0;
|
||||
return 0; // don't exit simulation
|
||||
else
|
||||
return 1;
|
||||
return 1; // exit simulation
|
||||
}
|
||||
};
|
||||
|
|
|
@ -162,10 +162,6 @@ class DefaultCommit
|
|||
/** Sets the pointer to the queue coming from IEW. */
|
||||
void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
|
||||
|
||||
void setFetchStage(Fetch *fetch_stage);
|
||||
|
||||
Fetch *fetchStage;
|
||||
|
||||
/** Sets the pointer to the IEW stage. */
|
||||
void setIEWStage(IEW *iew_stage);
|
||||
|
||||
|
@ -188,7 +184,7 @@ class DefaultCommit
|
|||
void initStage();
|
||||
|
||||
/** Initializes the draining of commit. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after draining. */
|
||||
void resume();
|
||||
|
@ -335,10 +331,6 @@ class DefaultCommit
|
|||
/** Vector of all of the threads. */
|
||||
std::vector<Thread *> thread;
|
||||
|
||||
Fault fetchFault;
|
||||
|
||||
int fetchTrapWait;
|
||||
|
||||
/** Records that commit has written to the time buffer this cycle. Used for
|
||||
* the CPU to determine if it can deschedule itself if there is no activity.
|
||||
*/
|
||||
|
@ -397,10 +389,6 @@ class DefaultCommit
|
|||
*/
|
||||
Tick trapLatency;
|
||||
|
||||
Tick fetchTrapLatency;
|
||||
|
||||
Tick fetchFaultTick;
|
||||
|
||||
/** The commit PC of each thread. Refers to the instruction that
|
||||
* is currently being processed/committed.
|
||||
*/
|
||||
|
|
|
@ -82,8 +82,7 @@ DefaultCommit<Impl>::DefaultCommit(Params *params)
|
|||
numThreads(params->numberOfThreads),
|
||||
drainPending(false),
|
||||
switchedOut(false),
|
||||
trapLatency(params->trapLatency),
|
||||
fetchTrapLatency(params->fetchTrapLatency)
|
||||
trapLatency(params->trapLatency)
|
||||
{
|
||||
_status = Active;
|
||||
_nextStatus = Inactive;
|
||||
|
@ -123,9 +122,6 @@ DefaultCommit<Impl>::DefaultCommit(Params *params)
|
|||
tcSquash[i] = false;
|
||||
PC[i] = nextPC[i] = 0;
|
||||
}
|
||||
|
||||
fetchFaultTick = 0;
|
||||
fetchTrapWait = 0;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -235,7 +231,6 @@ DefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
|
|||
cpu->activateStage(O3CPU::CommitIdx);
|
||||
|
||||
trapLatency = cpu->cycles(trapLatency);
|
||||
fetchTrapLatency = cpu->cycles(fetchTrapLatency);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -292,13 +287,6 @@ DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
|
|||
fromIEW = iewQueue->getWire(-iewToCommitDelay);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage)
|
||||
{
|
||||
fetchStage = fetch_stage;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
|
||||
|
@ -350,10 +338,18 @@ DefaultCommit<Impl>::initStage()
|
|||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
bool
|
||||
DefaultCommit<Impl>::drain()
|
||||
{
|
||||
drainPending = true;
|
||||
|
||||
// If it's already drained, return true.
|
||||
if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
|
||||
cpu->signalDrained();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -369,6 +365,7 @@ template <class Impl>
|
|||
void
|
||||
DefaultCommit<Impl>::resume()
|
||||
{
|
||||
drainPending = false;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -569,6 +566,9 @@ DefaultCommit<Impl>::tick()
|
|||
return;
|
||||
}
|
||||
|
||||
if ((*activeThreads).size() <= 0)
|
||||
return;
|
||||
|
||||
list<unsigned>::iterator threads = (*activeThreads).begin();
|
||||
|
||||
// Check if any of the threads are done squashing. Change the
|
||||
|
@ -582,7 +582,7 @@ DefaultCommit<Impl>::tick()
|
|||
commitStatus[tid] = Running;
|
||||
} else {
|
||||
DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
|
||||
"insts this cycle.\n", tid);
|
||||
" insts this cycle.\n", tid);
|
||||
rob->doSquash(tid);
|
||||
toIEW->commitInfo[tid].robSquashing = true;
|
||||
wroteToTimeBuffer = true;
|
||||
|
|
|
@ -114,6 +114,36 @@ FullO3CPU<Impl>::ActivateThreadEvent::description()
|
|||
return "FullO3CPU \"Activate Thread\" event";
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
|
||||
: Event(&mainEventQueue, CPU_Tick_Pri)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::DeallocateContextEvent::init(int thread_num,
|
||||
FullO3CPU<Impl> *thread_cpu)
|
||||
{
|
||||
tid = thread_num;
|
||||
cpu = thread_cpu;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::DeallocateContextEvent::process()
|
||||
{
|
||||
cpu->deactivateThread(tid);
|
||||
cpu->removeThread(tid);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
const char *
|
||||
FullO3CPU<Impl>::DeallocateContextEvent::description()
|
||||
{
|
||||
return "FullO3CPU \"Deallocate Context\" event";
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
FullO3CPU<Impl>::FullO3CPU(Params *params)
|
||||
: BaseO3CPU(params),
|
||||
|
@ -141,15 +171,14 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
|
|||
TheISA::NumMiscRegs * number_of_threads,
|
||||
TheISA::ZeroReg),
|
||||
|
||||
// For now just have these time buffers be pretty big.
|
||||
// @todo: Make these time buffer sizes parameters or derived
|
||||
// from latencies
|
||||
timeBuffer(5, 5),
|
||||
fetchQueue(5, 5),
|
||||
decodeQueue(5, 5),
|
||||
renameQueue(5, 5),
|
||||
iewQueue(5, 5),
|
||||
activityRec(NumStages, 10, params->activity),
|
||||
timeBuffer(params->backComSize, params->forwardComSize),
|
||||
fetchQueue(params->backComSize, params->forwardComSize),
|
||||
decodeQueue(params->backComSize, params->forwardComSize),
|
||||
renameQueue(params->backComSize, params->forwardComSize),
|
||||
iewQueue(params->backComSize, params->forwardComSize),
|
||||
activityRec(NumStages,
|
||||
params->backComSize + params->forwardComSize,
|
||||
params->activity),
|
||||
|
||||
globalSeqNum(1),
|
||||
|
||||
|
@ -214,7 +243,6 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
|
|||
commit.setIEWQueue(&iewQueue);
|
||||
commit.setRenameQueue(&renameQueue);
|
||||
|
||||
commit.setFetchStage(&fetch);
|
||||
commit.setIEWStage(&iew);
|
||||
rename.setIEWStage(&iew);
|
||||
rename.setCommitStage(&commit);
|
||||
|
@ -360,6 +388,18 @@ FullO3CPU<Impl>::fullCPURegStats()
|
|||
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
Port *
|
||||
FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "dcache_port")
|
||||
return iew.getDcachePort();
|
||||
else if (if_name == "icache_port")
|
||||
return fetch.getIcachePort();
|
||||
else
|
||||
panic("No Such Port\n");
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::tick()
|
||||
|
@ -400,7 +440,8 @@ FullO3CPU<Impl>::tick()
|
|||
}
|
||||
|
||||
if (!tickEvent.scheduled()) {
|
||||
if (_status == SwitchedOut) {
|
||||
if (_status == SwitchedOut ||
|
||||
getState() == SimObject::DrainedTiming) {
|
||||
// increment stat
|
||||
lastRunningCycle = curTick;
|
||||
} else if (!activityRec.active()) {
|
||||
|
@ -459,6 +500,118 @@ FullO3CPU<Impl>::init()
|
|||
commit.setThreads(thread);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::activateThread(unsigned tid)
|
||||
{
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (isActive == activeThreads.end()) {
|
||||
DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
|
||||
tid);
|
||||
|
||||
activeThreads.push_back(tid);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::deactivateThread(unsigned tid)
|
||||
{
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator thread_it =
|
||||
find(activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (thread_it != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(thread_it);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::activateContext(int tid, int delay)
|
||||
{
|
||||
// Needs to set each stage to running as well.
|
||||
if (delay){
|
||||
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
|
||||
"on cycle %d\n", tid, curTick + cycles(delay));
|
||||
scheduleActivateThreadEvent(tid, delay);
|
||||
} else {
|
||||
activateThread(tid);
|
||||
}
|
||||
|
||||
if(lastActivatedCycle < curTick) {
|
||||
scheduleTickEvent(delay);
|
||||
|
||||
// Be sure to signal that there's some activity so the CPU doesn't
|
||||
// deschedule itself.
|
||||
activityRec.activity();
|
||||
fetch.wakeFromQuiesce();
|
||||
|
||||
lastActivatedCycle = curTick;
|
||||
|
||||
_status = Running;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::deallocateContext(int tid, int delay)
|
||||
{
|
||||
// Schedule removal of thread data from CPU
|
||||
if (delay){
|
||||
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate "
|
||||
"on cycle %d\n", tid, curTick + cycles(delay));
|
||||
scheduleDeallocateContextEvent(tid, delay);
|
||||
} else {
|
||||
deactivateThread(tid);
|
||||
removeThread(tid);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::suspendContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
|
||||
unscheduleTickEvent();
|
||||
_status = Idle;
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (isActive != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(isActive);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::haltContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid);
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (isActive != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(isActive);
|
||||
|
||||
removeThread(tid);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::insertThread(unsigned tid)
|
||||
|
@ -511,7 +664,7 @@ template <class Impl>
|
|||
void
|
||||
FullO3CPU<Impl>::removeThread(unsigned tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i] Removing thread from CPU.");
|
||||
DPRINTF(O3CPU,"[tid:%i] Removing thread context from CPU.\n", tid);
|
||||
|
||||
// Copy Thread Data From RegFile
|
||||
// If thread is suspended, it might be re-allocated
|
||||
|
@ -537,6 +690,8 @@ FullO3CPU<Impl>::removeThread(unsigned tid)
|
|||
fetch.squash(0,tid);
|
||||
decode.squash(tid);
|
||||
rename.squash(tid);
|
||||
iew.squash(tid);
|
||||
commit.rob->squash(commit.rob->readHeadInst(tid)->seqNum, tid);
|
||||
|
||||
assert(iew.ldstQueue.getCount(tid) == 0);
|
||||
|
||||
|
@ -600,6 +755,7 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
|
|||
//blocks fetch
|
||||
contextSwitch = true;
|
||||
|
||||
//@todo: dont always add to waitlist
|
||||
//do waitlist
|
||||
cpuWaitList.push_back(tid);
|
||||
}
|
||||
|
@ -607,104 +763,43 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::activateThread(unsigned int tid)
|
||||
FullO3CPU<Impl>::serialize(std::ostream &os)
|
||||
{
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
SERIALIZE_ENUM(_status);
|
||||
BaseCPU::serialize(os);
|
||||
nameOut(os, csprintf("%s.tickEvent", name()));
|
||||
tickEvent.serialize(os);
|
||||
|
||||
if (isActive == activeThreads.end()) {
|
||||
DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
|
||||
tid);
|
||||
// Use SimpleThread's ability to checkpoint to make it easier to
|
||||
// write out the registers. Also make this static so it doesn't
|
||||
// get instantiated multiple times (causes a panic in statistics).
|
||||
static SimpleThread temp;
|
||||
|
||||
activeThreads.push_back(tid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::activateContext(int tid, int delay)
|
||||
{
|
||||
// Needs to set each stage to running as well.
|
||||
if (delay){
|
||||
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
|
||||
"on cycle %d\n", tid, curTick + cycles(delay));
|
||||
scheduleActivateThreadEvent(tid, delay);
|
||||
} else {
|
||||
activateThread(tid);
|
||||
}
|
||||
|
||||
if(lastActivatedCycle < curTick) {
|
||||
scheduleTickEvent(delay);
|
||||
|
||||
// Be sure to signal that there's some activity so the CPU doesn't
|
||||
// deschedule itself.
|
||||
activityRec.activity();
|
||||
fetch.wakeFromQuiesce();
|
||||
|
||||
lastActivatedCycle = curTick;
|
||||
|
||||
_status = Running;
|
||||
for (int i = 0; i < thread.size(); i++) {
|
||||
nameOut(os, csprintf("%s.xc.%i", name(), i));
|
||||
temp.copyTC(thread[i]->getTC());
|
||||
temp.serialize(os);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::suspendContext(int tid)
|
||||
FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
|
||||
unscheduleTickEvent();
|
||||
_status = Idle;
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
UNSERIALIZE_ENUM(_status);
|
||||
BaseCPU::unserialize(cp, section);
|
||||
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
|
||||
|
||||
if (isActive != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(isActive);
|
||||
// Use SimpleThread's ability to checkpoint to make it easier to
|
||||
// read in the registers. Also make this static so it doesn't
|
||||
// get instantiated multiple times (causes a panic in statistics).
|
||||
static SimpleThread temp;
|
||||
|
||||
for (int i = 0; i < thread.size(); i++) {
|
||||
temp.copyTC(thread[i]->getTC());
|
||||
temp.unserialize(cp, csprintf("%s.xc.%i", section, i));
|
||||
thread[i]->getTC()->copyArchRegs(temp.getTC());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::deallocateContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i]: Deallocating Thread Context", tid);
|
||||
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator thread_it =
|
||||
find(activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (thread_it != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(thread_it);
|
||||
|
||||
removeThread(tid);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::haltContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid);
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
|
||||
if (isActive != activeThreads.end()) {
|
||||
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
|
||||
tid);
|
||||
activeThreads.erase(isActive);
|
||||
|
||||
removeThread(tid);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -712,7 +807,6 @@ bool
|
|||
FullO3CPU<Impl>::drain(Event *drain_event)
|
||||
{
|
||||
drainCount = 0;
|
||||
drainEvent = drain_event;
|
||||
fetch.drain();
|
||||
decode.drain();
|
||||
rename.drain();
|
||||
|
@ -720,28 +814,40 @@ FullO3CPU<Impl>::drain(Event *drain_event)
|
|||
commit.drain();
|
||||
|
||||
// Wake the CPU and record activity so everything can drain out if
|
||||
// the CPU is currently idle.
|
||||
wakeCPU();
|
||||
activityRec.activity();
|
||||
// the CPU was not able to immediately drain.
|
||||
if (getState() != SimObject::DrainedTiming) {
|
||||
// A bit of a hack...set the drainEvent after all the drain()
|
||||
// calls have been made, that way if all of the stages drain
|
||||
// immediately, the signalDrained() function knows not to call
|
||||
// process on the drain event.
|
||||
drainEvent = drain_event;
|
||||
|
||||
return false;
|
||||
wakeCPU();
|
||||
activityRec.activity();
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::resume()
|
||||
{
|
||||
if (_status == SwitchedOut)
|
||||
return;
|
||||
fetch.resume();
|
||||
decode.resume();
|
||||
rename.resume();
|
||||
iew.resume();
|
||||
commit.resume();
|
||||
|
||||
if (_status == SwitchedOut || _status == Idle)
|
||||
return;
|
||||
|
||||
if (!tickEvent.scheduled())
|
||||
tickEvent.schedule(curTick);
|
||||
_status = Running;
|
||||
changeState(SimObject::Timing);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -751,8 +857,13 @@ FullO3CPU<Impl>::signalDrained()
|
|||
if (++drainCount == NumStages) {
|
||||
if (tickEvent.scheduled())
|
||||
tickEvent.squash();
|
||||
_status = Drained;
|
||||
drainEvent->process();
|
||||
|
||||
changeState(SimObject::DrainedTiming);
|
||||
|
||||
if (drainEvent) {
|
||||
drainEvent->process();
|
||||
drainEvent = NULL;
|
||||
}
|
||||
}
|
||||
assert(drainCount <= 5);
|
||||
}
|
||||
|
@ -781,7 +892,7 @@ void
|
|||
FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
|
||||
{
|
||||
// Flush out any old data from the time buffers.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int i = 0; i < timeBuffer.getSize(); ++i) {
|
||||
timeBuffer.advance();
|
||||
fetchQueue.advance();
|
||||
decodeQueue.advance();
|
||||
|
|
|
@ -111,7 +111,6 @@ class FullO3CPU : public BaseO3CPU
|
|||
Idle,
|
||||
Halted,
|
||||
Blocked,
|
||||
Drained,
|
||||
SwitchedOut
|
||||
};
|
||||
|
||||
|
@ -200,6 +199,49 @@ class FullO3CPU : public BaseO3CPU
|
|||
/** The tick event used for scheduling CPU ticks. */
|
||||
ActivateThreadEvent activateThreadEvent[Impl::MaxThreads];
|
||||
|
||||
class DeallocateContextEvent : public Event
|
||||
{
|
||||
private:
|
||||
/** Number of Thread to Activate */
|
||||
int tid;
|
||||
|
||||
/** Pointer to the CPU. */
|
||||
FullO3CPU<Impl> *cpu;
|
||||
|
||||
public:
|
||||
/** Constructs the event. */
|
||||
DeallocateContextEvent();
|
||||
|
||||
/** Initialize Event */
|
||||
void init(int thread_num, FullO3CPU<Impl> *thread_cpu);
|
||||
|
||||
/** Processes the event, calling activateThread() on the CPU. */
|
||||
void process();
|
||||
|
||||
/** Returns the description of the event. */
|
||||
const char *description();
|
||||
};
|
||||
|
||||
/** Schedule cpu to deallocate thread context.*/
|
||||
void scheduleDeallocateContextEvent(int tid, int delay)
|
||||
{
|
||||
// Schedule thread to activate, regardless of its current state.
|
||||
if (deallocateContextEvent[tid].squashed())
|
||||
deallocateContextEvent[tid].reschedule(curTick + cycles(delay));
|
||||
else if (!deallocateContextEvent[tid].scheduled())
|
||||
deallocateContextEvent[tid].schedule(curTick + cycles(delay));
|
||||
}
|
||||
|
||||
/** Unschedule thread deallocation in CPU */
|
||||
void unscheduleDeallocateContextEvent(int tid)
|
||||
{
|
||||
if (deallocateContextEvent[tid].scheduled())
|
||||
deallocateContextEvent[tid].squash();
|
||||
}
|
||||
|
||||
/** The tick event used for scheduling CPU ticks. */
|
||||
DeallocateContextEvent deallocateContextEvent[Impl::MaxThreads];
|
||||
|
||||
public:
|
||||
/** Constructs a CPU with the given parameters. */
|
||||
FullO3CPU(Params *params);
|
||||
|
@ -209,6 +251,9 @@ class FullO3CPU : public BaseO3CPU
|
|||
/** Registers statistics. */
|
||||
void fullCPURegStats();
|
||||
|
||||
/** Returns a specific port. */
|
||||
Port *getPort(const std::string &if_name, int idx);
|
||||
|
||||
/** Ticks CPU, calling tick() on each stage, and checking the overall
|
||||
* activity to see if the CPU should deschedule itself.
|
||||
*/
|
||||
|
@ -222,7 +267,10 @@ class FullO3CPU : public BaseO3CPU
|
|||
{ return activeThreads.size(); }
|
||||
|
||||
/** Add Thread to Active Threads List */
|
||||
void activateThread(unsigned int tid);
|
||||
void activateThread(unsigned tid);
|
||||
|
||||
/** Remove Thread from Active Threads List */
|
||||
void deactivateThread(unsigned tid);
|
||||
|
||||
/** Setup CPU to insert a thread's context */
|
||||
void insertThread(unsigned tid);
|
||||
|
@ -250,7 +298,7 @@ class FullO3CPU : public BaseO3CPU
|
|||
/** Remove Thread from Active Threads List &&
|
||||
* Remove Thread Context from CPU.
|
||||
*/
|
||||
void deallocateContext(int tid);
|
||||
void deallocateContext(int tid, int delay = 1);
|
||||
|
||||
/** Remove Thread from Active Threads List &&
|
||||
* Remove Thread Context from CPU.
|
||||
|
@ -266,6 +314,13 @@ class FullO3CPU : public BaseO3CPU
|
|||
/** Update The Order In Which We Process Threads. */
|
||||
void updateThreadPriority();
|
||||
|
||||
/** Serialize state. */
|
||||
virtual void serialize(std::ostream &os);
|
||||
|
||||
/** Unserialize from a checkpoint. */
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
public:
|
||||
/** Executes a syscall on this cycle.
|
||||
* ---------------------------------------
|
||||
* Note: this is a virtual function. CPU-Specific
|
||||
|
|
|
@ -110,7 +110,7 @@ class DefaultDecode
|
|||
void setActiveThreads(std::list<unsigned> *at_ptr);
|
||||
|
||||
/** Drains the decode stage. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume() { }
|
||||
|
|
|
@ -165,11 +165,12 @@ DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
|
|||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
bool
|
||||
DefaultDecode<Impl>::drain()
|
||||
{
|
||||
// Decode is done draining at any time.
|
||||
cpu->signalDrained();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
|
|
@ -162,6 +162,9 @@ class DefaultFetch
|
|||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
/** Returns the icache port. */
|
||||
Port *getIcachePort() { return icachePort; }
|
||||
|
||||
/** Sets CPU pointer. */
|
||||
void setCPU(O3CPU *cpu_ptr);
|
||||
|
||||
|
@ -181,7 +184,7 @@ class DefaultFetch
|
|||
void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Begins the drain of the fetch stage. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume();
|
||||
|
|
|
@ -280,10 +280,6 @@ DefaultFetch<Impl>::setCPU(O3CPU *cpu_ptr)
|
|||
// Name is finally available, so create the port.
|
||||
icachePort = new IcachePort(this);
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
icachePort->setPeer(mem_dport);
|
||||
mem_dport->setPeer(icachePort);
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setIcachePort(icachePort);
|
||||
|
@ -354,22 +350,23 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
|||
// to return.
|
||||
if (fetchStatus[tid] != IcacheWaitResponse ||
|
||||
pkt->req != memReq[tid] ||
|
||||
isSwitchedOut() ||
|
||||
drainPending) {
|
||||
isSwitchedOut()) {
|
||||
++fetchIcacheSquashes;
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
return;
|
||||
}
|
||||
|
||||
// Wake up the CPU (if it went to sleep and was waiting on this completion
|
||||
// event).
|
||||
cpu->wakeCPU();
|
||||
if (!drainPending) {
|
||||
// Wake up the CPU (if it went to sleep and was waiting on
|
||||
// this completion event).
|
||||
cpu->wakeCPU();
|
||||
|
||||
DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
|
||||
tid);
|
||||
DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
|
||||
tid);
|
||||
|
||||
switchToActive();
|
||||
switchToActive();
|
||||
}
|
||||
|
||||
// Only switch to IcacheAccessComplete if we're not stalled as well.
|
||||
if (checkStall(tid)) {
|
||||
|
@ -385,12 +382,13 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
|||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
bool
|
||||
DefaultFetch<Impl>::drain()
|
||||
{
|
||||
// Fetch is ready to drain at any time.
|
||||
cpu->signalDrained();
|
||||
drainPending = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -508,7 +506,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
|
|||
unsigned flags = 0;
|
||||
#endif // FULL_SYSTEM
|
||||
|
||||
if (cacheBlocked || (interruptPending && flags == 0) || drainPending) {
|
||||
if (cacheBlocked || (interruptPending && flags == 0)) {
|
||||
// Hold off fetch from getting new instructions when:
|
||||
// Cache is blocked, or
|
||||
// while an interrupt is pending and we're not in PAL mode, or
|
||||
|
@ -908,7 +906,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
|
|||
//////////////////////////////////////////
|
||||
int tid = getFetchingThread(fetchPolicy);
|
||||
|
||||
if (tid == -1) {
|
||||
if (tid == -1 || drainPending) {
|
||||
DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
|
||||
|
||||
// Breaks looping condition in tick()
|
||||
|
|
|
@ -125,6 +125,9 @@ class DefaultIEW
|
|||
/** Initializes stage; sends back the number of free IQ and LSQ entries. */
|
||||
void initStage();
|
||||
|
||||
/** Returns the dcache port. */
|
||||
Port *getDcachePort() { return ldstQueue.getDcachePort(); }
|
||||
|
||||
/** Sets CPU pointer for IEW, IQ, and LSQ. */
|
||||
void setCPU(O3CPU *cpu_ptr);
|
||||
|
||||
|
@ -144,7 +147,7 @@ class DefaultIEW
|
|||
void setScoreboard(Scoreboard *sb_ptr);
|
||||
|
||||
/** Drains IEW stage. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume();
|
||||
|
|
|
@ -42,8 +42,7 @@ using namespace std;
|
|||
|
||||
template<class Impl>
|
||||
DefaultIEW<Impl>::DefaultIEW(Params *params)
|
||||
: // @todo: Make this into a parameter.
|
||||
issueToExecQueue(5, 5),
|
||||
: issueToExecQueue(params->backComSize, params->forwardComSize),
|
||||
instQueue(params),
|
||||
ldstQueue(params),
|
||||
fuPool(params->fuPool),
|
||||
|
@ -354,11 +353,12 @@ DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
|
|||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
bool
|
||||
DefaultIEW<Impl>::drain()
|
||||
{
|
||||
// IEW is ready to drain at any time.
|
||||
cpu->signalDrained();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
@ -412,7 +412,7 @@ DefaultIEW<Impl>::takeOverFrom()
|
|||
updateLSQNextCycle = false;
|
||||
|
||||
// @todo: Fix hardcoded number
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int i = 0; i < issueToExecQueue.getSize(); ++i) {
|
||||
issueToExecQueue.advance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,13 @@ class LSQ {
|
|||
/** Registers statistics of each LSQ unit. */
|
||||
void regStats();
|
||||
|
||||
/** Returns dcache port.
|
||||
* @todo: Dcache port needs to be moved up to this level for SMT
|
||||
* to work. For now it just returns the port from one of the
|
||||
* threads.
|
||||
*/
|
||||
Port *getDcachePort() { return thread[0].getDcachePort(); }
|
||||
|
||||
/** Sets the pointer to the list of active threads. */
|
||||
void setActiveThreads(std::list<unsigned> *at_ptr);
|
||||
/** Sets the CPU pointer. */
|
||||
|
|
|
@ -502,6 +502,9 @@ LSQ<Impl>::hasStoresToWB()
|
|||
{
|
||||
list<unsigned>::iterator active_threads = (*activeThreads).begin();
|
||||
|
||||
if ((*activeThreads).empty())
|
||||
return false;
|
||||
|
||||
while (active_threads != (*activeThreads).end()) {
|
||||
unsigned tid = *active_threads++;
|
||||
if (!hasStoresToWB(tid))
|
||||
|
|
|
@ -77,6 +77,11 @@ class LSQUnit {
|
|||
/** Returns the name of the LSQ unit. */
|
||||
std::string name() const;
|
||||
|
||||
/** Returns the dcache port.
|
||||
* @todo: Remove this once the port moves up to the LSQ level.
|
||||
*/
|
||||
Port *getDcachePort() { return dcachePort; }
|
||||
|
||||
/** Registers statistics. */
|
||||
void regStats();
|
||||
|
||||
|
|
|
@ -182,10 +182,6 @@ LSQUnit<Impl>::setCPU(O3CPU *cpu_ptr)
|
|||
cpu = cpu_ptr;
|
||||
dcachePort = new DcachePort(cpu, this);
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
dcachePort->setPeer(mem_dport);
|
||||
mem_dport->setPeer(dcachePort);
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setDcachePort(dcachePort);
|
||||
|
|
|
@ -114,6 +114,12 @@ class O3Params : public BaseO3CPU::Params
|
|||
Tick trapLatency;
|
||||
Tick fetchTrapLatency;
|
||||
|
||||
//
|
||||
// Timebuffer sizes
|
||||
//
|
||||
unsigned backComSize;
|
||||
unsigned forwardComSize;
|
||||
|
||||
//
|
||||
// Branch predictor (BP, BTB, RAS)
|
||||
//
|
||||
|
|
|
@ -86,10 +86,6 @@ class PhysRegFile
|
|||
//The duplication is unfortunate but it's better than having
|
||||
//different ways to access certain registers.
|
||||
|
||||
//Add these in later when everything else is in place
|
||||
// void serialize(std::ostream &os);
|
||||
// void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntReg(PhysRegIndex reg_idx)
|
||||
{
|
||||
|
|
|
@ -158,7 +158,7 @@ class DefaultRename
|
|||
void setScoreboard(Scoreboard *_scoreboard);
|
||||
|
||||
/** Drains the rename stage. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume() { }
|
||||
|
|
|
@ -257,11 +257,12 @@ DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
|
|||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
bool
|
||||
DefaultRename<Impl>::drain()
|
||||
{
|
||||
// Rename is ready to switch out at any time.
|
||||
cpu->signalDrained();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
|
|
@ -308,7 +308,7 @@ class ROB
|
|||
|
||||
private:
|
||||
/** The sequence number of the squashed instruction. */
|
||||
InstSeqNum squashedSeqNum;
|
||||
InstSeqNum squashedSeqNum[Impl::MaxThreads];
|
||||
|
||||
/** Is the ROB done squashing. */
|
||||
bool doneSquashing[Impl::MaxThreads];
|
||||
|
|
|
@ -41,10 +41,10 @@ ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
|
|||
: numEntries(_numEntries),
|
||||
squashWidth(_squashWidth),
|
||||
numInstsInROB(0),
|
||||
squashedSeqNum(0),
|
||||
numThreads(_numThreads)
|
||||
{
|
||||
for (int tid=0; tid < numThreads; tid++) {
|
||||
squashedSeqNum[tid] = 0;
|
||||
doneSquashing[tid] = true;
|
||||
threadEntries[tid] = 0;
|
||||
}
|
||||
|
@ -352,11 +352,11 @@ void
|
|||
ROB<Impl>::doSquash(unsigned tid)
|
||||
{
|
||||
DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
|
||||
tid, squashedSeqNum);
|
||||
tid, squashedSeqNum[tid]);
|
||||
|
||||
assert(squashIt[tid] != instList[tid].end());
|
||||
|
||||
if ((*squashIt[tid])->seqNum < squashedSeqNum) {
|
||||
if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
|
||||
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
|
||||
tid);
|
||||
|
||||
|
@ -371,7 +371,7 @@ ROB<Impl>::doSquash(unsigned tid)
|
|||
for (int numSquashed = 0;
|
||||
numSquashed < squashWidth &&
|
||||
squashIt[tid] != instList[tid].end() &&
|
||||
(*squashIt[tid])->seqNum > squashedSeqNum;
|
||||
(*squashIt[tid])->seqNum > squashedSeqNum[tid];
|
||||
++numSquashed)
|
||||
{
|
||||
DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
|
||||
|
@ -408,7 +408,7 @@ ROB<Impl>::doSquash(unsigned tid)
|
|||
|
||||
|
||||
// Check if ROB is done squashing.
|
||||
if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
|
||||
if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
|
||||
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
|
||||
tid);
|
||||
|
||||
|
@ -520,7 +520,7 @@ ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
|
|||
|
||||
doneSquashing[tid] = false;
|
||||
|
||||
squashedSeqNum = squash_num;
|
||||
squashedSeqNum[tid] = squash_num;
|
||||
|
||||
if (!instList[tid].empty()) {
|
||||
InstIt tail_thread = instList[tid].end();
|
||||
|
@ -544,6 +544,7 @@ ROB<Impl>::readHeadInst()
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template <class Impl>
|
||||
typename Impl::DynInstPtr
|
||||
ROB<Impl>::readHeadInst(unsigned tid)
|
||||
|
@ -558,6 +559,7 @@ ROB<Impl>::readHeadInst(unsigned tid)
|
|||
return dummyInst;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
template <class Impl>
|
||||
uint64_t
|
||||
|
|
|
@ -112,7 +112,7 @@ class O3ThreadContext : public ThreadContext
|
|||
virtual void suspend();
|
||||
|
||||
/** Set the status to Unallocated. */
|
||||
virtual void deallocate();
|
||||
virtual void deallocate(int delay = 0);
|
||||
|
||||
/** Set the status to Halted. */
|
||||
virtual void halt();
|
||||
|
|
|
@ -115,7 +115,8 @@ template <class Impl>
|
|||
void
|
||||
O3ThreadContext<Impl>::activate(int delay)
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling activate on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Active)
|
||||
return;
|
||||
|
@ -139,7 +140,8 @@ template <class Impl>
|
|||
void
|
||||
O3ThreadContext<Impl>::suspend()
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling suspend on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Suspended)
|
||||
return;
|
||||
|
@ -163,22 +165,24 @@ O3ThreadContext<Impl>::suspend()
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::deallocate()
|
||||
O3ThreadContext<Impl>::deallocate(int delay)
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling deallocate on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling deallocate on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Unallocated)
|
||||
return;
|
||||
|
||||
thread->setStatus(ThreadContext::Unallocated);
|
||||
cpu->deallocateContext(thread->readTid());
|
||||
cpu->deallocateContext(thread->readTid(), delay);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::halt()
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling halt on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Halted)
|
||||
return;
|
||||
|
|
|
@ -150,7 +150,7 @@ class OzoneCPU : public BaseCPU
|
|||
void suspend();
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
void deallocate();
|
||||
void deallocate(int delay = 0);
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt();
|
||||
|
@ -372,6 +372,8 @@ class OzoneCPU : public BaseCPU
|
|||
PhysicalMemory *physmem;
|
||||
#endif
|
||||
|
||||
virtual Port *getPort(const std::string &name, int idx);
|
||||
|
||||
MemObject *mem;
|
||||
|
||||
FrontEnd *frontEnd;
|
||||
|
@ -383,7 +385,7 @@ class OzoneCPU : public BaseCPU
|
|||
|
||||
virtual void activateContext(int thread_num, int delay);
|
||||
virtual void suspendContext(int thread_num);
|
||||
virtual void deallocateContext(int thread_num);
|
||||
virtual void deallocateContext(int thread_num, int delay);
|
||||
virtual void haltContext(int thread_num);
|
||||
|
||||
// statistics
|
||||
|
|
|
@ -335,7 +335,7 @@ OzoneCPU<Impl>::suspendContext(int thread_num)
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
OzoneCPU<Impl>::deallocateContext(int thread_num)
|
||||
OzoneCPU<Impl>::deallocateContext(int thread_num, int delay)
|
||||
{
|
||||
// for now, these are equivalent
|
||||
suspendContext(thread_num);
|
||||
|
@ -418,6 +418,18 @@ OzoneCPU<Impl>::init()
|
|||
thread.inSyscall = false;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
Port *
|
||||
OzoneCPU<Impl>::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "dcache_port")
|
||||
return backEnd->getDcachePort();
|
||||
else if (if_name == "icache_port")
|
||||
return frontEnd->getIcachePort();
|
||||
else
|
||||
panic("No Such Port\n");
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
OzoneCPU<Impl>::serialize(std::ostream &os)
|
||||
|
@ -780,9 +792,9 @@ OzoneCPU<Impl>::OzoneTC::suspend()
|
|||
/// Set the status to Unallocated.
|
||||
template <class Impl>
|
||||
void
|
||||
OzoneCPU<Impl>::OzoneTC::deallocate()
|
||||
OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
|
||||
{
|
||||
cpu->deallocateContext(thread->readTid());
|
||||
cpu->deallocateContext(thread->readTid(), delay);
|
||||
}
|
||||
|
||||
/// Set the status to Halted.
|
||||
|
|
|
@ -119,6 +119,8 @@ class FrontEnd
|
|||
|
||||
void regStats();
|
||||
|
||||
Port *getIcachePort() { return &icachePort; }
|
||||
|
||||
void tick();
|
||||
Fault fetchCacheLine();
|
||||
void processInst(DynInstPtr &inst);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/ozone/front_end.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh"
|
||||
|
||||
|
@ -138,10 +139,6 @@ FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
|
|||
|
||||
icachePort.setName(this->name() + "-iport");
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
icachePort.setPeer(mem_dport);
|
||||
mem_dport->setPeer(&icachePort);
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setIcachePort(&icachePort);
|
||||
|
|
|
@ -51,6 +51,8 @@ class ThreadContext;
|
|||
template <class Impl>
|
||||
class OzoneThreadState;
|
||||
|
||||
class Port;
|
||||
|
||||
template <class Impl>
|
||||
class LWBackEnd
|
||||
{
|
||||
|
@ -114,6 +116,8 @@ class LWBackEnd
|
|||
|
||||
void setCommBuffer(TimeBuffer<CommStruct> *_comm);
|
||||
|
||||
Port *getDcachePort() { return LSQ.getDcachePort(); }
|
||||
|
||||
void tick();
|
||||
void squash();
|
||||
void generateTCEvent() { tcSquash = true; }
|
||||
|
|
|
@ -142,7 +142,7 @@ LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst)
|
|||
template <class Impl>
|
||||
LWBackEnd<Impl>::LWBackEnd(Params *params)
|
||||
: d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5),
|
||||
trapSquash(false), tcSquash(false), LSQ(params),
|
||||
trapSquash(false), tcSquash(false),
|
||||
width(params->backEndWidth), exactFullStall(true)
|
||||
{
|
||||
numROBEntries = params->numROBEntries;
|
||||
|
@ -557,6 +557,7 @@ LWBackEnd<Impl>::checkInterrupts()
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
|
@ -580,7 +581,6 @@ LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency)
|
|||
// Generate trap squash event.
|
||||
generateTrapEvent(latency);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
|
@ -602,6 +602,7 @@ LWBackEnd<Impl>::tick()
|
|||
|
||||
#if FULL_SYSTEM
|
||||
checkInterrupts();
|
||||
#endif
|
||||
|
||||
if (trapSquash) {
|
||||
assert(!tcSquash);
|
||||
|
@ -609,7 +610,6 @@ LWBackEnd<Impl>::tick()
|
|||
} else if (tcSquash) {
|
||||
squashFromTC();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dispatchStatus != Blocked) {
|
||||
dispatchInsts();
|
||||
|
@ -1137,13 +1137,9 @@ LWBackEnd<Impl>::commitInst(int inst_num)
|
|||
|
||||
thread->setInst(
|
||||
static_cast<TheISA::MachInst>(inst->staticInst->machInst));
|
||||
#if FULL_SYSTEM
|
||||
|
||||
handleFault(inst_fault);
|
||||
return false;
|
||||
#else // !FULL_SYSTEM
|
||||
panic("fault (%d) detected @ PC %08p", inst_fault,
|
||||
inst->PC);
|
||||
#endif // FULL_SYSTEM
|
||||
}
|
||||
|
||||
int freed_regs = 0;
|
||||
|
|
|
@ -91,8 +91,7 @@ class OzoneLWLSQ {
|
|||
void setBE(BackEnd *be_ptr)
|
||||
{ be = be_ptr; }
|
||||
|
||||
/** Sets the page table pointer. */
|
||||
// void setPageTable(PageTable *pt_ptr);
|
||||
Port *getDcachePort() { return &dcachePort; }
|
||||
|
||||
/** Ticks the LSQ unit, which in this case only resets the number of
|
||||
* used cache ports.
|
||||
|
@ -241,13 +240,11 @@ class OzoneLWLSQ {
|
|||
class DcachePort : public Port
|
||||
{
|
||||
protected:
|
||||
OzoneCPU *cpu;
|
||||
|
||||
OzoneLWLSQ *lsq;
|
||||
|
||||
public:
|
||||
DcachePort(OzoneCPU *_cpu, OzoneLWLSQ *_lsq)
|
||||
: Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
|
||||
DcachePort(OzoneLWLSQ *_lsq)
|
||||
: lsq(_lsq)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
@ -266,11 +263,8 @@ class OzoneLWLSQ {
|
|||
virtual void recvRetry();
|
||||
};
|
||||
|
||||
/** Pointer to the D-cache. */
|
||||
DcachePort *dcachePort;
|
||||
|
||||
/** Pointer to the page table. */
|
||||
// PageTable *pTable;
|
||||
/** D-cache port. */
|
||||
DcachePort dcachePort;
|
||||
|
||||
public:
|
||||
struct SQEntry {
|
||||
|
@ -639,7 +633,7 @@ OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
|
|||
data_pkt->senderState = state;
|
||||
|
||||
// if we have a cache, do cache access too
|
||||
if (!dcachePort->sendTiming(data_pkt)) {
|
||||
if (!dcachePort.sendTiming(data_pkt)) {
|
||||
// There's an older load that's already going to squash.
|
||||
if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
|
||||
return NoFault;
|
||||
|
|
|
@ -131,8 +131,9 @@ OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
|
|||
|
||||
template <class Impl>
|
||||
OzoneLWLSQ<Impl>::OzoneLWLSQ()
|
||||
: switchedOut(false), loads(0), stores(0), storesToWB(0), stalled(false),
|
||||
isStoreBlocked(false), isLoadBlocked(false), loadBlockedHandled(false)
|
||||
: switchedOut(false), dcachePort(this), loads(0), stores(0),
|
||||
storesToWB(0), stalled(false), isStoreBlocked(false),
|
||||
isLoadBlocked(false), loadBlockedHandled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -175,15 +176,11 @@ void
|
|||
OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
|
||||
{
|
||||
cpu = cpu_ptr;
|
||||
dcachePort = new DcachePort(cpu, this);
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
dcachePort->setPeer(mem_dport);
|
||||
mem_dport->setPeer(dcachePort);
|
||||
dcachePort.setName(this->name() + "-dport");
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setDcachePort(dcachePort);
|
||||
cpu->checker->setDcachePort(&dcachePort);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -614,7 +611,7 @@ OzoneLWLSQ<Impl>::writebackStores()
|
|||
state->noWB = true;
|
||||
}
|
||||
|
||||
if (!dcachePort->sendTiming(data_pkt)) {
|
||||
if (!dcachePort.sendTiming(data_pkt)) {
|
||||
// Need to handle becoming blocked on a store.
|
||||
isStoreBlocked = true;
|
||||
assert(retryPkt == NULL);
|
||||
|
|
|
@ -55,18 +55,28 @@ AtomicSimpleCPU::TickEvent::description()
|
|||
return "AtomicSimpleCPU tick event";
|
||||
}
|
||||
|
||||
Port *
|
||||
AtomicSimpleCPU::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "dcache_port")
|
||||
return &dcachePort;
|
||||
else if (if_name == "icache_port")
|
||||
return &icachePort;
|
||||
else
|
||||
panic("No Such Port\n");
|
||||
}
|
||||
|
||||
void
|
||||
AtomicSimpleCPU::init()
|
||||
{
|
||||
//Create Memory Ports (conect them up)
|
||||
Port *mem_dport = mem->getPort("");
|
||||
dcachePort.setPeer(mem_dport);
|
||||
mem_dport->setPeer(&dcachePort);
|
||||
// Port *mem_dport = mem->getPort("");
|
||||
// dcachePort.setPeer(mem_dport);
|
||||
// mem_dport->setPeer(&dcachePort);
|
||||
|
||||
Port *mem_iport = mem->getPort("");
|
||||
icachePort.setPeer(mem_iport);
|
||||
mem_iport->setPeer(&icachePort);
|
||||
// Port *mem_iport = mem->getPort("");
|
||||
// icachePort.setPeer(mem_iport);
|
||||
// mem_iport->setPeer(&icachePort);
|
||||
|
||||
BaseCPU::init();
|
||||
#if FULL_SYSTEM
|
||||
|
|
|
@ -122,6 +122,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU
|
|||
|
||||
public:
|
||||
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
|
|
|
@ -37,19 +37,20 @@
|
|||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
Port *
|
||||
TimingSimpleCPU::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "dcache_port")
|
||||
return &dcachePort;
|
||||
else if (if_name == "icache_port")
|
||||
return &icachePort;
|
||||
else
|
||||
panic("No Such Port\n");
|
||||
}
|
||||
|
||||
void
|
||||
TimingSimpleCPU::init()
|
||||
{
|
||||
//Create Memory Ports (conect them up)
|
||||
Port *mem_dport = mem->getPort("");
|
||||
dcachePort.setPeer(mem_dport);
|
||||
mem_dport->setPeer(&dcachePort);
|
||||
|
||||
Port *mem_iport = mem->getPort("");
|
||||
icachePort.setPeer(mem_iport);
|
||||
mem_iport->setPeer(&icachePort);
|
||||
|
||||
BaseCPU::init();
|
||||
#if FULL_SYSTEM
|
||||
for (int i = 0; i < threadContexts.size(); ++i) {
|
||||
|
@ -89,6 +90,7 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
|
|||
_status = Idle;
|
||||
ifetch_pkt = dcache_pkt = NULL;
|
||||
drainEvent = NULL;
|
||||
fetchEvent = NULL;
|
||||
state = SimObject::Timing;
|
||||
}
|
||||
|
||||
|
@ -118,11 +120,11 @@ TimingSimpleCPU::drain(Event *drain_event)
|
|||
// an access to complete.
|
||||
if (status() == Idle || status() == Running || status() == SwitchedOut) {
|
||||
changeState(SimObject::DrainedTiming);
|
||||
return false;
|
||||
return true;
|
||||
} else {
|
||||
changeState(SimObject::Draining);
|
||||
drainEvent = drain_event;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,9 +132,15 @@ void
|
|||
TimingSimpleCPU::resume()
|
||||
{
|
||||
if (_status != SwitchedOut && _status != Idle) {
|
||||
Event *e =
|
||||
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
|
||||
e->schedule(curTick);
|
||||
// Delete the old event if it existed.
|
||||
if (fetchEvent) {
|
||||
assert(!fetchEvent->scheduled());
|
||||
delete fetchEvent;
|
||||
}
|
||||
|
||||
fetchEvent =
|
||||
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
|
||||
fetchEvent->schedule(curTick);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,6 +155,11 @@ TimingSimpleCPU::switchOut()
|
|||
{
|
||||
assert(status() == Running || status() == Idle);
|
||||
_status = SwitchedOut;
|
||||
|
||||
// If we've been scheduled to resume but are then told to switch out,
|
||||
// we'll need to cancel it.
|
||||
if (fetchEvent && fetchEvent->scheduled())
|
||||
fetchEvent->deschedule();
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,9 +191,9 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
|
|||
notIdleFraction++;
|
||||
_status = Running;
|
||||
// kick things off by initiating the fetch of the next instruction
|
||||
Event *e =
|
||||
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
|
||||
e->schedule(curTick + cycles(delay));
|
||||
fetchEvent =
|
||||
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
|
||||
fetchEvent->schedule(curTick + cycles(delay));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
|||
|
||||
Event *drainEvent;
|
||||
|
||||
Event *fetchEvent;
|
||||
|
||||
private:
|
||||
|
||||
class CpuPort : public Port
|
||||
|
@ -130,6 +132,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
|||
|
||||
public:
|
||||
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
|
|
|
@ -123,15 +123,19 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num,
|
|||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
}
|
||||
|
||||
SimpleThread::SimpleThread(RegFile *regFile)
|
||||
: ThreadState(-1, -1, NULL, -1, NULL), cpu(NULL)
|
||||
{
|
||||
regs = *regFile;
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SimpleThread::SimpleThread()
|
||||
#if FULL_SYSTEM
|
||||
: ThreadState(-1, -1)
|
||||
#else
|
||||
: ThreadState(-1, -1, NULL, -1, NULL)
|
||||
#endif
|
||||
{
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
regs.clear();
|
||||
}
|
||||
|
||||
SimpleThread::~SimpleThread()
|
||||
{
|
||||
delete tc;
|
||||
|
@ -147,13 +151,8 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
|
|||
assert(process == oldContext->getProcessPtr());
|
||||
#endif
|
||||
|
||||
// copy over functional state
|
||||
_status = oldContext->status();
|
||||
copyArchRegs(oldContext);
|
||||
cpuId = oldContext->readCpuId();
|
||||
#if !FULL_SYSTEM
|
||||
funcExeInst = oldContext->readFuncExeInst();
|
||||
#else
|
||||
copyState(oldContext);
|
||||
#if FULL_SYSTEM
|
||||
EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
|
||||
if (quiesce) {
|
||||
// Point the quiesce event's TC at this TC so that it wakes up
|
||||
|
@ -171,42 +170,49 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
|
|||
}
|
||||
|
||||
void
|
||||
SimpleThread::serialize(ostream &os)
|
||||
SimpleThread::copyTC(ThreadContext *context)
|
||||
{
|
||||
SERIALIZE_ENUM(_status);
|
||||
regs.serialize(os);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
SERIALIZE_SCALAR(funcExeInst);
|
||||
SERIALIZE_SCALAR(inst);
|
||||
copyState(context);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick = 0;
|
||||
if (quiesceEvent->scheduled())
|
||||
quiesceEndTick = quiesceEvent->when();
|
||||
SERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->serialize(os);
|
||||
EndQuiesceEvent *quiesce = context->getQuiesceEvent();
|
||||
if (quiesce) {
|
||||
quiesceEvent = quiesce;
|
||||
}
|
||||
Kernel::Statistics *stats = context->getKernelStats();
|
||||
if (stats) {
|
||||
kernelStats = stats;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SimpleThread::copyState(ThreadContext *oldContext)
|
||||
{
|
||||
// copy over functional state
|
||||
_status = oldContext->status();
|
||||
copyArchRegs(oldContext);
|
||||
cpuId = oldContext->readCpuId();
|
||||
#if !FULL_SYSTEM
|
||||
funcExeInst = oldContext->readFuncExeInst();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SimpleThread::serialize(ostream &os)
|
||||
{
|
||||
ThreadState::serialize(os);
|
||||
regs.serialize(os);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleThread::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
UNSERIALIZE_ENUM(_status);
|
||||
ThreadState::unserialize(cp, section);
|
||||
regs.unserialize(cp, section);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
UNSERIALIZE_SCALAR(funcExeInst);
|
||||
UNSERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick;
|
||||
UNSERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (quiesceEndTick)
|
||||
quiesceEvent->schedule(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->unserialize(cp, section);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
|
|
@ -119,16 +119,20 @@ class SimpleThread : public ThreadState
|
|||
#else
|
||||
SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
|
||||
MemObject *memobj);
|
||||
// Constructor to use SimpleThread to pass reg file around. Not
|
||||
// used for anything else.
|
||||
SimpleThread(RegFile *regFile);
|
||||
#endif
|
||||
|
||||
SimpleThread();
|
||||
|
||||
virtual ~SimpleThread();
|
||||
|
||||
virtual void takeOverFrom(ThreadContext *oldContext);
|
||||
|
||||
void regStats(const std::string &name);
|
||||
|
||||
void copyTC(ThreadContext *context);
|
||||
|
||||
void copyState(ThreadContext *oldContext);
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ class ThreadContext
|
|||
virtual void suspend() = 0;
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
virtual void deallocate() = 0;
|
||||
virtual void deallocate(int delay = 0) = 0;
|
||||
|
||||
/// Set the status to Halted.
|
||||
virtual void halt() = 0;
|
||||
|
@ -318,7 +318,7 @@ class ProxyThreadContext : public ThreadContext
|
|||
void suspend() { actualTC->suspend(); }
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
void deallocate() { actualTC->deallocate(); }
|
||||
void deallocate(int delay = 0) { actualTC->deallocate(); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt() { actualTC->halt(); }
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
#include "base/output.hh"
|
||||
#include "cpu/profile.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
#include "sim/serialize.hh"
|
||||
|
||||
#if FULL_SYSTEM
|
||||
#include "cpu/quiesce_event.hh"
|
||||
#include "kern/kernel_stats.hh"
|
||||
#endif
|
||||
|
||||
#if FULL_SYSTEM
|
||||
ThreadState::ThreadState(int _cpuId, int _tid)
|
||||
|
@ -49,6 +55,43 @@ ThreadState::ThreadState(int _cpuId, int _tid, Process *_process,
|
|||
numLoad = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ThreadState::serialize(std::ostream &os)
|
||||
{
|
||||
SERIALIZE_ENUM(_status);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
SERIALIZE_SCALAR(funcExeInst);
|
||||
SERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick = 0;
|
||||
if (quiesceEvent->scheduled())
|
||||
quiesceEndTick = quiesceEvent->when();
|
||||
SERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->serialize(os);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ThreadState::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
|
||||
UNSERIALIZE_ENUM(_status);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
UNSERIALIZE_SCALAR(funcExeInst);
|
||||
UNSERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick;
|
||||
UNSERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (quiesceEndTick)
|
||||
quiesceEvent->schedule(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->unserialize(cp, section);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
||||
void
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace Kernel {
|
|||
};
|
||||
#endif
|
||||
|
||||
class Checkpoint;
|
||||
|
||||
/**
|
||||
* Struct for holding general thread state that is needed across CPU
|
||||
* models. This includes things such as pointers to the process,
|
||||
|
@ -65,6 +67,10 @@ struct ThreadState {
|
|||
short _asid, MemObject *mem);
|
||||
#endif
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
void setCpuId(int id) { cpuId = id; }
|
||||
|
||||
int readCpuId() { return cpuId; }
|
||||
|
|
|
@ -46,7 +46,7 @@ class TsunamiPChip : public BasicPioDevice
|
|||
{
|
||||
protected:
|
||||
|
||||
static const Addr TsunamiPciBus0Config = 0x801fe000000;
|
||||
static const Addr TsunamiPciBus0Config = ULL(0x801fe000000);
|
||||
|
||||
/** Pchip control register */
|
||||
uint64_t pctl;
|
||||
|
|
41
src/mem/cache/base_cache.cc
vendored
41
src/mem/cache/base_cache.cc
vendored
|
@ -59,7 +59,7 @@ void
|
|||
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
|
||||
AddrRangeList &snoop)
|
||||
{
|
||||
cache->getAddressRanges(resp, snoop);
|
||||
cache->getAddressRanges(resp, snoop, isCpuSide);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -117,10 +117,29 @@ BaseCache::CacheEvent::process()
|
|||
if (!pkt)
|
||||
{
|
||||
if (!cachePort->isCpuSide)
|
||||
{
|
||||
pkt = cachePort->cache->getPacket();
|
||||
//Else get coherence req
|
||||
bool success = cachePort->sendTiming(pkt);
|
||||
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
|
||||
pkt->getAddr(), success ? "succesful" : "unsuccesful");
|
||||
cachePort->cache->sendResult(pkt, success);
|
||||
if (success && cachePort->cache->doMasterRequest())
|
||||
{
|
||||
//Still more to issue, rerequest in 1 cycle
|
||||
pkt = NULL;
|
||||
this->schedule(curTick+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt = cachePort->cache->getCoherencePacket();
|
||||
cachePort->sendTiming(pkt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
cachePort->sendTiming(pkt);
|
||||
//Know the packet to send, no need to mark in service (must succed)
|
||||
bool success = cachePort->sendTiming(pkt);
|
||||
assert(success);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -138,7 +157,13 @@ BaseCache::getPort(const std::string &if_name, int idx)
|
|||
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
|
||||
return cpuSidePort;
|
||||
}
|
||||
if (if_name == "functional")
|
||||
else if (if_name == "functional")
|
||||
{
|
||||
if(cpuSidePort == NULL)
|
||||
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
|
||||
return cpuSidePort;
|
||||
}
|
||||
else if (if_name == "cpu_side")
|
||||
{
|
||||
if(cpuSidePort == NULL)
|
||||
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
|
||||
|
@ -154,6 +179,14 @@ BaseCache::getPort(const std::string &if_name, int idx)
|
|||
else panic("Port name %s unrecognized\n", if_name);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::init()
|
||||
{
|
||||
if (!cpuSidePort || !memSidePort)
|
||||
panic("Cache not hooked up on both sides\n");
|
||||
cpuSidePort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::regStats()
|
||||
{
|
||||
|
|
40
src/mem/cache/base_cache.hh
vendored
40
src/mem/cache/base_cache.hh
vendored
|
@ -143,9 +143,19 @@ class BaseCache : public MemObject
|
|||
fatal("No implementation");
|
||||
}
|
||||
|
||||
virtual void recvStatusChange(Port::Status status, bool isCpuSide)
|
||||
void recvStatusChange(Port::Status status, bool isCpuSide)
|
||||
{
|
||||
fatal("No implementation");
|
||||
if (status == Port::RangeChange)
|
||||
{
|
||||
if (!isCpuSide)
|
||||
{
|
||||
cpuSidePort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
memSidePort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual Packet *getPacket()
|
||||
|
@ -153,6 +163,17 @@ class BaseCache : public MemObject
|
|||
fatal("No implementation");
|
||||
}
|
||||
|
||||
virtual Packet *getCoherencePacket()
|
||||
{
|
||||
fatal("No implementation");
|
||||
}
|
||||
|
||||
virtual void sendResult(Packet* &pkt, bool success)
|
||||
{
|
||||
|
||||
fatal("No implementation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Bit vector of the blocking reasons for the access path.
|
||||
* @sa #BlockedCause
|
||||
|
@ -309,6 +330,8 @@ class BaseCache : public MemObject
|
|||
memSidePort = NULL;
|
||||
}
|
||||
|
||||
virtual void init();
|
||||
|
||||
/**
|
||||
* Query block size of a cache.
|
||||
* @return The block size
|
||||
|
@ -508,9 +531,18 @@ class BaseCache : public MemObject
|
|||
*/
|
||||
void rangeChange() {}
|
||||
|
||||
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
|
||||
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
|
||||
{
|
||||
panic("Unimplimented\n");
|
||||
if (isCpuSide)
|
||||
{
|
||||
AddrRangeList dummy;
|
||||
memSidePort->getPeerAddressRanges(resp, dummy);
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is where snoops get updated
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
4
src/mem/cache/cache.hh
vendored
4
src/mem/cache/cache.hh
vendored
|
@ -175,7 +175,7 @@ class Cache : public BaseCache
|
|||
* @param req The request.
|
||||
* @param success True if the request was sent successfully.
|
||||
*/
|
||||
void sendResult(Packet * &pkt, bool success);
|
||||
virtual void sendResult(Packet * &pkt, bool success);
|
||||
|
||||
/**
|
||||
* Handles a response (cache line fill/write ack) from the bus.
|
||||
|
@ -202,7 +202,7 @@ class Cache : public BaseCache
|
|||
* Selects a coherence message to forward to lower levels of the hierarchy.
|
||||
* @return The coherence message to forward.
|
||||
*/
|
||||
Packet * getCoherenceReq();
|
||||
virtual Packet * getCoherencePacket();
|
||||
|
||||
/**
|
||||
* Snoops bus transactions to maintain coherence.
|
||||
|
|
2
src/mem/cache/cache_impl.hh
vendored
2
src/mem/cache/cache_impl.hh
vendored
|
@ -350,7 +350,7 @@ Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
|
|||
|
||||
template<class TagStore, class Buffering, class Coherence>
|
||||
Packet *
|
||||
Cache<TagStore,Buffering,Coherence>::getCoherenceReq()
|
||||
Cache<TagStore,Buffering,Coherence>::getCoherencePacket()
|
||||
{
|
||||
return coherence->getPacket();
|
||||
}
|
||||
|
|
8
src/mem/cache/miss/miss_queue.cc
vendored
8
src/mem/cache/miss/miss_queue.cc
vendored
|
@ -352,7 +352,7 @@ MissQueue::setPrefetcher(BasePrefetcher *_prefetcher)
|
|||
MSHR*
|
||||
MissQueue::allocateMiss(Packet * &pkt, int size, Tick time)
|
||||
{
|
||||
MSHR* mshr = mq.allocate(pkt, size);
|
||||
MSHR* mshr = mq.allocate(pkt, blkSize);
|
||||
mshr->order = order++;
|
||||
if (!pkt->req->isUncacheable() ){//&& !pkt->isNoAllocate()) {
|
||||
// Mark this as a cache line fill
|
||||
|
@ -372,7 +372,7 @@ MissQueue::allocateMiss(Packet * &pkt, int size, Tick time)
|
|||
MSHR*
|
||||
MissQueue::allocateWrite(Packet * &pkt, int size, Tick time)
|
||||
{
|
||||
MSHR* mshr = wb.allocate(pkt,pkt->getSize());
|
||||
MSHR* mshr = wb.allocate(pkt,blkSize);
|
||||
mshr->order = order++;
|
||||
|
||||
//REMOVING COMPRESSION FOR NOW
|
||||
|
@ -446,11 +446,11 @@ MissQueue::handleMiss(Packet * &pkt, int blkSize, Tick time)
|
|||
/**
|
||||
* @todo Add write merging here.
|
||||
*/
|
||||
mshr = allocateWrite(pkt, pkt->getSize(), time);
|
||||
mshr = allocateWrite(pkt, blkSize, time);
|
||||
return;
|
||||
}
|
||||
|
||||
mshr = allocateMiss(pkt, size, time);
|
||||
mshr = allocateMiss(pkt, blkSize, time);
|
||||
}
|
||||
|
||||
MSHR*
|
||||
|
|
1
src/mem/cache/miss/mshr.cc
vendored
1
src/mem/cache/miss/mshr.cc
vendored
|
@ -57,6 +57,7 @@ void
|
|||
MSHR::allocate(Packet::Command cmd, Addr _addr, int _asid, int size,
|
||||
Packet * &target)
|
||||
{
|
||||
addr = _addr;
|
||||
if (target)
|
||||
{
|
||||
//Have a request, just use it
|
||||
|
|
|
@ -183,19 +183,19 @@ class Packet
|
|||
ReadReq = IsRead | IsRequest | NeedsResponse,
|
||||
WriteReq = IsWrite | IsRequest | NeedsResponse,
|
||||
WriteReqNoAck = IsWrite | IsRequest,
|
||||
ReadResp = IsRead | IsResponse,
|
||||
WriteResp = IsWrite | IsResponse,
|
||||
ReadResp = IsRead | IsResponse | NeedsResponse,
|
||||
WriteResp = IsWrite | IsResponse | NeedsResponse,
|
||||
Writeback = IsWrite | IsRequest,
|
||||
SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
|
||||
HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
|
||||
SoftPFResp = IsRead | IsRequest | IsSWPrefetch | IsResponse,
|
||||
HardPFResp = IsRead | IsRequest | IsHWPrefetch | IsResponse,
|
||||
SoftPFResp = IsRead | IsResponse | IsSWPrefetch | NeedsResponse,
|
||||
HardPFResp = IsRead | IsResponse | IsHWPrefetch | NeedsResponse,
|
||||
InvalidateReq = IsInvalidate | IsRequest,
|
||||
WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest,
|
||||
UpgradeReq = IsInvalidate | NeedsResponse,
|
||||
UpgradeResp = IsInvalidate | IsResponse,
|
||||
ReadExReq = IsRead | IsInvalidate | NeedsResponse,
|
||||
ReadExResp = IsRead | IsInvalidate | IsResponse
|
||||
UpgradeReq = IsInvalidate | IsRequest | NeedsResponse,
|
||||
UpgradeResp = IsInvalidate | IsResponse | NeedsResponse,
|
||||
ReadExReq = IsRead | IsInvalidate | IsRequest | NeedsResponse,
|
||||
ReadExResp = IsRead | IsInvalidate | IsResponse | NeedsResponse
|
||||
};
|
||||
|
||||
/** Return the string name of the cmd field (for debugging and
|
||||
|
@ -247,7 +247,7 @@ class Packet
|
|||
|
||||
Addr getAddr() const { assert(addrSizeValid); return addr; }
|
||||
int getSize() const { assert(addrSizeValid); return size; }
|
||||
Addr getOffset(int blkSize) const { return req->getPaddr() & (Addr)(blkSize - 1); }
|
||||
Addr getOffset(int blkSize) const { return addr & (Addr)(blkSize - 1); }
|
||||
|
||||
void addrOverride(Addr newAddr) { assert(addrSizeValid); addr = newAddr; }
|
||||
void cmdOverride(Command newCmd) { cmd = newCmd; }
|
||||
|
@ -311,8 +311,9 @@ class Packet
|
|||
* should not be called. */
|
||||
void makeTimingResponse() {
|
||||
assert(needsResponse());
|
||||
assert(isRequest());
|
||||
int icmd = (int)cmd;
|
||||
icmd &= ~(IsRequest | NeedsResponse);
|
||||
icmd &= ~(IsRequest);
|
||||
icmd |= IsResponse;
|
||||
cmd = (Command)icmd;
|
||||
dest = src;
|
||||
|
|
|
@ -75,16 +75,27 @@ def addPkg(pkgdir):
|
|||
# build_env flags.
|
||||
def MakeDefinesPyFile(target, source, env):
|
||||
f = file(str(target[0]), 'w')
|
||||
print >>f, "m5_build_env = ",
|
||||
print >>f, source[0]
|
||||
print >>f, "m5_build_env = ", source[0]
|
||||
f.close()
|
||||
|
||||
optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
|
||||
env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile)
|
||||
|
||||
def MakeInfoPyFile(target, source, env):
|
||||
f = file(str(target[0]), 'w')
|
||||
for src in source:
|
||||
data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
|
||||
print >>f, "%s = %s" % (src, repr(data))
|
||||
f.close()
|
||||
|
||||
env.Command('m5/info.py',
|
||||
[ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
|
||||
MakeInfoPyFile)
|
||||
|
||||
# Now specify the packages & files for the zip archive.
|
||||
addPkg('m5')
|
||||
pyzip_files.append('m5/defines.py')
|
||||
pyzip_files.append('m5/info.py')
|
||||
pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py'))
|
||||
|
||||
env.Command(['swig/cc_main_wrap.cc', 'm5/cc_main.py'],
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
# Authors: Nathan Binkert
|
||||
# Steve Reinhardt
|
||||
|
||||
import sys, os, time, atexit, optparse
|
||||
import atexit, os, sys
|
||||
|
||||
# import the SWIG-wrapped main C++ functions
|
||||
import cc_main
|
||||
# import a few SWIG-wrapped items (those that are likely to be used
|
||||
# directly by user scripts) completely into this module for
|
||||
# convenience
|
||||
from cc_main import simulate, SimLoopExitEvent, setCheckpointDir
|
||||
from cc_main import simulate, SimLoopExitEvent
|
||||
|
||||
# import the m5 compile options
|
||||
import defines
|
||||
|
@ -57,111 +57,6 @@ def AddToPath(path):
|
|||
# so place the new dir right after that.
|
||||
sys.path.insert(1, path)
|
||||
|
||||
|
||||
# The m5 module's pointer to the parsed options object
|
||||
options = None
|
||||
|
||||
|
||||
# User should call this function after calling parse_args() to pass
|
||||
# parsed standard option values back into the m5 module for
|
||||
# processing.
|
||||
def setStandardOptions(_options):
|
||||
# Set module global var
|
||||
global options
|
||||
options = _options
|
||||
# tell C++ about output directory
|
||||
cc_main.setOutputDir(options.outdir)
|
||||
|
||||
# Callback to set trace flags. Not necessarily the best way to do
|
||||
# things in the long run (particularly if we change how these global
|
||||
# options are handled).
|
||||
def setTraceFlags(option, opt_str, value, parser):
|
||||
objects.Trace.flags = value
|
||||
|
||||
def setTraceStart(option, opt_str, value, parser):
|
||||
objects.Trace.start = value
|
||||
|
||||
def setTraceFile(option, opt_str, value, parser):
|
||||
objects.Trace.file = value
|
||||
|
||||
def noPCSymbol(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.pc_symbol = False
|
||||
|
||||
def noPrintCycle(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_cycle = False
|
||||
|
||||
def noPrintOpclass(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_opclass = False
|
||||
|
||||
def noPrintThread(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_thread = False
|
||||
|
||||
def noPrintEA(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_effaddr = False
|
||||
|
||||
def noPrintData(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_data = False
|
||||
|
||||
def printFetchseq(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_fetchseq = True
|
||||
|
||||
def printCpseq(option, opt_str, value, parser):
|
||||
objects.ExecutionTrace.print_cpseq = True
|
||||
|
||||
def dumpOnExit(option, opt_str, value, parser):
|
||||
objects.Trace.dump_on_exit = True
|
||||
|
||||
def debugBreak(option, opt_str, value, parser):
|
||||
objects.Debug.break_cycles = value
|
||||
|
||||
def statsTextFile(option, opt_str, value, parser):
|
||||
objects.Statistics.text_file = value
|
||||
|
||||
# Standard optparse options. Need to be explicitly included by the
|
||||
# user script when it calls optparse.OptionParser().
|
||||
standardOptions = [
|
||||
optparse.make_option("--outdir", type="string", default="."),
|
||||
optparse.make_option("--traceflags", type="string", action="callback",
|
||||
callback=setTraceFlags),
|
||||
optparse.make_option("--tracestart", type="int", action="callback",
|
||||
callback=setTraceStart),
|
||||
optparse.make_option("--tracefile", type="string", action="callback",
|
||||
callback=setTraceFile),
|
||||
optparse.make_option("--nopcsymbol",
|
||||
action="callback", callback=noPCSymbol,
|
||||
help="Disable PC symbols in trace output"),
|
||||
optparse.make_option("--noprintcycle",
|
||||
action="callback", callback=noPrintCycle,
|
||||
help="Don't print cycle numbers in trace output"),
|
||||
optparse.make_option("--noprintopclass",
|
||||
action="callback", callback=noPrintOpclass,
|
||||
help="Don't print op class type in trace output"),
|
||||
optparse.make_option("--noprintthread",
|
||||
action="callback", callback=noPrintThread,
|
||||
help="Don't print thread number in trace output"),
|
||||
optparse.make_option("--noprinteffaddr",
|
||||
action="callback", callback=noPrintEA,
|
||||
help="Don't print effective address in trace output"),
|
||||
optparse.make_option("--noprintdata",
|
||||
action="callback", callback=noPrintData,
|
||||
help="Don't print result data in trace output"),
|
||||
optparse.make_option("--printfetchseq",
|
||||
action="callback", callback=printFetchseq,
|
||||
help="Print fetch sequence numbers in trace output"),
|
||||
optparse.make_option("--printcpseq",
|
||||
action="callback", callback=printCpseq,
|
||||
help="Print correct path sequence numbers in trace output"),
|
||||
optparse.make_option("--dumponexit",
|
||||
action="callback", callback=dumpOnExit,
|
||||
help="Dump trace buffer on exit"),
|
||||
optparse.make_option("--debugbreak", type="int", metavar="CYCLE",
|
||||
action="callback", callback=debugBreak,
|
||||
help="Cycle to create a breakpoint"),
|
||||
optparse.make_option("--statsfile", type="string", action="callback",
|
||||
callback=statsTextFile, metavar="FILE",
|
||||
help="Sets the output file for the statistics")
|
||||
]
|
||||
|
||||
# make a SmartDict out of the build options for our local use
|
||||
import smartdict
|
||||
build_env = smartdict.SmartDict()
|
||||
|
@ -171,12 +66,13 @@ build_env.update(defines.m5_build_env)
|
|||
env = smartdict.SmartDict()
|
||||
env.update(os.environ)
|
||||
|
||||
|
||||
# Function to provide to C++ so it can look up instances based on paths
|
||||
def resolveSimObject(name):
|
||||
obj = config.instanceDict[name]
|
||||
return obj.getCCObject()
|
||||
|
||||
from main import options, arguments, main
|
||||
|
||||
# The final hook to generate .ini files. Called from the user script
|
||||
# once the config is built.
|
||||
def instantiate(root):
|
||||
|
@ -213,29 +109,44 @@ atexit.register(cc_main.doExitCleanup)
|
|||
# matter since most scripts will probably 'from m5.objects import *'.
|
||||
import objects
|
||||
|
||||
# This loops until all objects have been fully drained.
|
||||
def doDrain(root):
|
||||
all_drained = drain(root)
|
||||
while (not all_drained):
|
||||
all_drained = drain(root)
|
||||
|
||||
# Tries to drain all objects. Draining might not be completed unless
|
||||
# all objects return that they are drained on the first call. This is
|
||||
# because as objects drain they may cause other objects to no longer
|
||||
# be drained.
|
||||
def drain(root):
|
||||
all_drained = False
|
||||
drain_event = cc_main.createCountedDrain()
|
||||
unready_objects = root.startDrain(drain_event, True)
|
||||
# If we've got some objects that can't drain immediately, then simulate
|
||||
if unready_objects > 0:
|
||||
drain_event.setCount(unready_objects)
|
||||
simulate()
|
||||
else:
|
||||
all_drained = True
|
||||
cc_main.cleanupCountedDrain(drain_event)
|
||||
return all_drained
|
||||
|
||||
def resume(root):
|
||||
root.resume()
|
||||
|
||||
def checkpoint(root):
|
||||
def checkpoint(root, dir):
|
||||
if not isinstance(root, objects.Root):
|
||||
raise TypeError, "Object is not a root object. Checkpoint must be called on a root object."
|
||||
doDrain(root)
|
||||
print "Writing checkpoint"
|
||||
cc_main.serializeAll()
|
||||
cc_main.serializeAll(dir)
|
||||
resume(root)
|
||||
|
||||
def restoreCheckpoint(root):
|
||||
def restoreCheckpoint(root, dir):
|
||||
print "Restoring from checkpoint"
|
||||
cc_main.unserializeAll()
|
||||
cc_main.unserializeAll(dir)
|
||||
resume(root)
|
||||
|
||||
def changeToAtomic(system):
|
||||
if not isinstance(system, objects.Root) and not isinstance(system, System):
|
||||
|
|
61
src/python/m5/attrdict.py
Normal file
61
src/python/m5/attrdict.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright (c) 2006 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Nathan Binkert
|
||||
|
||||
__all__ = [ 'attrdict' ]
|
||||
|
||||
class attrdict(dict):
|
||||
def __getattr__(self, attr):
|
||||
if attr in self:
|
||||
return self.__getitem__(attr)
|
||||
return super(attrdict, self).__getattribute__(attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in dir(self):
|
||||
return super(attrdict, self).__setattr__(attr, value)
|
||||
return self.__setitem__(attr, value)
|
||||
|
||||
def __delattr__(self, attr):
|
||||
if attr in self:
|
||||
return self.__delitem__(attr)
|
||||
return super(attrdict, self).__delattr__(attr, value)
|
||||
|
||||
if __name__ == '__main__':
|
||||
x = attrdict()
|
||||
x.y = 1
|
||||
x['z'] = 2
|
||||
print x['y'], x.y
|
||||
print x['z'], x.z
|
||||
print dir(x)
|
||||
print x
|
||||
|
||||
print
|
||||
|
||||
del x['y']
|
||||
del x.z
|
||||
print dir(x)
|
||||
print(x)
|
307
src/python/m5/main.py
Normal file
307
src/python/m5/main.py
Normal file
|
@ -0,0 +1,307 @@
|
|||
# Copyright (c) 2005 The Regents of The University of Michigan
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Nathan Binkert
|
||||
|
||||
import code, optparse, os, socket, sys
|
||||
from datetime import datetime
|
||||
from attrdict import attrdict
|
||||
|
||||
try:
|
||||
import info
|
||||
except ImportError:
|
||||
info = None
|
||||
|
||||
__all__ = [ 'options', 'arguments', 'main' ]
|
||||
|
||||
usage="%prog [m5 options] script.py [script options]"
|
||||
version="%prog 2.0"
|
||||
brief_copyright='''
|
||||
Copyright (c) 2001-2006
|
||||
The Regents of The University of Michigan
|
||||
All Rights Reserved
|
||||
'''
|
||||
|
||||
# there's only one option parsing done, so make it global and add some
|
||||
# helper functions to make it work well.
|
||||
parser = optparse.OptionParser(usage=usage, version=version,
|
||||
description=brief_copyright,
|
||||
formatter=optparse.TitledHelpFormatter())
|
||||
parser.disable_interspersed_args()
|
||||
|
||||
# current option group
|
||||
group = None
|
||||
|
||||
def set_group(*args, **kwargs):
|
||||
'''set the current option group'''
|
||||
global group
|
||||
if not args and not kwargs:
|
||||
group = None
|
||||
else:
|
||||
group = parser.add_option_group(*args, **kwargs)
|
||||
|
||||
class splitter(object):
|
||||
def __init__(self, split):
|
||||
self.split = split
|
||||
def __call__(self, option, opt_str, value, parser):
|
||||
getattr(parser.values, option.dest).extend(value.split(self.split))
|
||||
|
||||
def add_option(*args, **kwargs):
|
||||
'''add an option to the current option group, or global none set'''
|
||||
|
||||
# if action=split, but allows the option arguments
|
||||
# themselves to be lists separated by the split variable'''
|
||||
|
||||
if kwargs.get('action', None) == 'append' and 'split' in kwargs:
|
||||
split = kwargs.pop('split')
|
||||
kwargs['default'] = []
|
||||
kwargs['type'] = 'string'
|
||||
kwargs['action'] = 'callback'
|
||||
kwargs['callback'] = splitter(split)
|
||||
|
||||
if group:
|
||||
return group.add_option(*args, **kwargs)
|
||||
|
||||
return parser.add_option(*args, **kwargs)
|
||||
|
||||
def bool_option(name, default, help):
|
||||
'''add a boolean option called --name and --no-name.
|
||||
Display help depending on which is the default'''
|
||||
|
||||
tname = '--%s' % name
|
||||
fname = '--no-%s' % name
|
||||
dest = name.replace('-', '_')
|
||||
if default:
|
||||
thelp = optparse.SUPPRESS_HELP
|
||||
fhelp = help
|
||||
else:
|
||||
thelp = help
|
||||
fhelp = optparse.SUPPRESS_HELP
|
||||
|
||||
add_option(tname, action="store_true", default=default, help=thelp)
|
||||
add_option(fname, action="store_false", dest=dest, help=fhelp)
|
||||
|
||||
# Help options
|
||||
add_option('-A', "--authors", action="store_true", default=False,
|
||||
help="Show author information")
|
||||
add_option('-C', "--copyright", action="store_true", default=False,
|
||||
help="Show full copyright information")
|
||||
add_option('-R', "--readme", action="store_true", default=False,
|
||||
help="Show the readme")
|
||||
add_option('-N', "--release-notes", action="store_true", default=False,
|
||||
help="Show the release notes")
|
||||
|
||||
# Options for configuring the base simulator
|
||||
add_option('-d', "--outdir", metavar="DIR", default=".",
|
||||
help="Set the output directory to DIR [Default: %default]")
|
||||
add_option('-i', "--interactive", action="store_true", default=False,
|
||||
help="Invoke the interactive interpreter after running the script")
|
||||
add_option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
|
||||
help="Prepend PATH to the system path when invoking the script")
|
||||
add_option('-q', "--quiet", action="count", default=0,
|
||||
help="Reduce verbosity")
|
||||
add_option('-v', "--verbose", action="count", default=0,
|
||||
help="Increase verbosity")
|
||||
|
||||
# Statistics options
|
||||
set_group("Statistics Options")
|
||||
add_option("--stats-file", metavar="FILE", default="m5stats.txt",
|
||||
help="Sets the output file for statistics [Default: %default]")
|
||||
|
||||
# Debugging options
|
||||
set_group("Debugging Options")
|
||||
add_option("--debug-break", metavar="TIME[,TIME]", action='append', split=',',
|
||||
help="Cycle to create a breakpoint")
|
||||
|
||||
# Tracing options
|
||||
set_group("Trace Options")
|
||||
add_option("--trace-flags", metavar="FLAG[,FLAG]", action='append', split=',',
|
||||
help="Sets the flags for tracing")
|
||||
add_option("--trace-start", metavar="TIME", default='0s',
|
||||
help="Start tracing at TIME (must have units)")
|
||||
add_option("--trace-file", metavar="FILE", default="cout",
|
||||
help="Sets the output file for tracing [Default: %default]")
|
||||
add_option("--trace-circlebuf", metavar="SIZE", type="int", default=0,
|
||||
help="If SIZE is non-zero, turn on the circular buffer with SIZE lines")
|
||||
add_option("--no-trace-circlebuf", action="store_const", const=0,
|
||||
dest='trace_circlebuf', help=optparse.SUPPRESS_HELP)
|
||||
bool_option("trace-dumponexit", default=False,
|
||||
help="Dump trace buffer on exit")
|
||||
add_option("--trace-ignore", metavar="EXPR", action='append', split=':',
|
||||
help="Ignore EXPR sim objects")
|
||||
|
||||
# Execution Trace options
|
||||
set_group("Execution Trace Options")
|
||||
bool_option("speculative", default=True,
|
||||
help="Don't capture speculative instructions")
|
||||
bool_option("print-cycle", default=True,
|
||||
help="Don't print cycle numbers in trace output")
|
||||
bool_option("print-symbol", default=True,
|
||||
help="Disable PC symbols in trace output")
|
||||
bool_option("print-opclass", default=True,
|
||||
help="Don't print op class type in trace output")
|
||||
bool_option("print-thread", default=True,
|
||||
help="Don't print thread number in trace output")
|
||||
bool_option("print-effaddr", default=True,
|
||||
help="Don't print effective address in trace output")
|
||||
bool_option("print-data", default=True,
|
||||
help="Don't print result data in trace output")
|
||||
bool_option("print-iregs", default=False,
|
||||
help="Print fetch sequence numbers in trace output")
|
||||
bool_option("print-fetch-seq", default=False,
|
||||
help="Print fetch sequence numbers in trace output")
|
||||
bool_option("print-cpseq", default=False,
|
||||
help="Print correct path sequence numbers in trace output")
|
||||
|
||||
options = attrdict()
|
||||
arguments = []
|
||||
|
||||
def usage(exitcode=None):
|
||||
print parser.help
|
||||
if exitcode is not None:
|
||||
sys.exit(exitcode)
|
||||
|
||||
def parse_args():
|
||||
_opts,args = parser.parse_args()
|
||||
opts = attrdict(_opts.__dict__)
|
||||
|
||||
# setting verbose and quiet at the same time doesn't make sense
|
||||
if opts.verbose > 0 and opts.quiet > 0:
|
||||
usage(2)
|
||||
|
||||
# store the verbosity in a single variable. 0 is default,
|
||||
# negative numbers represent quiet and positive values indicate verbose
|
||||
opts.verbose -= opts.quiet
|
||||
|
||||
del opts.quiet
|
||||
|
||||
options.update(opts)
|
||||
arguments.extend(args)
|
||||
return opts,args
|
||||
|
||||
def main():
|
||||
import cc_main
|
||||
|
||||
parse_args()
|
||||
|
||||
done = False
|
||||
if options.copyright:
|
||||
done = True
|
||||
print info.LICENSE
|
||||
print
|
||||
|
||||
if options.authors:
|
||||
done = True
|
||||
print 'Author information:'
|
||||
print
|
||||
print info.AUTHORS
|
||||
print
|
||||
|
||||
if options.readme:
|
||||
done = True
|
||||
print 'Readme:'
|
||||
print
|
||||
print info.README
|
||||
print
|
||||
|
||||
if options.release_notes:
|
||||
done = True
|
||||
print 'Release Notes:'
|
||||
print
|
||||
print info.RELEASE_NOTES
|
||||
print
|
||||
|
||||
if done:
|
||||
sys.exit(0)
|
||||
|
||||
if options.verbose >= 0:
|
||||
print "M5 Simulator System"
|
||||
print brief_copyright
|
||||
print
|
||||
print "M5 compiled %s" % cc_main.cvar.compileDate;
|
||||
print "M5 started %s" % datetime.now().ctime()
|
||||
print "M5 executing on %s" % socket.gethostname()
|
||||
|
||||
# check to make sure we can find the listed script
|
||||
if not arguments or not os.path.isfile(arguments[0]):
|
||||
usage(2)
|
||||
|
||||
# tell C++ about output directory
|
||||
cc_main.setOutputDir(options.outdir)
|
||||
|
||||
# update the system path with elements from the -p option
|
||||
sys.path[0:0] = options.path
|
||||
|
||||
import objects
|
||||
|
||||
# set stats options
|
||||
objects.Statistics.text_file = options.stats_file
|
||||
|
||||
# set debugging options
|
||||
objects.Debug.break_cycles = options.debug_break
|
||||
|
||||
# set tracing options
|
||||
objects.Trace.flags = options.trace_flags
|
||||
objects.Trace.start = options.trace_start
|
||||
objects.Trace.file = options.trace_file
|
||||
objects.Trace.bufsize = options.trace_circlebuf
|
||||
objects.Trace.dump_on_exit = options.trace_dumponexit
|
||||
objects.Trace.ignore = options.trace_ignore
|
||||
|
||||
# set execution trace options
|
||||
objects.ExecutionTrace.speculative = options.speculative
|
||||
objects.ExecutionTrace.print_cycle = options.print_cycle
|
||||
objects.ExecutionTrace.pc_symbol = options.print_symbol
|
||||
objects.ExecutionTrace.print_opclass = options.print_opclass
|
||||
objects.ExecutionTrace.print_thread = options.print_thread
|
||||
objects.ExecutionTrace.print_effaddr = options.print_effaddr
|
||||
objects.ExecutionTrace.print_data = options.print_data
|
||||
objects.ExecutionTrace.print_iregs = options.print_iregs
|
||||
objects.ExecutionTrace.print_fetchseq = options.print_fetch_seq
|
||||
objects.ExecutionTrace.print_cpseq = options.print_cpseq
|
||||
|
||||
scope = { '__file__' : sys.argv[0] }
|
||||
sys.argv = arguments
|
||||
sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
|
||||
exec("import readline", scope)
|
||||
execfile(sys.argv[0], scope)
|
||||
|
||||
# once the script is done
|
||||
if options.interactive:
|
||||
interact = code.InteractiveConsole(scope)
|
||||
interact.interact("M5 Interactive Console")
|
||||
|
||||
if __name__ == '__main__':
|
||||
from pprint import pprint
|
||||
|
||||
parse_args()
|
||||
|
||||
print 'opts:'
|
||||
pprint(options, indent=4)
|
||||
print
|
||||
|
||||
print 'args:'
|
||||
pprint(arguments, indent=4)
|
|
@ -10,6 +10,8 @@ class DerivO3CPU(BaseCPU):
|
|||
checker = Param.BaseCPU(NULL, "checker")
|
||||
|
||||
cachePorts = Param.Unsigned("Cache Ports")
|
||||
icache_port = Port("Instruction Port")
|
||||
dcache_port = Port("Data Port")
|
||||
|
||||
decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
|
||||
renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
|
||||
|
@ -51,6 +53,9 @@ class DerivO3CPU(BaseCPU):
|
|||
trapLatency = Param.Tick("Trap latency")
|
||||
fetchTrapLatency = Param.Tick("Fetch trap latency")
|
||||
|
||||
backComSize = Param.Unsigned("Time buffer size for backwards communication")
|
||||
forwardComSize = Param.Unsigned("Time buffer size for forward communication")
|
||||
|
||||
predType = Param.String("Branch predictor type ('local', 'tournament')")
|
||||
localPredictorSize = Param.Unsigned("Size of local predictor")
|
||||
localCtrBits = Param.Unsigned("Bits per counter")
|
||||
|
|
|
@ -9,6 +9,9 @@ class DerivOzoneCPU(BaseCPU):
|
|||
|
||||
checker = Param.BaseCPU("Checker CPU")
|
||||
|
||||
icache_port = Port("Instruction Port")
|
||||
dcache_port = Port("Data Port")
|
||||
|
||||
width = Param.Unsigned("Width")
|
||||
frontEndWidth = Param.Unsigned("Front end width")
|
||||
backEndWidth = Param.Unsigned("Back end width")
|
||||
|
|
168
src/sim/main.cc
168
src/sim/main.cc
|
@ -115,70 +115,11 @@ abortHandler(int sigtype)
|
|||
#endif
|
||||
}
|
||||
|
||||
/// Simulator executable name
|
||||
char *myProgName = "";
|
||||
|
||||
/// Show brief help message.
|
||||
void
|
||||
showBriefHelp(ostream &out)
|
||||
{
|
||||
char *prog = basename(myProgName);
|
||||
|
||||
ccprintf(out, "Usage:\n");
|
||||
ccprintf(out,
|
||||
"%s [-p <path>] [-i ] [-h] <config file>\n"
|
||||
"\n"
|
||||
" -p, --path <path> prepends <path> to PYTHONPATH instead of using\n"
|
||||
" built-in zip archive. Useful when developing/debugging\n"
|
||||
" changes to built-in Python libraries, as the new Python\n"
|
||||
" can be tested without building a new m5 binary.\n\n"
|
||||
" -i, --interactive forces entry into interactive mode after the supplied\n"
|
||||
" script is executed (just like the -i option to the\n"
|
||||
" Python interpreter).\n\n"
|
||||
" -h Prints this help\n\n"
|
||||
" <configfile> config file name which ends in .py. (Normally you can\n"
|
||||
" run <configfile> --help to get help on that config files\n"
|
||||
" parameters.\n\n",
|
||||
prog);
|
||||
|
||||
}
|
||||
|
||||
const char *briefCopyright =
|
||||
"Copyright (c) 2001-2006\n"
|
||||
"The Regents of The University of Michigan\n"
|
||||
"All Rights Reserved\n";
|
||||
|
||||
/// Print welcome message.
|
||||
void
|
||||
sayHello(ostream &out)
|
||||
{
|
||||
extern const char *compileDate; // from date.cc
|
||||
|
||||
ccprintf(out, "M5 Simulator System\n");
|
||||
// display copyright
|
||||
ccprintf(out, "%s\n", briefCopyright);
|
||||
ccprintf(out, "M5 compiled %d\n", compileDate);
|
||||
ccprintf(out, "M5 started %s\n", Time::start);
|
||||
|
||||
char *host = getenv("HOSTNAME");
|
||||
if (!host)
|
||||
host = getenv("HOST");
|
||||
|
||||
if (host)
|
||||
ccprintf(out, "M5 executing on %s\n", host);
|
||||
}
|
||||
|
||||
|
||||
extern "C" { void init_cc_main(); }
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
// Saze off program name
|
||||
myProgName = argv[0];
|
||||
|
||||
sayHello(cerr);
|
||||
|
||||
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
|
||||
signal(SIGTRAP, SIG_IGN);
|
||||
signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
|
||||
|
@ -189,72 +130,18 @@ main(int argc, char **argv)
|
|||
Py_SetProgramName(argv[0]);
|
||||
|
||||
// default path to m5 python code is the currently executing
|
||||
// file... Python ZipImporter will find embedded zip archive
|
||||
char *pythonpath = argv[0];
|
||||
|
||||
bool interactive = false;
|
||||
bool show_help = false;
|
||||
bool getopt_done = false;
|
||||
int opt_index = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"python", 1, 0, 'p'},
|
||||
{"interactive", 0, 0, 'i'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
do {
|
||||
switch (getopt_long(argc, argv, "+p:ih", long_options, &opt_index)) {
|
||||
// -p <path> prepends <path> to PYTHONPATH instead of
|
||||
// using built-in zip archive. Useful when
|
||||
// developing/debugging changes to built-in Python
|
||||
// libraries, as the new Python can be tested without
|
||||
// building a new m5 binary.
|
||||
case 'p':
|
||||
pythonpath = optarg;
|
||||
break;
|
||||
|
||||
// -i forces entry into interactive mode after the
|
||||
// supplied script is executed (just like the -i option to
|
||||
// the Python interpreter).
|
||||
case 'i':
|
||||
interactive = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
show_help = true;
|
||||
break;
|
||||
case -1:
|
||||
getopt_done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Unrecognized option %c\n", optopt);
|
||||
}
|
||||
} while (!getopt_done);
|
||||
|
||||
if (show_help) {
|
||||
showBriefHelp(cerr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Fix up argc & argv to hide arguments we just processed.
|
||||
// getopt() sets optind to the index of the first non-processed
|
||||
// argv element.
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
// Set up PYTHONPATH to make sure the m5 module is found
|
||||
string newpath(pythonpath);
|
||||
// file... Python ZipImporter will find embedded zip archive.
|
||||
// The M5_ARCHIVE environment variable can be used to override this.
|
||||
char *m5_archive = getenv("M5_ARCHIVE");
|
||||
string pythonpath = m5_archive ? m5_archive : argv[0];
|
||||
|
||||
char *oldpath = getenv("PYTHONPATH");
|
||||
if (oldpath != NULL) {
|
||||
newpath += ":";
|
||||
newpath += oldpath;
|
||||
pythonpath += ":";
|
||||
pythonpath += oldpath;
|
||||
}
|
||||
|
||||
if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
|
||||
if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1)
|
||||
fatal("setenv: %s\n", strerror(errno));
|
||||
|
||||
// initialize embedded Python interpreter
|
||||
|
@ -264,37 +151,8 @@ main(int argc, char **argv)
|
|||
// initialize SWIG 'cc_main' module
|
||||
init_cc_main();
|
||||
|
||||
if (argc > 0) {
|
||||
// extra arg(s): first is script file, remaining ones are args
|
||||
// to script file
|
||||
char *filename = argv[0];
|
||||
FILE *fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
fatal("cannot open file '%s'\n", filename);
|
||||
}
|
||||
|
||||
PyRun_AnyFile(fp, filename);
|
||||
} else {
|
||||
// no script file argument... force interactive prompt
|
||||
interactive = true;
|
||||
}
|
||||
|
||||
if (interactive) {
|
||||
// The following code to import readline was copied from Python
|
||||
// 2.4.3's Modules/main.c.
|
||||
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
|
||||
// Python Software Foundation; All Rights Reserved
|
||||
// We should only enable this if we're actually using an
|
||||
// interactive prompt.
|
||||
PyObject *v;
|
||||
v = PyImport_ImportModule("readline");
|
||||
if (v == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
Py_DECREF(v);
|
||||
|
||||
PyRun_InteractiveLoop(stdin, "stdin");
|
||||
}
|
||||
PyRun_SimpleString("import m5");
|
||||
PyRun_SimpleString("m5.main()");
|
||||
|
||||
// clean up Python intepreter.
|
||||
Py_Finalize();
|
||||
|
@ -542,15 +400,15 @@ cleanupCountedDrain(Event *counted_drain)
|
|||
}
|
||||
|
||||
void
|
||||
serializeAll()
|
||||
serializeAll(const std::string &cpt_dir)
|
||||
{
|
||||
Serializable::serializeAll();
|
||||
Serializable::serializeAll(cpt_dir);
|
||||
}
|
||||
|
||||
void
|
||||
unserializeAll()
|
||||
unserializeAll(const std::string &cpt_dir)
|
||||
{
|
||||
Serializable::unserializeAll();
|
||||
Serializable::unserializeAll(cpt_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "sim/pseudo_inst.hh"
|
||||
#include "arch/vtophys.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/sampler/sampler.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/quiesce_event.hh"
|
||||
#include "kern/kernel_stats.hh"
|
||||
|
|
|
@ -231,8 +231,9 @@ Globals::unserialize(Checkpoint *cp)
|
|||
}
|
||||
|
||||
void
|
||||
Serializable::serializeAll()
|
||||
Serializable::serializeAll(const std::string &cpt_dir)
|
||||
{
|
||||
setCheckpointDir(cpt_dir);
|
||||
string dir = Checkpoint::dir();
|
||||
if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
|
||||
fatal("couldn't mkdir %s\n", dir);
|
||||
|
@ -247,8 +248,9 @@ Serializable::serializeAll()
|
|||
}
|
||||
|
||||
void
|
||||
Serializable::unserializeAll()
|
||||
Serializable::unserializeAll(const std::string &cpt_dir)
|
||||
{
|
||||
setCheckpointDir(cpt_dir);
|
||||
string dir = Checkpoint::dir();
|
||||
string cpt_file = dir + Checkpoint::baseFilename;
|
||||
string section = "";
|
||||
|
@ -289,9 +291,9 @@ Checkpoint::dir()
|
|||
}
|
||||
|
||||
void
|
||||
debug_serialize()
|
||||
debug_serialize(const std::string &cpt_dir)
|
||||
{
|
||||
Serializable::serializeAll();
|
||||
Serializable::serializeAll(cpt_dir);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,8 +126,8 @@ class Serializable
|
|||
static int ckptCount;
|
||||
static int ckptMaxCount;
|
||||
static int ckptPrevCount;
|
||||
static void serializeAll();
|
||||
static void unserializeAll();
|
||||
static void serializeAll(const std::string &cpt_dir);
|
||||
static void unserializeAll(const std::string &cpt_dir);
|
||||
static void unserializeGlobals(Checkpoint *cp);
|
||||
};
|
||||
|
||||
|
@ -206,7 +206,7 @@ SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
|
|||
OBJ_CLASS::createForUnserialize);
|
||||
|
||||
void
|
||||
setCheckpointName(const std::string &name);
|
||||
setCheckpointDir(const std::string &name);
|
||||
|
||||
class Checkpoint
|
||||
{
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*
|
||||
* Authors: Steve Reinhardt
|
||||
* Kevin Lim
|
||||
* Korey Sewell
|
||||
*/
|
||||
|
||||
#ifndef __SIM_SYSCALL_EMUL_HH__
|
||||
|
|
Loading…
Reference in a new issue