Merge ktlim@zizzer:/bk/newmem
into zamp.eecs.umich.edu:/z/ktlim2/clean/newmem --HG-- extra : convert_revision : 7c7fc8a2f9579d443786e86dbcf906b355de69fc
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import m5
|
||||
from m5.objects import *
|
||||
import os
|
||||
import os,optparse,sys
|
||||
from SysPaths import *
|
||||
|
||||
parser = optparse.OptionParser(option_list=m5.standardOptions)
|
||||
@@ -98,7 +98,7 @@ class SpecwebFilesetDisk(IdeDisk):
|
||||
class BaseTsunami(Tsunami):
|
||||
cchip = TsunamiCChip(pio_addr=0x801a0000000)
|
||||
pchip = TsunamiPChip(pio_addr=0x80180000000)
|
||||
pciconfig = PciConfigAll(pio_addr=0x801fe000000)
|
||||
pciconfig = PciConfigAll()
|
||||
fake_sm_chip = IsaFake(pio_addr=0x801fc000370)
|
||||
|
||||
fake_uart1 = IsaFake(pio_addr=0x801fc0002f8)
|
||||
@@ -151,16 +151,18 @@ class MyLinuxAlphaSystem(LinuxAlphaSystem):
|
||||
tsunami = LinuxTsunami()
|
||||
tsunami.cchip.pio = magicbus.port
|
||||
tsunami.pchip.pio = magicbus.port
|
||||
tsunami.pciconfig.pio = magicbus.port
|
||||
tsunami.pciconfig.pio = magicbus.default
|
||||
tsunami.fake_sm_chip.pio = magicbus.port
|
||||
tsunami.ethernet.pio = magicbus.port
|
||||
tsunami.ethernet.dma = magicbus.port
|
||||
tsunami.ethernet.config = magicbus.port
|
||||
tsunami.fake_uart1.pio = magicbus.port
|
||||
tsunami.fake_uart2.pio = magicbus.port
|
||||
tsunami.fake_uart3.pio = magicbus.port
|
||||
tsunami.fake_uart4.pio = magicbus.port
|
||||
tsunami.ide.pio = magicbus.port
|
||||
tsunami.ide.dma = magicbus.port
|
||||
tsunami.ide.config = magicbus.port
|
||||
tsunami.fake_ppc.pio = magicbus.port
|
||||
tsunami.fake_OROM.pio = magicbus.port
|
||||
tsunami.fake_pnp_addr.pio = magicbus.port
|
||||
|
||||
@@ -89,7 +89,6 @@ base_sources = Split('''
|
||||
cpu/pc_event.cc
|
||||
cpu/quiesce_event.cc
|
||||
cpu/static_inst.cc
|
||||
cpu/sampler/sampler.cc
|
||||
cpu/simple_thread.cc
|
||||
cpu/thread_state.cc
|
||||
|
||||
|
||||
@@ -142,10 +142,10 @@ output exec {{
|
||||
cpu->setFloatRegBits(inst, 0, mips_nan, size);
|
||||
|
||||
//Read FCSR from FloatRegFile
|
||||
uint32_t fcsr_bits = cpu->tc->readFloatRegBits(FCSR);
|
||||
uint32_t fcsr_bits = cpu->tcBase()->readFloatRegBits(FCSR);
|
||||
|
||||
//Write FCSR from FloatRegFile
|
||||
cpu->tc->setFloatRegBits(FCSR, genInvalidVector(fcsr_bits));
|
||||
cpu->tcBase()->setFloatRegBits(FCSR, genInvalidVector(fcsr_bits));
|
||||
|
||||
if (traceData) { traceData->setData(mips_nan); }
|
||||
return true;
|
||||
@@ -158,12 +158,12 @@ output exec {{
|
||||
fpResetCauseBits(%(CPU_exec_context)s *cpu)
|
||||
{
|
||||
//Read FCSR from FloatRegFile
|
||||
uint32_t fcsr = cpu->tc->readFloatRegBits(FCSR);
|
||||
uint32_t fcsr = cpu->tcBase()->readFloatRegBits(FCSR);
|
||||
|
||||
fcsr = bits(fcsr, 31, 18) << 18 | bits(fcsr, 11, 0);
|
||||
|
||||
//Write FCSR from FloatRegFile
|
||||
cpu->tc->setFloatRegBits(FCSR, fcsr);
|
||||
cpu->tcBase()->setFloatRegBits(FCSR, fcsr);
|
||||
}
|
||||
}};
|
||||
|
||||
@@ -176,8 +176,9 @@ def template FloatingPointExecute {{
|
||||
|
||||
//When is the right time to reset cause bits?
|
||||
//start of every instruction or every cycle?
|
||||
#if FULL_SYSTEM
|
||||
fpResetCauseBits(xc);
|
||||
|
||||
#endif
|
||||
%(op_decl)s;
|
||||
%(op_rd)s;
|
||||
|
||||
@@ -192,7 +193,10 @@ def template FloatingPointExecute {{
|
||||
//----
|
||||
//Check for IEEE 754 FP Exceptions
|
||||
//fault = fpNanOperands((FPOp*)this, xc, Fd, traceData);
|
||||
if (!fpInvalidOp((FPOp*)this, xc, Fd, traceData) &&
|
||||
if (
|
||||
#if FULL_SYSTEM
|
||||
!fpInvalidOp((FPOp*)this, xc, Fd, traceData) &&
|
||||
#endif
|
||||
fault == NoFault)
|
||||
{
|
||||
%(op_wb)s;
|
||||
|
||||
@@ -48,8 +48,10 @@ ccfilename = sys.argv[1] + '.cc'
|
||||
# To define a new flag, simply add it to this list.
|
||||
#
|
||||
baseFlags = [
|
||||
'Activity',
|
||||
'AlphaConsole',
|
||||
'BADADDR',
|
||||
'BE',
|
||||
'BPredRAS',
|
||||
'Bus',
|
||||
'BusAddrRanges',
|
||||
@@ -84,6 +86,7 @@ baseFlags = [
|
||||
'EthernetPIO',
|
||||
'EthernetSM',
|
||||
'Event',
|
||||
'FE',
|
||||
'Fault',
|
||||
'Fetch',
|
||||
'Flow',
|
||||
@@ -97,6 +100,7 @@ baseFlags = [
|
||||
'GDBSend',
|
||||
'GDBWrite',
|
||||
'HWPrefetch',
|
||||
'IBE',
|
||||
'IEW',
|
||||
'IIC',
|
||||
'IICMore',
|
||||
@@ -115,13 +119,8 @@ baseFlags = [
|
||||
'MSHR',
|
||||
'Mbox',
|
||||
'MemDepUnit',
|
||||
'BaseCPU'
|
||||
'O3CPU',
|
||||
'OzoneCPU',
|
||||
'FE',
|
||||
'IBE',
|
||||
'BE',
|
||||
'O3CPU',
|
||||
'OzoneLSQ',
|
||||
'PCEvent',
|
||||
'PCIA',
|
||||
@@ -135,6 +134,7 @@ baseFlags = [
|
||||
'RenameMap',
|
||||
'SQL',
|
||||
'Sampler',
|
||||
'Scoreboard',
|
||||
'ScsiCtrl',
|
||||
'ScsiDisk',
|
||||
'ScsiNone',
|
||||
@@ -158,8 +158,6 @@ baseFlags = [
|
||||
'Uart',
|
||||
'VtoPhys',
|
||||
'WriteBarrier',
|
||||
'Activity',
|
||||
'Scoreboard',
|
||||
'Writeback',
|
||||
]
|
||||
|
||||
@@ -178,7 +176,7 @@ compoundFlagMap = {
|
||||
'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
|
||||
'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
|
||||
'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ],
|
||||
'O3CPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'O3CPU', 'Activity','Scoreboard','Writeback'],
|
||||
'O3CPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'O3CPU', 'Activity','Scoreboard','Writeback'],
|
||||
'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU']
|
||||
}
|
||||
|
||||
|
||||
@@ -130,13 +130,13 @@ if need_simple_base:
|
||||
if 'FastCPU' in env['CPU_MODELS']:
|
||||
sources += Split('fast/cpu.cc')
|
||||
|
||||
need_bp_unit = False
|
||||
if 'O3CPU' in env['CPU_MODELS']:
|
||||
need_bp_unit = True
|
||||
sources += SConscript('o3/SConscript', exports = 'env')
|
||||
sources += Split('''
|
||||
o3/2bit_local_pred.cc
|
||||
o3/base_dyn_inst.cc
|
||||
o3/bpred_unit.cc
|
||||
o3/btb.cc
|
||||
o3/commit.cc
|
||||
o3/decode.cc
|
||||
o3/fetch.cc
|
||||
@@ -148,18 +148,17 @@ if 'O3CPU' in env['CPU_MODELS']:
|
||||
o3/lsq_unit.cc
|
||||
o3/lsq.cc
|
||||
o3/mem_dep_unit.cc
|
||||
o3/ras.cc
|
||||
o3/rename.cc
|
||||
o3/rename_map.cc
|
||||
o3/rob.cc
|
||||
o3/scoreboard.cc
|
||||
o3/store_set.cc
|
||||
o3/tournament_pred.cc
|
||||
''')
|
||||
if env['USE_CHECKER']:
|
||||
sources += Split('o3/checker_builder.cc')
|
||||
|
||||
if 'OzoneCPU' in env['CPU_MODELS']:
|
||||
need_bp_unit = True
|
||||
sources += Split('''
|
||||
ozone/base_dyn_inst.cc
|
||||
ozone/bpred_unit.cc
|
||||
@@ -174,6 +173,14 @@ if 'OzoneCPU' in env['CPU_MODELS']:
|
||||
if env['USE_CHECKER']:
|
||||
sources += Split('ozone/checker_builder.cc')
|
||||
|
||||
if need_bp_unit:
|
||||
sources += Split('''
|
||||
o3/2bit_local_pred.cc
|
||||
o3/btb.cc
|
||||
o3/ras.cc
|
||||
o3/tournament_pred.cc
|
||||
''')
|
||||
|
||||
if env['USE_CHECKER']:
|
||||
sources += Split('checker/cpu.cc')
|
||||
checker_supports = False
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "cpu/cpuevent.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/profile.hh"
|
||||
#include "cpu/sampler/sampler.hh"
|
||||
#include "sim/param.hh"
|
||||
#include "sim/process.hh"
|
||||
#include "sim/sim_events.hh"
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
|
||||
#include "base/statistics.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "cpu/sampler/sampler.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
|
||||
@@ -66,7 +66,6 @@ class ThreadContext;
|
||||
class MemInterface;
|
||||
class Checkpoint;
|
||||
class Request;
|
||||
class Sampler;
|
||||
|
||||
/**
|
||||
* CheckerCPU class. Dynamically verifies instructions as they are
|
||||
@@ -374,7 +373,7 @@ class Checker : public CheckerCPU
|
||||
: CheckerCPU(p)
|
||||
{ }
|
||||
|
||||
void switchOut(Sampler *s);
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
void verify(DynInstPtr &inst);
|
||||
|
||||
@@ -236,9 +236,7 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
willChangePC = true;
|
||||
newPC = thread->readPC();
|
||||
DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
|
||||
#else // !FULL_SYSTEM
|
||||
fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
|
||||
#endif // FULL_SYSTEM
|
||||
#endif
|
||||
} else {
|
||||
#if THE_ISA != MIPS_ISA
|
||||
// go to the next instruction
|
||||
@@ -295,7 +293,7 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
|
||||
|
||||
template <class DynInstPtr>
|
||||
void
|
||||
Checker<DynInstPtr>::switchOut(Sampler *s)
|
||||
Checker<DynInstPtr>::switchOut()
|
||||
{
|
||||
instList.clear();
|
||||
}
|
||||
|
||||
@@ -79,18 +79,6 @@ CpuModel('OzoneCPU', 'ozone_exec.cc',
|
||||
CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
|
||||
'#include "cpu/checker/cpu.hh"',
|
||||
{ 'CPU_exec_context': 'CheckerCPU' })
|
||||
|
||||
# Maybe there is a more clever way to determine ISA
|
||||
# here but since the environment variable isnt passed through
|
||||
# here the easiest way is this...
|
||||
sub_template = 'not found'
|
||||
for argument in sys.argv:
|
||||
if 'ALPHA' in argument:
|
||||
sub_template = 'AlphaDynInst<AlphaSimpleImpl>'
|
||||
|
||||
if sub_template == 'not found':
|
||||
sys.exit('NO CPU_exec_context substitution defined for this ISA')
|
||||
|
||||
CpuModel('O3CPU', 'o3_cpu_exec.cc',
|
||||
'#include "cpu/o3/isa_specific.hh"',
|
||||
{ 'CPU_exec_context': sub_template })
|
||||
{ 'CPU_exec_context': 'O3DynInst' })
|
||||
|
||||
@@ -91,7 +91,10 @@ Param<unsigned> renameWidth;
|
||||
Param<unsigned> commitToIEWDelay;
|
||||
Param<unsigned> renameToIEWDelay;
|
||||
Param<unsigned> issueToExecuteDelay;
|
||||
Param<unsigned> dispatchWidth;
|
||||
Param<unsigned> issueWidth;
|
||||
Param<unsigned> wbWidth;
|
||||
Param<unsigned> wbDepth;
|
||||
SimObjectParam<FUPool *> fuPool;
|
||||
|
||||
Param<unsigned> iewToCommitDelay;
|
||||
@@ -207,7 +210,10 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU)
|
||||
"Issue/Execute/Writeback delay"),
|
||||
INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal"
|
||||
"to the IEW stage)"),
|
||||
INIT_PARAM(dispatchWidth, "Dispatch width"),
|
||||
INIT_PARAM(issueWidth, "Issue width"),
|
||||
INIT_PARAM(wbWidth, "Writeback width"),
|
||||
INIT_PARAM(wbDepth, "Writeback depth (number of cycles it can buffer)"),
|
||||
INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL),
|
||||
|
||||
INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit "
|
||||
@@ -333,7 +339,10 @@ CREATE_SIM_OBJECT(DerivO3CPU)
|
||||
params->commitToIEWDelay = commitToIEWDelay;
|
||||
params->renameToIEWDelay = renameToIEWDelay;
|
||||
params->issueToExecuteDelay = issueToExecuteDelay;
|
||||
params->dispatchWidth = dispatchWidth;
|
||||
params->issueWidth = issueWidth;
|
||||
params->wbWidth = wbWidth;
|
||||
params->wbDepth = wbDepth;
|
||||
params->fuPool = fuPool;
|
||||
|
||||
params->iewToCommitDelay = iewToCommitDelay;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "cpu/o3/alpha/params.hh"
|
||||
#include "cpu/o3/cpu_policy.hh"
|
||||
|
||||
|
||||
// Forward declarations.
|
||||
template <class Impl>
|
||||
class AlphaDynInst;
|
||||
@@ -88,7 +89,4 @@ struct AlphaSimpleImpl
|
||||
/** The O3Impl to be used. */
|
||||
typedef AlphaSimpleImpl O3CPUImpl;
|
||||
|
||||
/** The O3Impl to be used. */
|
||||
typedef DynInst O3DynInst;
|
||||
|
||||
#endif // __CPU_O3_ALPHA_IMPL_HH__
|
||||
|
||||
@@ -54,16 +54,7 @@ class AlphaSimpleParams : public O3Params
|
||||
#if FULL_SYSTEM
|
||||
AlphaITB *itb;
|
||||
AlphaDTB *dtb;
|
||||
#else
|
||||
std::vector<Process *> workload;
|
||||
Process *process;
|
||||
#endif // FULL_SYSTEM
|
||||
|
||||
MemObject *mem;
|
||||
|
||||
BaseCPU *checker;
|
||||
|
||||
unsigned decodeToFetchDelay;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __CPU_O3_ALPHA_PARAMS_HH__
|
||||
|
||||
@@ -187,11 +187,14 @@ class DefaultCommit
|
||||
/** Initializes stage by sending back the number of free entries. */
|
||||
void initStage();
|
||||
|
||||
/** Initializes the switching out of commit. */
|
||||
void switchOut();
|
||||
/** Initializes the draining of commit. */
|
||||
void drain();
|
||||
|
||||
/** Resumes execution after draining. */
|
||||
void resume();
|
||||
|
||||
/** Completes the switch out of commit. */
|
||||
void doSwitchOut();
|
||||
void switchOut();
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
@@ -383,8 +386,8 @@ class DefaultCommit
|
||||
/** Number of Active Threads */
|
||||
unsigned numThreads;
|
||||
|
||||
/** Is a switch out pending. */
|
||||
bool switchPending;
|
||||
/** Is a drain pending. */
|
||||
bool drainPending;
|
||||
|
||||
/** Is commit switched out. */
|
||||
bool switchedOut;
|
||||
|
||||
@@ -80,7 +80,7 @@ DefaultCommit<Impl>::DefaultCommit(Params *params)
|
||||
renameWidth(params->renameWidth),
|
||||
commitWidth(params->commitWidth),
|
||||
numThreads(params->numberOfThreads),
|
||||
switchPending(false),
|
||||
drainPending(false),
|
||||
switchedOut(false),
|
||||
trapLatency(params->trapLatency),
|
||||
fetchTrapLatency(params->fetchTrapLatency)
|
||||
@@ -351,20 +351,26 @@ DefaultCommit<Impl>::initStage()
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::switchOut()
|
||||
DefaultCommit<Impl>::drain()
|
||||
{
|
||||
switchPending = true;
|
||||
drainPending = true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::doSwitchOut()
|
||||
DefaultCommit<Impl>::switchOut()
|
||||
{
|
||||
switchedOut = true;
|
||||
switchPending = false;
|
||||
drainPending = false;
|
||||
rob->switchOut();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::resume()
|
||||
{
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultCommit<Impl>::takeOverFrom()
|
||||
@@ -557,8 +563,9 @@ DefaultCommit<Impl>::tick()
|
||||
wroteToTimeBuffer = false;
|
||||
_nextStatus = Inactive;
|
||||
|
||||
if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
|
||||
cpu->signalSwitched();
|
||||
if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
|
||||
cpu->signalDrained();
|
||||
drainPending = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
|
||||
physmem(system->physmem),
|
||||
#endif // FULL_SYSTEM
|
||||
mem(params->mem),
|
||||
switchCount(0),
|
||||
drainCount(0),
|
||||
deferRegistration(params->deferRegistration),
|
||||
numThreads(number_of_threads)
|
||||
{
|
||||
@@ -463,14 +463,13 @@ template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::insertThread(unsigned tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i] Initializing thread data");
|
||||
DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
|
||||
// Will change now that the PC and thread state is internal to the CPU
|
||||
// and not in the ThreadContext.
|
||||
#if 0
|
||||
#if FULL_SYSTEM
|
||||
ThreadContext *src_tc = system->threadContexts[tid];
|
||||
#else
|
||||
ThreadContext *src_tc = thread[tid];
|
||||
ThreadContext *src_tc = tcBase(tid);
|
||||
#endif
|
||||
|
||||
//Bind Int Regs to Rename Map
|
||||
@@ -490,11 +489,14 @@ FullO3CPU<Impl>::insertThread(unsigned tid)
|
||||
}
|
||||
|
||||
//Copy Thread Data Into RegFile
|
||||
this->copyFromTC(tid);
|
||||
//this->copyFromTC(tid);
|
||||
|
||||
//Set PC/NPC
|
||||
regFile.pc[tid] = src_tc->readPC();
|
||||
regFile.npc[tid] = src_tc->readNextPC();
|
||||
//Set PC/NPC/NNPC
|
||||
setPC(src_tc->readPC(), tid);
|
||||
setNextPC(src_tc->readNextPC(), tid);
|
||||
#if THE_ISA != ALPHA_ISA
|
||||
setNextNPC(src_tc->readNextNPC(), tid);
|
||||
#endif
|
||||
|
||||
src_tc->setStatus(ThreadContext::Active);
|
||||
|
||||
@@ -503,16 +505,19 @@ FullO3CPU<Impl>::insertThread(unsigned tid)
|
||||
//Reset ROB/IQ/LSQ Entries
|
||||
commit.rob->resetEntries();
|
||||
iew.resetEntries();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::removeThread(unsigned tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i] Removing thread data");
|
||||
#if 0
|
||||
//Unbind Int Regs from Rename Map
|
||||
DPRINTF(O3CPU,"[tid:%i] Removing thread from CPU.");
|
||||
|
||||
// Copy Thread Data From RegFile
|
||||
// If thread is suspended, it might be re-allocated
|
||||
//this->copyToTC(tid);
|
||||
|
||||
// Unbind Int Regs from Rename Map
|
||||
for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
|
||||
PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);
|
||||
|
||||
@@ -520,7 +525,7 @@ FullO3CPU<Impl>::removeThread(unsigned tid)
|
||||
freeList.addReg(phys_reg);
|
||||
}
|
||||
|
||||
//Unbind Float Regs from Rename Map
|
||||
// Unbind Float Regs from Rename Map
|
||||
for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
|
||||
PhysRegIndex phys_reg = renameMap[tid].lookup(freg);
|
||||
|
||||
@@ -528,27 +533,18 @@ FullO3CPU<Impl>::removeThread(unsigned tid)
|
||||
freeList.addReg(phys_reg);
|
||||
}
|
||||
|
||||
//Copy Thread Data From RegFile
|
||||
/* Fix Me:
|
||||
* Do we really need to do this if we are removing a thread
|
||||
* in the sense that it's finished (exiting)? If the thread is just
|
||||
* being suspended we might...
|
||||
*/
|
||||
// this->copyToTC(tid);
|
||||
|
||||
//Squash Throughout Pipeline
|
||||
// Squash Throughout Pipeline
|
||||
fetch.squash(0,tid);
|
||||
decode.squash(tid);
|
||||
rename.squash(tid);
|
||||
|
||||
assert(iew.ldstQueue.getCount(tid) == 0);
|
||||
|
||||
//Reset ROB/IQ/LSQ Entries
|
||||
// Reset ROB/IQ/LSQ Entries
|
||||
if (activeThreads.size() >= 1) {
|
||||
commit.rob->resetEntries();
|
||||
iew.resetEntries();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -656,7 +652,7 @@ template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::suspendContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid: %i]: Suspended ...\n", tid);
|
||||
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
|
||||
unscheduleTickEvent();
|
||||
_status = Idle;
|
||||
/*
|
||||
@@ -676,27 +672,26 @@ template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::deallocateContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i]: Deallocating ...", tid);
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
activeThreads.begin(), activeThreads.end(), tid);
|
||||
DPRINTF(O3CPU,"[tid:%i]: Deallocating Thread Context", tid);
|
||||
|
||||
if (isActive != activeThreads.end()) {
|
||||
//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(isActive);
|
||||
activeThreads.erase(thread_it);
|
||||
|
||||
removeThread(tid);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::haltContext(int tid)
|
||||
{
|
||||
DPRINTF(O3CPU,"[tid:%i]: Halted ...", tid);
|
||||
DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid);
|
||||
/*
|
||||
//Remove From Active List, if Active
|
||||
list<unsigned>::iterator isActive = find(
|
||||
@@ -713,47 +708,72 @@ FullO3CPU<Impl>::haltContext(int tid)
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::switchOut(Sampler *_sampler)
|
||||
bool
|
||||
FullO3CPU<Impl>::drain(Event *drain_event)
|
||||
{
|
||||
sampler = _sampler;
|
||||
switchCount = 0;
|
||||
fetch.switchOut();
|
||||
decode.switchOut();
|
||||
rename.switchOut();
|
||||
iew.switchOut();
|
||||
commit.switchOut();
|
||||
drainCount = 0;
|
||||
drainEvent = drain_event;
|
||||
fetch.drain();
|
||||
decode.drain();
|
||||
rename.drain();
|
||||
iew.drain();
|
||||
commit.drain();
|
||||
|
||||
// Wake the CPU and record activity so everything can drain out if
|
||||
// the CPU is currently idle.
|
||||
wakeCPU();
|
||||
activityRec.activity();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::signalSwitched()
|
||||
FullO3CPU<Impl>::resume()
|
||||
{
|
||||
if (++switchCount == NumStages) {
|
||||
fetch.doSwitchOut();
|
||||
rename.doSwitchOut();
|
||||
commit.doSwitchOut();
|
||||
instList.clear();
|
||||
while (!removeList.empty()) {
|
||||
removeList.pop();
|
||||
}
|
||||
if (_status == SwitchedOut)
|
||||
return;
|
||||
fetch.resume();
|
||||
decode.resume();
|
||||
rename.resume();
|
||||
iew.resume();
|
||||
commit.resume();
|
||||
|
||||
#if USE_CHECKER
|
||||
if (checker)
|
||||
checker->switchOut(sampler);
|
||||
#endif
|
||||
if (!tickEvent.scheduled())
|
||||
tickEvent.schedule(curTick);
|
||||
_status = Running;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::signalDrained()
|
||||
{
|
||||
if (++drainCount == NumStages) {
|
||||
if (tickEvent.scheduled())
|
||||
tickEvent.squash();
|
||||
sampler->signalSwitched();
|
||||
_status = SwitchedOut;
|
||||
_status = Drained;
|
||||
drainEvent->process();
|
||||
}
|
||||
assert(switchCount <= 5);
|
||||
assert(drainCount <= 5);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
FullO3CPU<Impl>::switchOut()
|
||||
{
|
||||
fetch.switchOut();
|
||||
rename.switchOut();
|
||||
commit.switchOut();
|
||||
instList.clear();
|
||||
while (!removeList.empty()) {
|
||||
removeList.pop();
|
||||
}
|
||||
|
||||
_status = SwitchedOut;
|
||||
#if USE_CHECKER
|
||||
if (checker)
|
||||
checker->switchOut();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
||||
@@ -57,6 +57,8 @@ class Checker;
|
||||
class ThreadContext;
|
||||
template <class>
|
||||
class O3ThreadContext;
|
||||
|
||||
class Checkpoint;
|
||||
class MemObject;
|
||||
class Process;
|
||||
|
||||
@@ -109,6 +111,7 @@ class FullO3CPU : public BaseO3CPU
|
||||
Idle,
|
||||
Halted,
|
||||
Blocked,
|
||||
Drained,
|
||||
SwitchedOut
|
||||
};
|
||||
|
||||
@@ -270,14 +273,21 @@ class FullO3CPU : public BaseO3CPU
|
||||
*/
|
||||
virtual void syscall(int tid) { panic("Unimplemented!"); }
|
||||
|
||||
/** Switches out this CPU. */
|
||||
void switchOut(Sampler *sampler);
|
||||
/** Starts draining the CPU's pipeline of all instructions in
|
||||
* order to stop all memory accesses. */
|
||||
virtual bool drain(Event *drain_event);
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
virtual void resume();
|
||||
|
||||
/** Signals to this CPU that a stage has completed switching out. */
|
||||
void signalSwitched();
|
||||
void signalDrained();
|
||||
|
||||
/** Switches out this CPU. */
|
||||
virtual void switchOut();
|
||||
|
||||
/** Takes over from another CPU. */
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
virtual void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
/** Get the current instruction sequence number, and increment it. */
|
||||
InstSeqNum getAndIncrementInstSeq()
|
||||
@@ -550,11 +560,11 @@ class FullO3CPU : public BaseO3CPU
|
||||
/** Pointer to memory. */
|
||||
MemObject *mem;
|
||||
|
||||
/** Pointer to the sampler */
|
||||
Sampler *sampler;
|
||||
/** Event to call process() on once draining has completed. */
|
||||
Event *drainEvent;
|
||||
|
||||
/** Counter of how many stages have completed switching out. */
|
||||
int switchCount;
|
||||
/** Counter of how many stages have completed draining. */
|
||||
int drainCount;
|
||||
|
||||
/** Pointers to all of the threads in the CPU. */
|
||||
std::vector<Thread *> thread;
|
||||
|
||||
@@ -109,8 +109,14 @@ class DefaultDecode
|
||||
/** Sets pointer to list of active threads. */
|
||||
void setActiveThreads(std::list<unsigned> *at_ptr);
|
||||
|
||||
/** Drains the decode stage. */
|
||||
void drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume() { }
|
||||
|
||||
/** Switches out the decode stage. */
|
||||
void switchOut();
|
||||
void switchOut() { }
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
|
||||
@@ -166,10 +166,10 @@ DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultDecode<Impl>::switchOut()
|
||||
DefaultDecode<Impl>::drain()
|
||||
{
|
||||
// Decode can immediately switch out.
|
||||
cpu->signalSwitched();
|
||||
// Decode is done draining at any time.
|
||||
cpu->signalDrained();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
|
||||
45
src/cpu/o3/dyn_inst.hh
Normal file
45
src/cpu/o3/dyn_inst.hh
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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: Korey Sewell
|
||||
*/
|
||||
|
||||
#ifndef __CPU_O3_DYN_INST_HH__
|
||||
#define __CPU_O3_DYN_INST_HH__
|
||||
|
||||
#include "arch/isa_specific.hh"
|
||||
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
template <class Impl>
|
||||
class AlphaDynInst;
|
||||
|
||||
struct AlphaSimpleImpl;
|
||||
|
||||
typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst;
|
||||
#endif
|
||||
|
||||
#endif // __CPU_O3_DYN_INST_HH__
|
||||
@@ -40,8 +40,6 @@
|
||||
#include "mem/port.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class Sampler;
|
||||
|
||||
/**
|
||||
* DefaultFetch class handles both single threaded and SMT fetch. Its
|
||||
* width is specified by the parameters; each cycle it tries to fetch
|
||||
@@ -182,11 +180,14 @@ class DefaultFetch
|
||||
/** Processes cache completion event. */
|
||||
void processCacheCompletion(PacketPtr pkt);
|
||||
|
||||
/** Begins the switch out of the fetch stage. */
|
||||
void switchOut();
|
||||
/** Begins the drain of the fetch stage. */
|
||||
void drain();
|
||||
|
||||
/** Completes the switch out of the fetch stage. */
|
||||
void doSwitchOut();
|
||||
/** Resumes execution after a drain. */
|
||||
void resume();
|
||||
|
||||
/** Tells fetch stage to prepare to be switched out. */
|
||||
void switchOut();
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
@@ -423,6 +424,9 @@ class DefaultFetch
|
||||
*/
|
||||
bool interruptPending;
|
||||
|
||||
/** Is there a drain pending. */
|
||||
bool drainPending;
|
||||
|
||||
/** Records if fetch is switched out. */
|
||||
bool switchedOut;
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ DefaultFetch<Impl>::DefaultFetch(Params *params)
|
||||
numThreads(params->numberOfThreads),
|
||||
numFetchingThreads(params->smtNumFetchingThreads),
|
||||
interruptPending(false),
|
||||
drainPending(false),
|
||||
switchedOut(false)
|
||||
{
|
||||
if (numThreads > Impl::MaxThreads)
|
||||
@@ -353,7 +354,8 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
||||
// to return.
|
||||
if (fetchStatus[tid] != IcacheWaitResponse ||
|
||||
pkt->req != memReq[tid] ||
|
||||
isSwitchedOut()) {
|
||||
isSwitchedOut() ||
|
||||
drainPending) {
|
||||
++fetchIcacheSquashes;
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
@@ -384,17 +386,25 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultFetch<Impl>::switchOut()
|
||||
DefaultFetch<Impl>::drain()
|
||||
{
|
||||
// Fetch is ready to switch out at any time.
|
||||
switchedOut = true;
|
||||
cpu->signalSwitched();
|
||||
// Fetch is ready to drain at any time.
|
||||
cpu->signalDrained();
|
||||
drainPending = true;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultFetch<Impl>::doSwitchOut()
|
||||
DefaultFetch<Impl>::resume()
|
||||
{
|
||||
drainPending = false;
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultFetch<Impl>::switchOut()
|
||||
{
|
||||
switchedOut = true;
|
||||
// Branch predictor needs to have its state cleared.
|
||||
branchPred.switchOut();
|
||||
}
|
||||
@@ -498,7 +508,7 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
|
||||
unsigned flags = 0;
|
||||
#endif // FULL_SYSTEM
|
||||
|
||||
if (cacheBlocked || (interruptPending && flags == 0) || switchedOut) {
|
||||
if (cacheBlocked || (interruptPending && flags == 0) || drainPending) {
|
||||
// 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
|
||||
|
||||
@@ -143,11 +143,14 @@ class DefaultIEW
|
||||
/** Sets pointer to the scoreboard. */
|
||||
void setScoreboard(Scoreboard *sb_ptr);
|
||||
|
||||
/** Starts switch out of IEW stage. */
|
||||
void switchOut();
|
||||
/** Drains IEW stage. */
|
||||
void drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume();
|
||||
|
||||
/** Completes switch out of IEW stage. */
|
||||
void doSwitchOut();
|
||||
void switchOut();
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
@@ -204,6 +207,45 @@ class DefaultIEW
|
||||
/** Returns if the LSQ has any stores to writeback. */
|
||||
bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); }
|
||||
|
||||
void incrWb(InstSeqNum &sn)
|
||||
{
|
||||
if (++wbOutstanding == wbMax)
|
||||
ableToIssue = false;
|
||||
DPRINTF(IEW, "wbOutstanding: %i\n", wbOutstanding);
|
||||
#if DEBUG
|
||||
wbList.insert(sn);
|
||||
#endif
|
||||
}
|
||||
|
||||
void decrWb(InstSeqNum &sn)
|
||||
{
|
||||
if (wbOutstanding-- == wbMax)
|
||||
ableToIssue = true;
|
||||
DPRINTF(IEW, "wbOutstanding: %i\n", wbOutstanding);
|
||||
#if DEBUG
|
||||
assert(wbList.find(sn) != wbList.end());
|
||||
wbList.erase(sn);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
std::set<InstSeqNum> wbList;
|
||||
|
||||
void dumpWb()
|
||||
{
|
||||
std::set<InstSeqNum>::iterator wb_it = wbList.begin();
|
||||
while (wb_it != wbList.end()) {
|
||||
cprintf("[sn:%lli]\n",
|
||||
(*wb_it));
|
||||
wb_it++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool canIssue() { return ableToIssue; }
|
||||
|
||||
bool ableToIssue;
|
||||
|
||||
private:
|
||||
/** Sends commit proper information for a squash due to a branch
|
||||
* mispredict.
|
||||
@@ -384,11 +426,8 @@ class DefaultIEW
|
||||
*/
|
||||
unsigned issueToExecuteDelay;
|
||||
|
||||
/** Width of issue's read path, in instructions. The read path is both
|
||||
* the skid buffer and the rename instruction queue.
|
||||
* Note to self: is this really different than issueWidth?
|
||||
*/
|
||||
unsigned issueReadWidth;
|
||||
/** Width of dispatch, in instructions. */
|
||||
unsigned dispatchWidth;
|
||||
|
||||
/** Width of issue, in instructions. */
|
||||
unsigned issueWidth;
|
||||
@@ -403,6 +442,17 @@ class DefaultIEW
|
||||
*/
|
||||
unsigned wbCycle;
|
||||
|
||||
/** Number of instructions in flight that will writeback. */
|
||||
unsigned wbOutstanding;
|
||||
|
||||
/** Writeback width. */
|
||||
unsigned wbWidth;
|
||||
|
||||
/** Writeback width * writeback depth, where writeback depth is
|
||||
* the number of cycles of writing back instructions that can be
|
||||
* buffered. */
|
||||
unsigned wbMax;
|
||||
|
||||
/** Number of active threads. */
|
||||
unsigned numThreads;
|
||||
|
||||
|
||||
@@ -50,8 +50,10 @@ DefaultIEW<Impl>::DefaultIEW(Params *params)
|
||||
commitToIEWDelay(params->commitToIEWDelay),
|
||||
renameToIEWDelay(params->renameToIEWDelay),
|
||||
issueToExecuteDelay(params->issueToExecuteDelay),
|
||||
issueReadWidth(params->issueWidth),
|
||||
dispatchWidth(params->dispatchWidth),
|
||||
issueWidth(params->issueWidth),
|
||||
wbOutstanding(0),
|
||||
wbWidth(params->wbWidth),
|
||||
numThreads(params->numberOfThreads),
|
||||
switchedOut(false)
|
||||
{
|
||||
@@ -74,8 +76,12 @@ DefaultIEW<Impl>::DefaultIEW(Params *params)
|
||||
fetchRedirect[i] = false;
|
||||
}
|
||||
|
||||
wbMax = wbWidth * params->wbDepth;
|
||||
|
||||
updateLSQNextCycle = false;
|
||||
|
||||
ableToIssue = true;
|
||||
|
||||
skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth;
|
||||
}
|
||||
|
||||
@@ -349,15 +355,21 @@ DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultIEW<Impl>::switchOut()
|
||||
DefaultIEW<Impl>::drain()
|
||||
{
|
||||
// IEW is ready to switch out at any time.
|
||||
cpu->signalSwitched();
|
||||
// IEW is ready to drain at any time.
|
||||
cpu->signalDrained();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultIEW<Impl>::doSwitchOut()
|
||||
DefaultIEW<Impl>::resume()
|
||||
{
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultIEW<Impl>::switchOut()
|
||||
{
|
||||
// Clear any state.
|
||||
switchedOut = true;
|
||||
@@ -559,12 +571,12 @@ DefaultIEW<Impl>::instToCommit(DynInstPtr &inst)
|
||||
// free slot.
|
||||
while ((*iewQueue)[wbCycle].insts[wbNumInst]) {
|
||||
++wbNumInst;
|
||||
if (wbNumInst == issueWidth) {
|
||||
if (wbNumInst == wbWidth) {
|
||||
++wbCycle;
|
||||
wbNumInst = 0;
|
||||
}
|
||||
|
||||
assert(wbCycle < 5);
|
||||
assert((wbCycle * wbWidth + wbNumInst) < wbMax);
|
||||
}
|
||||
|
||||
// Add finished instruction to queue to commit.
|
||||
@@ -937,7 +949,7 @@ DefaultIEW<Impl>::dispatchInsts(unsigned tid)
|
||||
// Loop through the instructions, putting them in the instruction
|
||||
// queue.
|
||||
for ( ; dis_num_inst < insts_to_add &&
|
||||
dis_num_inst < issueReadWidth;
|
||||
dis_num_inst < dispatchWidth;
|
||||
++dis_num_inst)
|
||||
{
|
||||
inst = insts_to_dispatch.front();
|
||||
@@ -1189,6 +1201,7 @@ DefaultIEW<Impl>::executeInsts()
|
||||
|
||||
++iewExecSquashedInsts;
|
||||
|
||||
decrWb(inst->seqNum);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1351,6 +1364,8 @@ DefaultIEW<Impl>::writebackInsts()
|
||||
}
|
||||
writebackCount[tid]++;
|
||||
}
|
||||
|
||||
decrWb(inst->seqNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -687,6 +687,7 @@ InstructionQueue<Impl>::scheduleReadyInsts()
|
||||
int total_issued = 0;
|
||||
|
||||
while (total_issued < totalWidth &&
|
||||
iewStage->canIssue() &&
|
||||
order_it != order_end_it) {
|
||||
OpClass op_class = (*order_it).queueType;
|
||||
|
||||
@@ -784,6 +785,7 @@ InstructionQueue<Impl>::scheduleReadyInsts()
|
||||
|
||||
listOrder.erase(order_it++);
|
||||
statIssuedInstType[tid][op_class]++;
|
||||
iewStage->incrWb(issuing_inst->seqNum);
|
||||
} else {
|
||||
statFuBusy[op_class]++;
|
||||
fuBusy[tid]++;
|
||||
|
||||
@@ -77,6 +77,7 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
|
||||
//iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
|
||||
|
||||
if (isSwitchedOut() || inst->isSquashed()) {
|
||||
iewStage->decrWb(inst->seqNum);
|
||||
delete state;
|
||||
delete pkt;
|
||||
return;
|
||||
|
||||
@@ -46,6 +46,18 @@ class O3Params : public BaseO3CPU::Params
|
||||
public:
|
||||
unsigned activity;
|
||||
|
||||
//
|
||||
// Pointers to key objects
|
||||
//
|
||||
#if !FULL_SYSTEM
|
||||
std::vector<Process *> workload;
|
||||
Process *process;
|
||||
#endif // FULL_SYSTEM
|
||||
|
||||
MemObject *mem;
|
||||
|
||||
BaseCPU *checker;
|
||||
|
||||
//
|
||||
// Caches
|
||||
//
|
||||
@@ -86,7 +98,10 @@ class O3Params : public BaseO3CPU::Params
|
||||
unsigned commitToIEWDelay;
|
||||
unsigned renameToIEWDelay;
|
||||
unsigned issueToExecuteDelay;
|
||||
unsigned dispatchWidth;
|
||||
unsigned issueWidth;
|
||||
unsigned wbWidth;
|
||||
unsigned wbDepth;
|
||||
FUPool *fuPool;
|
||||
|
||||
//
|
||||
|
||||
@@ -157,12 +157,15 @@ class DefaultRename
|
||||
/** Sets pointer to the scoreboard. */
|
||||
void setScoreboard(Scoreboard *_scoreboard);
|
||||
|
||||
/** Drains the rename stage. */
|
||||
void drain();
|
||||
|
||||
/** Resumes execution after a drain. */
|
||||
void resume() { }
|
||||
|
||||
/** Switches out the rename stage. */
|
||||
void switchOut();
|
||||
|
||||
/** Completes the switch out. */
|
||||
void doSwitchOut();
|
||||
|
||||
/** Takes over from another CPU's thread. */
|
||||
void takeOverFrom();
|
||||
|
||||
|
||||
@@ -258,15 +258,15 @@ DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultRename<Impl>::switchOut()
|
||||
DefaultRename<Impl>::drain()
|
||||
{
|
||||
// Rename is ready to switch out at any time.
|
||||
cpu->signalSwitched();
|
||||
cpu->signalDrained();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
DefaultRename<Impl>::doSwitchOut()
|
||||
DefaultRename<Impl>::switchOut()
|
||||
{
|
||||
// Clear any state, fix up the rename map.
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
|
||||
@@ -55,7 +55,6 @@ class AlphaDTB;
|
||||
class PhysicalMemory;
|
||||
class MemoryController;
|
||||
|
||||
class Sampler;
|
||||
class RemoteGDB;
|
||||
class GDBListener;
|
||||
|
||||
@@ -356,12 +355,10 @@ class OzoneCPU : public BaseCPU
|
||||
|
||||
int cpuId;
|
||||
|
||||
void switchOut(Sampler *sampler);
|
||||
void switchOut();
|
||||
void signalSwitched();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
||||
Sampler *sampler;
|
||||
|
||||
int switchCount;
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
||||
@@ -244,9 +244,8 @@ OzoneCPU<Impl>::~OzoneCPU()
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
OzoneCPU<Impl>::switchOut(Sampler *_sampler)
|
||||
OzoneCPU<Impl>::switchOut()
|
||||
{
|
||||
sampler = _sampler;
|
||||
switchCount = 0;
|
||||
// Front end needs state from back end, so switch out the back end first.
|
||||
backEnd->switchOut();
|
||||
@@ -262,13 +261,12 @@ OzoneCPU<Impl>::signalSwitched()
|
||||
frontEnd->doSwitchOut();
|
||||
#if USE_CHECKER
|
||||
if (checker)
|
||||
checker->switchOut(sampler);
|
||||
checker->switchOut();
|
||||
#endif
|
||||
|
||||
_status = SwitchedOut;
|
||||
if (tickEvent.scheduled())
|
||||
tickEvent.squash();
|
||||
sampler->signalSwitched();
|
||||
}
|
||||
assert(switchCount <= 2);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/profile.hh"
|
||||
#include "cpu/sampler/sampler.hh"
|
||||
#include "cpu/simple/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/smt.hh"
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/simple_thread.hh"
|
||||
#include "cpu/pc_event.hh"
|
||||
#include "cpu/sampler/sampler.hh"
|
||||
#include "cpu/static_inst.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/port.hh"
|
||||
@@ -128,11 +127,6 @@ class BaseSimpleCPU : public BaseCPU
|
||||
// Static data storage
|
||||
TheISA::IntReg dataReg;
|
||||
|
||||
// Pointer to the sampler that is telling us to switchover.
|
||||
// Used to signal the completion of the pipe drain and schedule
|
||||
// the next switchover
|
||||
Sampler *sampler;
|
||||
|
||||
StaticInstPtr curStaticInst;
|
||||
|
||||
void checkForInterrupts();
|
||||
|
||||
@@ -88,7 +88,7 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
|
||||
{
|
||||
_status = Idle;
|
||||
ifetch_pkt = dcache_pkt = NULL;
|
||||
quiesceEvent = NULL;
|
||||
drainEvent = NULL;
|
||||
state = SimObject::Timing;
|
||||
}
|
||||
|
||||
@@ -112,17 +112,16 @@ TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion)
|
||||
}
|
||||
|
||||
bool
|
||||
TimingSimpleCPU::quiesce(Event *quiesce_event)
|
||||
TimingSimpleCPU::drain(Event *drain_event)
|
||||
{
|
||||
// TimingSimpleCPU is ready to quiesce if it's not waiting for
|
||||
// TimingSimpleCPU is ready to drain if it's not waiting for
|
||||
// an access to complete.
|
||||
if (status() == Idle || status() == Running || status() == SwitchedOut) {
|
||||
DPRINTF(Config, "Ready to quiesce\n");
|
||||
changeState(SimObject::DrainedTiming);
|
||||
return false;
|
||||
} else {
|
||||
DPRINTF(Config, "Waiting to quiesce\n");
|
||||
changeState(SimObject::Quiescing);
|
||||
quiesceEvent = quiesce_event;
|
||||
changeState(SimObject::Draining);
|
||||
drainEvent = drain_event;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -422,8 +421,8 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
|
||||
if (getState() == SimObject::Quiescing) {
|
||||
completeQuiesce();
|
||||
if (getState() == SimObject::Draining) {
|
||||
completeDrain();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -479,8 +478,8 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
|
||||
assert(_status == DcacheWaitResponse);
|
||||
_status = Running;
|
||||
|
||||
if (getState() == SimObject::Quiescing) {
|
||||
completeQuiesce();
|
||||
if (getState() == SimObject::Draining) {
|
||||
completeDrain();
|
||||
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
@@ -499,11 +498,11 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
|
||||
|
||||
|
||||
void
|
||||
TimingSimpleCPU::completeQuiesce()
|
||||
TimingSimpleCPU::completeDrain()
|
||||
{
|
||||
DPRINTF(Config, "Done quiescing\n");
|
||||
changeState(SimObject::QuiescedTiming);
|
||||
quiesceEvent->process();
|
||||
DPRINTF(Config, "Done draining\n");
|
||||
changeState(SimObject::DrainedTiming);
|
||||
drainEvent->process();
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -64,7 +64,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
|
||||
Status status() const { return _status; }
|
||||
|
||||
Event *quiesceEvent;
|
||||
Event *drainEvent;
|
||||
|
||||
private:
|
||||
|
||||
@@ -133,7 +133,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
virtual bool quiesce(Event *quiesce_event);
|
||||
virtual bool drain(Event *drain_event);
|
||||
virtual void resume();
|
||||
virtual void setMemoryMode(State new_mode);
|
||||
|
||||
@@ -154,7 +154,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
void completeDataAccess(Packet *);
|
||||
void advanceInst(Fault fault);
|
||||
private:
|
||||
void completeQuiesce();
|
||||
void completeDrain();
|
||||
};
|
||||
|
||||
#endif // __CPU_SIMPLE_TIMING_HH__
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "base/misc.hh"
|
||||
#include "base/refcnt.hh"
|
||||
#include "cpu/op_class.hh"
|
||||
#include "cpu/o3/dyn_inst.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
|
||||
@@ -50,9 +51,6 @@ class ThreadContext;
|
||||
class DynInst;
|
||||
class Packet;
|
||||
|
||||
template <class Impl>
|
||||
class AlphaDynInst;
|
||||
|
||||
template <class Impl>
|
||||
class OzoneDynInst;
|
||||
|
||||
|
||||
@@ -227,177 +227,143 @@ IdeController::setDmaComplete(IdeDisk *disk)
|
||||
// Read and write handling
|
||||
////
|
||||
|
||||
void
|
||||
IdeController::readConfig(int offset, uint8_t *data)
|
||||
Tick
|
||||
IdeController::readConfig(Packet *pkt)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 1) <= IDE_CTRL_CONF_END) {
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset < PCI_DEVICE_SPECIFIC)
|
||||
return PciDev::readConfig(pkt);
|
||||
assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
|
||||
|
||||
pkt->allocate();
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_DEV_TIMING:
|
||||
*data = config_regs.sidetim;
|
||||
pkt->set<uint8_t>(config_regs.sidetim);
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
*data = config_regs.udmactl;
|
||||
pkt->set<uint8_t>(config_regs.udmactl);
|
||||
break;
|
||||
case IDE_CTRL_CONF_PRIM_TIMING+1:
|
||||
*data = htole(config_regs.idetim0) >> 8;
|
||||
pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING+1:
|
||||
*data = htole(config_regs.idetim1) >> 8;
|
||||
pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
*data = htole(config_regs.ideconfig) & 0xFF;
|
||||
pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG+1:
|
||||
*data = htole(config_regs.ideconfig) >> 8;
|
||||
pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
|
||||
offset, (uint32_t)*data);
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::readConfig(int offset, uint16_t *data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 2) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
|
||||
(uint32_t)pkt->get<uint8_t>());
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
*data = config_regs.idetim0;
|
||||
pkt->set<uint16_t>(config_regs.idetim0);
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
*data = config_regs.idetim1;
|
||||
pkt->set<uint16_t>(config_regs.idetim1);
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
*data = config_regs.udmatim;
|
||||
pkt->set<uint16_t>(config_regs.udmatim);
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
*data = config_regs.ideconfig;
|
||||
pkt->set<uint16_t>(config_regs.ideconfig);
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
|
||||
(uint32_t)pkt->get<uint16_t>());
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
panic("No 32bit reads implemented for this device.");
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
|
||||
(uint32_t)pkt->get<uint32_t>());
|
||||
break;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::readConfig(int offset, uint32_t *data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, data);
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
|
||||
}
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint8_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 1) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_DEV_TIMING:
|
||||
config_regs.sidetim = data;
|
||||
Tick
|
||||
IdeController::writeConfig(Packet *pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(pkt);
|
||||
} else {
|
||||
assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_DEV_TIMING:
|
||||
config_regs.sidetim = pkt->get<uint8_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
config_regs.udmactl = pkt->get<uint8_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
|
||||
(pkt->get<uint8_t>());
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG+1:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
|
||||
pkt->get<uint8_t>() << 8;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
|
||||
offset, (uint32_t)pkt->get<uint8_t>());
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
config_regs.udmactl = data;
|
||||
case sizeof(uint16_t):
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
config_regs.idetim0 = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
config_regs.idetim1 = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
config_regs.udmatim = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = pkt->get<uint16_t>();
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
|
||||
offset, (uint32_t)pkt->get<uint16_t>());
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG+1:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
|
||||
case sizeof(uint32_t):
|
||||
panic("Write of unimplemented PCI config. register: %x\n", offset);
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
|
||||
offset);
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
|
||||
offset, (uint32_t)data);
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint16_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else if (offset >= IDE_CTRL_CONF_START &&
|
||||
(offset + 2) <= IDE_CTRL_CONF_END) {
|
||||
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
config_regs.idetim0 = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
config_regs.idetim1 = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
config_regs.udmatim = data;
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = data;
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
panic("Write of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
|
||||
|
||||
/* Trap command register writes and enable IO/BM as appropriate. */
|
||||
if (offset == PCI_COMMAND) {
|
||||
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||
io_enabled = true;
|
||||
else
|
||||
io_enabled = false;
|
||||
|
||||
if (letoh(config.command) & PCI_CMD_BME)
|
||||
bm_enabled = true;
|
||||
else
|
||||
bm_enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint32_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
|
||||
|
||||
/* Trap command register writes and enable IO/BM as appropriate as well as
|
||||
* BARs. */
|
||||
switch(offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
if (BARAddrs[0] != 0)
|
||||
@@ -423,9 +389,24 @@ IdeController::writeConfig(int offset, const uint32_t data)
|
||||
if (BARAddrs[4] != 0)
|
||||
bmi_addr = BARAddrs[4];
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||
io_enabled = true;
|
||||
else
|
||||
io_enabled = false;
|
||||
|
||||
if (letoh(config.command) & PCI_CMD_BME)
|
||||
bm_enabled = true;
|
||||
else
|
||||
bm_enabled = false;
|
||||
break;
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
IdeController::read(Packet *pkt)
|
||||
{
|
||||
@@ -770,7 +751,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
SimObjectParam<System *> system;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<PciConfigAll *> configspace;
|
||||
SimObjectParam<PciConfigData *> configdata;
|
||||
Param<uint32_t> pci_bus;
|
||||
Param<uint32_t> pci_dev;
|
||||
@@ -784,7 +764,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
|
||||
|
||||
INIT_PARAM(system, "System pointer"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(configspace, "PCI Configspace"),
|
||||
INIT_PARAM(configdata, "PCI Config data"),
|
||||
INIT_PARAM(pci_bus, "PCI bus ID"),
|
||||
INIT_PARAM(pci_dev, "PCI device number"),
|
||||
@@ -800,7 +779,6 @@ CREATE_SIM_OBJECT(IdeController)
|
||||
params->name = getInstanceName();
|
||||
params->platform = platform;
|
||||
params->system = system;
|
||||
params->configSpace = configspace;
|
||||
params->configData = configdata;
|
||||
params->busNum = pci_bus;
|
||||
params->deviceNum = pci_dev;
|
||||
|
||||
@@ -204,12 +204,8 @@ class IdeController : public PciDev
|
||||
IdeController(Params *p);
|
||||
~IdeController();
|
||||
|
||||
virtual void writeConfig(int offset, const uint8_t data);
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual void writeConfig(int offset, const uint32_t data);
|
||||
virtual void readConfig(int offset, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint16_t *data);
|
||||
virtual void readConfig(int offset, uint32_t *data);
|
||||
virtual Tick writeConfig(Packet *pkt);
|
||||
virtual Tick readConfig(Packet *pkt);
|
||||
|
||||
void setDmaComplete(IdeDisk *disk);
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "sim/builder.hh"
|
||||
|
||||
|
||||
PioPort::PioPort(PioDevice *dev, Platform *p)
|
||||
: Port(dev->name() + "-pioport"), device(dev), platform(p)
|
||||
PioPort::PioPort(PioDevice *dev, Platform *p, std::string pname)
|
||||
: Port(dev->name() + pname), device(dev), platform(p)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -79,19 +79,23 @@ PioPort::SendEvent::process()
|
||||
port->transmitList.push_back(packet);
|
||||
}
|
||||
|
||||
void
|
||||
PioPort::resendNacked(Packet *pkt) {
|
||||
pkt->reinitNacked();
|
||||
if (transmitList.size()) {
|
||||
transmitList.push_front(pkt);
|
||||
} else {
|
||||
if (!Port::sendTiming(pkt))
|
||||
transmitList.push_front(pkt);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
PioPort::recvTiming(Packet *pkt)
|
||||
{
|
||||
if (pkt->result == Packet::Nacked) {
|
||||
pkt->reinitNacked();
|
||||
if (transmitList.size()) {
|
||||
transmitList.push_front(pkt);
|
||||
} else {
|
||||
if (!Port::sendTiming(pkt))
|
||||
transmitList.push_front(pkt);
|
||||
}
|
||||
resendNacked(pkt);
|
||||
} else {
|
||||
Tick latency = device->recvAtomic(pkt);
|
||||
// turn packet around to go back to requester
|
||||
|
||||
@@ -82,6 +82,8 @@ class PioPort : public Port
|
||||
|
||||
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
|
||||
|
||||
void resendNacked(Packet *pkt);
|
||||
|
||||
/**
|
||||
* This class is used to implemented sendTiming() with a delay. When a delay
|
||||
* is requested a new event is created. When the event time expires it
|
||||
@@ -113,7 +115,7 @@ class PioPort : public Port
|
||||
virtual void recvRetry();
|
||||
|
||||
public:
|
||||
PioPort(PioDevice *dev, Platform *p);
|
||||
PioPort(PioDevice *dev, Platform *p, std::string pname = "-pioport");
|
||||
|
||||
friend class PioPort::SendEvent;
|
||||
};
|
||||
|
||||
@@ -465,11 +465,12 @@ NSGigE::regStats()
|
||||
/**
|
||||
* This is to write to the PCI general configuration registers
|
||||
*/
|
||||
void
|
||||
NSGigE::writeConfig(int offset, const uint16_t data)
|
||||
Tick
|
||||
NSGigE::writeConfig(Packet *pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset < PCI_DEVICE_SPECIFIC)
|
||||
PciDev::writeConfig(offset, data);
|
||||
PciDev::writeConfig(pkt);
|
||||
else
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
@@ -484,6 +485,8 @@ NSGigE::writeConfig(int offset, const uint16_t data)
|
||||
ioEnable = false;
|
||||
break;
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,14 +511,7 @@ NSGigE::read(Packet *pkt)
|
||||
if (daddr > LAST && daddr <= RESERVED) {
|
||||
panic("Accessing reserved register");
|
||||
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
||||
if (pkt->getSize() == sizeof(uint8_t))
|
||||
readConfig(daddr & 0xff, pkt->getPtr<uint8_t>());
|
||||
if (pkt->getSize() == sizeof(uint16_t))
|
||||
readConfig(daddr & 0xff, pkt->getPtr<uint16_t>());
|
||||
if (pkt->getSize() == sizeof(uint32_t))
|
||||
readConfig(daddr & 0xff, pkt->getPtr<uint32_t>());
|
||||
pkt->result = Packet::Success;
|
||||
return pioDelay;
|
||||
return readConfig(pkt);
|
||||
} else if (daddr >= MIB_START && daddr <= MIB_END) {
|
||||
// don't implement all the MIB's. hopefully the kernel
|
||||
// doesn't actually DEPEND upon their values
|
||||
@@ -733,14 +729,7 @@ NSGigE::write(Packet *pkt)
|
||||
if (daddr > LAST && daddr <= RESERVED) {
|
||||
panic("Accessing reserved register");
|
||||
} else if (daddr > RESERVED && daddr <= 0x3FC) {
|
||||
if (pkt->getSize() == sizeof(uint8_t))
|
||||
writeConfig(daddr & 0xff, pkt->get<uint8_t>());
|
||||
if (pkt->getSize() == sizeof(uint16_t))
|
||||
writeConfig(daddr & 0xff, pkt->get<uint16_t>());
|
||||
if (pkt->getSize() == sizeof(uint32_t))
|
||||
writeConfig(daddr & 0xff, pkt->get<uint32_t>());
|
||||
pkt->result = Packet::Success;
|
||||
return pioDelay;
|
||||
return writeConfig(pkt);
|
||||
} else if (daddr > 0x3FC)
|
||||
panic("Something is messed up!\n");
|
||||
|
||||
@@ -2807,7 +2796,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
|
||||
|
||||
SimObjectParam<System *> system;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<PciConfigAll *> configspace;
|
||||
SimObjectParam<PciConfigData *> configdata;
|
||||
Param<uint32_t> pci_bus;
|
||||
Param<uint32_t> pci_dev;
|
||||
@@ -2841,7 +2829,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
|
||||
|
||||
INIT_PARAM(system, "System pointer"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(configspace, "PCI Configspace"),
|
||||
INIT_PARAM(configdata, "PCI Config data"),
|
||||
INIT_PARAM(pci_bus, "PCI bus ID"),
|
||||
INIT_PARAM(pci_dev, "PCI device number"),
|
||||
@@ -2879,7 +2866,6 @@ CREATE_SIM_OBJECT(NSGigE)
|
||||
params->name = getInstanceName();
|
||||
params->platform = platform;
|
||||
params->system = system;
|
||||
params->configSpace = configspace;
|
||||
params->configData = configdata;
|
||||
params->busNum = pci_bus;
|
||||
params->deviceNum = pci_dev;
|
||||
|
||||
@@ -114,7 +114,6 @@ struct dp_rom {
|
||||
|
||||
class NSGigEInt;
|
||||
class Packet;
|
||||
class PciConfigAll;
|
||||
|
||||
/**
|
||||
* NS DP83820 Ethernet device model
|
||||
@@ -376,7 +375,7 @@ class NSGigE : public PciDev
|
||||
~NSGigE();
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual Tick writeConfig(Packet *pkt);
|
||||
|
||||
virtual Tick read(Packet *pkt);
|
||||
virtual Tick write(Packet *pkt);
|
||||
|
||||
@@ -33,14 +33,8 @@
|
||||
* PCI Configspace implementation
|
||||
*/
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "dev/pciconfigall.hh"
|
||||
#include "dev/pcidev.hh"
|
||||
#include "dev/pcireg.h"
|
||||
#include "dev/platform.hh"
|
||||
#include "mem/packet.hh"
|
||||
@@ -50,151 +44,61 @@
|
||||
using namespace std;
|
||||
|
||||
PciConfigAll::PciConfigAll(Params *p)
|
||||
: BasicPioDevice(p)
|
||||
: PioDevice(p)
|
||||
{
|
||||
pioSize = 0xffffff;
|
||||
|
||||
// Set backpointer for pci config. Really the config stuff should be able to
|
||||
// automagically do this
|
||||
p->platform->pciconfig = this;
|
||||
|
||||
// Make all the pointers to devices null
|
||||
for(int x=0; x < MAX_PCI_DEV; x++)
|
||||
for(int y=0; y < MAX_PCI_FUNC; y++)
|
||||
devices[x][y] = NULL;
|
||||
pioAddr = p->platform->calcConfigAddr(params()->bus,0,0);
|
||||
}
|
||||
|
||||
// If two interrupts share the same line largely bad things will happen.
|
||||
// Since we don't track how many times an interrupt was set and correspondingly
|
||||
// cleared two devices on the same interrupt line and assert and deassert each
|
||||
// others interrupt "line". Interrupts will not work correctly.
|
||||
void
|
||||
PciConfigAll::startup()
|
||||
{
|
||||
bitset<256> intLines;
|
||||
PciDev *tempDev;
|
||||
uint8_t intline;
|
||||
|
||||
for (int x = 0; x < MAX_PCI_DEV; x++) {
|
||||
for (int y = 0; y < MAX_PCI_FUNC; y++) {
|
||||
if (devices[x][y] != NULL) {
|
||||
tempDev = devices[x][y];
|
||||
intline = tempDev->interruptLine();
|
||||
if (intLines.test(intline))
|
||||
warn("Interrupt line %#X is used multiple times"
|
||||
"(You probably want to fix this).\n", (uint32_t)intline);
|
||||
else
|
||||
intLines.set(intline);
|
||||
} // devices != NULL
|
||||
} // PCI_FUNC
|
||||
} // PCI_DEV
|
||||
|
||||
}
|
||||
|
||||
Tick
|
||||
PciConfigAll::read(Packet *pkt)
|
||||
{
|
||||
assert(pkt->result == Packet::Unknown);
|
||||
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
|
||||
|
||||
Addr daddr = pkt->getAddr() - pioAddr;
|
||||
int device = (daddr >> 11) & 0x1F;
|
||||
int func = (daddr >> 8) & 0x7;
|
||||
int reg = daddr & 0xFF;
|
||||
|
||||
pkt->allocate();
|
||||
|
||||
DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->getAddr(), daddr,
|
||||
DPRINTF(PciConfigAll, "read va=%#x size=%d\n", pkt->getAddr(),
|
||||
pkt->getSize());
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint32_t):
|
||||
if (devices[device][func] == NULL)
|
||||
pkt->set<uint32_t>(0xFFFFFFFF);
|
||||
else
|
||||
devices[device][func]->readConfig(reg, pkt->getPtr<uint32_t>());
|
||||
pkt->set<uint32_t>(0xFFFFFFFF);
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
if (devices[device][func] == NULL)
|
||||
pkt->set<uint16_t>(0xFFFF);
|
||||
else
|
||||
devices[device][func]->readConfig(reg, pkt->getPtr<uint16_t>());
|
||||
pkt->set<uint16_t>(0xFFFF);
|
||||
break;
|
||||
case sizeof(uint8_t):
|
||||
if (devices[device][func] == NULL)
|
||||
pkt->set<uint8_t>(0xFF);
|
||||
else
|
||||
devices[device][func]->readConfig(reg, pkt->getPtr<uint8_t>());
|
||||
pkt->set<uint8_t>(0xFF);
|
||||
break;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return pioDelay;
|
||||
return params()->pio_delay;
|
||||
}
|
||||
|
||||
Tick
|
||||
PciConfigAll::write(Packet *pkt)
|
||||
{
|
||||
assert(pkt->result == Packet::Unknown);
|
||||
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
|
||||
assert(pkt->getSize() == sizeof(uint8_t) || pkt->getSize() == sizeof(uint16_t) ||
|
||||
pkt->getSize() == sizeof(uint32_t));
|
||||
Addr daddr = pkt->getAddr() - pioAddr;
|
||||
|
||||
int device = (daddr >> 11) & 0x1F;
|
||||
int func = (daddr >> 8) & 0x7;
|
||||
int reg = daddr & 0xFF;
|
||||
|
||||
if (devices[device][func] == NULL)
|
||||
panic("Attempting to write to config space on non-existant device\n");
|
||||
|
||||
DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize(), pkt->get<uint32_t>());
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
devices[device][func]->writeConfig(reg, pkt->get<uint8_t>());
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
devices[device][func]->writeConfig(reg, pkt->get<uint16_t>());
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
devices[device][func]->writeConfig(reg, pkt->get<uint32_t>());
|
||||
break;
|
||||
default:
|
||||
panic("invalid pci config write size\n");
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return pioDelay;
|
||||
panic("Attempting to write to config space on non-existant device\n");
|
||||
}
|
||||
|
||||
void
|
||||
PciConfigAll::serialize(std::ostream &os)
|
||||
PciConfigAll::addressRanges(AddrRangeList &range_list)
|
||||
{
|
||||
/*
|
||||
* There is no state associated with this object that requires
|
||||
* serialization. The only real state are the device pointers
|
||||
* which are all setup by the constructor of the PciDev class
|
||||
*/
|
||||
range_list.clear();
|
||||
range_list.push_back(RangeSize(pioAddr, params()->size));
|
||||
}
|
||||
|
||||
void
|
||||
PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
/*
|
||||
* There is no state associated with this object that requires
|
||||
* serialization. The only real state are the device pointers
|
||||
* which are all setup by the constructor of the PciDev class
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
Param<Addr> pio_addr;
|
||||
Param<Tick> pio_latency;
|
||||
Param<int> bus;
|
||||
Param<Addr> size;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<System *> system;
|
||||
|
||||
@@ -202,8 +106,9 @@ END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
INIT_PARAM(pio_addr, "Device Address"),
|
||||
INIT_PARAM(pio_latency, "Programmed IO latency"),
|
||||
INIT_PARAM(bus, "Bus that this object handles config space for"),
|
||||
INIT_PARAM(size, "The size of config space"),
|
||||
INIT_PARAM(platform, "platform"),
|
||||
INIT_PARAM(system, "system object")
|
||||
|
||||
@@ -211,11 +116,13 @@ END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
CREATE_SIM_OBJECT(PciConfigAll)
|
||||
{
|
||||
BasicPioDevice::Params *p = new BasicPioDevice::Params;
|
||||
p->pio_addr = pio_addr;
|
||||
PciConfigAll::Params *p = new PciConfigAll::Params;
|
||||
p->pio_delay = pio_latency;
|
||||
p->platform = platform;
|
||||
p->system = system;
|
||||
p->bus = bus;
|
||||
p->size = size;
|
||||
|
||||
return new PciConfigAll(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,11 +42,6 @@
|
||||
#include "dev/io_device.hh"
|
||||
|
||||
|
||||
static const uint32_t MAX_PCI_DEV = 32;
|
||||
static const uint32_t MAX_PCI_FUNC = 8;
|
||||
|
||||
class PciDev;
|
||||
|
||||
/**
|
||||
* PCI Config Space
|
||||
* All of PCI config space needs to return -1 on Tsunami, except
|
||||
@@ -54,45 +49,28 @@ class PciDev;
|
||||
* space and passes the requests on to TsunamiPCIDev devices as
|
||||
* appropriate.
|
||||
*/
|
||||
class PciConfigAll : public BasicPioDevice
|
||||
class PciConfigAll : public PioDevice
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Pointers to all the devices that are registered with this
|
||||
* particular config space.
|
||||
*/
|
||||
PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC];
|
||||
|
||||
public:
|
||||
struct Params : public PioDevice::Params
|
||||
{
|
||||
Tick pio_delay;
|
||||
Addr size;
|
||||
int bus;
|
||||
};
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
/**
|
||||
* Constructor for PCIConfigAll
|
||||
* @param p parameters structure
|
||||
*/
|
||||
PciConfigAll(Params *p);
|
||||
|
||||
/**
|
||||
* Check if a device exists.
|
||||
* @param pcidev PCI device to check
|
||||
* @param pcifunc PCI function to check
|
||||
* @return true if device exists, false otherwise
|
||||
*/
|
||||
bool deviceExists(uint32_t pcidev, uint32_t pcifunc)
|
||||
{ return devices[pcidev][pcifunc] != NULL ? true : false; }
|
||||
|
||||
/**
|
||||
* Registers a device with the config space object.
|
||||
* @param pcidev PCI device to register
|
||||
* @param pcifunc PCI function to register
|
||||
* @param device device to register
|
||||
*/
|
||||
void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device)
|
||||
{ devices[pcidev][pcifunc] = device; }
|
||||
|
||||
/**
|
||||
* Read something in PCI config space. If the device does not exist
|
||||
* -1 is returned, if the device does exist its PciDev::ReadConfig (or the
|
||||
* virtual function that overrides) it is called.
|
||||
* @param pkt Contains the address of the field to read.
|
||||
* @param pkt Contains information about the read operation
|
||||
* @return Amount of time to do the read
|
||||
*/
|
||||
virtual Tick read(Packet *pkt);
|
||||
@@ -101,31 +79,17 @@ class PciConfigAll : public BasicPioDevice
|
||||
* Write to PCI config spcae. If the device does not exit the simulator
|
||||
* panics. If it does it is passed on the PciDev::WriteConfig (or the virtual
|
||||
* function that overrides it).
|
||||
* @param req Contains the address to write to.
|
||||
* @param data The data to write.
|
||||
* @return The fault condition of the access.
|
||||
* @param pkt Contains information about the write operation
|
||||
* @return Amount of time to do the read
|
||||
*/
|
||||
|
||||
virtual Tick write(Packet *pkt);
|
||||
|
||||
/**
|
||||
* Start up function to check if more than one person is using an interrupt line
|
||||
* and print a warning if such a case exists
|
||||
*/
|
||||
virtual void startup();
|
||||
void addressRanges(AddrRangeList &range_list);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
*/
|
||||
virtual void serialize(std::ostream &os);
|
||||
private:
|
||||
Addr pioAddr;
|
||||
|
||||
/**
|
||||
* Reconstruct the state of this object from a checkpoint.
|
||||
* @param cp The checkpoint use.
|
||||
* @param section The section name of this object
|
||||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
};
|
||||
|
||||
#endif // __PCICONFIGALL_HH__
|
||||
|
||||
@@ -53,9 +53,63 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
|
||||
int funcid, Platform *p)
|
||||
: PioPort(dev,p,"-pciconf"), device(dev), busId(busid), deviceId(devid),
|
||||
functionId(funcid)
|
||||
{
|
||||
configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
PciDev::PciConfigPort::recvAtomic(Packet *pkt)
|
||||
{
|
||||
assert(pkt->result == Packet::Unknown);
|
||||
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
|
||||
PCI_CONFIG_SIZE);
|
||||
return device->recvConfig(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::PciConfigPort::recvFunctional(Packet *pkt)
|
||||
{
|
||||
assert(pkt->result == Packet::Unknown);
|
||||
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
|
||||
PCI_CONFIG_SIZE);
|
||||
device->recvConfig(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::PciConfigPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
|
||||
{
|
||||
snoop.clear();
|
||||
resp.push_back(RangeSize(configAddr, PCI_CONFIG_SIZE+1));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PciDev::PciConfigPort::recvTiming(Packet *pkt)
|
||||
{
|
||||
if (pkt->result == Packet::Nacked) {
|
||||
resendNacked(pkt);
|
||||
} else {
|
||||
assert(pkt->result == Packet::Unknown);
|
||||
assert(pkt->getAddr() >= configAddr && pkt->getAddr() < configAddr +
|
||||
PCI_CONFIG_SIZE);
|
||||
Tick latency = device->recvConfig(pkt);
|
||||
// turn packet around to go back to requester
|
||||
pkt->makeTimingResponse();
|
||||
sendTiming(pkt, latency);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PciDev::PciDev(Params *p)
|
||||
: DmaDevice(p), plat(p->platform), configData(p->configData),
|
||||
pioDelay(p->pio_delay)
|
||||
pioDelay(p->pio_delay), configDelay(p->config_delay),
|
||||
configPort(NULL)
|
||||
{
|
||||
// copy the config data from the PciConfigData object
|
||||
if (configData) {
|
||||
@@ -65,25 +119,56 @@ PciDev::PciDev(Params *p)
|
||||
} else
|
||||
panic("NULL pointer to configuration data");
|
||||
|
||||
// Setup pointer in config space to point to this entry
|
||||
if (p->configSpace->deviceExists(p->deviceNum, p->functionNum))
|
||||
panic("Two PCI devices occuping same dev: %#x func: %#x",
|
||||
p->deviceNum, p->functionNum);
|
||||
else
|
||||
p->configSpace->registerDevice(p->deviceNum, p->functionNum, this);
|
||||
plat->registerPciDevice(0, p->deviceNum, p->functionNum,
|
||||
letoh(configData->config.interruptLine));
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::readConfig(int offset, uint8_t *data)
|
||||
PciDev::init()
|
||||
{
|
||||
if (!configPort)
|
||||
panic("pci config port not connected to anything!");
|
||||
configPort->sendStatusChange(Port::RangeChange);
|
||||
PioDevice::init();
|
||||
}
|
||||
|
||||
Tick
|
||||
PciDev::readConfig(Packet *pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
*data = config.data[offset];
|
||||
pkt->allocate();
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
pkt->set<uint8_t>(config.data[offset]);
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint8_t>());
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
pkt->set<uint16_t>(*(uint16_t*)&config.data[offset]);
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint16_t>());
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
pkt->set<uint32_t>(*(uint32_t*)&config.data[offset]);
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint32_t>());
|
||||
break;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -96,158 +181,128 @@ PciDev::addressRanges(AddrRangeList &range_list)
|
||||
range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::readConfig(int offset, uint16_t *data)
|
||||
Tick
|
||||
PciDev::writeConfig(Packet *pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
*data = *(uint16_t*)&config.data[offset];
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::readConfig(int offset, uint32_t *data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
*data = *(uint32_t*)&config.data[offset];
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, *data);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint8_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 1 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCI0_INTERRUPT_LINE:
|
||||
config.interruptLine = data;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
case PCI_LATENCY_TIMER:
|
||||
config.latencyTimer = data;
|
||||
break;
|
||||
/* Do nothing for these read-only registers */
|
||||
case PCI0_INTERRUPT_PIN:
|
||||
case PCI0_MINIMUM_GRANT:
|
||||
case PCI0_MAXIMUM_LATENCY:
|
||||
case PCI_CLASS_CODE:
|
||||
case PCI_REVISION_ID:
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint16_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 2 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCI_COMMAND:
|
||||
config.command = data;
|
||||
case PCI_STATUS:
|
||||
config.status = data;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PciDev::writeConfig(int offset, const uint32_t data)
|
||||
{
|
||||
if (offset >= PCI_DEVICE_SPECIFIC)
|
||||
panic("Device specific PCI config space not implemented!\n");
|
||||
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x reg: %#x size: 4 data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
case PCI0_BASE_ADDR1:
|
||||
case PCI0_BASE_ADDR2:
|
||||
case PCI0_BASE_ADDR3:
|
||||
case PCI0_BASE_ADDR4:
|
||||
case PCI0_BASE_ADDR5:
|
||||
|
||||
uint32_t barnum, bar_mask;
|
||||
Addr base_addr, base_size, space_base;
|
||||
|
||||
barnum = BAR_NUMBER(offset);
|
||||
|
||||
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
|
||||
bar_mask = BAR_IO_MASK;
|
||||
space_base = TSUNAMI_PCI0_IO;
|
||||
} else {
|
||||
bar_mask = BAR_MEM_MASK;
|
||||
space_base = TSUNAMI_PCI0_MEMORY;
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
switch (offset) {
|
||||
case PCI0_INTERRUPT_LINE:
|
||||
config.interruptLine = pkt->get<uint8_t>();
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = pkt->get<uint8_t>();
|
||||
case PCI_LATENCY_TIMER:
|
||||
config.latencyTimer = pkt->get<uint8_t>();
|
||||
break;
|
||||
/* Do nothing for these read-only registers */
|
||||
case PCI0_INTERRUPT_PIN:
|
||||
case PCI0_MINIMUM_GRANT:
|
||||
case PCI0_MAXIMUM_LATENCY:
|
||||
case PCI_CLASS_CODE:
|
||||
case PCI_REVISION_ID:
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint8_t>());
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
switch (offset) {
|
||||
case PCI_COMMAND:
|
||||
config.command = pkt->get<uint8_t>();
|
||||
case PCI_STATUS:
|
||||
config.status = pkt->get<uint8_t>();
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = pkt->get<uint8_t>();
|
||||
break;
|
||||
default:
|
||||
panic("writing to a read only register");
|
||||
}
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint16_t>());
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
switch (offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
case PCI0_BASE_ADDR1:
|
||||
case PCI0_BASE_ADDR2:
|
||||
case PCI0_BASE_ADDR3:
|
||||
case PCI0_BASE_ADDR4:
|
||||
case PCI0_BASE_ADDR5:
|
||||
|
||||
// Writing 0xffffffff to a BAR tells the card to set the
|
||||
// value of the bar to size of memory it needs
|
||||
if (letoh(data) == 0xffffffff) {
|
||||
// This is I/O Space, bottom two bits are read only
|
||||
uint32_t barnum, bar_mask;
|
||||
Addr base_addr, base_size, space_base;
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(~(BARSize[barnum] - 1) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
} else {
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(letoh(data) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
barnum = BAR_NUMBER(offset);
|
||||
|
||||
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||
base_addr = (letoh(data) & ~bar_mask) + space_base;
|
||||
base_size = BARSize[barnum];
|
||||
BARAddrs[barnum] = base_addr;
|
||||
|
||||
pioPort->sendStatusChange(Port::RangeChange);
|
||||
if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
|
||||
bar_mask = BAR_IO_MASK;
|
||||
space_base = TSUNAMI_PCI0_IO;
|
||||
} else {
|
||||
bar_mask = BAR_MEM_MASK;
|
||||
space_base = TSUNAMI_PCI0_MEMORY;
|
||||
}
|
||||
|
||||
// Writing 0xffffffff to a BAR tells the card to set the
|
||||
// value of the bar to size of memory it needs
|
||||
if (letoh(pkt->get<uint32_t>()) == 0xffffffff) {
|
||||
// This is I/O Space, bottom two bits are read only
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(~(BARSize[barnum] - 1) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
} else {
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(letoh(pkt->get<uint32_t>()) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
|
||||
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||
base_addr = (letoh(pkt->get<uint32_t>()) & ~bar_mask) + space_base;
|
||||
base_size = BARSize[barnum];
|
||||
BARAddrs[barnum] = base_addr;
|
||||
|
||||
pioPort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI0_ROM_BASE_ADDR:
|
||||
if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
|
||||
config.expansionROM = htole((uint32_t)0xffffffff);
|
||||
else
|
||||
config.expansionROM = pkt->get<uint32_t>();
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
// This could also clear some of the error bits in the Status
|
||||
// register. However they should never get set, so lets ignore
|
||||
// it for now
|
||||
config.command = pkt->get<uint32_t>();
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(PCIDEV, "Writing to a read only register");
|
||||
}
|
||||
DPRINTF(PCIDEV,
|
||||
"write device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
|
||||
params()->deviceNum, params()->functionNum, offset,
|
||||
(uint32_t)pkt->get<uint32_t>());
|
||||
break;
|
||||
|
||||
case PCI0_ROM_BASE_ADDR:
|
||||
if (letoh(data) == 0xfffffffe)
|
||||
config.expansionROM = htole((uint32_t)0xffffffff);
|
||||
else
|
||||
config.expansionROM = data;
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
// This could also clear some of the error bits in the Status
|
||||
// register. However they should never get set, so lets ignore
|
||||
// it for now
|
||||
config.command = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(PCIDEV, "Writing to a read only register");
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -47,8 +47,6 @@
|
||||
#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
|
||||
#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
|
||||
|
||||
class PciConfigAll;
|
||||
|
||||
|
||||
/**
|
||||
* This class encapulates the first 64 bytes of a singles PCI
|
||||
@@ -78,24 +76,41 @@ class PciConfigData : public SimObject
|
||||
Addr BARAddrs[6];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* PCI device, base implemnation is only config space.
|
||||
* Each device is connected to a PCIConfigSpace device
|
||||
* which returns -1 for everything but the pcidevs that
|
||||
* register with it. This object registers with the PCIConfig space
|
||||
* object.
|
||||
*/
|
||||
class PciDev : public DmaDevice
|
||||
{
|
||||
public:
|
||||
struct Params : public ::PioDevice::Params
|
||||
class PciConfigPort : public PioPort
|
||||
{
|
||||
/**
|
||||
* A pointer to the configspace all object that calls us when
|
||||
* a read comes to this particular device/function.
|
||||
*/
|
||||
PciConfigAll *configSpace;
|
||||
protected:
|
||||
PciDev *device;
|
||||
|
||||
virtual bool recvTiming(Packet *pkt);
|
||||
|
||||
virtual Tick recvAtomic(Packet *pkt);
|
||||
|
||||
virtual void recvFunctional(Packet *pkt) ;
|
||||
|
||||
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
|
||||
|
||||
int busId;
|
||||
int deviceId;
|
||||
int functionId;
|
||||
|
||||
Addr configAddr;
|
||||
|
||||
public:
|
||||
PciConfigPort(PciDev *dev, int busid, int devid, int funcid,
|
||||
Platform *p);
|
||||
|
||||
friend class PioPort::SendEvent;
|
||||
};
|
||||
|
||||
public:
|
||||
struct Params : public PioDevice::Params
|
||||
{
|
||||
/**
|
||||
* A pointer to the object that contains the first 64 bytes of
|
||||
* config space
|
||||
@@ -113,6 +128,9 @@ class PciDev : public DmaDevice
|
||||
|
||||
/** The latency for pio accesses. */
|
||||
Tick pio_delay;
|
||||
|
||||
/** The latency for a config access. */
|
||||
Tick config_delay;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -164,6 +182,25 @@ class PciDev : public DmaDevice
|
||||
Platform *plat;
|
||||
PciConfigData *configData;
|
||||
Tick pioDelay;
|
||||
Tick configDelay;
|
||||
PciConfigPort *configPort;
|
||||
|
||||
/**
|
||||
* Write to the PCI config space data that is stored locally. This may be
|
||||
* overridden by the device but at some point it will eventually call this
|
||||
* for normal operations that it does not need to override.
|
||||
* @param pkt packet containing the write the offset into config space
|
||||
*/
|
||||
virtual Tick writeConfig(Packet *pkt);
|
||||
|
||||
|
||||
/**
|
||||
* Read from the PCI config space data that is stored locally. This may be
|
||||
* overridden by the device but at some point it will eventually call this
|
||||
* for normal operations that it does not need to override.
|
||||
* @param pkt packet containing the write the offset into config space
|
||||
*/
|
||||
virtual Tick readConfig(Packet *pkt);
|
||||
|
||||
public:
|
||||
Addr pciToDma(Addr pciAddr) const
|
||||
@@ -171,21 +208,25 @@ class PciDev : public DmaDevice
|
||||
|
||||
void
|
||||
intrPost()
|
||||
{ plat->postPciInt(configData->config.interruptLine); }
|
||||
{ plat->postPciInt(letoh(configData->config.interruptLine)); }
|
||||
|
||||
void
|
||||
intrClear()
|
||||
{ plat->clearPciInt(configData->config.interruptLine); }
|
||||
{ plat->clearPciInt(letoh(configData->config.interruptLine)); }
|
||||
|
||||
uint8_t
|
||||
interruptLine()
|
||||
{ return configData->config.interruptLine; }
|
||||
{ return letoh(configData->config.interruptLine); }
|
||||
|
||||
/** return the address ranges that this device responds to.
|
||||
* @params range_list range list to populate with ranges
|
||||
*/
|
||||
void addressRanges(AddrRangeList &range_list);
|
||||
|
||||
/** Do a PCI Configspace memory access. */
|
||||
Tick recvConfig(Packet *pkt)
|
||||
{ return pkt->isRead() ? readConfig(pkt) : writeConfig(pkt); }
|
||||
|
||||
/**
|
||||
* Constructor for PCI Dev. This function copies data from the
|
||||
* config file object PCIConfigData and registers the device with
|
||||
@@ -193,30 +234,7 @@ class PciDev : public DmaDevice
|
||||
*/
|
||||
PciDev(Params *params);
|
||||
|
||||
/**
|
||||
* Write to the PCI config space data that is stored locally. This may be
|
||||
* overridden by the device but at some point it will eventually call this
|
||||
* for normal operations that it does not need to override.
|
||||
* @param offset the offset into config space
|
||||
* @param size the size of the write
|
||||
* @param data the data to write
|
||||
*/
|
||||
virtual void writeConfig(int offset, const uint8_t data);
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual void writeConfig(int offset, const uint32_t data);
|
||||
|
||||
|
||||
/**
|
||||
* Read from the PCI config space data that is stored locally. This may be
|
||||
* overridden by the device but at some point it will eventually call this
|
||||
* for normal operations that it does not need to override.
|
||||
* @param offset the offset into config space
|
||||
* @param size the size of the read
|
||||
* @param data pointer to the location where the read value should be stored
|
||||
*/
|
||||
virtual void readConfig(int offset, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint16_t *data);
|
||||
virtual void readConfig(int offset, uint32_t *data);
|
||||
virtual void init();
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
@@ -230,5 +248,19 @@ class PciDev : public DmaDevice
|
||||
* @param section The section name of this object
|
||||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1)
|
||||
{
|
||||
if (if_name == "config") {
|
||||
if (configPort != NULL)
|
||||
panic("pciconfig port already connected to.");
|
||||
configPort = new PciConfigPort(this, params()->busNum,
|
||||
params()->deviceNum, params()->functionNum,
|
||||
params()->platform);
|
||||
return configPort;
|
||||
}
|
||||
return DmaDevice::getPort(if_name, idx);
|
||||
}
|
||||
|
||||
};
|
||||
#endif // __DEV_PCIDEV_HH__
|
||||
|
||||
@@ -142,6 +142,7 @@ union PCIConfig {
|
||||
|
||||
// Device specific offsets
|
||||
#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
|
||||
#define PCI_CONFIG_SIZE 0xFF
|
||||
|
||||
// Some Vendor IDs
|
||||
#define PCI_VENDOR_DEC 0x1011
|
||||
|
||||
@@ -63,5 +63,21 @@ Platform::pciToDma(Addr pciAddr) const
|
||||
panic("No PCI dma support in platform.");
|
||||
}
|
||||
|
||||
void
|
||||
Platform::registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func, uint8_t intr)
|
||||
{
|
||||
uint32_t bdf = bus << 16 | dev << 8 | func << 0;
|
||||
if (pciDevices.find(bdf) != pciDevices.end())
|
||||
fatal("Two PCI devices have same bus:device:function\n");
|
||||
|
||||
if (intLines.test(intr))
|
||||
fatal("Two PCI devices have same interrupt line: %d\n", intr);
|
||||
|
||||
pciDevices.insert(bdf);
|
||||
|
||||
intLines.set(intr);
|
||||
}
|
||||
|
||||
|
||||
DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform)
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
#ifndef __DEV_PLATFORM_HH__
|
||||
#define __DEV_PLATFORM_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <set>
|
||||
|
||||
#include "sim/sim_object.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
|
||||
@@ -52,9 +55,6 @@ class Platform : public SimObject
|
||||
/** Pointer to the interrupt controller */
|
||||
IntrControl *intrctrl;
|
||||
|
||||
/** Pointer to the PCI configuration space */
|
||||
PciConfigAll *pciconfig;
|
||||
|
||||
/** Pointer to the UART, set by the uart */
|
||||
Uart *uart;
|
||||
|
||||
@@ -64,13 +64,20 @@ class Platform : public SimObject
|
||||
public:
|
||||
Platform(const std::string &name, IntrControl *intctrl);
|
||||
virtual ~Platform();
|
||||
virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); }
|
||||
virtual void postConsoleInt() = 0;
|
||||
virtual void clearConsoleInt() = 0;
|
||||
virtual Tick intrFrequency() = 0;
|
||||
virtual void postPciInt(int line);
|
||||
virtual void clearPciInt(int line);
|
||||
virtual Addr pciToDma(Addr pciAddr) const;
|
||||
virtual Addr calcConfigAddr(int bus, int dev, int func) = 0;
|
||||
virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
|
||||
uint8_t intr);
|
||||
|
||||
private:
|
||||
std::bitset<256> intLines;
|
||||
std::set<uint32_t> pciDevices;
|
||||
|
||||
};
|
||||
|
||||
#endif // __DEV_PLATFORM_HH__
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "cpu/intr_control.hh"
|
||||
#include "dev/etherlink.hh"
|
||||
#include "dev/sinic.hh"
|
||||
#include "dev/pciconfigall.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/debug.hh"
|
||||
@@ -1623,7 +1622,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
|
||||
|
||||
SimObjectParam<System *> system;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<PciConfigAll *> configspace;
|
||||
SimObjectParam<PciConfigData *> configdata;
|
||||
Param<uint32_t> pci_bus;
|
||||
Param<uint32_t> pci_dev;
|
||||
@@ -1666,7 +1664,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
|
||||
|
||||
INIT_PARAM(system, "System pointer"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(configspace, "PCI Configspace"),
|
||||
INIT_PARAM(configdata, "PCI Config data"),
|
||||
INIT_PARAM(pci_bus, "PCI bus ID"),
|
||||
INIT_PARAM(pci_dev, "PCI device number"),
|
||||
@@ -1711,7 +1708,6 @@ CREATE_SIM_OBJECT(Device)
|
||||
params->name = getInstanceName();
|
||||
params->platform = platform;
|
||||
params->system = system;
|
||||
params->configSpace = configspace;
|
||||
params->configData = configdata;
|
||||
params->busNum = pci_bus;
|
||||
params->deviceNum = pci_dev;
|
||||
|
||||
@@ -95,6 +95,13 @@ Tsunami::pciToDma(Addr pciAddr) const
|
||||
return pchip->translatePciToDma(pciAddr);
|
||||
}
|
||||
|
||||
|
||||
Addr
|
||||
Tsunami::calcConfigAddr(int bus, int dev, int func)
|
||||
{
|
||||
return pchip->calcConfigAddr(bus, dev, func);
|
||||
}
|
||||
|
||||
void
|
||||
Tsunami::serialize(std::ostream &os)
|
||||
{
|
||||
|
||||
@@ -113,8 +113,14 @@ class Tsunami : public Platform
|
||||
*/
|
||||
virtual void clearPciInt(int line);
|
||||
|
||||
|
||||
virtual Addr pciToDma(Addr pciAddr) const;
|
||||
|
||||
/**
|
||||
* Calculate the configuration address given a bus/dev/func.
|
||||
*/
|
||||
virtual Addr calcConfigAddr(int bus, int dev, int func);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
|
||||
@@ -302,6 +302,17 @@ TsunamiPChip::translatePciToDma(Addr busAddr)
|
||||
// if no match was found, then return the original address
|
||||
return busAddr;
|
||||
}
|
||||
Addr
|
||||
TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
|
||||
{
|
||||
assert(func < 8);
|
||||
assert(dev < 32);
|
||||
assert(bus == 0);
|
||||
|
||||
return TsunamiPciBus0Config | (func << 8) | (dev << 11);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
TsunamiPChip::serialize(std::ostream &os)
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
class TsunamiPChip : public BasicPioDevice
|
||||
{
|
||||
protected:
|
||||
|
||||
static const Addr TsunamiPciBus0Config = 0x801fe000000;
|
||||
|
||||
/** Pchip control register */
|
||||
uint64_t pctl;
|
||||
|
||||
@@ -80,6 +83,8 @@ class TsunamiPChip : public BasicPioDevice
|
||||
*/
|
||||
Addr translatePciToDma(Addr busAddr);
|
||||
|
||||
Addr calcConfigAddr(int bus, int dev, int func);
|
||||
|
||||
virtual Tick read(Packet *pkt);
|
||||
virtual Tick write(Packet *pkt);
|
||||
|
||||
|
||||
116
src/mem/bus.cc
116
src/mem/bus.cc
@@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "base/misc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "mem/bus.hh"
|
||||
#include "sim/builder.hh"
|
||||
@@ -40,6 +41,14 @@
|
||||
Port *
|
||||
Bus::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "default")
|
||||
if (defaultPort == NULL) {
|
||||
defaultPort = new BusPort(csprintf("%s-default",name()), this,
|
||||
defaultId);
|
||||
return defaultPort;
|
||||
} else
|
||||
fatal("Default port already set\n");
|
||||
|
||||
// if_name ignored? forced to be empty?
|
||||
int id = interfaces.size();
|
||||
BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
|
||||
@@ -47,11 +56,12 @@ Bus::getPort(const std::string &if_name, int idx)
|
||||
return bp;
|
||||
}
|
||||
|
||||
/** Get the ranges of anyone that we are connected to. */
|
||||
/** Get the ranges of anyone other buses that we are connected to. */
|
||||
void
|
||||
Bus::init()
|
||||
{
|
||||
std::vector<Port*>::iterator intIter;
|
||||
|
||||
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
|
||||
(*intIter)->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
@@ -110,6 +120,7 @@ Bus::findPort(Addr addr, int id)
|
||||
int dest_id = -1;
|
||||
int i = 0;
|
||||
bool found = false;
|
||||
AddrRangeIter iter;
|
||||
|
||||
while (i < portList.size() && !found)
|
||||
{
|
||||
@@ -120,8 +131,18 @@ Bus::findPort(Addr addr, int id)
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (dest_id == -1)
|
||||
|
||||
// Check if this matches the default range
|
||||
if (dest_id == -1) {
|
||||
for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
|
||||
if (*iter == addr) {
|
||||
DPRINTF(Bus, " found addr 0x%llx on default\n", addr);
|
||||
return defaultPort;
|
||||
}
|
||||
}
|
||||
panic("Unable to find destination for addr: %llx", addr);
|
||||
}
|
||||
|
||||
|
||||
// we shouldn't be sending this back to where it came from
|
||||
assert(dest_id != id);
|
||||
@@ -155,39 +176,52 @@ Bus::recvFunctional(Packet *pkt)
|
||||
void
|
||||
Bus::recvStatusChange(Port::Status status, int id)
|
||||
{
|
||||
AddrRangeList ranges;
|
||||
AddrRangeList snoops;
|
||||
int x;
|
||||
AddrRangeIter iter;
|
||||
|
||||
assert(status == Port::RangeChange &&
|
||||
"The other statuses need to be implemented.");
|
||||
|
||||
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
|
||||
|
||||
assert(id < interfaces.size() && id >= 0);
|
||||
int x;
|
||||
Port *port = interfaces[id];
|
||||
AddrRangeList ranges;
|
||||
AddrRangeList snoops;
|
||||
AddrRangeIter iter;
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
if (id == defaultId) {
|
||||
defaultRange.clear();
|
||||
defaultPort->getPeerAddressRanges(ranges, snoops);
|
||||
assert(snoops.size() == 0);
|
||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||
defaultRange.push_back(*iter);
|
||||
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for default\n",
|
||||
iter->start, iter->end);
|
||||
}
|
||||
} else {
|
||||
|
||||
// Clean out any previously existent ids
|
||||
for (portIter = portList.begin(); portIter != portList.end(); ) {
|
||||
if (portIter->portId == id)
|
||||
portIter = portList.erase(portIter);
|
||||
else
|
||||
portIter++;
|
||||
}
|
||||
assert((id < interfaces.size() && id >= 0) || id == -1);
|
||||
Port *port = interfaces[id];
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
|
||||
port->getPeerAddressRanges(ranges, snoops);
|
||||
// Clean out any previously existent ids
|
||||
for (portIter = portList.begin(); portIter != portList.end(); ) {
|
||||
if (portIter->portId == id)
|
||||
portIter = portList.erase(portIter);
|
||||
else
|
||||
portIter++;
|
||||
}
|
||||
|
||||
// not dealing with snooping yet either
|
||||
assert(snoops.size() == 0);
|
||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||
DevMap dm;
|
||||
dm.portId = id;
|
||||
dm.range = *iter;
|
||||
port->getPeerAddressRanges(ranges, snoops);
|
||||
|
||||
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
|
||||
dm.range.start, dm.range.end, id);
|
||||
portList.push_back(dm);
|
||||
// not dealing with snooping yet either
|
||||
assert(snoops.size() == 0);
|
||||
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
|
||||
DevMap dm;
|
||||
dm.portId = id;
|
||||
dm.range = *iter;
|
||||
|
||||
DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n",
|
||||
dm.range.start, dm.range.end, id);
|
||||
portList.push_back(dm);
|
||||
}
|
||||
}
|
||||
DPRINTF(MMU, "port list has %d entries\n", portList.size());
|
||||
|
||||
@@ -196,19 +230,47 @@ Bus::recvStatusChange(Port::Status status, int id)
|
||||
for (x = 0; x < interfaces.size(); x++)
|
||||
if (x != id)
|
||||
interfaces[x]->sendStatusChange(Port::RangeChange);
|
||||
|
||||
if (id != defaultId && defaultPort)
|
||||
defaultPort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
void
|
||||
Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
|
||||
{
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
AddrRangeIter dflt_iter;
|
||||
bool subset;
|
||||
|
||||
resp.clear();
|
||||
snoop.clear();
|
||||
|
||||
DPRINTF(BusAddrRanges, "received address range request, returning:\n");
|
||||
|
||||
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
|
||||
dflt_iter++) {
|
||||
resp.push_back(*dflt_iter);
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",dflt_iter->start,
|
||||
dflt_iter->end);
|
||||
}
|
||||
for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
|
||||
if (portIter->portId != id) {
|
||||
subset = false;
|
||||
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
|
||||
dflt_iter++) {
|
||||
if ((portIter->range.start < dflt_iter->start &&
|
||||
portIter->range.end >= dflt_iter->start) ||
|
||||
(portIter->range.start < dflt_iter->end &&
|
||||
portIter->range.end >= dflt_iter->end))
|
||||
fatal("Devices can not set ranges that itersect the default set\
|
||||
but are not a subset of the default set.\n");
|
||||
if (portIter->range.start >= dflt_iter->start &&
|
||||
portIter->range.end <= dflt_iter->end) {
|
||||
subset = true;
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX is a SUBSET\n",
|
||||
portIter->range.start, portIter->range.end);
|
||||
}
|
||||
}
|
||||
if (portIter->portId != id && !subset) {
|
||||
resp.push_back(portIter->range);
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",
|
||||
portIter->range.start, portIter->range.end);
|
||||
|
||||
@@ -51,19 +51,22 @@ class Bus : public MemObject
|
||||
/** a globally unique id for this bus. */
|
||||
int busId;
|
||||
|
||||
static const int defaultId = -1;
|
||||
|
||||
struct DevMap {
|
||||
int portId;
|
||||
Range<Addr> range;
|
||||
};
|
||||
std::vector<DevMap> portList;
|
||||
AddrRangeList defaultRange;
|
||||
|
||||
|
||||
/** Function called by the port when the bus is recieving a Timing
|
||||
transaction.*/
|
||||
transaction.*/
|
||||
bool recvTiming(Packet *pkt);
|
||||
|
||||
/** Function called by the port when the bus is recieving a Atomic
|
||||
transaction.*/
|
||||
transaction.*/
|
||||
Tick recvAtomic(Packet *pkt);
|
||||
|
||||
/** Function called by the port when the bus is recieving a Functional
|
||||
@@ -159,6 +162,9 @@ class Bus : public MemObject
|
||||
* original send failed for whatever reason.*/
|
||||
std::list<Port*> retryList;
|
||||
|
||||
/** Port that handles requests that don't match any of the interfaces.*/
|
||||
Port *defaultPort;
|
||||
|
||||
public:
|
||||
|
||||
/** A function used to return the port associated with this bus object. */
|
||||
@@ -167,7 +173,7 @@ class Bus : public MemObject
|
||||
virtual void init();
|
||||
|
||||
Bus(const std::string &n, int bus_id)
|
||||
: MemObject(n), busId(bus_id) {}
|
||||
: MemObject(n), busId(bus_id), defaultPort(NULL) {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
31
src/mem/cache/base_cache.cc
vendored
31
src/mem/cache/base_cache.cc
vendored
@@ -98,6 +98,37 @@ BaseCache::CachePort::clearBlocked()
|
||||
blocked = false;
|
||||
}
|
||||
|
||||
BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort)
|
||||
: Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
|
||||
{
|
||||
this->setFlags(AutoDelete);
|
||||
pkt = NULL;
|
||||
}
|
||||
|
||||
BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, Packet *_pkt)
|
||||
: Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), pkt(_pkt)
|
||||
{
|
||||
this->setFlags(AutoDelete);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::CacheEvent::process()
|
||||
{
|
||||
if (!pkt)
|
||||
{
|
||||
if (!cachePort->isCpuSide)
|
||||
pkt = cachePort->cache->getPacket();
|
||||
//Else get coherence req
|
||||
}
|
||||
cachePort->sendTiming(pkt);
|
||||
}
|
||||
|
||||
const char *
|
||||
BaseCache::CacheEvent::description()
|
||||
{
|
||||
return "timing event\n";
|
||||
}
|
||||
|
||||
Port*
|
||||
BaseCache::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
|
||||
32
src/mem/cache/base_cache.hh
vendored
32
src/mem/cache/base_cache.hh
vendored
@@ -79,9 +79,9 @@ class BaseCache : public MemObject
|
||||
{
|
||||
class CachePort : public Port
|
||||
{
|
||||
public:
|
||||
BaseCache *cache;
|
||||
|
||||
public:
|
||||
CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
|
||||
|
||||
protected:
|
||||
@@ -110,10 +110,11 @@ class BaseCache : public MemObject
|
||||
|
||||
struct CacheEvent : public Event
|
||||
{
|
||||
Packet *pkt;
|
||||
CachePort *cachePort;
|
||||
Packet *pkt;
|
||||
|
||||
CacheEvent(Packet *pkt, CachePort *cachePort);
|
||||
CacheEvent(CachePort *_cachePort);
|
||||
CacheEvent(CachePort *_cachePort, Packet *_pkt);
|
||||
void process();
|
||||
const char *description();
|
||||
};
|
||||
@@ -147,6 +148,11 @@ class BaseCache : public MemObject
|
||||
fatal("No implementation");
|
||||
}
|
||||
|
||||
virtual Packet *getPacket()
|
||||
{
|
||||
fatal("No implementation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Bit vector of the blocking reasons for the access path.
|
||||
* @sa #BlockedCause
|
||||
@@ -388,7 +394,6 @@ class BaseCache : public MemObject
|
||||
if (!isBlockedForSnoop()) {
|
||||
memSidePort->clearBlocked();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,10 +412,13 @@ class BaseCache : public MemObject
|
||||
*/
|
||||
void setMasterRequest(RequestCause cause, Tick time)
|
||||
{
|
||||
if (!doMasterRequest())
|
||||
{
|
||||
BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort);
|
||||
reqCpu->schedule(time);
|
||||
}
|
||||
uint8_t flag = 1<<cause;
|
||||
masterRequests |= flag;
|
||||
assert("Implement\n" && 0);
|
||||
// mi->pktuest(time);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,8 +470,10 @@ class BaseCache : public MemObject
|
||||
*/
|
||||
void respond(Packet *pkt, Tick time)
|
||||
{
|
||||
assert("Implement\n" && 0);
|
||||
// si->respond(pkt,time);
|
||||
pkt->makeTimingResponse();
|
||||
pkt->result = Packet::Success;
|
||||
CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
|
||||
reqCpu->schedule(time);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,8 +486,10 @@ class BaseCache : public MemObject
|
||||
if (!pkt->req->isUncacheable()) {
|
||||
missLatency[pkt->cmdToIndex()][pkt->req->getThreadNum()] += time - pkt->time;
|
||||
}
|
||||
assert("Implement\n" && 0);
|
||||
// si->respond(pkt,time);
|
||||
pkt->makeTimingResponse();
|
||||
pkt->result = Packet::Success;
|
||||
CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
|
||||
reqCpu->schedule(time);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
13
src/mem/cache/cache.hh
vendored
13
src/mem/cache/cache.hh
vendored
@@ -168,7 +168,7 @@ class Cache : public BaseCache
|
||||
* Selects a request to send on the bus.
|
||||
* @return The memory request to service.
|
||||
*/
|
||||
Packet * getPacket();
|
||||
virtual Packet * getPacket();
|
||||
|
||||
/**
|
||||
* Was the request was sent successfully?
|
||||
@@ -241,17 +241,6 @@ class Cache : public BaseCache
|
||||
return missQueue->getMisses();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a response to the slave interface.
|
||||
* @param req The request being responded to.
|
||||
* @param time The time the response is ready.
|
||||
*/
|
||||
void respond(Packet * &pkt, Tick time)
|
||||
{
|
||||
//si->respond(pkt,time);
|
||||
cpuSidePort->sendAtomic(pkt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the access specified in the request and return the estimated
|
||||
* time of completion. This function can either update the hierarchy state
|
||||
|
||||
@@ -213,14 +213,14 @@ atexit.register(cc_main.doExitCleanup)
|
||||
# matter since most scripts will probably 'from m5.objects import *'.
|
||||
import objects
|
||||
|
||||
def doQuiesce(root):
|
||||
quiesce = cc_main.createCountedQuiesce()
|
||||
unready_objects = root.startQuiesce(quiesce, True)
|
||||
# If we've got some objects that can't quiesce immediately, then simulate
|
||||
def doDrain(root):
|
||||
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:
|
||||
quiesce.setCount(unready_objects)
|
||||
drain_event.setCount(unready_objects)
|
||||
simulate()
|
||||
cc_main.cleanupCountedQuiesce(quiesce)
|
||||
cc_main.cleanupCountedDrain(drain_event)
|
||||
|
||||
def resume(root):
|
||||
root.resume()
|
||||
@@ -228,7 +228,7 @@ def resume(root):
|
||||
def checkpoint(root):
|
||||
if not isinstance(root, objects.Root):
|
||||
raise TypeError, "Object is not a root object. Checkpoint must be called on a root object."
|
||||
doQuiesce(root)
|
||||
doDrain(root)
|
||||
print "Writing checkpoint"
|
||||
cc_main.serializeAll()
|
||||
resume(root)
|
||||
@@ -241,7 +241,7 @@ def changeToAtomic(system):
|
||||
if not isinstance(system, objects.Root) and not isinstance(system, System):
|
||||
raise TypeError, "Object is not a root or system object. Checkpoint must be "
|
||||
"called on a root object."
|
||||
doQuiesce(system)
|
||||
doDrain(system)
|
||||
print "Changing memory mode to atomic"
|
||||
system.changeTiming(cc_main.SimObject.Atomic)
|
||||
resume(system)
|
||||
@@ -250,7 +250,7 @@ def changeToTiming(system):
|
||||
if not isinstance(system, objects.Root) and not isinstance(system, System):
|
||||
raise TypeError, "Object is not a root or system object. Checkpoint must be "
|
||||
"called on a root object."
|
||||
doQuiesce(system)
|
||||
doDrain(system)
|
||||
print "Changing memory mode to timing"
|
||||
system.changeTiming(cc_main.SimObject.Timing)
|
||||
resume(system)
|
||||
@@ -271,16 +271,16 @@ def switchCpus(cpuList):
|
||||
if not isinstance(cpu, objects.BaseCPU):
|
||||
raise TypeError, "%s is not of type BaseCPU", cpu
|
||||
|
||||
# Quiesce all of the individual CPUs
|
||||
quiesce = cc_main.createCountedQuiesce()
|
||||
# Drain all of the individual CPUs
|
||||
drain_event = cc_main.createCountedDrain()
|
||||
unready_cpus = 0
|
||||
for old_cpu in old_cpus:
|
||||
unready_cpus += old_cpu.startQuiesce(quiesce, False)
|
||||
# If we've got some objects that can't quiesce immediately, then simulate
|
||||
unready_cpus += old_cpu.startDrain(drain_event, False)
|
||||
# If we've got some objects that can't drain immediately, then simulate
|
||||
if unready_cpus > 0:
|
||||
quiesce.setCount(unready_cpus)
|
||||
drain_event.setCount(unready_cpus)
|
||||
simulate()
|
||||
cc_main.cleanupCountedQuiesce(quiesce)
|
||||
cc_main.cleanupCountedDrain(drain_event)
|
||||
# Now all of the CPUs are ready to be switched out
|
||||
for old_cpu in old_cpus:
|
||||
old_cpu._ccObject.switchOut()
|
||||
|
||||
@@ -543,15 +543,15 @@ class SimObject(object):
|
||||
for child in self._children.itervalues():
|
||||
child.connectPorts()
|
||||
|
||||
def startQuiesce(self, quiesce_event, recursive):
|
||||
def startDrain(self, drain_event, recursive):
|
||||
count = 0
|
||||
# ParamContexts don't serialize
|
||||
if isinstance(self, SimObject) and not isinstance(self, ParamContext):
|
||||
if self._ccObject.quiesce(quiesce_event):
|
||||
if not self._ccObject.drain(drain_event):
|
||||
count = 1
|
||||
if recursive:
|
||||
for child in self._children.itervalues():
|
||||
count += child.startQuiesce(quiesce_event, True)
|
||||
count += child.startDrain(drain_event, True)
|
||||
return count
|
||||
|
||||
def resume(self):
|
||||
|
||||
@@ -4,4 +4,5 @@ from MemObject import MemObject
|
||||
class Bus(MemObject):
|
||||
type = 'Bus'
|
||||
port = VectorPort("vector port for connecting devices")
|
||||
default = Port("Default port for requests that aren't handeled by a device.")
|
||||
bus_id = Param.Int(0, "blah")
|
||||
|
||||
@@ -37,12 +37,10 @@ class DerivO3CPU(BaseCPU):
|
||||
"Issue/Execute/Writeback delay")
|
||||
issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal "
|
||||
"to the IEW stage)")
|
||||
dispatchWidth = Param.Unsigned("Dispatch width")
|
||||
issueWidth = Param.Unsigned("Issue width")
|
||||
executeWidth = Param.Unsigned("Execute width")
|
||||
executeIntWidth = Param.Unsigned("Integer execute width")
|
||||
executeFloatWidth = Param.Unsigned("Floating point execute width")
|
||||
executeBranchWidth = Param.Unsigned("Branch execute width")
|
||||
executeMemoryWidth = Param.Unsigned("Memory execute width")
|
||||
wbWidth = Param.Unsigned("Writeback width")
|
||||
wbDepth = Param.Unsigned("Writeback depth")
|
||||
fuPool = Param.FUPool(NULL, "Functional Unit pool")
|
||||
|
||||
iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit "
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from m5.config import *
|
||||
from Device import BasicPioDevice, DmaDevice
|
||||
from Device import BasicPioDevice, DmaDevice, PioDevice
|
||||
|
||||
class PciConfigData(SimObject):
|
||||
type = 'PciConfigData'
|
||||
@@ -38,18 +38,22 @@ class PciConfigData(SimObject):
|
||||
MaximumLatency = Param.UInt8(0x00, "Maximum Latency")
|
||||
MinimumGrant = Param.UInt8(0x00, "Minimum Grant")
|
||||
|
||||
class PciConfigAll(BasicPioDevice):
|
||||
class PciConfigAll(PioDevice):
|
||||
type = 'PciConfigAll'
|
||||
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
|
||||
bus = Param.UInt8(0x00, "PCI bus to act as config space for")
|
||||
size = Param.MemorySize32('16MB', "Size of config space")
|
||||
|
||||
|
||||
class PciDevice(DmaDevice):
|
||||
type = 'PciDevice'
|
||||
abstract = True
|
||||
config = Port("PCI configuration space port")
|
||||
pci_bus = Param.Int("PCI bus")
|
||||
pci_dev = Param.Int("PCI device number")
|
||||
pci_func = Param.Int("PCI function code")
|
||||
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
|
||||
configdata = Param.PciConfigData(Parent.any, "PCI Config data")
|
||||
configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
|
||||
|
||||
class PciFake(PciDevice):
|
||||
type = 'PciFake'
|
||||
|
||||
@@ -523,19 +523,19 @@ simulate(Tick num_cycles = -1)
|
||||
}
|
||||
|
||||
Event *
|
||||
createCountedQuiesce()
|
||||
createCountedDrain()
|
||||
{
|
||||
return new CountedQuiesceEvent();
|
||||
return new CountedDrainEvent();
|
||||
}
|
||||
|
||||
void
|
||||
cleanupCountedQuiesce(Event *counted_quiesce)
|
||||
cleanupCountedDrain(Event *counted_drain)
|
||||
{
|
||||
CountedQuiesceEvent *event =
|
||||
dynamic_cast<CountedQuiesceEvent *>(counted_quiesce);
|
||||
CountedDrainEvent *event =
|
||||
dynamic_cast<CountedDrainEvent *>(counted_drain);
|
||||
if (event == NULL) {
|
||||
fatal("Called cleanupCountedQuiesce() on an event that was not "
|
||||
"a CountedQuiesceEvent.");
|
||||
fatal("Called cleanupCountedDrain() on an event that was not "
|
||||
"a CountedDrainEvent.");
|
||||
}
|
||||
assert(event->getCount() == 0);
|
||||
delete event;
|
||||
|
||||
@@ -52,8 +52,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern Sampler *SampCPU;
|
||||
|
||||
using namespace Stats;
|
||||
using namespace TheISA;
|
||||
|
||||
@@ -209,6 +207,7 @@ namespace AlphaPseudo
|
||||
{
|
||||
if (!doCheckpointInsts)
|
||||
return;
|
||||
exitSimLoop("checkpoint");
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@@ -280,7 +279,6 @@ namespace AlphaPseudo
|
||||
|
||||
void switchcpu(ThreadContext *tc)
|
||||
{
|
||||
if (SampCPU)
|
||||
SampCPU->switchCPUs();
|
||||
exitSimLoop("switchcpu");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,10 @@ exitSimLoop(const std::string &message, int exit_code)
|
||||
}
|
||||
|
||||
void
|
||||
CountedQuiesceEvent::process()
|
||||
CountedDrainEvent::process()
|
||||
{
|
||||
if (--count == 0) {
|
||||
exitSimLoop("Finished quiesce");
|
||||
exitSimLoop("Finished drain");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,13 @@ class SimLoopExitEvent : public Event
|
||||
virtual const char *description();
|
||||
};
|
||||
|
||||
class CountedQuiesceEvent : public SimLoopExitEvent
|
||||
class CountedDrainEvent : public SimLoopExitEvent
|
||||
{
|
||||
private:
|
||||
// Count down to quiescing
|
||||
// Count of how many objects have not yet drained
|
||||
int count;
|
||||
public:
|
||||
CountedQuiesceEvent()
|
||||
CountedDrainEvent()
|
||||
: count(0)
|
||||
{ }
|
||||
void process();
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "base/misc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "base/stats/events.hh"
|
||||
#include "base/serializer.hh"
|
||||
#include "sim/host.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
@@ -271,22 +270,22 @@ SimObject::recordEvent(const std::string &stat)
|
||||
}
|
||||
|
||||
bool
|
||||
SimObject::quiesce(Event *quiesce_event)
|
||||
SimObject::drain(Event *drain_event)
|
||||
{
|
||||
if (state != QuiescedAtomic && state != Atomic) {
|
||||
panic("Must implement your own quiesce function if it is to be used "
|
||||
if (state != DrainedAtomic && state != Atomic) {
|
||||
panic("Must implement your own drain function if it is to be used "
|
||||
"in timing mode!");
|
||||
}
|
||||
state = QuiescedAtomic;
|
||||
return false;
|
||||
state = DrainedAtomic;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SimObject::resume()
|
||||
{
|
||||
if (state == QuiescedAtomic) {
|
||||
if (state == DrainedAtomic) {
|
||||
state = Atomic;
|
||||
} else if (state == QuiescedTiming) {
|
||||
} else if (state == DrainedTiming) {
|
||||
state = Timing;
|
||||
}
|
||||
}
|
||||
@@ -295,10 +294,10 @@ void
|
||||
SimObject::setMemoryMode(State new_mode)
|
||||
{
|
||||
assert(new_mode == Timing || new_mode == Atomic);
|
||||
if (state == QuiescedAtomic && new_mode == Timing) {
|
||||
state = QuiescedTiming;
|
||||
} else if (state == QuiescedTiming && new_mode == Atomic) {
|
||||
state = QuiescedAtomic;
|
||||
if (state == DrainedAtomic && new_mode == Timing) {
|
||||
state = DrainedTiming;
|
||||
} else if (state == DrainedTiming && new_mode == Atomic) {
|
||||
state = DrainedAtomic;
|
||||
} else {
|
||||
state = new_mode;
|
||||
}
|
||||
|
||||
@@ -62,9 +62,9 @@ class SimObject : public Serializable, protected StartupCallback
|
||||
enum State {
|
||||
Atomic,
|
||||
Timing,
|
||||
Quiescing,
|
||||
QuiescedAtomic,
|
||||
QuiescedTiming
|
||||
Draining,
|
||||
DrainedAtomic,
|
||||
DrainedTiming
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -116,8 +116,8 @@ class SimObject : public Serializable, protected StartupCallback
|
||||
|
||||
// Methods to drain objects in order to take checkpoints
|
||||
// Or switch from timing -> atomic memory model
|
||||
// Quiesce returns true if the SimObject cannot quiesce immediately.
|
||||
virtual bool quiesce(Event *quiesce_event);
|
||||
// Drain returns false if the SimObject cannot drain immediately.
|
||||
virtual bool drain(Event *drain_event);
|
||||
virtual void resume();
|
||||
virtual void setMemoryMode(State new_mode);
|
||||
virtual void switchOut();
|
||||
|
||||
Reference in New Issue
Block a user