Merge zizzer:/bk/newmem

into  zeep.pool:/z/saidi/work/m5.newmem.head

--HG--
extra : convert_revision : 8c747208d72ffbb0160a2ad4a75383420debdf83
This commit is contained in:
Ali Saidi 2006-07-19 17:59:04 -04:00
commit 15e5ce96c7
148 changed files with 6416 additions and 1921 deletions

View file

@ -494,10 +494,10 @@ for build_path in build_paths:
exports = 'env')
# Set up the regression tests for each build.
# for e in envList:
# SConscript('m5-test/SConscript',
# build_dir = os.path.join(build_dir, 'test', e.Label),
# exports = { 'env' : e }, duplicate = False)
for e in envList:
SConscript('tests/SConscript',
build_dir = os.path.join(build_path, 'test', e.Label),
exports = { 'env' : e }, duplicate = False)
Help(help_text)

View file

@ -2,41 +2,39 @@ import os, sys
from os.path import isdir, join as joinpath
from os import environ as env
systemdir = None
bindir = None
diskdir = None
scriptdir = None
def disk(file):
system()
return joinpath(disk.dir, file)
def load_defaults():
global systemdir, bindir, diskdir, scriptdir
if not systemdir:
def binary(file):
system()
return joinpath(binary.dir, file)
def script(file):
system()
return joinpath(script.dir, file)
def system():
if not system.dir:
try:
path = env['M5_PATH'].split(':')
except KeyError:
path = [ '/dist/m5/system', '/n/poolfs/z/dist/m5/system' ]
for systemdir in path:
if os.path.isdir(systemdir):
for system.dir in path:
if os.path.isdir(system.dir):
break
else:
raise ImportError, "Can't find a path to system files."
if not bindir:
bindir = joinpath(systemdir, 'binaries')
if not diskdir:
diskdir = joinpath(systemdir, 'disks')
if not scriptdir:
scriptdir = joinpath(systemdir, 'boot')
def disk(file):
load_defaults()
return joinpath(diskdir, file)
def binary(file):
load_defaults()
return joinpath(bindir, file)
def script(file):
load_defaults()
return joinpath(scriptdir, file)
if not binary.dir:
binary.dir = joinpath(system.dir, 'binaries')
if not disk.dir:
disk.dir = joinpath(system.dir, 'disks')
if not script.dir:
script.dir = joinpath(system.dir, 'boot')
system.dir = None
binary.dir = None
disk.dir = None
script.dir = None

View file

@ -1,14 +1,19 @@
import optparse, os, sys
import m5
from m5.objects import *
import os
from SysPaths import *
from FullO3Config import *
parser = optparse.OptionParser(option_list=m5.standardOptions)
parser = optparse.OptionParser()
parser.add_option("-d", "--detailed", action="store_true")
parser.add_option("-t", "--timing", action="store_true")
parser.add_option("-m", "--maxtick", type="int")
parser.add_option("--dual", help="Run full system using dual systems",
action="store_true")
(options, args) = parser.parse_args()
m5.setStandardOptions(options)
if args:
print "Error: script doesn't take any positional arguments"
@ -17,192 +22,69 @@ if args:
# Base for tests is directory containing this file.
test_base = os.path.dirname(__file__)
script.dir = '/z/saidi/work/m5.newmem/configs/boot'
linux_image = env.get('LINUX_IMAGE', disk('linux-latest.img'))
class IdeControllerPciData(PciConfigData):
VendorID = 0x8086
DeviceID = 0x7111
Command = 0x0
Status = 0x280
Revision = 0x0
ClassCode = 0x01
SubClassCode = 0x01
ProgIF = 0x85
BAR0 = 0x00000001
BAR1 = 0x00000001
BAR2 = 0x00000001
BAR3 = 0x00000001
BAR4 = 0x00000001
BAR5 = 0x00000001
InterruptLine = 0x1f
InterruptPin = 0x01
BAR0Size = '8B'
BAR1Size = '4B'
BAR2Size = '8B'
BAR3Size = '4B'
BAR4Size = '16B'
class CowIdeDisk(IdeDisk):
image = CowDiskImage(child=RawDiskImage(read_only=True),
read_only=False)
class SinicPciData(PciConfigData):
VendorID = 0x1291
DeviceID = 0x1293
Status = 0x0290
SubClassCode = 0x00
ClassCode = 0x02
ProgIF = 0x00
BAR0 = 0x00000000
BAR1 = 0x00000000
BAR2 = 0x00000000
BAR3 = 0x00000000
BAR4 = 0x00000000
BAR5 = 0x00000000
MaximumLatency = 0x34
MinimumGrant = 0xb0
InterruptLine = 0x1e
InterruptPin = 0x01
BAR0Size = '64kB'
class NSGigEPciData(PciConfigData):
VendorID = 0x100B
DeviceID = 0x0022
Status = 0x0290
SubClassCode = 0x00
ClassCode = 0x02
ProgIF = 0x00
BAR0 = 0x00000001
BAR1 = 0x00000000
BAR2 = 0x00000000
BAR3 = 0x00000000
BAR4 = 0x00000000
BAR5 = 0x00000000
MaximumLatency = 0x34
MinimumGrant = 0xb0
InterruptLine = 0x1e
InterruptPin = 0x01
BAR0Size = '256B'
BAR1Size = '4kB'
class LinuxRootDisk(IdeDisk):
raw_image = RawDiskImage(image_file=linux_image, read_only=True)
image = CowDiskImage(child=Parent.raw_image, read_only=False)
class LinuxSwapDisk(IdeDisk):
raw_image = RawDiskImage(image_file = disk('linux-bigswap2.img'),
read_only=True)
image = CowDiskImage(child = Parent.raw_image, read_only=False)
class SpecwebFilesetDisk(IdeDisk):
raw_image = RawDiskImage(image_file = disk('specweb-fileset.img'),
read_only=True)
image = CowDiskImage(child = Parent.raw_image, read_only=False)
def childImage(self, ci):
self.image.child.image_file = ci
class BaseTsunami(Tsunami):
cchip = TsunamiCChip(pio_addr=0x801a0000000)
pchip = TsunamiPChip(pio_addr=0x80180000000)
pciconfig = PciConfigAll(pio_addr=0x801fe000000)
fake_sm_chip = IsaFake(pio_addr=0x801fc000370)
fake_uart1 = IsaFake(pio_addr=0x801fc0002f8)
fake_uart2 = IsaFake(pio_addr=0x801fc0003e8)
fake_uart3 = IsaFake(pio_addr=0x801fc0002e8)
fake_uart4 = IsaFake(pio_addr=0x801fc0003f0)
fake_ppc = IsaFake(pio_addr=0x801fc0003bc)
fake_OROM = IsaFake(pio_addr=0x800000a0000, pio_size=0x60000)
fake_pnp_addr = IsaFake(pio_addr=0x801fc000279)
fake_pnp_write = IsaFake(pio_addr=0x801fc000a79)
fake_pnp_read0 = IsaFake(pio_addr=0x801fc000203)
fake_pnp_read1 = IsaFake(pio_addr=0x801fc000243)
fake_pnp_read2 = IsaFake(pio_addr=0x801fc000283)
fake_pnp_read3 = IsaFake(pio_addr=0x801fc0002c3)
fake_pnp_read4 = IsaFake(pio_addr=0x801fc000303)
fake_pnp_read5 = IsaFake(pio_addr=0x801fc000343)
fake_pnp_read6 = IsaFake(pio_addr=0x801fc000383)
fake_pnp_read7 = IsaFake(pio_addr=0x801fc0003c3)
fake_ata0 = IsaFake(pio_addr=0x801fc0001f0)
fake_ata1 = IsaFake(pio_addr=0x801fc000170)
fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer')
io = TsunamiIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0x801fc0003f8)
ethernet = NSGigE(configdata=NSGigEPciData(),
pci_bus=0, pci_dev=1, pci_func=0)
etherint = NSGigEInt(device=Parent.ethernet)
console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk)
class LinuxTsunami(BaseTsunami):
disk0 = LinuxRootDisk(driveID='master')
disk1 = SpecwebFilesetDisk(driveID='slave')
disk2 = LinuxSwapDisk(driveID='master')
ide = IdeController(disks=[Parent.disk0, Parent.disk1, Parent.disk2],
configdata=IdeControllerPciData(),
ide = IdeController(disks=[Parent.disk0, Parent.disk2],
pci_func=0, pci_dev=0, pci_bus=0)
class MyLinuxAlphaSystem(LinuxAlphaSystem):
magicbus = Bus(bus_id=0)
magicbus2 = Bus(bus_id=1)
iobus = Bus(bus_id=0)
membus = Bus(bus_id=1)
bridge = Bridge()
physmem = PhysicalMemory(range = AddrRange('128MB'))
bridge.side_a = magicbus.port
bridge.side_b = magicbus2.port
physmem.port = magicbus2.port
tsunami = LinuxTsunami()
tsunami.cchip.pio = magicbus.port
tsunami.pchip.pio = magicbus.port
tsunami.pciconfig.pio = magicbus.port
tsunami.fake_sm_chip.pio = magicbus.port
tsunami.ethernet.pio = magicbus.port
tsunami.ethernet.dma = 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.fake_ppc.pio = magicbus.port
tsunami.fake_OROM.pio = magicbus.port
tsunami.fake_pnp_addr.pio = magicbus.port
tsunami.fake_pnp_write.pio = magicbus.port
tsunami.fake_pnp_read0.pio = magicbus.port
tsunami.fake_pnp_read1.pio = magicbus.port
tsunami.fake_pnp_read2.pio = magicbus.port
tsunami.fake_pnp_read3.pio = magicbus.port
tsunami.fake_pnp_read4.pio = magicbus.port
tsunami.fake_pnp_read5.pio = magicbus.port
tsunami.fake_pnp_read6.pio = magicbus.port
tsunami.fake_pnp_read7.pio = magicbus.port
tsunami.fake_ata0.pio = magicbus.port
tsunami.fake_ata1.pio = magicbus.port
tsunami.fb.pio = magicbus.port
tsunami.io.pio = magicbus.port
tsunami.uart.pio = magicbus.port
tsunami.console.pio = magicbus.port
raw_image = RawDiskImage(image_file=disk('linux-latest.img'),
read_only=True)
simple_disk = SimpleDisk(disk=Parent.raw_image)
bridge.side_a = iobus.port
bridge.side_b = membus.port
physmem.port = membus.port
disk0 = CowIdeDisk(driveID='master')
disk2 = CowIdeDisk(driveID='master')
disk0.childImage(linux_image)
disk2.childImage(disk('linux-bigswap2.img'))
tsunami = BaseTsunami()
tsunami.attachIO(iobus)
tsunami.ide.pio = iobus.port
tsunami.ide.dma = iobus.port
tsunami.ide.config = iobus.port
tsunami.ethernet.pio = iobus.port
tsunami.ethernet.dma = iobus.port
tsunami.ethernet.config = iobus.port
simple_disk = SimpleDisk(disk=RawDiskImage(image_file = linux_image,
read_only = True))
intrctrl = IntrControl()
if options.timing:
if options.detailed:
cpu = DetailedO3CPU()
elif options.timing:
cpu = TimingSimpleCPU()
mem_mode = 'timing'
else:
cpu = AtomicSimpleCPU()
cpu.mem = magicbus2
cpu.mem = membus
cpu.icache_port = membus.port
cpu.dcache_port = membus.port
cpu.itb = AlphaITB()
cpu.dtb = AlphaDTB()
cpu.clock = '2GHz'
sim_console = SimConsole(listener=ConsoleListener(port=3456))
kernel = binary('vmlinux')
pal = binary('ts_osfpal')
console = binary('console')
boot_osflags = 'root=/dev/hda1 console=ttyS0'
# readfile = os.path.join(test_base, 'halt.sh')
class TsunamiRoot(System):
class TsunamiRoot(Root):
pass
def DualRoot(clientSystem, serverSystem):
self = Root()
self.client = clientSystem
@ -212,15 +94,29 @@ def DualRoot(clientSystem, serverSystem):
self.etherlink = EtherLink(int1 = Parent.client.tsunami.etherint[0],
int2 = Parent.server.tsunami.etherint[0],
dump = Parent.etherdump)
self.clock = '5GHz'
self.clock = '1THz'
return self
root = DualRoot(
MyLinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
MyLinuxAlphaSystem(readfile=script('netperf-server.rcS')))
if options.dual:
root = DualRoot(
MyLinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')),
MyLinuxAlphaSystem(readfile=script('netperf-server.rcS')))
else:
root = TsunamiRoot(clock = '2GHz', system = MyLinuxAlphaSystem())
m5.instantiate(root)
exit_event = m5.simulate()
#exit_event = m5.simulate(2600000000000)
#if exit_event.getCause() != "user interrupt received":
# m5.checkpoint(root, 'cpt')
# exit_event = m5.simulate(300000000000)
# if exit_event.getCause() != "user interrupt received":
# m5.checkpoint(root, 'cptA')
if options.maxtick:
exit_event = m5.simulate(options.maxtick)
else:
exit_event = m5.simulate()
print 'Exiting @ cycle', m5.curTick(), 'because', exit_event.getCause()

View file

@ -1,38 +1,14 @@
# Simple test script
#
# Alpha: "m5 test.py"
# MIPS: "m5 test.py -a Mips -c hello_mips"
# MIPS: "m5 test.py -c hello_mips"
import os, optparse, sys
import m5
import os, optparse, sys
m5.AddToPath('../common')
from SEConfig import *
from m5.objects import *
from FullO3Config import *
# parse command-line arguments
parser = optparse.OptionParser(option_list=m5.standardOptions)
parser.add_option("-c", "--cmd", default="hello",
help="The binary to run in syscall emulation mode.")
parser.add_option("-o", "--options", default="",
help="The options to pass to the binary, use \" \" around the entire\
string.")
parser.add_option("-i", "--input", default="",
help="A file of input to give to the binary.")
parser.add_option("-t", "--timing", action="store_true",
help="Use simple timing CPU.")
parser.add_option("-d", "--detailed", action="store_true",
help="Use detailed CPU.")
parser.add_option("-m", "--maxtick", type="int",
help="Set the maximum number of ticks to run for")
(options, args) = parser.parse_args()
m5.setStandardOptions(options)
if args:
print "Error: script doesn't take any positional arguments"
sys.exit(1)
# build configuration
this_dir = os.path.dirname(__file__)
process = LiveProcess()
@ -41,16 +17,7 @@ process.cmd = options.cmd + " " + options.options
if options.input != "":
process.input = options.input
magicbus = Bus()
mem = PhysicalMemory()
if options.timing and options.detailed:
print "Error: you may only specify one cpu model";
sys.exit(1)
if options.timing:
cpu = TimingSimpleCPU()
elif options.detailed:
if options.detailed:
#check for SMT workload
workloads = options.cmd.split(';')
if len(workloads) > 1:
@ -70,15 +37,10 @@ elif options.detailed:
process += [smt_process, ]
smt_idx += 1
cpu = DetailedO3CPU()
else:
cpu = AtomicSimpleCPU()
cpu.workload = process
cpu.mem = magicbus
root = MySESystem(process)
system = System(physmem = mem, cpu = cpu)
mem.port = magicbus.port
root = Root(system = system)
if options.timing or options.detailed:
root.system.mem_mode = 'timing'
# instantiate configuration
m5.instantiate(root)

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
@ -299,7 +298,7 @@ alpha_eio_sources = Split('''
encumbered/eio/eio.cc
''')
if env['TARGET_ISA'] == 'ALPHA_ISA':
if env['TARGET_ISA'] == 'alpha':
syscall_emulation_sources += alpha_eio_sources
memtest_sources = Split('''

View file

@ -140,8 +140,15 @@ def isa_desc_emitter(target, source, env):
# Pieces are in place, so create the builder.
python = sys.executable # use same Python binary used to run scons
isa_desc_builder = Builder(action=python + ' $SOURCES $TARGET.dir $CPU_MODELS',
emitter = isa_desc_emitter)
# Also include the CheckerCPU as one of the models if it is being
# enabled via command line.
if env['USE_CHECKER']:
isa_desc_builder = Builder(action=python + ' $SOURCES $TARGET.dir $CPU_MODELS CheckerCPU',
emitter = isa_desc_emitter)
else:
isa_desc_builder = Builder(action=python + ' $SOURCES $TARGET.dir $CPU_MODELS',
emitter = isa_desc_emitter)
env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })

View file

@ -97,6 +97,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
Param<Tick> boot_cpu_frequency;
SimObjectParam<PhysicalMemory *> physmem;
SimpleEnumParam<System::MemoryMode> mem_mode;
Param<string> kernel;
Param<string> console;
@ -115,6 +116,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
System::MemoryModeStrings),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(console, "file that contains the console code"),
INIT_PARAM(pal, "file that contains palcode"),
@ -133,6 +136,7 @@ CREATE_SIM_OBJECT(FreebsdAlphaSystem)
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->mem_mode = mem_mode;
p->kernel_path = kernel;
p->console_path = console;
p->palcode = pal;

View file

@ -191,6 +191,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
Param<Tick> boot_cpu_frequency;
SimObjectParam<PhysicalMemory *> physmem;
SimpleEnumParam<System::MemoryMode> mem_mode;
Param<string> kernel;
Param<string> console;
@ -209,6 +210,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
System::MemoryModeStrings),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(console, "file that contains the console code"),
INIT_PARAM(pal, "file that contains palcode"),
@ -227,6 +230,7 @@ CREATE_SIM_OBJECT(LinuxAlphaSystem)
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->mem_mode = mem_mode;
p->kernel_path = kernel;
p->console_path = console;
p->palcode = pal;

View file

@ -112,6 +112,10 @@ namespace AlphaISA
lock_flag = 0;
lock_addr = 0;
}
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
#if FULL_SYSTEM
protected:
typedef uint64_t InternalProcReg;

View file

@ -221,6 +221,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem)
Param<Tick> boot_cpu_frequency;
SimObjectParam<PhysicalMemory *> physmem;
SimpleEnumParam<System::MemoryMode> mem_mode;
Param<std::string> kernel;
Param<std::string> console;
@ -239,6 +240,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
System::MemoryModeStrings),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(console, "file that contains the console code"),
INIT_PARAM(pal, "file that contains palcode"),
@ -257,6 +260,7 @@ CREATE_SIM_OBJECT(AlphaSystem)
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->mem_mode = mem_mode;
p->kernel_path = kernel;
p->console_path = console;
p->palcode = pal;

View file

@ -95,6 +95,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
Param<Tick> boot_cpu_frequency;
SimObjectParam<PhysicalMemory *> physmem;
SimpleEnumParam<System::MemoryMode> mem_mode;
Param<string> kernel;
Param<string> console;
@ -113,6 +114,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
System::MemoryModeStrings),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(console, "file that contains the console code"),
INIT_PARAM(pal, "file that contains palcode"),
@ -131,6 +134,7 @@ CREATE_SIM_OBJECT(Tru64AlphaSystem)
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->mem_mode = mem_mode;
p->kernel_path = kernel;
p->console_path = console;
p->palcode = pal;

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

@ -45,6 +45,12 @@ MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest)
panic("Copy Regs Not Implemented Yet\n");
}
void
MipsISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
{
panic("Copy Misc. Regs Not Implemented Yet\n");
}
void
MipsISA::MiscRegFile::copyMiscRegs(ThreadContext *tc)
{

View file

@ -129,7 +129,7 @@ namespace MipsISA
template <class TC>
void zeroRegisters(TC *tc);
const Addr MaxAddr = (Addr)-1;
// const Addr MaxAddr = (Addr)-1;
void copyRegs(ThreadContext *src, ThreadContext *dest);

View file

@ -41,6 +41,8 @@
using namespace std;
using namespace MipsISA;
Addr MipsLiveProcess::stack_start = 0x7FFFFFFF;
MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv, std::vector<std::string> &envp)
@ -49,10 +51,11 @@ MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile,
{
// Set up stack. On MIPS, stack starts at the top of kuseg
// user address space. MIPS stack grows down from here
stack_base = 0x7FFFFFFF;
stack_base = stack_start;
// Set pointer for next thread stack. Reserve 8M for main stack.
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
stack_start = next_thread_stack_base;
// Set up break point (Top of Heap)
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();

View file

@ -50,6 +50,9 @@ class MipsLiveProcess : public LiveProcess
std::vector<std::string> &envp);
void startup();
static Addr stack_start;
};

View file

@ -141,6 +141,7 @@ SparcSystem::unserialize(Checkpoint *cp, const std::string &section)
BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem)
SimObjectParam<PhysicalMemory *> physmem;
SimpleEnumParam<System::MemoryMode> mem_mode;
Param<std::string> kernel;
Param<std::string> reset_bin;
@ -161,6 +162,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem)
INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)",
System::MemoryModeStrings),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(reset_bin, "file that contains the reset code"),
INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"),
@ -183,6 +186,7 @@ CREATE_SIM_OBJECT(SparcSystem)
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->mem_mode = mem_mode;
p->kernel_path = kernel;
p->reset_bin = reset_bin;
p->hypervisor_bin = hypervisor_bin;

View file

@ -215,6 +215,11 @@ class TimeBuffer
{
return wire(this, 0);
}
int getSize()
{
return size;
}
};
#endif // __BASE_TIMEBUF_HH__

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

@ -71,7 +71,8 @@ virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) c
# Generate a temporary CPU list, including the CheckerCPU if
# it's enabled. This isn't used for anything else other than StaticInst
# headers.
temp_cpu_list = env['CPU_MODELS']
temp_cpu_list = env['CPU_MODELS'][:]
if env['USE_CHECKER']:
temp_cpu_list.append('CheckerCPU')
@ -113,6 +114,9 @@ CheckerSupportedCPUList = ['O3CPU', 'OzoneCPU']
#
#################################################################
# Keep a list of CPU models that support SMT
env['SMT_CPU_MODELS'] = []
sources = []
need_simple_base = False
@ -130,13 +134,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 +152,18 @@ 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')
env['SMT_CPU_MODELS'].append('O3CPU')
if 'OzoneCPU' in env['CPU_MODELS']:
need_bp_unit = True
sources += Split('''
ozone/base_dyn_inst.cc
ozone/bpred_unit.cc
@ -174,6 +178,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
@ -181,9 +193,10 @@ if env['USE_CHECKER']:
if i in env['CPU_MODELS']:
checker_supports = True
if not checker_supports:
print "Checker only supports CPU models %s, please " \
"set USE_CHECKER=False or use one of those CPU models" \
% CheckerSupportedCPUList
print "Checker only supports CPU models",
for i in CheckerSupportedCPUList:
print i,
print ", please set USE_CHECKER=False or use one of those CPU models"
Exit(1)

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"
@ -60,11 +59,11 @@ int maxThreadsPerCPU = 1;
#if FULL_SYSTEM
BaseCPU::BaseCPU(Params *p)
: SimObject(p->name), clock(p->clock), checkInterrupts(true),
: MemObject(p->name), clock(p->clock), checkInterrupts(true),
params(p), number_of_threads(p->numberOfThreads), system(p->system)
#else
BaseCPU::BaseCPU(Params *p)
: SimObject(p->name), clock(p->clock), params(p),
: MemObject(p->name), clock(p->clock), params(p),
number_of_threads(p->numberOfThreads), system(p->system)
#endif
{

View file

@ -36,17 +36,17 @@
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "cpu/sampler/sampler.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
#include "mem/mem_object.hh"
#include "arch/isa_traits.hh"
class BranchPred;
class CheckerCPU;
class ThreadContext;
class System;
class Port;
class BaseCPU : public SimObject
class BaseCPU : public MemObject
{
protected:
// CPU's clock period in terms of the number of ticks of curTime.

View file

@ -66,7 +66,6 @@ class ThreadContext;
class MemInterface;
class Checkpoint;
class Request;
class Sampler;
/**
* CheckerCPU class. Dynamically verifies instructions as they are
@ -128,6 +127,12 @@ class CheckerCPU : public BaseCPU
Port *dcachePort;
virtual Port *getPort(const std::string &name, int idx)
{
panic("Not supported on checker!");
return NULL;
}
public:
// Primary thread being run.
SimpleThread *thread;
@ -165,7 +170,7 @@ class CheckerCPU : public BaseCPU
virtual Counter totalInstructions() const
{
return numInst - startNumInst;
return 0;
}
// number of simulated loads
@ -374,7 +379,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

@ -120,7 +120,7 @@ class CheckerThreadContext : public ThreadContext
void suspend() { actualTC->suspend(); }
/// Set the status to Unallocated.
void deallocate() { actualTC->deallocate(); }
void deallocate(int delay = 0) { actualTC->deallocate(delay); }
/// Set the status to Halted.
void halt() { actualTC->halt(); }

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;
@ -99,7 +102,9 @@ Param<unsigned> renameToROBDelay;
Param<unsigned> commitWidth;
Param<unsigned> squashWidth;
Param<Tick> trapLatency;
Param<Tick> fetchTrapLatency;
Param<unsigned> backComSize;
Param<unsigned> forwardComSize;
Param<std::string> predType;
Param<unsigned> localPredictorSize;
@ -207,7 +212,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 "
@ -216,7 +224,9 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU)
INIT_PARAM(commitWidth, "Commit width"),
INIT_PARAM(squashWidth, "Squash width"),
INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6),
INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12),
INIT_PARAM(backComSize, "Time buffer size for backwards communication"),
INIT_PARAM(forwardComSize, "Time buffer size for forward communication"),
INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"),
INIT_PARAM(localPredictorSize, "Size of local predictor"),
@ -333,7 +343,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;
@ -341,7 +354,9 @@ CREATE_SIM_OBJECT(DerivO3CPU)
params->commitWidth = commitWidth;
params->squashWidth = squashWidth;
params->trapLatency = trapLatency;
params->fetchTrapLatency = fetchTrapLatency;
params->backComSize = backComSize;
params->forwardComSize = forwardComSize;
params->predType = predType;
params->localPredictorSize = localPredictorSize;

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

@ -70,18 +70,19 @@ class AlphaTC : public O3ThreadContext<Impl>
{ panic("Not supported on Alpha!"); }
// This function exits the thread context in the CPU and returns
// 1 if the CPU has no more active threads (meaning it's OK to exit);
// Used in syscall-emulation mode when a thread executes the 'exit'
// syscall.
/** This function exits the thread context in the CPU and returns
* 1 if the CPU has no more active threads (meaning it's OK to exit);
* Used in syscall-emulation mode when a thread executes the 'exit'
* syscall.
*/
virtual int exit()
{
this->cpu->deallocateContext(this->thread->readTid());
this->deallocate();
// If there are still threads executing in the system
if (this->cpu->numActiveThreads())
return 0;
return 0; // don't exit simulation
else
return 1;
return 1; // exit simulation
}
};

View file

@ -162,10 +162,6 @@ class DefaultCommit
/** Sets the pointer to the queue coming from IEW. */
void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
void setFetchStage(Fetch *fetch_stage);
Fetch *fetchStage;
/** Sets the pointer to the IEW stage. */
void setIEWStage(IEW *iew_stage);
@ -187,11 +183,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. */
bool 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();
@ -332,10 +331,6 @@ class DefaultCommit
/** Vector of all of the threads. */
std::vector<Thread *> thread;
Fault fetchFault;
int fetchTrapWait;
/** Records that commit has written to the time buffer this cycle. Used for
* the CPU to determine if it can deschedule itself if there is no activity.
*/
@ -383,8 +378,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;
@ -394,10 +389,6 @@ class DefaultCommit
*/
Tick trapLatency;
Tick fetchTrapLatency;
Tick fetchFaultTick;
/** The commit PC of each thread. Refers to the instruction that
* is currently being processed/committed.
*/

View file

@ -80,10 +80,9 @@ 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)
trapLatency(params->trapLatency)
{
_status = Active;
_nextStatus = Inactive;
@ -123,9 +122,6 @@ DefaultCommit<Impl>::DefaultCommit(Params *params)
tcSquash[i] = false;
PC[i] = nextPC[i] = 0;
}
fetchFaultTick = 0;
fetchTrapWait = 0;
}
template <class Impl>
@ -235,7 +231,6 @@ DefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
cpu->activateStage(O3CPU::CommitIdx);
trapLatency = cpu->cycles(trapLatency);
fetchTrapLatency = cpu->cycles(fetchTrapLatency);
}
template <class Impl>
@ -292,13 +287,6 @@ DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
fromIEW = iewQueue->getWire(-iewToCommitDelay);
}
template <class Impl>
void
DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage)
{
fetchStage = fetch_stage;
}
template <class Impl>
void
DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
@ -350,21 +338,36 @@ DefaultCommit<Impl>::initStage()
}
template <class Impl>
void
DefaultCommit<Impl>::switchOut()
bool
DefaultCommit<Impl>::drain()
{
switchPending = true;
drainPending = true;
// If it's already drained, return true.
if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
cpu->signalDrained();
return true;
}
return false;
}
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()
{
drainPending = false;
}
template <class Impl>
void
DefaultCommit<Impl>::takeOverFrom()
@ -557,11 +560,15 @@ 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;
}
if ((*activeThreads).size() <= 0)
return;
list<unsigned>::iterator threads = (*activeThreads).begin();
// Check if any of the threads are done squashing. Change the
@ -575,7 +582,7 @@ DefaultCommit<Impl>::tick()
commitStatus[tid] = Running;
} else {
DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
"insts this cycle.\n", tid);
" insts this cycle.\n", tid);
rob->doSquash(tid);
toIEW->commitInfo[tid].robSquashing = true;
wroteToTimeBuffer = true;
@ -989,6 +996,12 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
// Check if the instruction caused a fault. If so, trap.
Fault inst_fault = head_inst->getFault();
// DTB will sometimes need the machine instruction for when
// faults happen. So we will set it here, prior to the DTB
// possibly needing it for its fault.
thread[tid]->setInst(
static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
if (inst_fault != NoFault) {
head_inst->setCompleted();
DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
@ -1011,12 +1024,6 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
// execution doesn't generate extra squashes.
thread[tid]->inSyscall = true;
// DTB will sometimes need the machine instruction for when
// faults happen. So we will set it here, prior to the DTB
// possibly needing it for its fault.
thread[tid]->setInst(
static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
// Execute the trap. Although it's slightly unrealistic in
// terms of timing (as it doesn't wait for the full timing of
// the trap event to complete before updating state), it's

View file

@ -114,6 +114,36 @@ FullO3CPU<Impl>::ActivateThreadEvent::description()
return "FullO3CPU \"Activate Thread\" event";
}
template <class Impl>
FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
: Event(&mainEventQueue, CPU_Tick_Pri)
{
}
template <class Impl>
void
FullO3CPU<Impl>::DeallocateContextEvent::init(int thread_num,
FullO3CPU<Impl> *thread_cpu)
{
tid = thread_num;
cpu = thread_cpu;
}
template <class Impl>
void
FullO3CPU<Impl>::DeallocateContextEvent::process()
{
cpu->deactivateThread(tid);
cpu->removeThread(tid);
}
template <class Impl>
const char *
FullO3CPU<Impl>::DeallocateContextEvent::description()
{
return "FullO3CPU \"Deallocate Context\" event";
}
template <class Impl>
FullO3CPU<Impl>::FullO3CPU(Params *params)
: BaseO3CPU(params),
@ -141,15 +171,14 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
TheISA::NumMiscRegs * number_of_threads,
TheISA::ZeroReg),
// For now just have these time buffers be pretty big.
// @todo: Make these time buffer sizes parameters or derived
// from latencies
timeBuffer(5, 5),
fetchQueue(5, 5),
decodeQueue(5, 5),
renameQueue(5, 5),
iewQueue(5, 5),
activityRec(NumStages, 10, params->activity),
timeBuffer(params->backComSize, params->forwardComSize),
fetchQueue(params->backComSize, params->forwardComSize),
decodeQueue(params->backComSize, params->forwardComSize),
renameQueue(params->backComSize, params->forwardComSize),
iewQueue(params->backComSize, params->forwardComSize),
activityRec(NumStages,
params->backComSize + params->forwardComSize,
params->activity),
globalSeqNum(1),
@ -158,7 +187,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)
{
@ -214,7 +243,6 @@ FullO3CPU<Impl>::FullO3CPU(Params *params)
commit.setIEWQueue(&iewQueue);
commit.setRenameQueue(&renameQueue);
commit.setFetchStage(&fetch);
commit.setIEWStage(&iew);
rename.setIEWStage(&iew);
rename.setCommitStage(&commit);
@ -360,6 +388,18 @@ FullO3CPU<Impl>::fullCPURegStats()
}
template <class Impl>
Port *
FullO3CPU<Impl>::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return iew.getDcachePort();
else if (if_name == "icache_port")
return fetch.getIcachePort();
else
panic("No Such Port\n");
}
template <class Impl>
void
FullO3CPU<Impl>::tick()
@ -400,7 +440,8 @@ FullO3CPU<Impl>::tick()
}
if (!tickEvent.scheduled()) {
if (_status == SwitchedOut) {
if (_status == SwitchedOut ||
getState() == SimObject::Drained) {
// increment stat
lastRunningCycle = curTick;
} else if (!activityRec.active()) {
@ -459,18 +500,109 @@ FullO3CPU<Impl>::init()
commit.setThreads(thread);
}
template <class Impl>
void
FullO3CPU<Impl>::activateThread(unsigned tid)
{
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive == activeThreads.end()) {
DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
tid);
activeThreads.push_back(tid);
}
}
template <class Impl>
void
FullO3CPU<Impl>::deactivateThread(unsigned tid)
{
//Remove From Active List, if Active
list<unsigned>::iterator thread_it =
find(activeThreads.begin(), activeThreads.end(), tid);
if (thread_it != activeThreads.end()) {
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(thread_it);
}
}
template <class Impl>
void
FullO3CPU<Impl>::activateContext(int tid, int delay)
{
// Needs to set each stage to running as well.
if (delay){
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
"on cycle %d\n", tid, curTick + cycles(delay));
scheduleActivateThreadEvent(tid, delay);
} else {
activateThread(tid);
}
if(lastActivatedCycle < curTick) {
scheduleTickEvent(delay);
// Be sure to signal that there's some activity so the CPU doesn't
// deschedule itself.
activityRec.activity();
fetch.wakeFromQuiesce();
lastActivatedCycle = curTick;
_status = Running;
}
}
template <class Impl>
void
FullO3CPU<Impl>::deallocateContext(int tid, int delay)
{
// Schedule removal of thread data from CPU
if (delay){
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to deallocate "
"on cycle %d\n", tid, curTick + cycles(delay));
scheduleDeallocateContextEvent(tid, delay);
} else {
deactivateThread(tid);
removeThread(tid);
}
}
template <class Impl>
void
FullO3CPU<Impl>::suspendContext(int tid)
{
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
deactivateThread(tid);
if (activeThreads.size() == 0)
unscheduleTickEvent();
_status = Idle;
}
template <class Impl>
void
FullO3CPU<Impl>::haltContext(int tid)
{
//For now, this is the same as deallocate
DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
deallocateContext(tid, 1);
}
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 +622,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 +638,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 context from CPU.\n", tid);
// 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 +658,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 +666,20 @@ 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);
iew.squash(tid);
commit.rob->squash(commit.rob->readHeadInst(tid)->seqNum, 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
}
@ -604,6 +735,7 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
//blocks fetch
contextSwitch = true;
//@todo: dont always add to waitlist
//do waitlist
cpuWaitList.push_back(tid);
}
@ -611,149 +743,132 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
template <class Impl>
void
FullO3CPU<Impl>::activateThread(unsigned int tid)
FullO3CPU<Impl>::serialize(std::ostream &os)
{
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
BaseCPU::serialize(os);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
if (isActive == activeThreads.end()) {
DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
tid);
// Use SimpleThread's ability to checkpoint to make it easier to
// write out the registers. Also make this static so it doesn't
// get instantiated multiple times (causes a panic in statistics).
static SimpleThread temp;
activeThreads.push_back(tid);
}
}
template <class Impl>
void
FullO3CPU<Impl>::activateContext(int tid, int delay)
{
// Needs to set each stage to running as well.
if (delay){
DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
"on cycle %d\n", tid, curTick + cycles(delay));
scheduleActivateThreadEvent(tid, delay);
} else {
activateThread(tid);
}
if(lastActivatedCycle < curTick) {
scheduleTickEvent(delay);
// Be sure to signal that there's some activity so the CPU doesn't
// deschedule itself.
activityRec.activity();
fetch.wakeFromQuiesce();
lastActivatedCycle = curTick;
_status = Running;
for (int i = 0; i < thread.size(); i++) {
nameOut(os, csprintf("%s.xc.%i", name(), i));
temp.copyTC(thread[i]->getTC());
temp.serialize(os);
}
}
template <class Impl>
void
FullO3CPU<Impl>::suspendContext(int tid)
FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(O3CPU,"[tid: %i]: Suspended ...\n", tid);
unscheduleTickEvent();
_status = Idle;
/*
//Remove From Active List, if Active
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
BaseCPU::unserialize(cp, section);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
if (isActive != activeThreads.end()) {
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(isActive);
// Use SimpleThread's ability to checkpoint to make it easier to
// read in the registers. Also make this static so it doesn't
// get instantiated multiple times (causes a panic in statistics).
static SimpleThread temp;
for (int i = 0; i < thread.size(); i++) {
temp.copyTC(thread[i]->getTC());
temp.unserialize(cp, csprintf("%s.xc.%i", section, i));
thread[i]->getTC()->copyArchRegs(temp.getTC());
}
*/
}
template <class Impl>
void
FullO3CPU<Impl>::deallocateContext(int tid)
unsigned int
FullO3CPU<Impl>::drain(Event *drain_event)
{
DPRINTF(O3CPU,"[tid:%i]: Deallocating ...", tid);
/*
//Remove From Active List, if Active
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive != activeThreads.end()) {
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(isActive);
removeThread(tid);
}
*/
}
template <class Impl>
void
FullO3CPU<Impl>::haltContext(int tid)
{
DPRINTF(O3CPU,"[tid:%i]: Halted ...", tid);
/*
//Remove From Active List, if Active
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive != activeThreads.end()) {
DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(isActive);
removeThread(tid);
}
*/
}
template <class Impl>
void
FullO3CPU<Impl>::switchOut(Sampler *_sampler)
{
sampler = _sampler;
switchCount = 0;
fetch.switchOut();
decode.switchOut();
rename.switchOut();
iew.switchOut();
commit.switchOut();
drainCount = 0;
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();
// the CPU was not able to immediately drain.
if (getState() != SimObject::Drained) {
// A bit of a hack...set the drainEvent after all the drain()
// calls have been made, that way if all of the stages drain
// immediately, the signalDrained() function knows not to call
// process on the drain event.
drainEvent = drain_event;
wakeCPU();
activityRec.activity();
return 1;
} else {
return 0;
}
}
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();
}
assert(system->getMemoryMode() == System::Timing);
fetch.resume();
decode.resume();
rename.resume();
iew.resume();
commit.resume();
#if USE_CHECKER
if (checker)
checker->switchOut(sampler);
#endif
changeState(SimObject::Running);
if (_status == SwitchedOut || _status == Idle)
return;
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;
changeState(SimObject::Drained);
if (drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
}
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>
@ -761,7 +876,7 @@ void
FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
{
// Flush out any old data from the time buffers.
for (int i = 0; i < 10; ++i) {
for (int i = 0; i < timeBuffer.getSize(); ++i) {
timeBuffer.advance();
fetchQueue.advance();
decodeQueue.advance();
@ -932,7 +1047,8 @@ template <class Impl>
void
FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid)
{
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
int idx = reg_idx + TheISA::FP_Base_DepTag;
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
regFile.setFloatReg(phys_reg, val);
}
@ -941,7 +1057,8 @@ template <class Impl>
void
FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid)
{
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
int idx = reg_idx + TheISA::FP_Base_DepTag;
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
regFile.setFloatReg(phys_reg, val, 64);
}
@ -950,7 +1067,8 @@ template <class Impl>
void
FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid)
{
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
int idx = reg_idx + TheISA::FP_Base_DepTag;
PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
regFile.setFloatRegBits(phys_reg, val);
}

View file

@ -57,6 +57,8 @@ class Checker;
class ThreadContext;
template <class>
class O3ThreadContext;
class Checkpoint;
class MemObject;
class Process;
@ -197,6 +199,49 @@ class FullO3CPU : public BaseO3CPU
/** The tick event used for scheduling CPU ticks. */
ActivateThreadEvent activateThreadEvent[Impl::MaxThreads];
class DeallocateContextEvent : public Event
{
private:
/** Number of Thread to Activate */
int tid;
/** Pointer to the CPU. */
FullO3CPU<Impl> *cpu;
public:
/** Constructs the event. */
DeallocateContextEvent();
/** Initialize Event */
void init(int thread_num, FullO3CPU<Impl> *thread_cpu);
/** Processes the event, calling activateThread() on the CPU. */
void process();
/** Returns the description of the event. */
const char *description();
};
/** Schedule cpu to deallocate thread context.*/
void scheduleDeallocateContextEvent(int tid, int delay)
{
// Schedule thread to activate, regardless of its current state.
if (deallocateContextEvent[tid].squashed())
deallocateContextEvent[tid].reschedule(curTick + cycles(delay));
else if (!deallocateContextEvent[tid].scheduled())
deallocateContextEvent[tid].schedule(curTick + cycles(delay));
}
/** Unschedule thread deallocation in CPU */
void unscheduleDeallocateContextEvent(int tid)
{
if (deallocateContextEvent[tid].scheduled())
deallocateContextEvent[tid].squash();
}
/** The tick event used for scheduling CPU ticks. */
DeallocateContextEvent deallocateContextEvent[Impl::MaxThreads];
public:
/** Constructs a CPU with the given parameters. */
FullO3CPU(Params *params);
@ -206,6 +251,9 @@ class FullO3CPU : public BaseO3CPU
/** Registers statistics. */
void fullCPURegStats();
/** Returns a specific port. */
Port *getPort(const std::string &if_name, int idx);
/** Ticks CPU, calling tick() on each stage, and checking the overall
* activity to see if the CPU should deschedule itself.
*/
@ -219,7 +267,10 @@ class FullO3CPU : public BaseO3CPU
{ return activeThreads.size(); }
/** Add Thread to Active Threads List */
void activateThread(unsigned int tid);
void activateThread(unsigned tid);
/** Remove Thread from Active Threads List */
void deactivateThread(unsigned tid);
/** Setup CPU to insert a thread's context */
void insertThread(unsigned tid);
@ -247,7 +298,7 @@ class FullO3CPU : public BaseO3CPU
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
*/
void deallocateContext(int tid);
void deallocateContext(int tid, int delay = 1);
/** Remove Thread from Active Threads List &&
* Remove Thread Context from CPU.
@ -263,6 +314,13 @@ class FullO3CPU : public BaseO3CPU
/** Update The Order In Which We Process Threads. */
void updateThreadPriority();
/** Serialize state. */
virtual void serialize(std::ostream &os);
/** Unserialize from a checkpoint. */
virtual void unserialize(Checkpoint *cp, const std::string &section);
public:
/** Executes a syscall on this cycle.
* ---------------------------------------
* Note: this is a virtual function. CPU-Specific
@ -270,14 +328,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 unsigned int 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 +615,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. */
bool 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

@ -165,11 +165,12 @@ DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
}
template <class Impl>
void
DefaultDecode<Impl>::switchOut()
bool
DefaultDecode<Impl>::drain()
{
// Decode can immediately switch out.
cpu->signalSwitched();
// Decode is done draining at any time.
cpu->signalDrained();
return true;
}
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
@ -164,6 +162,9 @@ class DefaultFetch
/** Registers statistics. */
void regStats();
/** Returns the icache port. */
Port *getIcachePort() { return icachePort; }
/** Sets CPU pointer. */
void setCPU(O3CPU *cpu_ptr);
@ -182,11 +183,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. */
bool 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();
@ -400,6 +404,12 @@ class DefaultFetch
/** The cache line being fetched. */
uint8_t *cacheData[Impl::MaxThreads];
/** The PC of the cacheline that has been loaded. */
Addr cacheDataPC[Impl::MaxThreads];
/** Whether or not the cache data is valid. */
bool cacheDataValid[Impl::MaxThreads];
/** Size of instructions. */
int instSize;
@ -423,6 +433,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)
@ -161,6 +162,8 @@ DefaultFetch<Impl>::DefaultFetch(Params *params)
// Create space to store a cache line.
cacheData[tid] = new uint8_t[cacheBlkSize];
cacheDataPC[tid] = 0;
cacheDataValid[tid] = false;
stalls[tid].decode = 0;
stalls[tid].rename = 0;
@ -279,10 +282,6 @@ DefaultFetch<Impl>::setCPU(O3CPU *cpu_ptr)
// Name is finally available, so create the port.
icachePort = new IcachePort(this);
Port *mem_dport = mem->getPort("");
icachePort->setPeer(mem_dport);
mem_dport->setPeer(icachePort);
#if USE_CHECKER
if (cpu->checker) {
cpu->checker->setIcachePort(icachePort);
@ -360,14 +359,19 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
return;
}
// Wake up the CPU (if it went to sleep and was waiting on this completion
// event).
cpu->wakeCPU();
memcpy(cacheData[tid], pkt->getPtr<uint8_t *>(), cacheBlkSize);
cacheDataValid[tid] = true;
DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
tid);
if (!drainPending) {
// Wake up the CPU (if it went to sleep and was waiting on
// this completion event).
cpu->wakeCPU();
switchToActive();
DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
tid);
switchToActive();
}
// Only switch to IcacheAccessComplete if we're not stalled as well.
if (checkStall(tid)) {
@ -383,18 +387,27 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
}
template <class Impl>
void
DefaultFetch<Impl>::switchOut()
bool
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;
return 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 +511,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)) {
// 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
@ -509,6 +522,11 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
// Align the fetch PC so it's at the start of a cache block.
fetch_PC = icacheBlockAlignPC(fetch_PC);
// If we've already got the block, no need to try to fetch it again.
if (cacheDataValid[tid] && fetch_PC == cacheDataPC[tid]) {
return true;
}
// Setup the memReq to do a read of the first instruction's address.
// Set the appropriate read size and flags as well.
// Build request here.
@ -540,7 +558,10 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
// Build packet here.
PacketPtr data_pkt = new Packet(mem_req,
Packet::ReadReq, Packet::Broadcast);
data_pkt->dataStatic(cacheData[tid]);
data_pkt->dataDynamicArray(new uint8_t[cacheBlkSize]);
cacheDataPC[tid] = fetch_PC;
cacheDataValid[tid] = false;
DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
@ -898,7 +919,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
//////////////////////////////////////////
int tid = getFetchingThread(fetchPolicy);
if (tid == -1) {
if (tid == -1 || drainPending) {
DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
// Breaks looping condition in tick()

View file

@ -31,11 +31,12 @@
#ifndef __CPU_O3_IEW_HH__
#define __CPU_O3_IEW_HH__
#include "config/full_system.hh"
#include <queue>
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "config/full_system.hh"
#include "cpu/o3/comm.hh"
#include "cpu/o3/scoreboard.hh"
#include "cpu/o3/lsq.hh"
@ -125,6 +126,9 @@ class DefaultIEW
/** Initializes stage; sends back the number of free IQ and LSQ entries. */
void initStage();
/** Returns the dcache port. */
Port *getDcachePort() { return ldstQueue.getDcachePort(); }
/** Sets CPU pointer for IEW, IQ, and LSQ. */
void setCPU(O3CPU *cpu_ptr);
@ -143,11 +147,14 @@ class DefaultIEW
/** Sets pointer to the scoreboard. */
void setScoreboard(Scoreboard *sb_ptr);
/** Starts switch out of IEW stage. */
void switchOut();
/** Drains IEW stage. */
bool 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 +211,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);
#ifdef DEBUG
wbList.insert(sn);
#endif
}
void decrWb(InstSeqNum &sn)
{
if (wbOutstanding-- == wbMax)
ableToIssue = true;
DPRINTF(IEW, "wbOutstanding: %i\n", wbOutstanding);
#ifdef DEBUG
assert(wbList.find(sn) != wbList.end());
wbList.erase(sn);
#endif
}
#ifdef 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 +430,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 +446,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

@ -42,16 +42,17 @@ using namespace std;
template<class Impl>
DefaultIEW<Impl>::DefaultIEW(Params *params)
: // @todo: Make this into a parameter.
issueToExecQueue(5, 5),
: issueToExecQueue(params->backComSize, params->forwardComSize),
instQueue(params),
ldstQueue(params),
fuPool(params->fuPool),
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 +75,12 @@ DefaultIEW<Impl>::DefaultIEW(Params *params)
fetchRedirect[i] = false;
}
wbMax = wbWidth * params->wbDepth;
updateLSQNextCycle = false;
ableToIssue = true;
skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth;
}
@ -348,16 +353,23 @@ DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
}
template <class Impl>
void
DefaultIEW<Impl>::switchOut()
bool
DefaultIEW<Impl>::drain()
{
// IEW is ready to switch out at any time.
cpu->signalSwitched();
// IEW is ready to drain at any time.
cpu->signalDrained();
return true;
}
template <class Impl>
void
DefaultIEW<Impl>::doSwitchOut()
DefaultIEW<Impl>::resume()
{
}
template <class Impl>
void
DefaultIEW<Impl>::switchOut()
{
// Clear any state.
switchedOut = true;
@ -400,7 +412,7 @@ DefaultIEW<Impl>::takeOverFrom()
updateLSQNextCycle = false;
// @todo: Fix hardcoded number
for (int i = 0; i < 6; ++i) {
for (int i = 0; i < issueToExecQueue.getSize(); ++i) {
issueToExecQueue.advance();
}
}
@ -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

@ -65,6 +65,13 @@ class LSQ {
/** Registers statistics of each LSQ unit. */
void regStats();
/** Returns dcache port.
* @todo: Dcache port needs to be moved up to this level for SMT
* to work. For now it just returns the port from one of the
* threads.
*/
Port *getDcachePort() { return &dcachePort; }
/** Sets the pointer to the list of active threads. */
void setActiveThreads(std::list<unsigned> *at_ptr);
/** Sets the CPU pointer. */
@ -251,6 +258,15 @@ class LSQ {
bool willWB(unsigned tid)
{ return thread[tid].willWB(); }
/** Returns if the cache is currently blocked. */
bool cacheBlocked()
{ return retryTid != -1; }
/** Sets the retry thread id, indicating that one of the LSQUnits
* tried to access the cache but the cache was blocked. */
void setRetryTid(int tid)
{ retryTid = tid; }
/** Debugging function to print out all instructions. */
void dumpInsts();
/** Debugging function to print out instructions from a specific thread. */
@ -267,7 +283,49 @@ class LSQ {
template <class T>
Fault write(RequestPtr req, T &data, int store_idx);
private:
/** DcachePort class for this LSQ. Handles doing the
* communication with the cache/memory.
*/
class DcachePort : public Port
{
protected:
/** Pointer to LSQ. */
LSQ *lsq;
public:
/** Default constructor. */
DcachePort(LSQ *_lsq)
: lsq(_lsq)
{ }
protected:
/** Atomic version of receive. Panics. */
virtual Tick recvAtomic(PacketPtr pkt);
/** Functional version of receive. Panics. */
virtual void recvFunctional(PacketPtr pkt);
/** Receives status change. Other than range changing, panics. */
virtual void recvStatusChange(Status status);
/** Returns the address ranges of this device. */
virtual void getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
{ resp.clear(); snoop.clear(); }
/** Timing version of receive. Handles writing back and
* completing the load or store that has returned from
* memory. */
virtual bool recvTiming(PacketPtr pkt);
/** Handles doing a retry of the previous send. */
virtual void recvRetry();
};
/** D-cache port. */
DcachePort dcachePort;
protected:
/** The LSQ policy for SMT mode. */
LSQPolicy lsqPolicy;
@ -296,6 +354,10 @@ class LSQ {
/** Number of Threads. */
unsigned numThreads;
/** The thread id of the LSQ Unit that is currently waiting for a
* retry. */
int retryTid;
};
template <class Impl>

View file

@ -35,10 +35,54 @@
using namespace std;
template <class Impl>
Tick
LSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
{
panic("O3CPU model does not work with atomic mode!");
return curTick;
}
template <class Impl>
void
LSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
{
panic("O3CPU doesn't expect recvFunctional callback!");
}
template <class Impl>
void
LSQ<Impl>::DcachePort::recvStatusChange(Status status)
{
if (status == RangeChange)
return;
panic("O3CPU doesn't expect recvStatusChange callback!");
}
template <class Impl>
bool
LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
{
lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt);
return true;
}
template <class Impl>
void
LSQ<Impl>::DcachePort::recvRetry()
{
lsq->thread[lsq->retryTid].recvRetry();
// Speculatively clear the retry Tid. This will get set again if
// the LSQUnit was unable to complete its access.
lsq->retryTid = -1;
}
template <class Impl>
LSQ<Impl>::LSQ(Params *params)
: LQEntries(params->LQEntries), SQEntries(params->SQEntries),
numThreads(params->numberOfThreads)
: dcachePort(this), LQEntries(params->LQEntries),
SQEntries(params->SQEntries), numThreads(params->numberOfThreads),
retryTid(-1)
{
DPRINTF(LSQ, "Creating LSQ object.\n");
@ -94,7 +138,8 @@ LSQ<Impl>::LSQ(Params *params)
//Initialize LSQs
for (int tid=0; tid < numThreads; tid++) {
thread[tid].init(params, maxLQEntries, maxSQEntries, tid);
thread[tid].init(params, this, maxLQEntries, maxSQEntries, tid);
thread[tid].setDcachePort(&dcachePort);
}
}
@ -130,6 +175,8 @@ LSQ<Impl>::setCPU(O3CPU *cpu_ptr)
{
cpu = cpu_ptr;
dcachePort.setName(name());
for (int tid=0; tid < numThreads; tid++) {
thread[tid].setCPU(cpu_ptr);
}
@ -502,6 +549,9 @@ LSQ<Impl>::hasStoresToWB()
{
list<unsigned>::iterator active_threads = (*activeThreads).begin();
if ((*activeThreads).empty())
return false;
while (active_threads != (*activeThreads).end()) {
unsigned tid = *active_threads++;
if (!hasStoresToWB(tid))

View file

@ -64,6 +64,7 @@ class LSQUnit {
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::CPUPol::IEW IEW;
typedef typename Impl::CPUPol::LSQ LSQ;
typedef typename Impl::CPUPol::IssueStruct IssueStruct;
public:
@ -71,7 +72,7 @@ class LSQUnit {
LSQUnit();
/** Initializes the LSQ unit with the specified number of entries. */
void init(Params *params, unsigned maxLQEntries,
void init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries,
unsigned maxSQEntries, unsigned id);
/** Returns the name of the LSQ unit. */
@ -87,6 +88,10 @@ class LSQUnit {
void setIEW(IEW *iew_ptr)
{ iewStage = iew_ptr; }
/** Sets the pointer to the dcache port. */
void setDcachePort(Port *dcache_port)
{ dcachePort = dcache_port; }
/** Switches out LSQ unit. */
void switchOut();
@ -206,6 +211,9 @@ class LSQUnit {
!storeQueue[storeWBIdx].completed &&
!isStoreBlocked; }
/** Handles doing the retry. */
void recvRetry();
private:
/** Writes back the instruction, sending it to IEW. */
void writeback(DynInstPtr &inst, PacketPtr pkt);
@ -216,9 +224,6 @@ class LSQUnit {
/** Completes the store at the specified index. */
void completeStore(int store_idx);
/** Handles doing the retry. */
void recvRetry();
/** Increments the given store index (circular queue). */
inline void incrStIdx(int &store_idx);
/** Decrements the given store index (circular queue). */
@ -239,54 +244,11 @@ class LSQUnit {
/** Pointer to the IEW stage. */
IEW *iewStage;
/** Pointer to memory object. */
MemObject *mem;
/** Pointer to the LSQ. */
LSQ *lsq;
/** DcachePort class for this LSQ Unit. Handles doing the
* communication with the cache/memory.
* @todo: Needs to be moved to the LSQ level and have some sort
* of arbitration.
*/
class DcachePort : public Port
{
protected:
/** Pointer to CPU. */
O3CPU *cpu;
/** Pointer to LSQ. */
LSQUnit *lsq;
public:
/** Default constructor. */
DcachePort(O3CPU *_cpu, LSQUnit *_lsq)
: Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
{ }
protected:
/** Atomic version of receive. Panics. */
virtual Tick recvAtomic(PacketPtr pkt);
/** Functional version of receive. Panics. */
virtual void recvFunctional(PacketPtr pkt);
/** Receives status change. Other than range changing, panics. */
virtual void recvStatusChange(Status status);
/** Returns the address ranges of this device. */
virtual void getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
{ resp.clear(); snoop.clear(); }
/** Timing version of receive. Handles writing back and
* completing the load or store that has returned from
* memory. */
virtual bool recvTiming(PacketPtr pkt);
/** Handles doing a retry of the previous send. */
virtual void recvRetry();
};
/** Pointer to the D-cache. */
DcachePort *dcachePort;
/** Pointer to the dcache port. Used only for sending. */
Port *dcachePort;
/** Derived class to hold any sender state the LSQ needs. */
class LSQSenderState : public Packet::SenderState
@ -639,6 +601,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
// Tell IQ/mem dep unit that this instruction will need to be
// rescheduled eventually
iewStage->rescheduleMemInst(load_inst);
iewStage->decrWb(load_inst->seqNum);
++lsqRescheduledLoads;
// Do not generate a writeback event as this instruction is not
@ -653,7 +616,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
}
// If there's no forwarding case, then go access memory
DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n",
DPRINTF(LSQUnit, "Doing memory access for inst [sn:%lli] PC %#x\n",
load_inst->seqNum, load_inst->readPC());
assert(!load_inst->memData);
@ -661,9 +624,6 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
++usedPorts;
DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n",
load_inst->readPC());
PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
data_pkt->dataStatic(load_inst->memData);
@ -673,8 +633,18 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
state->inst = load_inst;
data_pkt->senderState = state;
// if we have a cache, do cache access too
if (!dcachePort->sendTiming(data_pkt)) {
// if we the cache is not blocked, do cache access
if (!lsq->cacheBlocked()) {
if (!dcachePort->sendTiming(data_pkt)) {
// If the access didn't succeed, tell the LSQ by setting
// the retry thread id.
lsq->setRetryTid(lsqID);
}
}
// If the cache was blocked, or has become blocked due to the access,
// handle it.
if (lsq->cacheBlocked()) {
++lsqCacheBlocked;
// There's an older load that's already going to squash.
if (isLoadBlocked && blockedLoadSeqNum < load_inst->seqNum)

View file

@ -31,6 +31,7 @@
#include "config/use_checker.hh"
#include "cpu/o3/lsq.hh"
#include "cpu/o3/lsq_unit.hh"
#include "base/str.hh"
#include "mem/packet.hh"
@ -77,6 +78,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;
@ -94,46 +96,6 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
delete pkt;
}
template <class Impl>
Tick
LSQUnit<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
{
panic("O3CPU model does not work with atomic mode!");
return curTick;
}
template <class Impl>
void
LSQUnit<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
{
panic("O3CPU doesn't expect recvFunctional callback!");
}
template <class Impl>
void
LSQUnit<Impl>::DcachePort::recvStatusChange(Status status)
{
if (status == RangeChange)
return;
panic("O3CPU doesn't expect recvStatusChange callback!");
}
template <class Impl>
bool
LSQUnit<Impl>::DcachePort::recvTiming(PacketPtr pkt)
{
lsq->completeDataAccess(pkt);
return true;
}
template <class Impl>
void
LSQUnit<Impl>::DcachePort::recvRetry()
{
lsq->recvRetry();
}
template <class Impl>
LSQUnit<Impl>::LSQUnit()
: loads(0), stores(0), storesToWB(0), stalled(false),
@ -144,13 +106,15 @@ LSQUnit<Impl>::LSQUnit()
template<class Impl>
void
LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
LSQUnit<Impl>::init(Params *params, LSQ *lsq_ptr, unsigned maxLQEntries,
unsigned maxSQEntries, unsigned id)
{
DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
switchedOut = false;
lsq = lsq_ptr;
lsqID = id;
// Add 1 for the sentinel entry (they are circular queues).
@ -167,8 +131,6 @@ LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
usedPorts = 0;
cachePorts = params->cachePorts;
mem = params->mem;
memDepViolator = NULL;
blockedLoadSeqNum = 0;
@ -179,11 +141,6 @@ void
LSQUnit<Impl>::setCPU(O3CPU *cpu_ptr)
{
cpu = cpu_ptr;
dcachePort = new DcachePort(cpu, this);
Port *mem_dport = mem->getPort("");
dcachePort->setPeer(mem_dport);
mem_dport->setPeer(dcachePort);
#if USE_CHECKER
if (cpu->checker) {
@ -591,7 +548,7 @@ LSQUnit<Impl>::writebackStores()
storeQueue[storeWBIdx].canWB &&
usedPorts < cachePorts) {
if (isStoreBlocked) {
if (isStoreBlocked || lsq->cacheBlocked()) {
DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
" is blocked!\n");
break;
@ -833,6 +790,7 @@ LSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
// Squashed instructions do not need to complete their access.
if (inst->isSquashed()) {
iewStage->decrWb(inst->seqNum);
assert(!inst->isStore());
++lsqIgnoredResponses;
return;
@ -914,6 +872,7 @@ LSQUnit<Impl>::recvRetry()
} else {
// Still blocked!
++lsqCacheBlocked;
lsq->setRetryTid(lsqID);
}
} else if (isLoadBlocked) {
DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, "

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;
//
@ -99,6 +114,12 @@ class O3Params : public BaseO3CPU::Params
Tick trapLatency;
Tick fetchTrapLatency;
//
// Timebuffer sizes
//
unsigned backComSize;
unsigned forwardComSize;
//
// Branch predictor (BP, BTB, RAS)
//

View file

@ -86,10 +86,6 @@ class PhysRegFile
//The duplication is unfortunate but it's better than having
//different ways to access certain registers.
//Add these in later when everything else is in place
// void serialize(std::ostream &os);
// void unserialize(Checkpoint *cp, const std::string &section);
/** Reads an integer register. */
uint64_t readIntReg(PhysRegIndex reg_idx)
{

View file

@ -157,12 +157,15 @@ class DefaultRename
/** Sets pointer to the scoreboard. */
void setScoreboard(Scoreboard *_scoreboard);
/** Drains the rename stage. */
bool 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

@ -257,16 +257,17 @@ DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
}
template <class Impl>
void
DefaultRename<Impl>::switchOut()
bool
DefaultRename<Impl>::drain()
{
// Rename is ready to switch out at any time.
cpu->signalSwitched();
cpu->signalDrained();
return true;
}
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

@ -308,7 +308,7 @@ class ROB
private:
/** The sequence number of the squashed instruction. */
InstSeqNum squashedSeqNum;
InstSeqNum squashedSeqNum[Impl::MaxThreads];
/** Is the ROB done squashing. */
bool doneSquashing[Impl::MaxThreads];

View file

@ -41,10 +41,10 @@ ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
: numEntries(_numEntries),
squashWidth(_squashWidth),
numInstsInROB(0),
squashedSeqNum(0),
numThreads(_numThreads)
{
for (int tid=0; tid < numThreads; tid++) {
squashedSeqNum[tid] = 0;
doneSquashing[tid] = true;
threadEntries[tid] = 0;
}
@ -352,11 +352,11 @@ void
ROB<Impl>::doSquash(unsigned tid)
{
DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
tid, squashedSeqNum);
tid, squashedSeqNum[tid]);
assert(squashIt[tid] != instList[tid].end());
if ((*squashIt[tid])->seqNum < squashedSeqNum) {
if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
tid);
@ -371,7 +371,7 @@ ROB<Impl>::doSquash(unsigned tid)
for (int numSquashed = 0;
numSquashed < squashWidth &&
squashIt[tid] != instList[tid].end() &&
(*squashIt[tid])->seqNum > squashedSeqNum;
(*squashIt[tid])->seqNum > squashedSeqNum[tid];
++numSquashed)
{
DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
@ -408,7 +408,7 @@ ROB<Impl>::doSquash(unsigned tid)
// Check if ROB is done squashing.
if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
tid);
@ -520,7 +520,7 @@ ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
doneSquashing[tid] = false;
squashedSeqNum = squash_num;
squashedSeqNum[tid] = squash_num;
if (!instList[tid].empty()) {
InstIt tail_thread = instList[tid].end();
@ -544,6 +544,7 @@ ROB<Impl>::readHeadInst()
}
}
*/
template <class Impl>
typename Impl::DynInstPtr
ROB<Impl>::readHeadInst(unsigned tid)
@ -558,6 +559,7 @@ ROB<Impl>::readHeadInst(unsigned tid)
return dummyInst;
}
}
/*
template <class Impl>
uint64_t

View file

@ -112,7 +112,7 @@ class O3ThreadContext : public ThreadContext
virtual void suspend();
/** Set the status to Unallocated. */
virtual void deallocate();
virtual void deallocate(int delay = 0);
/** Set the status to Halted. */
virtual void halt();

View file

@ -115,7 +115,8 @@ template <class Impl>
void
O3ThreadContext<Impl>::activate(int delay)
{
DPRINTF(O3CPU, "Calling activate on AlphaTC\n");
DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Active)
return;
@ -139,7 +140,8 @@ template <class Impl>
void
O3ThreadContext<Impl>::suspend()
{
DPRINTF(O3CPU, "Calling suspend on AlphaTC\n");
DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Suspended)
return;
@ -163,22 +165,24 @@ O3ThreadContext<Impl>::suspend()
template <class Impl>
void
O3ThreadContext<Impl>::deallocate()
O3ThreadContext<Impl>::deallocate(int delay)
{
DPRINTF(O3CPU, "Calling deallocate on AlphaTC\n");
DPRINTF(O3CPU, "Calling deallocate on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Unallocated)
return;
thread->setStatus(ThreadContext::Unallocated);
cpu->deallocateContext(thread->readTid());
cpu->deallocateContext(thread->readTid(), delay);
}
template <class Impl>
void
O3ThreadContext<Impl>::halt()
{
DPRINTF(O3CPU, "Calling halt on AlphaTC\n");
DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
getThreadNum());
if (thread->status() == ThreadContext::Halted)
return;

View file

@ -55,7 +55,6 @@ class AlphaDTB;
class PhysicalMemory;
class MemoryController;
class Sampler;
class RemoteGDB;
class GDBListener;
@ -151,7 +150,7 @@ class OzoneCPU : public BaseCPU
void suspend();
/// Set the status to Unallocated.
void deallocate();
void deallocate(int delay = 0);
/// Set the status to Halted.
void halt();
@ -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
@ -375,6 +372,8 @@ class OzoneCPU : public BaseCPU
PhysicalMemory *physmem;
#endif
virtual Port *getPort(const std::string &name, int idx);
MemObject *mem;
FrontEnd *frontEnd;
@ -386,7 +385,7 @@ class OzoneCPU : public BaseCPU
virtual void activateContext(int thread_num, int delay);
virtual void suspendContext(int thread_num);
virtual void deallocateContext(int thread_num);
virtual void deallocateContext(int thread_num, int delay);
virtual void haltContext(int thread_num);
// statistics

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);
}
@ -337,7 +335,7 @@ OzoneCPU<Impl>::suspendContext(int thread_num)
template <class Impl>
void
OzoneCPU<Impl>::deallocateContext(int thread_num)
OzoneCPU<Impl>::deallocateContext(int thread_num, int delay)
{
// for now, these are equivalent
suspendContext(thread_num);
@ -420,6 +418,18 @@ OzoneCPU<Impl>::init()
thread.inSyscall = false;
}
template <class Impl>
Port *
OzoneCPU<Impl>::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return backEnd->getDcachePort();
else if (if_name == "icache_port")
return frontEnd->getIcachePort();
else
panic("No Such Port\n");
}
template <class Impl>
void
OzoneCPU<Impl>::serialize(std::ostream &os)
@ -782,9 +792,9 @@ OzoneCPU<Impl>::OzoneTC::suspend()
/// Set the status to Unallocated.
template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::deallocate()
OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
{
cpu->deallocateContext(thread->readTid());
cpu->deallocateContext(thread->readTid(), delay);
}
/// Set the status to Halted.

View file

@ -119,6 +119,8 @@ class FrontEnd
void regStats();
Port *getIcachePort() { return &icachePort; }
void tick();
Fault fetchCacheLine();
void processInst(DynInstPtr &inst);

View file

@ -36,6 +36,7 @@
#include "cpu/thread_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/ozone/front_end.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/request.hh"
@ -138,10 +139,6 @@ FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
icachePort.setName(this->name() + "-iport");
Port *mem_dport = mem->getPort("");
icachePort.setPeer(mem_dport);
mem_dport->setPeer(&icachePort);
#if USE_CHECKER
if (cpu->checker) {
cpu->checker->setIcachePort(&icachePort);

View file

@ -51,6 +51,8 @@ class ThreadContext;
template <class Impl>
class OzoneThreadState;
class Port;
template <class Impl>
class LWBackEnd
{
@ -114,6 +116,8 @@ class LWBackEnd
void setCommBuffer(TimeBuffer<CommStruct> *_comm);
Port *getDcachePort() { return LSQ.getDcachePort(); }
void tick();
void squash();
void generateTCEvent() { tcSquash = true; }

View file

@ -142,7 +142,7 @@ LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst)
template <class Impl>
LWBackEnd<Impl>::LWBackEnd(Params *params)
: d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5),
trapSquash(false), tcSquash(false), LSQ(params),
trapSquash(false), tcSquash(false),
width(params->backEndWidth), exactFullStall(true)
{
numROBEntries = params->numROBEntries;
@ -557,6 +557,7 @@ LWBackEnd<Impl>::checkInterrupts()
}
}
}
#endif
template <class Impl>
void
@ -580,7 +581,6 @@ LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency)
// Generate trap squash event.
generateTrapEvent(latency);
}
#endif
template <class Impl>
void
@ -602,6 +602,7 @@ LWBackEnd<Impl>::tick()
#if FULL_SYSTEM
checkInterrupts();
#endif
if (trapSquash) {
assert(!tcSquash);
@ -609,7 +610,6 @@ LWBackEnd<Impl>::tick()
} else if (tcSquash) {
squashFromTC();
}
#endif
if (dispatchStatus != Blocked) {
dispatchInsts();
@ -1137,13 +1137,9 @@ LWBackEnd<Impl>::commitInst(int inst_num)
thread->setInst(
static_cast<TheISA::MachInst>(inst->staticInst->machInst));
#if FULL_SYSTEM
handleFault(inst_fault);
return false;
#else // !FULL_SYSTEM
panic("fault (%d) detected @ PC %08p", inst_fault,
inst->PC);
#endif // FULL_SYSTEM
}
int freed_regs = 0;

View file

@ -91,8 +91,7 @@ class OzoneLWLSQ {
void setBE(BackEnd *be_ptr)
{ be = be_ptr; }
/** Sets the page table pointer. */
// void setPageTable(PageTable *pt_ptr);
Port *getDcachePort() { return &dcachePort; }
/** Ticks the LSQ unit, which in this case only resets the number of
* used cache ports.
@ -241,13 +240,11 @@ class OzoneLWLSQ {
class DcachePort : public Port
{
protected:
OzoneCPU *cpu;
OzoneLWLSQ *lsq;
public:
DcachePort(OzoneCPU *_cpu, OzoneLWLSQ *_lsq)
: Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
DcachePort(OzoneLWLSQ *_lsq)
: lsq(_lsq)
{ }
protected:
@ -266,11 +263,8 @@ class OzoneLWLSQ {
virtual void recvRetry();
};
/** Pointer to the D-cache. */
DcachePort *dcachePort;
/** Pointer to the page table. */
// PageTable *pTable;
/** D-cache port. */
DcachePort dcachePort;
public:
struct SQEntry {
@ -639,7 +633,7 @@ OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
data_pkt->senderState = state;
// if we have a cache, do cache access too
if (!dcachePort->sendTiming(data_pkt)) {
if (!dcachePort.sendTiming(data_pkt)) {
// There's an older load that's already going to squash.
if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
return NoFault;

View file

@ -131,8 +131,9 @@ OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
template <class Impl>
OzoneLWLSQ<Impl>::OzoneLWLSQ()
: switchedOut(false), loads(0), stores(0), storesToWB(0), stalled(false),
isStoreBlocked(false), isLoadBlocked(false), loadBlockedHandled(false)
: switchedOut(false), dcachePort(this), loads(0), stores(0),
storesToWB(0), stalled(false), isStoreBlocked(false),
isLoadBlocked(false), loadBlockedHandled(false)
{
}
@ -175,15 +176,11 @@ void
OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
{
cpu = cpu_ptr;
dcachePort = new DcachePort(cpu, this);
Port *mem_dport = mem->getPort("");
dcachePort->setPeer(mem_dport);
mem_dport->setPeer(dcachePort);
dcachePort.setName(this->name() + "-dport");
#if USE_CHECKER
if (cpu->checker) {
cpu->checker->setDcachePort(dcachePort);
cpu->checker->setDcachePort(&dcachePort);
}
#endif
}
@ -614,7 +611,7 @@ OzoneLWLSQ<Impl>::writebackStores()
state->noWB = true;
}
if (!dcachePort->sendTiming(data_pkt)) {
if (!dcachePort.sendTiming(data_pkt)) {
// Need to handle becoming blocked on a store.
isStoreBlocked = true;
assert(retryPkt == NULL);

View file

@ -33,6 +33,7 @@
#include "cpu/simple/atomic.hh"
#include "mem/packet_impl.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
using namespace std;
using namespace TheISA;
@ -55,18 +56,28 @@ AtomicSimpleCPU::TickEvent::description()
return "AtomicSimpleCPU tick event";
}
Port *
AtomicSimpleCPU::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return &dcachePort;
else if (if_name == "icache_port")
return &icachePort;
else
panic("No Such Port\n");
}
void
AtomicSimpleCPU::init()
{
//Create Memory Ports (conect them up)
Port *mem_dport = mem->getPort("");
dcachePort.setPeer(mem_dport);
mem_dport->setPeer(&dcachePort);
// Port *mem_dport = mem->getPort("");
// dcachePort.setPeer(mem_dport);
// mem_dport->setPeer(&dcachePort);
Port *mem_iport = mem->getPort("");
icachePort.setPeer(mem_iport);
mem_iport->setPeer(&icachePort);
// Port *mem_iport = mem->getPort("");
// icachePort.setPeer(mem_iport);
// mem_iport->setPeer(&icachePort);
BaseCPU::init();
#if FULL_SYSTEM
@ -148,18 +159,31 @@ AtomicSimpleCPU::~AtomicSimpleCPU()
void
AtomicSimpleCPU::serialize(ostream &os)
{
SERIALIZE_ENUM(_status);
BaseSimpleCPU::serialize(os);
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
BaseSimpleCPU::serialize(os);
}
void
AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
UNSERIALIZE_ENUM(_status);
BaseSimpleCPU::unserialize(cp, section);
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
BaseSimpleCPU::unserialize(cp, section);
}
void
AtomicSimpleCPU::resume()
{
assert(system->getMemoryMode() == System::Atomic);
changeState(SimObject::Running);
if (thread->status() == ThreadContext::Active) {
if (!tickEvent.scheduled())
tickEvent.schedule(curTick);
}
}
void
@ -441,11 +465,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
Param<Counter> max_loads_any_thread;
Param<Counter> max_loads_all_threads;
SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system;
#if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb;
SimObjectParam<System *> system;
Param<int> cpu_id;
Param<Tick> profile;
#else
@ -473,11 +497,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
INIT_PARAM(max_loads_all_threads,
"terminate when all threads have reached this load count"),
INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"),
#if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""),
#else
@ -510,11 +534,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU)
params->width = width;
params->simulate_stalls = simulate_stalls;
params->mem = mem;
params->system = system;
#if FULL_SYSTEM
params->itb = itb;
params->dtb = dtb;
params->system = system;
params->cpu_id = cpu_id;
params->profile = profile;
#else

View file

@ -122,8 +122,11 @@ class AtomicSimpleCPU : public BaseSimpleCPU
public:
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
void switchOut();
void takeOverFrom(BaseCPU *oldCPU);

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"
@ -56,10 +55,10 @@
#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
#include "sim/system.hh"
#if FULL_SYSTEM
#include "base/remote_gdb.hh"
#include "sim/system.hh"
#include "arch/tlb.hh"
#include "arch/stacktrace.hh"
#include "arch/vtophys.hh"
@ -179,8 +178,8 @@ void
BaseSimpleCPU::serialize(ostream &os)
{
BaseCPU::serialize(os);
SERIALIZE_SCALAR(inst);
nameOut(os, csprintf("%s.xc", name()));
// SERIALIZE_SCALAR(inst);
nameOut(os, csprintf("%s.xc.0", name()));
thread->serialize(os);
}
@ -188,8 +187,8 @@ void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
BaseCPU::unserialize(cp, section);
UNSERIALIZE_SCALAR(inst);
thread->unserialize(cp, csprintf("%s.xc", section));
// UNSERIALIZE_SCALAR(inst);
thread->unserialize(cp, csprintf("%s.xc.0", section));
}
void

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

@ -33,23 +33,25 @@
#include "cpu/simple/timing.hh"
#include "mem/packet_impl.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
using namespace std;
using namespace TheISA;
Port *
TimingSimpleCPU::getPort(const std::string &if_name, int idx)
{
if (if_name == "dcache_port")
return &dcachePort;
else if (if_name == "icache_port")
return &icachePort;
else
panic("No Such Port\n");
}
void
TimingSimpleCPU::init()
{
//Create Memory Ports (conect them up)
Port *mem_dport = mem->getPort("");
dcachePort.setPeer(mem_dport);
mem_dport->setPeer(&dcachePort);
Port *mem_iport = mem->getPort("");
icachePort.setPeer(mem_iport);
mem_iport->setPeer(&icachePort);
BaseCPU::init();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
@ -88,8 +90,9 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
{
_status = Idle;
ifetch_pkt = dcache_pkt = NULL;
quiesceEvent = NULL;
state = SimObject::Timing;
drainEvent = NULL;
fetchEvent = NULL;
changeState(SimObject::Running);
}
@ -100,30 +103,31 @@ TimingSimpleCPU::~TimingSimpleCPU()
void
TimingSimpleCPU::serialize(ostream &os)
{
SERIALIZE_ENUM(_status);
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
BaseSimpleCPU::serialize(os);
}
void
TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
UNSERIALIZE_ENUM(_status);
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
BaseSimpleCPU::unserialize(cp, section);
}
bool
TimingSimpleCPU::quiesce(Event *quiesce_event)
unsigned int
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");
return false;
changeState(SimObject::Drained);
return 0;
} else {
DPRINTF(Config, "Waiting to quiesce\n");
changeState(SimObject::Quiescing);
quiesceEvent = quiesce_event;
return true;
changeState(SimObject::Draining);
drainEvent = drain_event;
return 1;
}
}
@ -131,16 +135,21 @@ void
TimingSimpleCPU::resume()
{
if (_status != SwitchedOut && _status != Idle) {
Event *e =
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
e->schedule(curTick);
}
}
// Delete the old event if it existed.
if (fetchEvent) {
if (fetchEvent->scheduled())
fetchEvent->deschedule();
void
TimingSimpleCPU::setMemoryMode(State new_mode)
{
assert(new_mode == SimObject::Timing);
delete fetchEvent;
}
fetchEvent =
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
fetchEvent->schedule(curTick);
}
assert(system->getMemoryMode() == System::Timing);
changeState(SimObject::Running);
}
void
@ -148,6 +157,11 @@ TimingSimpleCPU::switchOut()
{
assert(status() == Running || status() == Idle);
_status = SwitchedOut;
// If we've been scheduled to resume but are then told to switch out,
// we'll need to cancel it.
if (fetchEvent && fetchEvent->scheduled())
fetchEvent->deschedule();
}
@ -179,9 +193,9 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
notIdleFraction++;
_status = Running;
// kick things off by initiating the fetch of the next instruction
Event *e =
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
e->schedule(curTick + cycles(delay));
fetchEvent =
new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
fetchEvent->schedule(curTick + cycles(delay));
}
@ -422,8 +436,8 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
delete pkt->req;
delete pkt;
if (getState() == SimObject::Quiescing) {
completeQuiesce();
if (getState() == SimObject::Draining) {
completeDrain();
return;
}
@ -479,8 +493,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 +513,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::Drained);
drainEvent->process();
}
bool
@ -539,11 +553,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
Param<Counter> max_loads_any_thread;
Param<Counter> max_loads_all_threads;
SimObjectParam<MemObject *> mem;
SimObjectParam<System *> system;
#if FULL_SYSTEM
SimObjectParam<AlphaITB *> itb;
SimObjectParam<AlphaDTB *> dtb;
SimObjectParam<System *> system;
Param<int> cpu_id;
Param<Tick> profile;
#else
@ -571,11 +585,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
INIT_PARAM(max_loads_all_threads,
"terminate when all threads have reached this load count"),
INIT_PARAM(mem, "memory"),
INIT_PARAM(system, "system object"),
#if FULL_SYSTEM
INIT_PARAM(itb, "Instruction TLB"),
INIT_PARAM(dtb, "Data TLB"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu_id, "processor ID"),
INIT_PARAM(profile, ""),
#else
@ -606,11 +620,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
params->functionTrace = function_trace;
params->functionTraceStart = function_trace_start;
params->mem = mem;
params->system = system;
#if FULL_SYSTEM
params->itb = itb;
params->dtb = dtb;
params->system = system;
params->cpu_id = cpu_id;
params->profile = profile;
#else

View file

@ -64,7 +64,9 @@ class TimingSimpleCPU : public BaseSimpleCPU
Status status() const { return _status; }
Event *quiesceEvent;
Event *drainEvent;
Event *fetchEvent;
private:
@ -130,12 +132,13 @@ class TimingSimpleCPU : public BaseSimpleCPU
public:
virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual bool quiesce(Event *quiesce_event);
virtual unsigned int drain(Event *drain_event);
virtual void resume();
virtual void setMemoryMode(State new_mode);
void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
@ -154,7 +157,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
void completeDataAccess(Packet *);
void advanceInst(Fault fault);
private:
void completeQuiesce();
void completeDrain();
};
#endif // __CPU_SIMPLE_TIMING_HH__

View file

@ -123,15 +123,19 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num,
tc = new ProxyThreadContext<SimpleThread>(this);
}
SimpleThread::SimpleThread(RegFile *regFile)
: ThreadState(-1, -1, NULL, -1, NULL), cpu(NULL)
{
regs = *regFile;
tc = new ProxyThreadContext<SimpleThread>(this);
}
#endif
SimpleThread::SimpleThread()
#if FULL_SYSTEM
: ThreadState(-1, -1)
#else
: ThreadState(-1, -1, NULL, -1, NULL)
#endif
{
tc = new ProxyThreadContext<SimpleThread>(this);
regs.clear();
}
SimpleThread::~SimpleThread()
{
delete tc;
@ -147,13 +151,8 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
assert(process == oldContext->getProcessPtr());
#endif
// copy over functional state
_status = oldContext->status();
copyArchRegs(oldContext);
cpuId = oldContext->readCpuId();
#if !FULL_SYSTEM
funcExeInst = oldContext->readFuncExeInst();
#else
copyState(oldContext);
#if FULL_SYSTEM
EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
if (quiesce) {
// Point the quiesce event's TC at this TC so that it wakes up
@ -171,42 +170,50 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
}
void
SimpleThread::serialize(ostream &os)
SimpleThread::copyTC(ThreadContext *context)
{
SERIALIZE_ENUM(_status);
regs.serialize(os);
// thread_num and cpu_id are deterministic from the config
SERIALIZE_SCALAR(funcExeInst);
SERIALIZE_SCALAR(inst);
copyState(context);
#if FULL_SYSTEM
Tick quiesceEndTick = 0;
if (quiesceEvent->scheduled())
quiesceEndTick = quiesceEvent->when();
SERIALIZE_SCALAR(quiesceEndTick);
if (kernelStats)
kernelStats->serialize(os);
EndQuiesceEvent *quiesce = context->getQuiesceEvent();
if (quiesce) {
quiesceEvent = quiesce;
}
Kernel::Statistics *stats = context->getKernelStats();
if (stats) {
kernelStats = stats;
}
#endif
}
void
SimpleThread::copyState(ThreadContext *oldContext)
{
// copy over functional state
_status = oldContext->status();
copyArchRegs(oldContext);
cpuId = oldContext->readCpuId();
#if !FULL_SYSTEM
funcExeInst = oldContext->readFuncExeInst();
#endif
inst = oldContext->getInst();
}
void
SimpleThread::serialize(ostream &os)
{
ThreadState::serialize(os);
regs.serialize(os);
// thread_num and cpu_id are deterministic from the config
}
void
SimpleThread::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ENUM(_status);
ThreadState::unserialize(cp, section);
regs.unserialize(cp, section);
// thread_num and cpu_id are deterministic from the config
UNSERIALIZE_SCALAR(funcExeInst);
UNSERIALIZE_SCALAR(inst);
#if FULL_SYSTEM
Tick quiesceEndTick;
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
quiesceEvent->schedule(quiesceEndTick);
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
}
#if FULL_SYSTEM

View file

@ -119,16 +119,20 @@ class SimpleThread : public ThreadState
#else
SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
MemObject *memobj);
// Constructor to use SimpleThread to pass reg file around. Not
// used for anything else.
SimpleThread(RegFile *regFile);
#endif
SimpleThread();
virtual ~SimpleThread();
virtual void takeOverFrom(ThreadContext *oldContext);
void regStats(const std::string &name);
void copyTC(ThreadContext *context);
void copyState(ThreadContext *oldContext);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);

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

@ -143,7 +143,7 @@ class ThreadContext
virtual void suspend() = 0;
/// Set the status to Unallocated.
virtual void deallocate() = 0;
virtual void deallocate(int delay = 0) = 0;
/// Set the status to Halted.
virtual void halt() = 0;
@ -318,7 +318,7 @@ class ProxyThreadContext : public ThreadContext
void suspend() { actualTC->suspend(); }
/// Set the status to Unallocated.
void deallocate() { actualTC->deallocate(); }
void deallocate(int delay = 0) { actualTC->deallocate(); }
/// Set the status to Halted.
void halt() { actualTC->halt(); }

View file

@ -31,6 +31,12 @@
#include "base/output.hh"
#include "cpu/profile.hh"
#include "cpu/thread_state.hh"
#include "sim/serialize.hh"
#if FULL_SYSTEM
#include "cpu/quiesce_event.hh"
#include "kern/kernel_stats.hh"
#endif
#if FULL_SYSTEM
ThreadState::ThreadState(int _cpuId, int _tid)
@ -49,6 +55,43 @@ ThreadState::ThreadState(int _cpuId, int _tid, Process *_process,
numLoad = 0;
}
void
ThreadState::serialize(std::ostream &os)
{
SERIALIZE_ENUM(_status);
// thread_num and cpu_id are deterministic from the config
SERIALIZE_SCALAR(funcExeInst);
SERIALIZE_SCALAR(inst);
#if FULL_SYSTEM
Tick quiesceEndTick = 0;
if (quiesceEvent->scheduled())
quiesceEndTick = quiesceEvent->when();
SERIALIZE_SCALAR(quiesceEndTick);
if (kernelStats)
kernelStats->serialize(os);
#endif
}
void
ThreadState::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ENUM(_status);
// thread_num and cpu_id are deterministic from the config
UNSERIALIZE_SCALAR(funcExeInst);
UNSERIALIZE_SCALAR(inst);
#if FULL_SYSTEM
Tick quiesceEndTick;
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
quiesceEvent->schedule(quiesceEndTick);
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
}
#if FULL_SYSTEM
void

View file

@ -49,6 +49,8 @@ namespace Kernel {
};
#endif
class Checkpoint;
/**
* Struct for holding general thread state that is needed across CPU
* models. This includes things such as pointers to the process,
@ -65,6 +67,10 @@ struct ThreadState {
short _asid, MemObject *mem);
#endif
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
void setCpuId(int id) { cpuId = id; }
int readCpuId() { return cpuId; }

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

@ -318,7 +318,7 @@ IdeDisk::doDmaTransfer()
panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
dmaState, devState);
if (ctrl->dmaPending()) {
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
} else
@ -398,8 +398,7 @@ IdeDisk::doDmaRead()
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending()) {
panic("shouldn't be reentant??");
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaReadCG->done()) {
@ -474,8 +473,7 @@ IdeDisk::doDmaWrite()
dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending()) {
panic("shouldn't be reentant??");
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaWriteCG->done()) {

View file

@ -32,10 +32,12 @@
#include "base/trace.hh"
#include "dev/io_device.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
PioPort::PioPort(PioDevice *dev, Platform *p)
: Port(dev->name() + "-pioport"), device(dev), platform(p)
PioPort::PioPort(PioDevice *dev, System *s, std::string pname)
: Port(dev->name() + pname), device(dev), sys(s),
outTiming(0), drainEvent(NULL)
{ }
@ -68,30 +70,44 @@ PioPort::recvRetry()
if (result)
transmitList.pop_front();
}
if (transmitList.size() == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
}
void
PioPort::SendEvent::process()
{
port->outTiming--;
assert(port->outTiming >= 0);
if (port->Port::sendTiming(packet))
return;
if (port->transmitList.size() == 0 && port->drainEvent) {
port->drainEvent->process();
port->drainEvent = NULL;
}
return;
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
@ -101,6 +117,15 @@ PioPort::recvTiming(Packet *pkt)
return true;
}
unsigned int
PioPort::drain(Event *de)
{
if (outTiming == 0 && transmitList.size() == 0)
return 0;
drainEvent = de;
return 1;
}
PioDevice::~PioDevice()
{
if (pioPort)
@ -115,6 +140,19 @@ PioDevice::init()
pioPort->sendStatusChange(Port::RangeChange);
}
unsigned int
PioDevice::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
void
BasicPioDevice::addressRanges(AddrRangeList &range_list)
{
@ -124,8 +162,9 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list)
}
DmaPort::DmaPort(DmaDevice *dev, Platform *p)
: Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0)
DmaPort::DmaPort(DmaDevice *dev, System *s)
: Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0),
actionInProgress(0), drainEvent(NULL)
{ }
bool
@ -155,6 +194,11 @@ DmaPort::recvTiming(Packet *pkt)
}
delete pkt->req;
delete pkt;
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} else {
panic("Got packet without sender state... huh?\n");
}
@ -166,6 +210,29 @@ DmaDevice::DmaDevice(Params *p)
: PioDevice(p), dmaPort(NULL)
{ }
unsigned int
DmaDevice::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de) + dmaPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
unsigned int
DmaPort::drain(Event *de)
{
if (pendingCount == 0)
return 0;
drainEvent = de;
return 1;
}
void
DmaPort::recvRetry()
{
@ -191,6 +258,8 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
{
assert(event);
assert(device->getState() == SimObject::Running);
DmaReqState *reqState = new DmaReqState(event, this, size);
for (ChunkGenerator gen(addr, size, peerBlockSize());
@ -208,51 +277,54 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
pendingCount++;
sendDma(pkt);
}
}
void
DmaPort::sendDma(Packet *pkt, bool front)
{
// some kind of selction between access methods
// more work is going to have to be done to make
// switching actually work
/* MemState state = device->platform->system->memState;
// some kind of selction between access methods
// more work is going to have to be done to make
// switching actually work
if (state == Timing) { */
DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
pkt, pkt->getAddr());
if (transmitList.size() || !sendTiming(pkt)) {
if (front)
transmitList.push_front(pkt);
else
transmitList.push_back(pkt);
DPRINTF(DMA, "-- Failed: queued\n");
} else {
DPRINTF(DMA, "-- Done\n");
}
/* } else if (state == Atomic) {
sendAtomic(pkt);
if (pkt->senderState) {
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
assert(state);
state->completionEvent->schedule(curTick + (pkt->time -
pkt->req->getTime()) +1);
delete state;
}
pendingCount--;
assert(pendingCount >= 0);
delete pkt->req;
delete pkt;
System::MemoryMode state = sys->getMemoryMode();
if (state == System::Timing) {
DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
pkt, pkt->getAddr());
if (transmitList.size() || !sendTiming(pkt)) {
if (front)
transmitList.push_front(pkt);
else
transmitList.push_back(pkt);
DPRINTF(DMA, "-- Failed: queued\n");
} else {
DPRINTF(DMA, "-- Done\n");
}
} else if (state == System::Atomic) {
Tick lat;
lat = sendAtomic(pkt);
assert(pkt->senderState);
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
assert(state);
state->numBytes += pkt->req->getSize();
if (state->totBytes == state->numBytes) {
state->completionEvent->schedule(curTick + lat);
delete state;
delete pkt->req;
}
pendingCount--;
assert(pendingCount >= 0);
delete pkt;
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} else if (state == Functional) {
sendFunctional(pkt);
// Is this correct???
completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime);
completionEvent == NULL;
} else
panic("Unknown memory command state.");
*/
}
DmaDevice::~DmaDevice()

View file

@ -60,9 +60,9 @@ class PioPort : public Port
/** The device that this port serves. */
PioDevice *device;
/** The platform that device/port are in. This is used to select which mode
/** The system that device/port are in. This is used to select which mode
* we are currently operating in. */
Platform *platform;
System *sys;
/** A list of outgoing timing response packets that haven't been serviced
* yet. */
@ -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
@ -104,16 +106,27 @@ class PioPort : public Port
friend class PioPort;
};
/** Number of timing requests that are emulating the device timing before
* attempting to end up on the bus.
*/
int outTiming;
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
/** Schedule a sendTiming() event to be called in the future. */
void sendTiming(Packet *pkt, Tick time)
{ new PioPort::SendEvent(this, pkt, time); }
{ outTiming++; new PioPort::SendEvent(this, pkt, time); }
/** This function is notification that the device should attempt to send a
* packet again. */
virtual void recvRetry();
public:
PioPort(PioDevice *dev, Platform *p);
PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
unsigned int drain(Event *de);
friend class PioPort::SendEvent;
};
@ -145,13 +158,20 @@ class DmaPort : public Port
DmaDevice *device;
std::list<Packet*> transmitList;
/** The platform that device/port are in. This is used to select which mode
/** The system that device/port are in. This is used to select which mode
* we are currently operating in. */
Platform *platform;
System *sys;
/** Number of outstanding packets the dma port has. */
int pendingCount;
/** If a dmaAction is in progress. */
int actionInProgress;
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
virtual bool recvTiming(Packet *pkt);
virtual Tick recvAtomic(Packet *pkt)
{ panic("dma port shouldn't be used for pio access."); }
@ -169,13 +189,14 @@ class DmaPort : public Port
void sendDma(Packet *pkt, bool front = false);
public:
DmaPort(DmaDevice *dev, Platform *p);
DmaPort(DmaDevice *dev, System *s);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data = NULL);
bool dmaPending() { return pendingCount > 0; }
unsigned int drain(Event *de);
};
/**
@ -194,6 +215,8 @@ class PioDevice : public MemObject
* transaction we should perform. */
Platform *platform;
System *sys;
/** The pioPort that handles the requests for us and provides us requests
* that it sees. */
PioPort *pioPort;
@ -238,20 +261,22 @@ class PioDevice : public MemObject
const Params *params() const { return _params; }
PioDevice(Params *p)
: MemObject(p->name), platform(p->platform), pioPort(NULL),
_params(p)
: MemObject(p->name), platform(p->platform), sys(p->system),
pioPort(NULL), _params(p)
{}
virtual ~PioDevice();
virtual void init();
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "pio") {
if (pioPort != NULL)
panic("pio port already connected to.");
pioPort = new PioPort(this, params()->platform);
pioPort = new PioPort(this, sys);
return pioPort;
} else
return NULL;
@ -308,17 +333,19 @@ class DmaDevice : public PioDevice
bool dmaPending() { return dmaPort->dmaPending(); }
virtual unsigned int drain(Event *de);
virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "pio") {
if (pioPort != NULL)
panic("pio port already connected to.");
pioPort = new PioPort(this, params()->platform);
pioPort = new PioPort(this, sys);
return pioPort;
} else if (if_name == "dma") {
if (dmaPort != NULL)
panic("dma port already connected to.");
dmaPort = new DmaPort(this, params()->platform);
dmaPort = new DmaPort(this, sys);
return dmaPort;
} else
return NULL;

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");
@ -1388,7 +1377,7 @@ NSGigE::doRxDmaRead()
assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
rxDmaState = dmaReading;
if (dmaPending())
if (dmaPending() || getState() != Running)
rxDmaState = dmaReadWaiting;
else
dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
@ -1419,7 +1408,7 @@ NSGigE::doRxDmaWrite()
assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
rxDmaState = dmaWriting;
if (dmaPending())
if (dmaPending() || getState() != Running)
rxDmaState = dmaWriteWaiting;
else
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
@ -1837,7 +1826,7 @@ NSGigE::doTxDmaRead()
assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
txDmaState = dmaReading;
if (dmaPending())
if (dmaPending() || getState() != Running)
txDmaState = dmaReadWaiting;
else
dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
@ -1868,7 +1857,7 @@ NSGigE::doTxDmaWrite()
assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
txDmaState = dmaWriting;
if (dmaPending())
if (dmaPending() || getState() != Running)
txDmaState = dmaWriteWaiting;
else
dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
@ -2417,6 +2406,20 @@ NSGigE::recvPacket(EthPacketPtr packet)
return true;
}
void
NSGigE::resume()
{
SimObject::resume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.
// This way they'll get out immediately
txKick();
rxKick();
}
//=====================================================================
//
//
@ -2807,7 +2810,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 +2843,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 +2880,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);
@ -392,6 +391,8 @@ class NSGigE : public PciDev
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
public:
void regStats();

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->system,"-pciconf"), device(dev), platform(p),
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,68 @@ 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();
}
unsigned int
PciDev::drain(Event *de)
{
unsigned int count;
count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
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 +193,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,43 @@ 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);
Platform *platform;
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 +130,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 +184,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 +210,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 +236,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 +250,22 @@ class PciDev : public DmaDevice
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
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"
@ -922,7 +921,7 @@ Device::rxKick()
break;
case rxBeginCopy:
if (dmaPending())
if (dmaPending() || getState() != Running)
goto exit;
rxDmaAddr = params()->platform->pciToDma(
@ -1110,7 +1109,7 @@ Device::txKick()
break;
case txBeginCopy:
if (dmaPending())
if (dmaPending() || getState() != Running)
goto exit;
txDmaAddr = params()->platform->pciToDma(
@ -1288,6 +1287,18 @@ Device::recvPacket(EthPacketPtr packet)
return true;
}
void
Device::resume()
{
SimObject::resume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.
// This way they'll get out immediately
txKick();
rxKick();
}
//=====================================================================
//
//
@ -1623,7 +1634,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 +1676,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 +1720,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

@ -266,6 +266,7 @@ class Device : public Base
public:
virtual Tick read(Packet *pkt);
virtual Tick write(Packet *pkt);
virtual void resume();
void prepareIO(int cpu, int index);
void prepareRead(int cpu, int index);

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 = ULL(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

@ -59,7 +59,7 @@ void
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
{
cache->getAddressRanges(resp, snoop);
cache->getAddressRanges(resp, snoop, isCpuSide);
}
int
@ -98,6 +98,56 @@ 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();
bool success = cachePort->sendTiming(pkt);
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
pkt->getAddr(), success ? "succesful" : "unsuccesful");
cachePort->cache->sendResult(pkt, success);
if (success && cachePort->cache->doMasterRequest())
{
//Still more to issue, rerequest in 1 cycle
pkt = NULL;
this->schedule(curTick+1);
}
}
else
{
pkt = cachePort->cache->getCoherencePacket();
cachePort->sendTiming(pkt);
}
return;
}
//Know the packet to send, no need to mark in service (must succed)
bool success = cachePort->sendTiming(pkt);
assert(success);
}
const char *
BaseCache::CacheEvent::description()
{
return "timing event\n";
}
Port*
BaseCache::getPort(const std::string &if_name, int idx)
{
@ -107,7 +157,13 @@ BaseCache::getPort(const std::string &if_name, int idx)
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
return cpuSidePort;
}
if (if_name == "functional")
else if (if_name == "functional")
{
if(cpuSidePort == NULL)
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
return cpuSidePort;
}
else if (if_name == "cpu_side")
{
if(cpuSidePort == NULL)
cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
@ -123,6 +179,14 @@ BaseCache::getPort(const std::string &if_name, int idx)
else panic("Port name %s unrecognized\n", if_name);
}
void
BaseCache::init()
{
if (!cpuSidePort || !memSidePort)
panic("Cache not hooked up on both sides\n");
cpuSidePort->sendStatusChange(Port::RangeChange);
}
void
BaseCache::regStats()
{

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();
};
@ -142,8 +143,34 @@ class BaseCache : public MemObject
fatal("No implementation");
}
virtual void recvStatusChange(Port::Status status, bool isCpuSide)
void recvStatusChange(Port::Status status, bool isCpuSide)
{
if (status == Port::RangeChange)
{
if (!isCpuSide)
{
cpuSidePort->sendStatusChange(Port::RangeChange);
}
else
{
memSidePort->sendStatusChange(Port::RangeChange);
}
}
}
virtual Packet *getPacket()
{
fatal("No implementation");
}
virtual Packet *getCoherencePacket()
{
fatal("No implementation");
}
virtual void sendResult(Packet* &pkt, bool success)
{
fatal("No implementation");
}
@ -303,6 +330,8 @@ class BaseCache : public MemObject
memSidePort = NULL;
}
virtual void init();
/**
* Query block size of a cache.
* @return The block size
@ -388,7 +417,6 @@ class BaseCache : public MemObject
if (!isBlockedForSnoop()) {
memSidePort->clearBlocked();
}
}
/**
@ -407,10 +435,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 +493,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 +509,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);
}
/**
@ -496,9 +531,18 @@ class BaseCache : public MemObject
*/
void rangeChange() {}
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
{
panic("Unimplimented\n");
if (isCpuSide)
{
AddrRangeList dummy;
memSidePort->getPeerAddressRanges(resp, dummy);
}
else
{
//This is where snoops get updated
return;
}
}
};

View file

@ -168,14 +168,14 @@ 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?
* @param req The request.
* @param success True if the request was sent successfully.
*/
void sendResult(Packet * &pkt, bool success);
virtual void sendResult(Packet * &pkt, bool success);
/**
* Handles a response (cache line fill/write ack) from the bus.
@ -202,7 +202,7 @@ class Cache : public BaseCache
* Selects a coherence message to forward to lower levels of the hierarchy.
* @return The coherence message to forward.
*/
Packet * getCoherenceReq();
virtual Packet * getCoherencePacket();
/**
* Snoops bus transactions to maintain coherence.
@ -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

@ -350,7 +350,7 @@ Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
template<class TagStore, class Buffering, class Coherence>
Packet *
Cache<TagStore,Buffering,Coherence>::getCoherenceReq()
Cache<TagStore,Buffering,Coherence>::getCoherencePacket()
{
return coherence->getPacket();
}

Some files were not shown because too many files have changed in this diff Show more