Merge ktlim@zizzer:/bk/newmem

into  zamp.eecs.umich.edu:/z/ktlim2/clean/newmem

--HG--
extra : convert_revision : 7c7fc8a2f9579d443786e86dbcf906b355de69fc
This commit is contained in:
Kevin Lim
2006-07-06 16:51:50 -04:00
70 changed files with 1092 additions and 853 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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']
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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' })

View File

@@ -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;

View File

@@ -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__

View File

@@ -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__

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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();

View File

@@ -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
View 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__

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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]++;

View File

@@ -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;

View File

@@ -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;
//

View File

@@ -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();

View File

@@ -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++) {

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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();

View File

@@ -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 &section)
}
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

View File

@@ -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 &section);
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__

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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);

View File

@@ -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 &section)
{
/*
* 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);
}

View File

@@ -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 &section);
};
#endif // __PCICONFIGALL_HH__

View File

@@ -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

View File

@@ -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 &section);
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__

View File

@@ -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

View File

@@ -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)

View File

@@ -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__

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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.

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {}
};

View File

@@ -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)
{

View File

@@ -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);
}
/**

View File

@@ -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

View File

@@ -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()

View File

@@ -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):

View File

@@ -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")

View File

@@ -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 "

View File

@@ -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'

View File

@@ -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;

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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();