Merge zizzer:/bk/newmem
into zeep.pool:/z/saidi/work/m5.newmem.head --HG-- extra : convert_revision : 8c747208d72ffbb0160a2ad4a75383420debdf83
This commit is contained in:
commit
15e5ce96c7
148 changed files with 6416 additions and 1921 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
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(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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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('''
|
||||
|
|
|
@ -140,6 +140,13 @@ 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
|
||||
|
||||
# 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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -112,6 +112,10 @@ namespace AlphaISA
|
|||
lock_flag = 0;
|
||||
lock_addr = 0;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
#if FULL_SYSTEM
|
||||
protected:
|
||||
typedef uint64_t InternalProcReg;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -50,6 +50,9 @@ class MipsLiveProcess : public LiveProcess
|
|||
std::vector<std::string> &envp);
|
||||
|
||||
void startup();
|
||||
|
||||
|
||||
static Addr stack_start;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ SparcSystem::unserialize(Checkpoint *cp, const std::string §ion)
|
|||
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;
|
||||
|
|
|
@ -215,6 +215,11 @@ class TimeBuffer
|
|||
{
|
||||
return wire(this, 0);
|
||||
}
|
||||
|
||||
int getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __BASE_TIMEBUF_HH__
|
||||
|
|
|
@ -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']
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -79,18 +79,6 @@ CpuModel('OzoneCPU', 'ozone_exec.cc',
|
|||
CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
|
||||
'#include "cpu/checker/cpu.hh"',
|
||||
{ 'CPU_exec_context': 'CheckerCPU' })
|
||||
|
||||
# Maybe there is a more clever way to determine ISA
|
||||
# here but since the environment variable isnt passed through
|
||||
# here the easiest way is this...
|
||||
sub_template = 'not found'
|
||||
for argument in sys.argv:
|
||||
if 'ALPHA' in argument:
|
||||
sub_template = 'AlphaDynInst<AlphaSimpleImpl>'
|
||||
|
||||
if sub_template == 'not found':
|
||||
sys.exit('NO CPU_exec_context substitution defined for this ISA')
|
||||
|
||||
CpuModel('O3CPU', 'o3_cpu_exec.cc',
|
||||
'#include "cpu/o3/isa_specific.hh"',
|
||||
{ 'CPU_exec_context': sub_template })
|
||||
{ 'CPU_exec_context': 'O3DynInst' })
|
||||
|
|
|
@ -91,7 +91,10 @@ Param<unsigned> renameWidth;
|
|||
Param<unsigned> commitToIEWDelay;
|
||||
Param<unsigned> renameToIEWDelay;
|
||||
Param<unsigned> issueToExecuteDelay;
|
||||
Param<unsigned> dispatchWidth;
|
||||
Param<unsigned> issueWidth;
|
||||
Param<unsigned> wbWidth;
|
||||
Param<unsigned> wbDepth;
|
||||
SimObjectParam<FUPool *> fuPool;
|
||||
|
||||
Param<unsigned> iewToCommitDelay;
|
||||
|
@ -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;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "cpu/o3/alpha/params.hh"
|
||||
#include "cpu/o3/cpu_policy.hh"
|
||||
|
||||
|
||||
// Forward declarations.
|
||||
template <class Impl>
|
||||
class AlphaDynInst;
|
||||
|
@ -88,7 +89,4 @@ struct AlphaSimpleImpl
|
|||
/** The O3Impl to be used. */
|
||||
typedef AlphaSimpleImpl O3CPUImpl;
|
||||
|
||||
/** The O3Impl to be used. */
|
||||
typedef DynInst O3DynInst;
|
||||
|
||||
#endif // __CPU_O3_ALPHA_IMPL_HH__
|
||||
|
|
|
@ -54,16 +54,7 @@ class AlphaSimpleParams : public O3Params
|
|||
#if FULL_SYSTEM
|
||||
AlphaITB *itb;
|
||||
AlphaDTB *dtb;
|
||||
#else
|
||||
std::vector<Process *> workload;
|
||||
Process *process;
|
||||
#endif // FULL_SYSTEM
|
||||
|
||||
MemObject *mem;
|
||||
|
||||
BaseCPU *checker;
|
||||
|
||||
unsigned decodeToFetchDelay;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // __CPU_O3_ALPHA_PARAMS_HH__
|
||||
|
|
|
@ -70,18 +70,19 @@ class AlphaTC : public O3ThreadContext<Impl>
|
|||
{ panic("Not supported on Alpha!"); }
|
||||
|
||||
|
||||
// This function exits the thread context in the CPU and returns
|
||||
// 1 if the CPU has no more active threads (meaning it's OK to exit);
|
||||
// Used in syscall-emulation mode when a thread executes the 'exit'
|
||||
// syscall.
|
||||
/** This function exits the thread context in the CPU and returns
|
||||
* 1 if the CPU has no more active threads (meaning it's OK to exit);
|
||||
* Used in syscall-emulation mode when a thread executes the 'exit'
|
||||
* syscall.
|
||||
*/
|
||||
virtual int exit()
|
||||
{
|
||||
this->cpu->deallocateContext(this->thread->readTid());
|
||||
this->deallocate();
|
||||
|
||||
// If there are still threads executing in the system
|
||||
if (this->cpu->numActiveThreads())
|
||||
return 0;
|
||||
return 0; // don't exit simulation
|
||||
else
|
||||
return 1;
|
||||
return 1; // exit simulation
|
||||
}
|
||||
};
|
||||
|
|
|
@ -162,10 +162,6 @@ class DefaultCommit
|
|||
/** Sets the pointer to the queue coming from IEW. */
|
||||
void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
|
||||
|
||||
void setFetchStage(Fetch *fetch_stage);
|
||||
|
||||
Fetch *fetchStage;
|
||||
|
||||
/** Sets the pointer to the IEW stage. */
|
||||
void setIEWStage(IEW *iew_stage);
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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,15 +638,18 @@ 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
|
||||
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);
|
||||
|
@ -528,18 +666,12 @@ 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
|
||||
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);
|
||||
|
||||
|
@ -548,7 +680,6 @@ FullO3CPU<Impl>::removeThread(unsigned tid)
|
|||
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 §ion)
|
||||
{
|
||||
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.
|
||||
// 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();
|
||||
assert(system->getMemoryMode() == System::Timing);
|
||||
fetch.resume();
|
||||
decode.resume();
|
||||
rename.resume();
|
||||
iew.resume();
|
||||
commit.resume();
|
||||
|
||||
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();
|
||||
|
||||
changeState(SimObject::Drained);
|
||||
|
||||
if (drainEvent) {
|
||||
drainEvent->process();
|
||||
drainEvent = NULL;
|
||||
}
|
||||
}
|
||||
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(sampler);
|
||||
checker->switchOut();
|
||||
#endif
|
||||
|
||||
if (tickEvent.scheduled())
|
||||
tickEvent.squash();
|
||||
sampler->signalSwitched();
|
||||
_status = SwitchedOut;
|
||||
}
|
||||
assert(switchCount <= 5);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 §ion);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
45
src/cpu/o3/dyn_inst.hh
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2006 The Regents of The University of Michigan
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Korey Sewell
|
||||
*/
|
||||
|
||||
#ifndef __CPU_O3_DYN_INST_HH__
|
||||
#define __CPU_O3_DYN_INST_HH__
|
||||
|
||||
#include "arch/isa_specific.hh"
|
||||
|
||||
#if THE_ISA == ALPHA_ISA
|
||||
template <class Impl>
|
||||
class AlphaDynInst;
|
||||
|
||||
struct AlphaSimpleImpl;
|
||||
|
||||
typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst;
|
||||
#endif
|
||||
|
||||
#endif // __CPU_O3_DYN_INST_HH__
|
|
@ -40,8 +40,6 @@
|
|||
#include "mem/port.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class Sampler;
|
||||
|
||||
/**
|
||||
* DefaultFetch class handles both single threaded and SMT fetch. Its
|
||||
* width is specified by the parameters; each cycle it tries to fetch
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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).
|
||||
memcpy(cacheData[tid], pkt->getPtr<uint8_t *>(), cacheBlkSize);
|
||||
cacheDataValid[tid] = true;
|
||||
|
||||
if (!drainPending) {
|
||||
// Wake up the CPU (if it went to sleep and was waiting on
|
||||
// this completion event).
|
||||
cpu->wakeCPU();
|
||||
|
||||
DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
|
||||
tid);
|
||||
|
||||
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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]++;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 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)
|
||||
|
|
|
@ -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, "
|
||||
|
|
|
@ -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)
|
||||
//
|
||||
|
|
|
@ -86,10 +86,6 @@ class PhysRegFile
|
|||
//The duplication is unfortunate but it's better than having
|
||||
//different ways to access certain registers.
|
||||
|
||||
//Add these in later when everything else is in place
|
||||
// void serialize(std::ostream &os);
|
||||
// void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntReg(PhysRegIndex reg_idx)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -308,7 +308,7 @@ class ROB
|
|||
|
||||
private:
|
||||
/** The sequence number of the squashed instruction. */
|
||||
InstSeqNum squashedSeqNum;
|
||||
InstSeqNum squashedSeqNum[Impl::MaxThreads];
|
||||
|
||||
/** Is the ROB done squashing. */
|
||||
bool doneSquashing[Impl::MaxThreads];
|
||||
|
|
|
@ -41,10 +41,10 @@ ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
|
|||
: numEntries(_numEntries),
|
||||
squashWidth(_squashWidth),
|
||||
numInstsInROB(0),
|
||||
squashedSeqNum(0),
|
||||
numThreads(_numThreads)
|
||||
{
|
||||
for (int tid=0; tid < numThreads; tid++) {
|
||||
squashedSeqNum[tid] = 0;
|
||||
doneSquashing[tid] = true;
|
||||
threadEntries[tid] = 0;
|
||||
}
|
||||
|
@ -352,11 +352,11 @@ void
|
|||
ROB<Impl>::doSquash(unsigned tid)
|
||||
{
|
||||
DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
|
||||
tid, squashedSeqNum);
|
||||
tid, squashedSeqNum[tid]);
|
||||
|
||||
assert(squashIt[tid] != instList[tid].end());
|
||||
|
||||
if ((*squashIt[tid])->seqNum < squashedSeqNum) {
|
||||
if ((*squashIt[tid])->seqNum < squashedSeqNum[tid]) {
|
||||
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
|
||||
tid);
|
||||
|
||||
|
@ -371,7 +371,7 @@ ROB<Impl>::doSquash(unsigned tid)
|
|||
for (int numSquashed = 0;
|
||||
numSquashed < squashWidth &&
|
||||
squashIt[tid] != instList[tid].end() &&
|
||||
(*squashIt[tid])->seqNum > squashedSeqNum;
|
||||
(*squashIt[tid])->seqNum > squashedSeqNum[tid];
|
||||
++numSquashed)
|
||||
{
|
||||
DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
|
||||
|
@ -408,7 +408,7 @@ ROB<Impl>::doSquash(unsigned tid)
|
|||
|
||||
|
||||
// Check if ROB is done squashing.
|
||||
if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
|
||||
if ((*squashIt[tid])->seqNum <= squashedSeqNum[tid]) {
|
||||
DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
|
||||
tid);
|
||||
|
||||
|
@ -520,7 +520,7 @@ ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
|
|||
|
||||
doneSquashing[tid] = false;
|
||||
|
||||
squashedSeqNum = squash_num;
|
||||
squashedSeqNum[tid] = squash_num;
|
||||
|
||||
if (!instList[tid].empty()) {
|
||||
InstIt tail_thread = instList[tid].end();
|
||||
|
@ -544,6 +544,7 @@ ROB<Impl>::readHeadInst()
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template <class Impl>
|
||||
typename Impl::DynInstPtr
|
||||
ROB<Impl>::readHeadInst(unsigned tid)
|
||||
|
@ -558,6 +559,7 @@ ROB<Impl>::readHeadInst(unsigned tid)
|
|||
return dummyInst;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
template <class Impl>
|
||||
uint64_t
|
||||
|
|
|
@ -112,7 +112,7 @@ class O3ThreadContext : public ThreadContext
|
|||
virtual void suspend();
|
||||
|
||||
/** Set the status to Unallocated. */
|
||||
virtual void deallocate();
|
||||
virtual void deallocate(int delay = 0);
|
||||
|
||||
/** Set the status to Halted. */
|
||||
virtual void halt();
|
||||
|
|
|
@ -115,7 +115,8 @@ template <class Impl>
|
|||
void
|
||||
O3ThreadContext<Impl>::activate(int delay)
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling activate on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Active)
|
||||
return;
|
||||
|
@ -139,7 +140,8 @@ template <class Impl>
|
|||
void
|
||||
O3ThreadContext<Impl>::suspend()
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling suspend on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Suspended)
|
||||
return;
|
||||
|
@ -163,22 +165,24 @@ O3ThreadContext<Impl>::suspend()
|
|||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::deallocate()
|
||||
O3ThreadContext<Impl>::deallocate(int delay)
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling deallocate on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling deallocate on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Unallocated)
|
||||
return;
|
||||
|
||||
thread->setStatus(ThreadContext::Unallocated);
|
||||
cpu->deallocateContext(thread->readTid());
|
||||
cpu->deallocateContext(thread->readTid(), delay);
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::halt()
|
||||
{
|
||||
DPRINTF(O3CPU, "Calling halt on AlphaTC\n");
|
||||
DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
|
||||
getThreadNum());
|
||||
|
||||
if (thread->status() == ThreadContext::Halted)
|
||||
return;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -119,6 +119,8 @@ class FrontEnd
|
|||
|
||||
void regStats();
|
||||
|
||||
Port *getIcachePort() { return &icachePort; }
|
||||
|
||||
void tick();
|
||||
Fault fetchCacheLine();
|
||||
void processInst(DynInstPtr &inst);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/exetrace.hh"
|
||||
#include "cpu/ozone/front_end.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/request.hh"
|
||||
|
||||
|
@ -138,10 +139,6 @@ FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
|
|||
|
||||
icachePort.setName(this->name() + "-iport");
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
icachePort.setPeer(mem_dport);
|
||||
mem_dport->setPeer(&icachePort);
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setIcachePort(&icachePort);
|
||||
|
|
|
@ -51,6 +51,8 @@ class ThreadContext;
|
|||
template <class Impl>
|
||||
class OzoneThreadState;
|
||||
|
||||
class Port;
|
||||
|
||||
template <class Impl>
|
||||
class LWBackEnd
|
||||
{
|
||||
|
@ -114,6 +116,8 @@ class LWBackEnd
|
|||
|
||||
void setCommBuffer(TimeBuffer<CommStruct> *_comm);
|
||||
|
||||
Port *getDcachePort() { return LSQ.getDcachePort(); }
|
||||
|
||||
void tick();
|
||||
void squash();
|
||||
void generateTCEvent() { tcSquash = true; }
|
||||
|
|
|
@ -142,7 +142,7 @@ LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst)
|
|||
template <class Impl>
|
||||
LWBackEnd<Impl>::LWBackEnd(Params *params)
|
||||
: d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5),
|
||||
trapSquash(false), tcSquash(false), LSQ(params),
|
||||
trapSquash(false), tcSquash(false),
|
||||
width(params->backEndWidth), exactFullStall(true)
|
||||
{
|
||||
numROBEntries = params->numROBEntries;
|
||||
|
@ -557,6 +557,7 @@ LWBackEnd<Impl>::checkInterrupts()
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
|
@ -580,7 +581,6 @@ LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency)
|
|||
// Generate trap squash event.
|
||||
generateTrapEvent(latency);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
|
@ -602,6 +602,7 @@ LWBackEnd<Impl>::tick()
|
|||
|
||||
#if FULL_SYSTEM
|
||||
checkInterrupts();
|
||||
#endif
|
||||
|
||||
if (trapSquash) {
|
||||
assert(!tcSquash);
|
||||
|
@ -609,7 +610,6 @@ LWBackEnd<Impl>::tick()
|
|||
} else if (tcSquash) {
|
||||
squashFromTC();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dispatchStatus != Blocked) {
|
||||
dispatchInsts();
|
||||
|
@ -1137,13 +1137,9 @@ LWBackEnd<Impl>::commitInst(int inst_num)
|
|||
|
||||
thread->setInst(
|
||||
static_cast<TheISA::MachInst>(inst->staticInst->machInst));
|
||||
#if FULL_SYSTEM
|
||||
|
||||
handleFault(inst_fault);
|
||||
return false;
|
||||
#else // !FULL_SYSTEM
|
||||
panic("fault (%d) detected @ PC %08p", inst_fault,
|
||||
inst->PC);
|
||||
#endif // FULL_SYSTEM
|
||||
}
|
||||
|
||||
int freed_regs = 0;
|
||||
|
|
|
@ -91,8 +91,7 @@ class OzoneLWLSQ {
|
|||
void setBE(BackEnd *be_ptr)
|
||||
{ be = be_ptr; }
|
||||
|
||||
/** Sets the page table pointer. */
|
||||
// void setPageTable(PageTable *pt_ptr);
|
||||
Port *getDcachePort() { return &dcachePort; }
|
||||
|
||||
/** Ticks the LSQ unit, which in this case only resets the number of
|
||||
* used cache ports.
|
||||
|
@ -241,13 +240,11 @@ class OzoneLWLSQ {
|
|||
class DcachePort : public Port
|
||||
{
|
||||
protected:
|
||||
OzoneCPU *cpu;
|
||||
|
||||
OzoneLWLSQ *lsq;
|
||||
|
||||
public:
|
||||
DcachePort(OzoneCPU *_cpu, OzoneLWLSQ *_lsq)
|
||||
: Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
|
||||
DcachePort(OzoneLWLSQ *_lsq)
|
||||
: lsq(_lsq)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
@ -266,11 +263,8 @@ class OzoneLWLSQ {
|
|||
virtual void recvRetry();
|
||||
};
|
||||
|
||||
/** Pointer to the D-cache. */
|
||||
DcachePort *dcachePort;
|
||||
|
||||
/** Pointer to the page table. */
|
||||
// PageTable *pTable;
|
||||
/** D-cache port. */
|
||||
DcachePort dcachePort;
|
||||
|
||||
public:
|
||||
struct SQEntry {
|
||||
|
@ -639,7 +633,7 @@ OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
|
|||
data_pkt->senderState = state;
|
||||
|
||||
// if we have a cache, do cache access too
|
||||
if (!dcachePort->sendTiming(data_pkt)) {
|
||||
if (!dcachePort.sendTiming(data_pkt)) {
|
||||
// There's an older load that's already going to squash.
|
||||
if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
|
||||
return NoFault;
|
||||
|
|
|
@ -131,8 +131,9 @@ OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
|
|||
|
||||
template <class Impl>
|
||||
OzoneLWLSQ<Impl>::OzoneLWLSQ()
|
||||
: switchedOut(false), loads(0), stores(0), storesToWB(0), stalled(false),
|
||||
isStoreBlocked(false), isLoadBlocked(false), loadBlockedHandled(false)
|
||||
: switchedOut(false), dcachePort(this), loads(0), stores(0),
|
||||
storesToWB(0), stalled(false), isStoreBlocked(false),
|
||||
isLoadBlocked(false), loadBlockedHandled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -175,15 +176,11 @@ void
|
|||
OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
|
||||
{
|
||||
cpu = cpu_ptr;
|
||||
dcachePort = new DcachePort(cpu, this);
|
||||
|
||||
Port *mem_dport = mem->getPort("");
|
||||
dcachePort->setPeer(mem_dport);
|
||||
mem_dport->setPeer(dcachePort);
|
||||
dcachePort.setName(this->name() + "-dport");
|
||||
|
||||
#if USE_CHECKER
|
||||
if (cpu->checker) {
|
||||
cpu->checker->setDcachePort(dcachePort);
|
||||
cpu->checker->setDcachePort(&dcachePort);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -614,7 +611,7 @@ OzoneLWLSQ<Impl>::writebackStores()
|
|||
state->noWB = true;
|
||||
}
|
||||
|
||||
if (!dcachePort->sendTiming(data_pkt)) {
|
||||
if (!dcachePort.sendTiming(data_pkt)) {
|
||||
// Need to handle becoming blocked on a store.
|
||||
isStoreBlocked = true;
|
||||
assert(retryPkt == NULL);
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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 §ion);
|
||||
virtual void resume();
|
||||
|
||||
void switchOut();
|
||||
void takeOverFrom(BaseCPU *oldCPU);
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
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();
|
||||
|
||||
delete fetchEvent;
|
||||
}
|
||||
|
||||
void
|
||||
TimingSimpleCPU::setMemoryMode(State new_mode)
|
||||
{
|
||||
assert(new_mode == SimObject::Timing);
|
||||
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
|
||||
|
|
|
@ -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 §ion);
|
||||
|
||||
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__
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
UNSERIALIZE_ENUM(_status);
|
||||
ThreadState::unserialize(cp, section);
|
||||
regs.unserialize(cp, section);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
UNSERIALIZE_SCALAR(funcExeInst);
|
||||
UNSERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick;
|
||||
UNSERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (quiesceEndTick)
|
||||
quiesceEvent->schedule(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->unserialize(cp, section);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
|
|
@ -119,16 +119,20 @@ class SimpleThread : public ThreadState
|
|||
#else
|
||||
SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
|
||||
MemObject *memobj);
|
||||
// Constructor to use SimpleThread to pass reg file around. Not
|
||||
// used for anything else.
|
||||
SimpleThread(RegFile *regFile);
|
||||
#endif
|
||||
|
||||
SimpleThread();
|
||||
|
||||
virtual ~SimpleThread();
|
||||
|
||||
virtual void takeOverFrom(ThreadContext *oldContext);
|
||||
|
||||
void regStats(const std::string &name);
|
||||
|
||||
void copyTC(ThreadContext *context);
|
||||
|
||||
void copyState(ThreadContext *oldContext);
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ class ThreadContext
|
|||
virtual void suspend() = 0;
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
virtual void deallocate() = 0;
|
||||
virtual void deallocate(int delay = 0) = 0;
|
||||
|
||||
/// Set the status to Halted.
|
||||
virtual void halt() = 0;
|
||||
|
@ -318,7 +318,7 @@ class ProxyThreadContext : public ThreadContext
|
|||
void suspend() { actualTC->suspend(); }
|
||||
|
||||
/// Set the status to Unallocated.
|
||||
void deallocate() { actualTC->deallocate(); }
|
||||
void deallocate(int delay = 0) { actualTC->deallocate(); }
|
||||
|
||||
/// Set the status to Halted.
|
||||
void halt() { actualTC->halt(); }
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
#include "base/output.hh"
|
||||
#include "cpu/profile.hh"
|
||||
#include "cpu/thread_state.hh"
|
||||
#include "sim/serialize.hh"
|
||||
|
||||
#if FULL_SYSTEM
|
||||
#include "cpu/quiesce_event.hh"
|
||||
#include "kern/kernel_stats.hh"
|
||||
#endif
|
||||
|
||||
#if FULL_SYSTEM
|
||||
ThreadState::ThreadState(int _cpuId, int _tid)
|
||||
|
@ -49,6 +55,43 @@ ThreadState::ThreadState(int _cpuId, int _tid, Process *_process,
|
|||
numLoad = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ThreadState::serialize(std::ostream &os)
|
||||
{
|
||||
SERIALIZE_ENUM(_status);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
SERIALIZE_SCALAR(funcExeInst);
|
||||
SERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick = 0;
|
||||
if (quiesceEvent->scheduled())
|
||||
quiesceEndTick = quiesceEvent->when();
|
||||
SERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->serialize(os);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ThreadState::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
|
||||
UNSERIALIZE_ENUM(_status);
|
||||
// thread_num and cpu_id are deterministic from the config
|
||||
UNSERIALIZE_SCALAR(funcExeInst);
|
||||
UNSERIALIZE_SCALAR(inst);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Tick quiesceEndTick;
|
||||
UNSERIALIZE_SCALAR(quiesceEndTick);
|
||||
if (quiesceEndTick)
|
||||
quiesceEvent->schedule(quiesceEndTick);
|
||||
if (kernelStats)
|
||||
kernelStats->unserialize(cp, section);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
||||
void
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace Kernel {
|
|||
};
|
||||
#endif
|
||||
|
||||
class Checkpoint;
|
||||
|
||||
/**
|
||||
* Struct for holding general thread state that is needed across CPU
|
||||
* models. This includes things such as pointers to the process,
|
||||
|
@ -65,6 +67,10 @@ struct ThreadState {
|
|||
short _asid, MemObject *mem);
|
||||
#endif
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
void setCpuId(int id) { cpuId = id; }
|
||||
|
||||
int readCpuId() { return cpuId; }
|
||||
|
|
|
@ -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)
|
||||
|
||||
Tick
|
||||
IdeController::writeConfig(Packet *pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::readConfig(offset, data);
|
||||
PciDev::writeConfig(pkt);
|
||||
} 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) {
|
||||
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 = data;
|
||||
config_regs.sidetim = pkt->get<uint8_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_CNTRL:
|
||||
config_regs.udmactl = data;
|
||||
config_regs.udmactl = pkt->get<uint8_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
|
||||
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) | data << 8;
|
||||
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);
|
||||
}
|
||||
|
||||
} 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) {
|
||||
|
||||
offset, (uint32_t)pkt->get<uint8_t>());
|
||||
break;
|
||||
case sizeof(uint16_t):
|
||||
switch (offset) {
|
||||
case IDE_CTRL_CONF_PRIM_TIMING:
|
||||
config_regs.idetim0 = data;
|
||||
config_regs.idetim0 = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_SEC_TIMING:
|
||||
config_regs.idetim1 = data;
|
||||
config_regs.idetim1 = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_UDMA_TIMING:
|
||||
config_regs.udmatim = data;
|
||||
config_regs.udmatim = pkt->get<uint16_t>();
|
||||
break;
|
||||
case IDE_CTRL_CONF_IDE_CONFIG:
|
||||
config_regs.ideconfig = data;
|
||||
config_regs.ideconfig = pkt->get<uint16_t>();
|
||||
break;
|
||||
default:
|
||||
panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
} else {
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
|
||||
offset, (uint32_t)pkt->get<uint16_t>());
|
||||
break;
|
||||
case sizeof(uint32_t):
|
||||
panic("Write of unimplemented PCI config. register: %x\n", offset);
|
||||
break;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
|
||||
|
||||
/* Trap command register writes and enable IO/BM as appropriate. */
|
||||
if (offset == PCI_COMMAND) {
|
||||
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||
io_enabled = true;
|
||||
else
|
||||
io_enabled = false;
|
||||
|
||||
if (letoh(config.command) & PCI_CMD_BME)
|
||||
bm_enabled = true;
|
||||
else
|
||||
bm_enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
IdeController::writeConfig(int offset, const uint32_t data)
|
||||
{
|
||||
if (offset < PCI_DEVICE_SPECIFIC) {
|
||||
PciDev::writeConfig(offset, data);
|
||||
} else {
|
||||
panic("Read of unimplemented PCI config. register: %x\n", offset);
|
||||
}
|
||||
|
||||
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
|
||||
|
||||
/* Trap command register writes and enable IO/BM as appropriate as well as
|
||||
* BARs. */
|
||||
switch(offset) {
|
||||
case PCI0_BASE_ADDR0:
|
||||
if (BARAddrs[0] != 0)
|
||||
|
@ -423,9 +389,24 @@ IdeController::writeConfig(int offset, const uint32_t data)
|
|||
if (BARAddrs[4] != 0)
|
||||
bmi_addr = BARAddrs[4];
|
||||
break;
|
||||
|
||||
case PCI_COMMAND:
|
||||
if (letoh(config.command) & PCI_CMD_IOSE)
|
||||
io_enabled = true;
|
||||
else
|
||||
io_enabled = false;
|
||||
|
||||
if (letoh(config.command) & PCI_CMD_BME)
|
||||
bm_enabled = true;
|
||||
else
|
||||
bm_enabled = false;
|
||||
break;
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
}
|
||||
|
||||
|
||||
Tick
|
||||
IdeController::read(Packet *pkt)
|
||||
{
|
||||
|
@ -770,7 +751,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
|
|||
|
||||
SimObjectParam<System *> system;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<PciConfigAll *> configspace;
|
||||
SimObjectParam<PciConfigData *> configdata;
|
||||
Param<uint32_t> pci_bus;
|
||||
Param<uint32_t> pci_dev;
|
||||
|
@ -784,7 +764,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
|
|||
|
||||
INIT_PARAM(system, "System pointer"),
|
||||
INIT_PARAM(platform, "Platform pointer"),
|
||||
INIT_PARAM(configspace, "PCI Configspace"),
|
||||
INIT_PARAM(configdata, "PCI Config data"),
|
||||
INIT_PARAM(pci_bus, "PCI bus ID"),
|
||||
INIT_PARAM(pci_dev, "PCI device number"),
|
||||
|
@ -800,7 +779,6 @@ CREATE_SIM_OBJECT(IdeController)
|
|||
params->name = getInstanceName();
|
||||
params->platform = platform;
|
||||
params->system = system;
|
||||
params->configSpace = configspace;
|
||||
params->configData = configdata;
|
||||
params->busNum = pci_bus;
|
||||
params->deviceNum = pci_dev;
|
||||
|
|
|
@ -204,12 +204,8 @@ class IdeController : public PciDev
|
|||
IdeController(Params *p);
|
||||
~IdeController();
|
||||
|
||||
virtual void writeConfig(int offset, const uint8_t data);
|
||||
virtual void writeConfig(int offset, const uint16_t data);
|
||||
virtual void writeConfig(int offset, const uint32_t data);
|
||||
virtual void readConfig(int offset, uint8_t *data);
|
||||
virtual void readConfig(int offset, uint16_t *data);
|
||||
virtual void readConfig(int offset, uint32_t *data);
|
||||
virtual Tick writeConfig(Packet *pkt);
|
||||
virtual Tick readConfig(Packet *pkt);
|
||||
|
||||
void setDmaComplete(IdeDisk *disk);
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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,23 +70,29 @@ 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))
|
||||
if (port->transmitList.size() == 0 && port->drainEvent) {
|
||||
port->drainEvent->process();
|
||||
port->drainEvent = NULL;
|
||||
}
|
||||
return;
|
||||
|
||||
port->transmitList.push_back(packet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
PioPort::recvTiming(Packet *pkt)
|
||||
{
|
||||
if (pkt->result == Packet::Nacked) {
|
||||
void
|
||||
PioPort::resendNacked(Packet *pkt) {
|
||||
pkt->reinitNacked();
|
||||
if (transmitList.size()) {
|
||||
transmitList.push_front(pkt);
|
||||
|
@ -92,6 +100,14 @@ PioPort::recvTiming(Packet *pkt)
|
|||
if (!Port::sendTiming(pkt))
|
||||
transmitList.push_front(pkt);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
PioPort::recvTiming(Packet *pkt)
|
||||
{
|
||||
if (pkt->result == Packet::Nacked) {
|
||||
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,6 +277,7 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
|
|||
pendingCount++;
|
||||
sendDma(pkt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -217,9 +287,9 @@ 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;
|
||||
|
||||
if (state == Timing) { */
|
||||
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)) {
|
||||
|
@ -231,28 +301,30 @@ DmaPort::sendDma(Packet *pkt, bool front)
|
|||
} else {
|
||||
DPRINTF(DMA, "-- Done\n");
|
||||
}
|
||||
/* } else if (state == Atomic) {
|
||||
sendAtomic(pkt);
|
||||
if (pkt->senderState) {
|
||||
} else if (state == System::Atomic) {
|
||||
Tick lat;
|
||||
lat = sendAtomic(pkt);
|
||||
assert(pkt->senderState);
|
||||
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
|
||||
assert(state);
|
||||
state->completionEvent->schedule(curTick + (pkt->time -
|
||||
pkt->req->getTime()) +1);
|
||||
|
||||
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->req;
|
||||
delete pkt;
|
||||
|
||||
} else if (state == Functional) {
|
||||
sendFunctional(pkt);
|
||||
// Is this correct???
|
||||
completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime);
|
||||
completionEvent == NULL;
|
||||
if (pendingCount == 0 && drainEvent) {
|
||||
drainEvent->process();
|
||||
drainEvent = NULL;
|
||||
}
|
||||
|
||||
} else
|
||||
panic("Unknown memory command state.");
|
||||
*/
|
||||
}
|
||||
|
||||
DmaDevice::~DmaDevice()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 §ion);
|
||||
|
||||
virtual void resume();
|
||||
|
||||
public:
|
||||
void regStats();
|
||||
|
||||
|
|
|
@ -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>());
|
||||
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>());
|
||||
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>());
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
PciConfigAll::serialize(std::ostream &os)
|
||||
PciConfigAll::addressRanges(AddrRangeList &range_list)
|
||||
{
|
||||
/*
|
||||
* There is no state associated with this object that requires
|
||||
* serialization. The only real state are the device pointers
|
||||
* which are all setup by the constructor of the PciDev class
|
||||
*/
|
||||
range_list.clear();
|
||||
range_list.push_back(RangeSize(pioAddr, params()->size));
|
||||
}
|
||||
|
||||
void
|
||||
PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
{
|
||||
/*
|
||||
* There is no state associated with this object that requires
|
||||
* serialization. The only real state are the device pointers
|
||||
* which are all setup by the constructor of the PciDev class
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
Param<Addr> pio_addr;
|
||||
Param<Tick> pio_latency;
|
||||
Param<int> bus;
|
||||
Param<Addr> size;
|
||||
SimObjectParam<Platform *> platform;
|
||||
SimObjectParam<System *> system;
|
||||
|
||||
|
@ -202,8 +106,9 @@ END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
|
|||
|
||||
BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
|
||||
|
||||
INIT_PARAM(pio_addr, "Device Address"),
|
||||
INIT_PARAM(pio_latency, "Programmed IO latency"),
|
||||
INIT_PARAM(bus, "Bus that this object handles config space for"),
|
||||
INIT_PARAM(size, "The size of config space"),
|
||||
INIT_PARAM(platform, "platform"),
|
||||
INIT_PARAM(system, "system object")
|
||||
|
||||
|
@ -211,11 +116,13 @@ END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
|
|||
|
||||
CREATE_SIM_OBJECT(PciConfigAll)
|
||||
{
|
||||
BasicPioDevice::Params *p = new BasicPioDevice::Params;
|
||||
p->pio_addr = pio_addr;
|
||||
PciConfigAll::Params *p = new PciConfigAll::Params;
|
||||
p->pio_delay = pio_latency;
|
||||
p->platform = platform;
|
||||
p->system = system;
|
||||
p->bus = bus;
|
||||
p->size = size;
|
||||
|
||||
return new PciConfigAll(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,11 +42,6 @@
|
|||
#include "dev/io_device.hh"
|
||||
|
||||
|
||||
static const uint32_t MAX_PCI_DEV = 32;
|
||||
static const uint32_t MAX_PCI_FUNC = 8;
|
||||
|
||||
class PciDev;
|
||||
|
||||
/**
|
||||
* PCI Config Space
|
||||
* All of PCI config space needs to return -1 on Tsunami, except
|
||||
|
@ -54,45 +49,28 @@ class PciDev;
|
|||
* space and passes the requests on to TsunamiPCIDev devices as
|
||||
* appropriate.
|
||||
*/
|
||||
class PciConfigAll : public BasicPioDevice
|
||||
class PciConfigAll : public PioDevice
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Pointers to all the devices that are registered with this
|
||||
* particular config space.
|
||||
*/
|
||||
PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC];
|
||||
|
||||
public:
|
||||
struct Params : public PioDevice::Params
|
||||
{
|
||||
Tick pio_delay;
|
||||
Addr size;
|
||||
int bus;
|
||||
};
|
||||
const Params *params() const { return (const Params *)_params; }
|
||||
|
||||
/**
|
||||
* Constructor for PCIConfigAll
|
||||
* @param p parameters structure
|
||||
*/
|
||||
PciConfigAll(Params *p);
|
||||
|
||||
/**
|
||||
* Check if a device exists.
|
||||
* @param pcidev PCI device to check
|
||||
* @param pcifunc PCI function to check
|
||||
* @return true if device exists, false otherwise
|
||||
*/
|
||||
bool deviceExists(uint32_t pcidev, uint32_t pcifunc)
|
||||
{ return devices[pcidev][pcifunc] != NULL ? true : false; }
|
||||
|
||||
/**
|
||||
* Registers a device with the config space object.
|
||||
* @param pcidev PCI device to register
|
||||
* @param pcifunc PCI function to register
|
||||
* @param device device to register
|
||||
*/
|
||||
void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device)
|
||||
{ devices[pcidev][pcifunc] = device; }
|
||||
|
||||
/**
|
||||
* Read something in PCI config space. If the device does not exist
|
||||
* -1 is returned, if the device does exist its PciDev::ReadConfig (or the
|
||||
* virtual function that overrides) it is called.
|
||||
* @param pkt Contains the address of the field to read.
|
||||
* @param pkt Contains information about the read operation
|
||||
* @return Amount of time to do the read
|
||||
*/
|
||||
virtual Tick read(Packet *pkt);
|
||||
|
@ -101,31 +79,17 @@ class PciConfigAll : public BasicPioDevice
|
|||
* Write to PCI config spcae. If the device does not exit the simulator
|
||||
* panics. If it does it is passed on the PciDev::WriteConfig (or the virtual
|
||||
* function that overrides it).
|
||||
* @param req Contains the address to write to.
|
||||
* @param data The data to write.
|
||||
* @return The fault condition of the access.
|
||||
* @param pkt Contains information about the write operation
|
||||
* @return Amount of time to do the read
|
||||
*/
|
||||
|
||||
virtual Tick write(Packet *pkt);
|
||||
|
||||
/**
|
||||
* Start up function to check if more than one person is using an interrupt line
|
||||
* and print a warning if such a case exists
|
||||
*/
|
||||
virtual void startup();
|
||||
void addressRanges(AddrRangeList &range_list);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
*/
|
||||
virtual void serialize(std::ostream &os);
|
||||
private:
|
||||
Addr pioAddr;
|
||||
|
||||
/**
|
||||
* Reconstruct the state of this object from a checkpoint.
|
||||
* @param cp The checkpoint use.
|
||||
* @param section The section name of this object
|
||||
*/
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
};
|
||||
|
||||
#endif // __PCICONFIGALL_HH__
|
||||
|
|
|
@ -53,9 +53,63 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
|
||||
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
|
||||
int funcid, Platform *p)
|
||||
: PioPort(dev,p->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();
|
||||
|
||||
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,50 +193,22 @@ 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 (pkt->getSize()) {
|
||||
case sizeof(uint8_t):
|
||||
switch (offset) {
|
||||
case PCI0_INTERRUPT_LINE:
|
||||
config.interruptLine = data;
|
||||
config.interruptLine = pkt->get<uint8_t>();
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
config.cacheLineSize = pkt->get<uint8_t>();
|
||||
case PCI_LATENCY_TIMER:
|
||||
config.latencyTimer = data;
|
||||
config.latencyTimer = pkt->get<uint8_t>();
|
||||
break;
|
||||
/* Do nothing for these read-only registers */
|
||||
case PCI0_INTERRUPT_PIN:
|
||||
|
@ -151,42 +220,29 @@ PciDev::writeConfig(int offset, const uint8_t data)
|
|||
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);
|
||||
|
||||
"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 = data;
|
||||
config.command = pkt->get<uint8_t>();
|
||||
case PCI_STATUS:
|
||||
config.status = data;
|
||||
config.status = pkt->get<uint8_t>();
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
config.cacheLineSize = data;
|
||||
config.cacheLineSize = pkt->get<uint8_t>();
|
||||
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);
|
||||
|
||||
"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:
|
||||
|
@ -210,7 +266,7 @@ PciDev::writeConfig(int offset, const uint32_t data)
|
|||
|
||||
// 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) {
|
||||
if (letoh(pkt->get<uint32_t>()) == 0xffffffff) {
|
||||
// This is I/O Space, bottom two bits are read only
|
||||
|
||||
config.baseAddr[barnum] = letoh(
|
||||
|
@ -218,11 +274,11 @@ PciDev::writeConfig(int offset, const uint32_t data)
|
|||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
} else {
|
||||
config.baseAddr[barnum] = letoh(
|
||||
(letoh(data) & ~bar_mask) |
|
||||
(letoh(pkt->get<uint32_t>()) & ~bar_mask) |
|
||||
(letoh(config.baseAddr[barnum]) & bar_mask));
|
||||
|
||||
if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
|
||||
base_addr = (letoh(data) & ~bar_mask) + space_base;
|
||||
base_addr = (letoh(pkt->get<uint32_t>()) & ~bar_mask) + space_base;
|
||||
base_size = BARSize[barnum];
|
||||
BARAddrs[barnum] = base_addr;
|
||||
|
||||
|
@ -232,22 +288,33 @@ PciDev::writeConfig(int offset, const uint32_t data)
|
|||
break;
|
||||
|
||||
case PCI0_ROM_BASE_ADDR:
|
||||
if (letoh(data) == 0xfffffffe)
|
||||
if (letoh(pkt->get<uint32_t>()) == 0xfffffffe)
|
||||
config.expansionROM = htole((uint32_t)0xffffffff);
|
||||
else
|
||||
config.expansionROM = data;
|
||||
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 = data;
|
||||
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;
|
||||
default:
|
||||
panic("invalid access size(?) for PCI configspace!\n");
|
||||
}
|
||||
pkt->result = Packet::Success;
|
||||
return configDelay;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
|
||||
#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
|
||||
|
||||
class PciConfigAll;
|
||||
|
||||
|
||||
/**
|
||||
* This class encapulates the first 64 bytes of a singles PCI
|
||||
|
@ -78,24 +76,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 §ion);
|
||||
|
||||
|
||||
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__
|
||||
|
|
|
@ -142,6 +142,7 @@ union PCIConfig {
|
|||
|
||||
// Device specific offsets
|
||||
#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
|
||||
#define PCI_CONFIG_SIZE 0xFF
|
||||
|
||||
// Some Vendor IDs
|
||||
#define PCI_VENDOR_DEC 0x1011
|
||||
|
|
|
@ -63,5 +63,21 @@ Platform::pciToDma(Addr pciAddr) const
|
|||
panic("No PCI dma support in platform.");
|
||||
}
|
||||
|
||||
void
|
||||
Platform::registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func, uint8_t intr)
|
||||
{
|
||||
uint32_t bdf = bus << 16 | dev << 8 | func << 0;
|
||||
if (pciDevices.find(bdf) != pciDevices.end())
|
||||
fatal("Two PCI devices have same bus:device:function\n");
|
||||
|
||||
if (intLines.test(intr))
|
||||
fatal("Two PCI devices have same interrupt line: %d\n", intr);
|
||||
|
||||
pciDevices.insert(bdf);
|
||||
|
||||
intLines.set(intr);
|
||||
}
|
||||
|
||||
|
||||
DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform)
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
#ifndef __DEV_PLATFORM_HH__
|
||||
#define __DEV_PLATFORM_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <set>
|
||||
|
||||
#include "sim/sim_object.hh"
|
||||
#include "arch/isa_traits.hh"
|
||||
|
||||
|
@ -52,9 +55,6 @@ class Platform : public SimObject
|
|||
/** Pointer to the interrupt controller */
|
||||
IntrControl *intrctrl;
|
||||
|
||||
/** Pointer to the PCI configuration space */
|
||||
PciConfigAll *pciconfig;
|
||||
|
||||
/** Pointer to the UART, set by the uart */
|
||||
Uart *uart;
|
||||
|
||||
|
@ -64,13 +64,20 @@ class Platform : public SimObject
|
|||
public:
|
||||
Platform(const std::string &name, IntrControl *intctrl);
|
||||
virtual ~Platform();
|
||||
virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); }
|
||||
virtual void postConsoleInt() = 0;
|
||||
virtual void clearConsoleInt() = 0;
|
||||
virtual Tick intrFrequency() = 0;
|
||||
virtual void postPciInt(int line);
|
||||
virtual void clearPciInt(int line);
|
||||
virtual Addr pciToDma(Addr pciAddr) const;
|
||||
virtual Addr calcConfigAddr(int bus, int dev, int func) = 0;
|
||||
virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
|
||||
uint8_t intr);
|
||||
|
||||
private:
|
||||
std::bitset<256> intLines;
|
||||
std::set<uint32_t> pciDevices;
|
||||
|
||||
};
|
||||
|
||||
#endif // __DEV_PLATFORM_HH__
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "cpu/intr_control.hh"
|
||||
#include "dev/etherlink.hh"
|
||||
#include "dev/sinic.hh"
|
||||
#include "dev/pciconfigall.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "sim/builder.hh"
|
||||
#include "sim/debug.hh"
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -95,6 +95,13 @@ Tsunami::pciToDma(Addr pciAddr) const
|
|||
return pchip->translatePciToDma(pciAddr);
|
||||
}
|
||||
|
||||
|
||||
Addr
|
||||
Tsunami::calcConfigAddr(int bus, int dev, int func)
|
||||
{
|
||||
return pchip->calcConfigAddr(bus, dev, func);
|
||||
}
|
||||
|
||||
void
|
||||
Tsunami::serialize(std::ostream &os)
|
||||
{
|
||||
|
|
|
@ -113,8 +113,14 @@ class Tsunami : public Platform
|
|||
*/
|
||||
virtual void clearPciInt(int line);
|
||||
|
||||
|
||||
virtual Addr pciToDma(Addr pciAddr) const;
|
||||
|
||||
/**
|
||||
* Calculate the configuration address given a bus/dev/func.
|
||||
*/
|
||||
virtual Addr calcConfigAddr(int bus, int dev, int func);
|
||||
|
||||
/**
|
||||
* Serialize this object to the given output stream.
|
||||
* @param os The stream to serialize to.
|
||||
|
|
|
@ -302,6 +302,17 @@ TsunamiPChip::translatePciToDma(Addr busAddr)
|
|||
// if no match was found, then return the original address
|
||||
return busAddr;
|
||||
}
|
||||
Addr
|
||||
TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
|
||||
{
|
||||
assert(func < 8);
|
||||
assert(dev < 32);
|
||||
assert(bus == 0);
|
||||
|
||||
return TsunamiPciBus0Config | (func << 8) | (dev << 11);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
TsunamiPChip::serialize(std::ostream &os)
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
class TsunamiPChip : public BasicPioDevice
|
||||
{
|
||||
protected:
|
||||
|
||||
static const Addr TsunamiPciBus0Config = 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);
|
||||
|
||||
|
|
|
@ -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,17 +176,29 @@ 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;
|
||||
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 {
|
||||
|
||||
assert((id < interfaces.size() && id >= 0) || id == -1);
|
||||
Port *port = interfaces[id];
|
||||
AddrRangeList ranges;
|
||||
AddrRangeList snoops;
|
||||
AddrRangeIter iter;
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
|
||||
// Clean out any previously existent ids
|
||||
|
@ -189,6 +222,7 @@ Bus::recvStatusChange(Port::Status status, int id)
|
|||
dm.range.start, dm.range.end, id);
|
||||
portList.push_back(dm);
|
||||
}
|
||||
}
|
||||
DPRINTF(MMU, "port list has %d entries\n", portList.size());
|
||||
|
||||
// tell all our peers that our address range has changed.
|
||||
|
@ -196,19 +230,47 @@ Bus::recvStatusChange(Port::Status status, int id)
|
|||
for (x = 0; x < interfaces.size(); x++)
|
||||
if (x != id)
|
||||
interfaces[x]->sendStatusChange(Port::RangeChange);
|
||||
|
||||
if (id != defaultId && defaultPort)
|
||||
defaultPort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
|
||||
void
|
||||
Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
|
||||
{
|
||||
std::vector<DevMap>::iterator portIter;
|
||||
AddrRangeIter dflt_iter;
|
||||
bool subset;
|
||||
|
||||
resp.clear();
|
||||
snoop.clear();
|
||||
|
||||
DPRINTF(BusAddrRanges, "received address range request, returning:\n");
|
||||
|
||||
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
|
||||
dflt_iter++) {
|
||||
resp.push_back(*dflt_iter);
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",dflt_iter->start,
|
||||
dflt_iter->end);
|
||||
}
|
||||
for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
|
||||
if (portIter->portId != id) {
|
||||
subset = false;
|
||||
for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
|
||||
dflt_iter++) {
|
||||
if ((portIter->range.start < dflt_iter->start &&
|
||||
portIter->range.end >= dflt_iter->start) ||
|
||||
(portIter->range.start < dflt_iter->end &&
|
||||
portIter->range.end >= dflt_iter->end))
|
||||
fatal("Devices can not set ranges that itersect the default set\
|
||||
but are not a subset of the default set.\n");
|
||||
if (portIter->range.start >= dflt_iter->start &&
|
||||
portIter->range.end <= dflt_iter->end) {
|
||||
subset = true;
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX is a SUBSET\n",
|
||||
portIter->range.start, portIter->range.end);
|
||||
}
|
||||
}
|
||||
if (portIter->portId != id && !subset) {
|
||||
resp.push_back(portIter->range);
|
||||
DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n",
|
||||
portIter->range.start, portIter->range.end);
|
||||
|
|
|
@ -51,11 +51,14 @@ 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
|
||||
|
@ -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) {}
|
||||
|
||||
};
|
||||
|
||||
|
|
68
src/mem/cache/base_cache.cc
vendored
68
src/mem/cache/base_cache.cc
vendored
|
@ -59,7 +59,7 @@ void
|
|||
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
|
||||
AddrRangeList &snoop)
|
||||
{
|
||||
cache->getAddressRanges(resp, snoop);
|
||||
cache->getAddressRanges(resp, snoop, isCpuSide);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -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()
|
||||
{
|
||||
|
|
70
src/mem/cache/base_cache.hh
vendored
70
src/mem/cache/base_cache.hh
vendored
|
@ -79,9 +79,9 @@ class BaseCache : public MemObject
|
|||
{
|
||||
class CachePort : public Port
|
||||
{
|
||||
public:
|
||||
BaseCache *cache;
|
||||
|
||||
public:
|
||||
CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
|
||||
|
||||
protected:
|
||||
|
@ -110,10 +110,11 @@ class BaseCache : public MemObject
|
|||
|
||||
struct CacheEvent : public Event
|
||||
{
|
||||
Packet *pkt;
|
||||
CachePort *cachePort;
|
||||
Packet *pkt;
|
||||
|
||||
CacheEvent(Packet *pkt, CachePort *cachePort);
|
||||
CacheEvent(CachePort *_cachePort);
|
||||
CacheEvent(CachePort *_cachePort, Packet *_pkt);
|
||||
void process();
|
||||
const char *description();
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
17
src/mem/cache/cache.hh
vendored
17
src/mem/cache/cache.hh
vendored
|
@ -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
|
||||
|
|
2
src/mem/cache/cache_impl.hh
vendored
2
src/mem/cache/cache_impl.hh
vendored
|
@ -350,7 +350,7 @@ Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
|
|||
|
||||
template<class TagStore, class Buffering, class Coherence>
|
||||
Packet *
|
||||
Cache<TagStore,Buffering,Coherence>::getCoherenceReq()
|
||||
Cache<TagStore,Buffering,Coherence>::getCoherencePacket()
|
||||
{
|
||||
return coherence->getPacket();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue