Adding gem5 source to svn.

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1819 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
friemel
2012-10-24 19:18:57 +00:00
parent f7ff71bd46
commit b41eec3f65
3222 changed files with 658579 additions and 1 deletions

View File

@ -0,0 +1,34 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.params import *
from Device import BasicPioDevice
class BadDevice(BasicPioDevice):
type = 'BadDevice'
devicename = Param.String("Name of device to error on")

View File

@ -0,0 +1,60 @@
# Copyright (c) 2008 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: Ali Saidi
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
from Pci import PciDevice
class CopyEngine(PciDevice):
type = 'CopyEngine'
dma = VectorMasterPort("Copy engine DMA port")
VendorID = 0x8086
DeviceID = 0x1a38
Revision = 0xA2 # CM2 stepping (newest listed)
SubsystemID = 0
SubsystemVendorID = 0
Status = 0x0000
SubClassCode = 0x08
ClassCode = 0x80
ProgIF = 0x00
MaximumLatency = 0x00
MinimumGrant = 0xff
InterruptLine = 0x20
InterruptPin = 0x01
BAR0Size = '1kB'
ChanCnt = Param.UInt8(4, "Number of DMA channels that exist on device")
XferCap = Param.MemorySize('4kB', "Number of bits of transfer size that are supported")
clock = Param.Clock('500MHz', "Clock speed of the device")
latBeforeBegin = Param.Latency('20ns', "Latency after a DMA command is seen before it's proccessed")
latAfterCompletion = Param.Latency('20ns', "Latency after a DMA command is complete before it's reported as such")

View File

@ -0,0 +1,73 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.params import *
from m5.proxy import *
from MemObject import MemObject
class PioDevice(MemObject):
type = 'PioDevice'
abstract = True
pio = SlavePort("Programmed I/O port")
system = Param.System(Parent.any, "System this device is part of")
class BasicPioDevice(PioDevice):
type = 'BasicPioDevice'
abstract = True
pio_addr = Param.Addr("Device Address")
pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
class DmaDevice(PioDevice):
type = 'DmaDevice'
abstract = True
dma = MasterPort("DMA port")
min_backoff_delay = Param.Latency('4ns',
"min time between a nack packet being received and the next request made by the device")
max_backoff_delay = Param.Latency('10us',
"max time between a nack packet being received and the next request made by the device")
class IsaFake(BasicPioDevice):
type = 'IsaFake'
pio_size = Param.Addr(0x8, "Size of address range")
ret_data8 = Param.UInt8(0xFF, "Default data to return")
ret_data16 = Param.UInt16(0xFFFF, "Default data to return")
ret_data32 = Param.UInt32(0xFFFFFFFF, "Default data to return")
ret_data64 = Param.UInt64(0xFFFFFFFFFFFFFFFF, "Default data to return")
ret_bad_addr = Param.Bool(False, "Return pkt status bad address on access")
update_data = Param.Bool(False, "Update the data that is returned on writes")
warn_access = Param.String("", "String to print when device is accessed")
fake_mem = Param.Bool(False,
"Is this device acting like a memory and thus may get a cache line sized req")
class BadAddr(IsaFake):
pio_addr = 0
ret_bad_addr = Param.Bool(True, "Return pkt status bad address on access")

View File

@ -0,0 +1,45 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
class DiskImage(SimObject):
type = 'DiskImage'
abstract = True
image_file = Param.String("disk image file")
read_only = Param.Bool(False, "read only image")
class RawDiskImage(DiskImage):
type = 'RawDiskImage'
class CowDiskImage(DiskImage):
type = 'CowDiskImage'
child = Param.DiskImage(RawDiskImage(read_only=True),
"child image")
table_size = Param.Int(65536, "initial table size")
image_file = ""

View File

@ -0,0 +1,213 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
from Pci import PciDevice
class EtherObject(SimObject):
type = 'EtherObject'
abstract = True
class EtherLink(EtherObject):
type = 'EtherLink'
int0 = SlavePort("interface 0")
int1 = SlavePort("interface 1")
delay = Param.Latency('0us', "packet transmit delay")
delay_var = Param.Latency('0ns', "packet transmit delay variability")
speed = Param.NetworkBandwidth('1Gbps', "link speed")
dump = Param.EtherDump(NULL, "dump object")
class EtherBus(EtherObject):
type = 'EtherBus'
loopback = Param.Bool(True, "send packet back to the sending interface")
dump = Param.EtherDump(NULL, "dump object")
speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second")
class EtherTap(EtherObject):
type = 'EtherTap'
bufsz = Param.Int(10000, "tap buffer size")
dump = Param.EtherDump(NULL, "dump object")
port = Param.UInt16(3500, "tap port")
class EtherDump(SimObject):
type = 'EtherDump'
file = Param.String("dump file")
maxlen = Param.Int(96, "max portion of packet data to dump")
class EtherDevice(PciDevice):
type = 'EtherDevice'
abstract = True
interface = MasterPort("Ethernet Interface")
class IGbE(EtherDevice):
# Base class for two IGbE adapters listed above
type = 'IGbE'
hardware_address = Param.EthernetAddr(NextEthernetAddr,
"Ethernet Hardware Address")
use_flow_control = Param.Bool(False,
"Should we use xon/xoff flow contorl (UNIMPLEMENTD)")
rx_fifo_size = Param.MemorySize('384kB', "Size of the rx FIFO")
tx_fifo_size = Param.MemorySize('384kB', "Size of the tx FIFO")
rx_desc_cache_size = Param.Int(64,
"Number of enteries in the rx descriptor cache")
tx_desc_cache_size = Param.Int(64,
"Number of enteries in the rx descriptor cache")
clock = Param.Clock('500MHz', "Clock speed of the device")
VendorID = 0x8086
SubsystemID = 0x1008
SubsystemVendorID = 0x8086
Status = 0x0000
SubClassCode = 0x00
ClassCode = 0x02
ProgIF = 0x00
BAR0 = 0x00000000
BAR1 = 0x00000000
BAR2 = 0x00000000
BAR3 = 0x00000000
BAR4 = 0x00000000
BAR5 = 0x00000000
MaximumLatency = 0x00
MinimumGrant = 0xff
InterruptLine = 0x1e
InterruptPin = 0x01
BAR0Size = '128kB'
wb_delay = Param.Latency('10ns', "delay before desc writeback occurs")
fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs")
fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs")
wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs")
tx_read_delay = Param.Latency('0ns', "delay after tx dma read")
rx_write_delay = Param.Latency('0ns', "delay after rx dma read")
phy_pid = Param.UInt16("Phy PID that corresponds to device ID")
phy_epid = Param.UInt16("Phy EPID that corresponds to device ID")
class IGbE_e1000(IGbE):
# Older Intel 8254x based gigabit ethernet adapter
# Uses Intel e1000 driver
DeviceID = 0x1075
phy_pid = 0x02A8
phy_epid = 0x0380
class IGbE_igb(IGbE):
# Newer Intel 8257x based gigabit ethernet adapter
# Uses Intel igb driver and in theory supports packet splitting and LRO
DeviceID = 0x10C9
phy_pid = 0x0141
phy_epid = 0x0CC0
class EtherDevBase(EtherDevice):
type = 'EtherDevBase'
abstract = True
hardware_address = Param.EthernetAddr(NextEthernetAddr,
"Ethernet Hardware Address")
clock = Param.Clock('0ns', "State machine processor frequency")
dma_read_delay = Param.Latency('0us', "fixed delay for dma reads")
dma_read_factor = Param.Latency('0us', "multiplier for dma reads")
dma_write_delay = Param.Latency('0us', "fixed delay for dma writes")
dma_write_factor = Param.Latency('0us', "multiplier for dma writes")
rx_delay = Param.Latency('1us', "Receive Delay")
tx_delay = Param.Latency('1us', "Transmit Delay")
rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo")
tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo")
rx_filter = Param.Bool(True, "Enable Receive Filter")
intr_delay = Param.Latency('10us', "Interrupt propagation delay")
rx_thread = Param.Bool(False, "dedicated kernel thread for transmit")
tx_thread = Param.Bool(False, "dedicated kernel threads for receive")
rss = Param.Bool(False, "Receive Side Scaling")
class NSGigE(EtherDevBase):
type = 'NSGigE'
dma_data_free = Param.Bool(False, "DMA of Data is free")
dma_desc_free = Param.Bool(False, "DMA of Descriptors is free")
dma_no_allocate = Param.Bool(True, "Should we allocate cache on read")
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 Sinic(EtherDevBase):
type = 'Sinic'
cxx_class = 'Sinic::Device'
rx_max_copy = Param.MemorySize('1514B', "rx max copy")
tx_max_copy = Param.MemorySize('16kB', "tx max copy")
rx_max_intr = Param.UInt32(10, "max rx packets per interrupt")
rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold")
rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold")
tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold")
tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold")
virtual_count = Param.UInt32(1, "Virtualized SINIC")
zero_copy_size = Param.UInt32(64, "Bytes to copy if below threshold")
zero_copy_threshold = Param.UInt32(256,
"Only zero copy above this threshold")
zero_copy = Param.Bool(False, "Zero copy receive")
delay_copy = Param.Bool(False, "Delayed copy transmit")
virtual_addr = Param.Bool(False, "Virtual addressing")
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'

View File

@ -0,0 +1,68 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from Pci import PciDevice
class IdeID(Enum): vals = ['master', 'slave']
class IdeDisk(SimObject):
type = 'IdeDisk'
delay = Param.Latency('1us', "Fixed disk delay in microseconds")
driveID = Param.IdeID('master', "Drive ID")
image = Param.DiskImage("Disk image")
class IdeController(PciDevice):
type = 'IdeController'
disks = VectorParam.IdeDisk("IDE disks attached to this controller")
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'
io_shift = Param.UInt32(0x0, "IO port shift");
ctrl_offset = Param.UInt32(0x0, "IDE disk control offset")

View File

@ -0,0 +1,94 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice, DmaDevice, PioDevice
class PciConfigAll(PioDevice):
type = 'PciConfigAll'
platform = Param.Platform(Parent.any, "Platform this device is part of.")
pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
bus = Param.UInt8(0x00, "PCI bus to act as config space for")
size = Param.MemorySize32('16MB', "Size of config space")
class PciDevice(DmaDevice):
type = 'PciDevice'
abstract = True
platform = Param.Platform(Parent.any, "Platform this device is part of.")
config = SlavePort("PCI configuration space port")
pci_bus = Param.Int("PCI bus")
pci_dev = Param.Int("PCI device number")
pci_func = Param.Int("PCI function code")
pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
config_latency = Param.Latency('20ns', "Config read or write latency")
VendorID = Param.UInt16("Vendor ID")
DeviceID = Param.UInt16("Device ID")
Command = Param.UInt16(0, "Command")
Status = Param.UInt16(0, "Status")
Revision = Param.UInt8(0, "Device")
ProgIF = Param.UInt8(0, "Programming Interface")
SubClassCode = Param.UInt8(0, "Sub-Class Code")
ClassCode = Param.UInt8(0, "Class Code")
CacheLineSize = Param.UInt8(0, "System Cacheline Size")
LatencyTimer = Param.UInt8(0, "PCI Latency Timer")
HeaderType = Param.UInt8(0, "PCI Header Type")
BIST = Param.UInt8(0, "Built In Self Test")
BAR0 = Param.UInt32(0x00, "Base Address Register 0")
BAR1 = Param.UInt32(0x00, "Base Address Register 1")
BAR2 = Param.UInt32(0x00, "Base Address Register 2")
BAR3 = Param.UInt32(0x00, "Base Address Register 3")
BAR4 = Param.UInt32(0x00, "Base Address Register 4")
BAR5 = Param.UInt32(0x00, "Base Address Register 5")
BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size")
BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size")
BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size")
BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size")
BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size")
BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size")
BAR0LegacyIO = Param.Bool(False, "Whether BAR0 is hardwired legacy IO")
BAR1LegacyIO = Param.Bool(False, "Whether BAR1 is hardwired legacy IO")
BAR2LegacyIO = Param.Bool(False, "Whether BAR2 is hardwired legacy IO")
BAR3LegacyIO = Param.Bool(False, "Whether BAR3 is hardwired legacy IO")
BAR4LegacyIO = Param.Bool(False, "Whether BAR4 is hardwired legacy IO")
BAR5LegacyIO = Param.Bool(False, "Whether BAR5 is hardwired legacy IO")
CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure")
SubsystemID = Param.UInt16(0x00, "Subsystem ID")
SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID")
ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address")
InterruptLine = Param.UInt8(0x00, "Interrupt Line")
InterruptPin = Param.UInt8(0x00, "Interrupt Pin")
MaximumLatency = Param.UInt8(0x00, "Maximum Latency")
MinimumGrant = Param.UInt8(0x00, "Minimum Grant")

View File

@ -0,0 +1,35 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
class Platform(SimObject):
type = 'Platform'
abstract = True
intrctrl = Param.IntrControl(Parent.any, "interrupt controller")

View File

@ -0,0 +1,111 @@
# -*- mode:python -*-
# 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: Steve Reinhardt
# Gabe Black
Import('*')
if env['TARGET_ISA'] == 'no':
Return()
SimObject('BadDevice.py')
SimObject('CopyEngine.py')
SimObject('Device.py')
SimObject('DiskImage.py')
SimObject('Ethernet.py')
SimObject('Ide.py')
SimObject('Pci.py')
SimObject('Platform.py')
SimObject('SimpleDisk.py')
SimObject('Terminal.py')
SimObject('Uart.py')
Source('baddev.cc')
Source('copy_engine.cc')
Source('disk_image.cc')
Source('dma_device.cc')
Source('etherbus.cc')
Source('etherdevice.cc')
Source('etherdump.cc')
Source('etherint.cc')
Source('etherlink.cc')
Source('etherpkt.cc')
Source('ethertap.cc')
Source('i8254xGBe.cc')
Source('ide_ctrl.cc')
Source('ide_disk.cc')
Source('intel_8254_timer.cc')
Source('io_device.cc')
Source('isa_fake.cc')
Source('mc146818.cc')
Source('ns_gige.cc')
Source('pciconfigall.cc')
Source('pcidev.cc')
Source('pktfifo.cc')
Source('platform.cc')
Source('ps2.cc')
Source('simple_disk.cc')
Source('sinic.cc')
Source('terminal.cc')
Source('uart.cc')
Source('uart8250.cc')
DebugFlag('DiskImageRead')
DebugFlag('DiskImageWrite')
DebugFlag('DMA')
DebugFlag('DMACopyEngine')
DebugFlag('Ethernet')
DebugFlag('EthernetCksum')
DebugFlag('EthernetDMA')
DebugFlag('EthernetData')
DebugFlag('EthernetDesc')
DebugFlag('EthernetEEPROM')
DebugFlag('EthernetIntr')
DebugFlag('EthernetPIO')
DebugFlag('EthernetSM')
DebugFlag('IdeCtrl')
DebugFlag('IdeDisk')
DebugFlag('Intel8254Timer')
DebugFlag('IsaFake')
DebugFlag('MC146818')
DebugFlag('PCIDEV')
DebugFlag('PciConfigAll')
DebugFlag('SimpleDisk')
DebugFlag('SimpleDiskData')
DebugFlag('Terminal')
DebugFlag('TerminalVerbose')
DebugFlag('Uart')
CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
'EthernetCksum', 'EthernetEEPROM' ])
CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])

View File

@ -0,0 +1,35 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
class SimpleDisk(SimObject):
type = 'SimpleDisk'
disk = Param.DiskImage("Disk Image")
system = Param.System(Parent.any, "System Pointer")

View File

@ -0,0 +1,38 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
class Terminal(SimObject):
type = 'Terminal'
intr_control = Param.IntrControl(Parent.any, "interrupt controller")
port = Param.TcpPort(3456, "listen port")
number = Param.Int(0, "terminal number")
output = Param.Bool(True, "Enable output dump to file")

View File

@ -0,0 +1,40 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
class Uart(BasicPioDevice):
type = 'Uart'
abstract = True
platform = Param.Platform(Parent.any, "Platform this device is part of.")
terminal = Param.Terminal(Parent.any, "The terminal")
class Uart8250(Uart):
type = 'Uart8250'

View File

@ -0,0 +1,40 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.defines import buildEnv
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
class AlphaBackdoor(BasicPioDevice):
type = 'AlphaBackdoor'
cpu = Param.BaseCPU(Parent.cpu[0], "Processor")
disk = Param.SimpleDisk("Simple Disk")
terminal = Param.Terminal(Parent.any, "The console terminal")
platform = Param.Platform(Parent.any, "Platform this device is part of.")
system = Param.AlphaSystem(Parent.any, "system object")

View File

@ -0,0 +1,45 @@
# -*- mode:python -*-
# 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: Steve Reinhardt
# Gabe Black
Import('*')
if env['TARGET_ISA'] == 'alpha':
SimObject('AlphaBackdoor.py')
SimObject('Tsunami.py')
Source('backdoor.cc')
Source('tsunami.cc')
Source('tsunami_cchip.cc')
Source('tsunami_io.cc')
Source('tsunami_pchip.cc')
DebugFlag('AlphaBackdoor')
DebugFlag('Tsunami')

View File

@ -0,0 +1,122 @@
# Copyright (c) 2005-2007 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Nathan Binkert
from m5.params import *
from m5.proxy import *
from BadDevice import BadDevice
from AlphaBackdoor import AlphaBackdoor
from Device import BasicPioDevice, IsaFake, BadAddr
from Pci import PciConfigAll
from Platform import Platform
from Uart import Uart8250
class TsunamiCChip(BasicPioDevice):
type = 'TsunamiCChip'
tsunami = Param.Tsunami(Parent.any, "Tsunami")
class TsunamiIO(BasicPioDevice):
type = 'TsunamiIO'
time = Param.Time('01/01/2009',
"System time to use ('Now' for actual time)")
year_is_bcd = Param.Bool(False,
"The RTC should interpret the year as a BCD value")
tsunami = Param.Tsunami(Parent.any, "Tsunami")
frequency = Param.Frequency('1024Hz', "frequency of interrupts")
class TsunamiPChip(BasicPioDevice):
type = 'TsunamiPChip'
tsunami = Param.Tsunami(Parent.any, "Tsunami")
class Tsunami(Platform):
type = 'Tsunami'
system = Param.System(Parent.any, "system")
cchip = TsunamiCChip(pio_addr=0x801a0000000)
pchip = TsunamiPChip(pio_addr=0x80180000000)
pciconfig = PciConfigAll()
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=0x801fc0003bb)
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)
backdoor = AlphaBackdoor(pio_addr=0x80200000000, disk=Parent.simple_disk)
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
self.cchip.pio = bus.master
self.pchip.pio = bus.master
self.pciconfig.pio = bus.default
bus.use_default_range = True
self.fake_sm_chip.pio = bus.master
self.fake_uart1.pio = bus.master
self.fake_uart2.pio = bus.master
self.fake_uart3.pio = bus.master
self.fake_uart4.pio = bus.master
self.fake_ppc.pio = bus.master
self.fake_OROM.pio = bus.master
self.fake_pnp_addr.pio = bus.master
self.fake_pnp_write.pio = bus.master
self.fake_pnp_read0.pio = bus.master
self.fake_pnp_read1.pio = bus.master
self.fake_pnp_read2.pio = bus.master
self.fake_pnp_read3.pio = bus.master
self.fake_pnp_read4.pio = bus.master
self.fake_pnp_read5.pio = bus.master
self.fake_pnp_read6.pio = bus.master
self.fake_pnp_read7.pio = bus.master
self.fake_ata0.pio = bus.master
self.fake_ata1.pio = bus.master
self.fb.pio = bus.master
self.io.pio = bus.master
self.uart.pio = bus.master
self.backdoor.pio = bus.master

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
#ifndef __ALPHA_ACCESS_H__
#define __ALPHA_ACCESS_H__
/** @file
* System Console Memory Mapped Register Definition
*/
#define ALPHA_ACCESS_VERSION (1305)
#ifdef CONSOLE
typedef unsigned uint32_t;
typedef unsigned long uint64_t;
#endif
// This structure hacked up from simos
struct AlphaAccess
{
uint32_t last_offset; // 00: must be first field
uint32_t version; // 04:
uint32_t numCPUs; // 08:
uint32_t intrClockFrequency; // 0C: Hz
uint64_t cpuClock; // 10: MHz
uint64_t mem_size; // 18:
// Loaded kernel
uint64_t kernStart; // 20:
uint64_t kernEnd; // 28:
uint64_t entryPoint; // 30:
// console disk stuff
uint64_t diskUnit; // 38:
uint64_t diskCount; // 40:
uint64_t diskPAddr; // 48:
uint64_t diskBlock; // 50:
uint64_t diskOperation; // 58:
// console simple output stuff
uint64_t outputChar; // 60: Placeholder for output
uint64_t inputChar; // 68: Placeholder for input
// MP boot
uint64_t cpuStack[64]; // 70:
};
#endif // __ALPHA_ACCESS_H__

View File

@ -0,0 +1,317 @@
/*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Ali Saidi
* Steve Reinhardt
* Erik Hallnor
*/
/** @file
* Alpha Console Backdoor Definition
*/
#include <cstddef>
#include <string>
#include "arch/alpha/system.hh"
#include "base/inifile.hh"
#include "base/str.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "debug/AlphaBackdoor.hh"
#include "dev/alpha/backdoor.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/platform.hh"
#include "dev/simple_disk.hh"
#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
#include "params/AlphaBackdoor.hh"
#include "sim/sim_object.hh"
using namespace std;
using namespace AlphaISA;
AlphaBackdoor::AlphaBackdoor(const Params *p)
: BasicPioDevice(p), disk(p->disk), terminal(p->terminal),
system(p->system), cpu(p->cpu)
{
pioSize = sizeof(struct AlphaAccess);
alphaAccess = new Access();
alphaAccess->last_offset = pioSize - 1;
alphaAccess->version = ALPHA_ACCESS_VERSION;
alphaAccess->diskUnit = 1;
alphaAccess->diskCount = 0;
alphaAccess->diskPAddr = 0;
alphaAccess->diskBlock = 0;
alphaAccess->diskOperation = 0;
alphaAccess->outputChar = 0;
alphaAccess->inputChar = 0;
std::memset(alphaAccess->cpuStack, 0, sizeof(alphaAccess->cpuStack));
}
void
AlphaBackdoor::startup()
{
system->setAlphaAccess(pioAddr);
alphaAccess->numCPUs = system->numContexts();
alphaAccess->kernStart = system->getKernelStart();
alphaAccess->kernEnd = system->getKernelEnd();
alphaAccess->entryPoint = system->getKernelEntry();
alphaAccess->mem_size = system->memSize();
alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz
Tsunami *tsunami = dynamic_cast<Tsunami *>(params()->platform);
if (!tsunami)
fatal("Platform is not Tsunami.\n");
alphaAccess->intrClockFrequency = tsunami->io->frequency();
}
Tick
AlphaBackdoor::read(PacketPtr pkt)
{
/** XXX Do we want to push the addr munging to a bus brige or something? So
* the device has it's physical address and then the bridge adds on whatever
* machine dependent address swizzle is required?
*/
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
pkt->makeAtomicResponse();
switch (pkt->getSize())
{
case sizeof(uint32_t):
switch (daddr)
{
case offsetof(AlphaAccess, last_offset):
pkt->set(alphaAccess->last_offset);
break;
case offsetof(AlphaAccess, version):
pkt->set(alphaAccess->version);
break;
case offsetof(AlphaAccess, numCPUs):
pkt->set(alphaAccess->numCPUs);
break;
case offsetof(AlphaAccess, intrClockFrequency):
pkt->set(alphaAccess->intrClockFrequency);
break;
default:
/* Old console code read in everyting as a 32bit int
* we now break that for better error checking.
*/
pkt->setBadAddress();
}
DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr,
pkt->get<uint32_t>());
break;
case sizeof(uint64_t):
switch (daddr)
{
case offsetof(AlphaAccess, inputChar):
pkt->set(terminal->console_in());
break;
case offsetof(AlphaAccess, cpuClock):
pkt->set(alphaAccess->cpuClock);
break;
case offsetof(AlphaAccess, mem_size):
pkt->set(alphaAccess->mem_size);
break;
case offsetof(AlphaAccess, kernStart):
pkt->set(alphaAccess->kernStart);
break;
case offsetof(AlphaAccess, kernEnd):
pkt->set(alphaAccess->kernEnd);
break;
case offsetof(AlphaAccess, entryPoint):
pkt->set(alphaAccess->entryPoint);
break;
case offsetof(AlphaAccess, diskUnit):
pkt->set(alphaAccess->diskUnit);
break;
case offsetof(AlphaAccess, diskCount):
pkt->set(alphaAccess->diskCount);
break;
case offsetof(AlphaAccess, diskPAddr):
pkt->set(alphaAccess->diskPAddr);
break;
case offsetof(AlphaAccess, diskBlock):
pkt->set(alphaAccess->diskBlock);
break;
case offsetof(AlphaAccess, diskOperation):
pkt->set(alphaAccess->diskOperation);
break;
case offsetof(AlphaAccess, outputChar):
pkt->set(alphaAccess->outputChar);
break;
default:
int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) /
sizeof(alphaAccess->cpuStack[0]);
if (cpunum >= 0 && cpunum < 64)
pkt->set(alphaAccess->cpuStack[cpunum]);
else
panic("Unknown 64bit access, %#x\n", daddr);
}
DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr,
pkt->get<uint64_t>());
break;
default:
pkt->setBadAddress();
}
return pioDelay;
}
Tick
AlphaBackdoor::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
uint64_t val = pkt->get<uint64_t>();
assert(pkt->getSize() == sizeof(uint64_t));
switch (daddr) {
case offsetof(AlphaAccess, diskUnit):
alphaAccess->diskUnit = val;
break;
case offsetof(AlphaAccess, diskCount):
alphaAccess->diskCount = val;
break;
case offsetof(AlphaAccess, diskPAddr):
alphaAccess->diskPAddr = val;
break;
case offsetof(AlphaAccess, diskBlock):
alphaAccess->diskBlock = val;
break;
case offsetof(AlphaAccess, diskOperation):
if (val == 0x13)
disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
alphaAccess->diskCount);
else
panic("Invalid disk operation!");
break;
case offsetof(AlphaAccess, outputChar):
terminal->out((char)(val & 0xff));
break;
default:
int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) /
sizeof(alphaAccess->cpuStack[0]);
inform("Launching CPU %d @ %d", cpunum, curTick());
assert(val > 0 && "Must not access primary cpu");
if (cpunum >= 0 && cpunum < 64)
alphaAccess->cpuStack[cpunum] = val;
else
panic("Unknown 64bit access, %#x\n", daddr);
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
AlphaBackdoor::Access::serialize(ostream &os)
{
SERIALIZE_SCALAR(last_offset);
SERIALIZE_SCALAR(version);
SERIALIZE_SCALAR(numCPUs);
SERIALIZE_SCALAR(mem_size);
SERIALIZE_SCALAR(cpuClock);
SERIALIZE_SCALAR(intrClockFrequency);
SERIALIZE_SCALAR(kernStart);
SERIALIZE_SCALAR(kernEnd);
SERIALIZE_SCALAR(entryPoint);
SERIALIZE_SCALAR(diskUnit);
SERIALIZE_SCALAR(diskCount);
SERIALIZE_SCALAR(diskPAddr);
SERIALIZE_SCALAR(diskBlock);
SERIALIZE_SCALAR(diskOperation);
SERIALIZE_SCALAR(outputChar);
SERIALIZE_SCALAR(inputChar);
SERIALIZE_ARRAY(cpuStack,64);
}
void
AlphaBackdoor::Access::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(last_offset);
UNSERIALIZE_SCALAR(version);
UNSERIALIZE_SCALAR(numCPUs);
UNSERIALIZE_SCALAR(mem_size);
UNSERIALIZE_SCALAR(cpuClock);
UNSERIALIZE_SCALAR(intrClockFrequency);
UNSERIALIZE_SCALAR(kernStart);
UNSERIALIZE_SCALAR(kernEnd);
UNSERIALIZE_SCALAR(entryPoint);
UNSERIALIZE_SCALAR(diskUnit);
UNSERIALIZE_SCALAR(diskCount);
UNSERIALIZE_SCALAR(diskPAddr);
UNSERIALIZE_SCALAR(diskBlock);
UNSERIALIZE_SCALAR(diskOperation);
UNSERIALIZE_SCALAR(outputChar);
UNSERIALIZE_SCALAR(inputChar);
UNSERIALIZE_ARRAY(cpuStack, 64);
}
void
AlphaBackdoor::serialize(ostream &os)
{
alphaAccess->serialize(os);
}
void
AlphaBackdoor::unserialize(Checkpoint *cp, const std::string &section)
{
alphaAccess->unserialize(cp, section);
}
AlphaBackdoor *
AlphaBackdoorParams::create()
{
return new AlphaBackdoor(this);
}

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/** @file
* System Console Backdoor Interface
*/
#ifndef __DEV_ALPHA_BACKDOOR_HH__
#define __DEV_ALPHA_BACKDOOR_HH__
#include "base/range.hh"
#include "base/types.hh"
#include "dev/alpha/access.h"
#include "dev/io_device.hh"
#include "params/AlphaBackdoor.hh"
#include "sim/sim_object.hh"
class BaseCPU;
class Terminal;
class AlphaSystem;
class SimpleDisk;
/**
* Memory mapped interface to the system console. This device
* represents a shared data region between the OS Kernel and the
* System Console Backdoor.
*
* The system console is a small standalone program that is initially
* run when the system boots. It contains the necessary code to
* access the boot disk, to read/write from the console, and to pass
* boot parameters to the kernel.
*
* This version of the system console is very different from the one
* that would be found in a real system. Many of the functions use
* some sort of backdoor to get their job done. For example, reading
* from the boot device on a real system would require a minimal
* device driver to access the disk controller, but since we have a
* simulator here, we are able to bypass the disk controller and
* access the disk image directly. There are also some things like
* reading the kernel off the disk image into memory that are normally
* taken care of by the console that are now taken care of by the
* simulator.
*
* These shortcuts are acceptable since the system console is
* primarily used doing boot before the kernel has loaded its device
* drivers.
*/
class AlphaBackdoor : public BasicPioDevice
{
protected:
struct Access : public AlphaAccess
{
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
};
union {
Access *alphaAccess;
uint8_t *consoleData;
};
/** the disk must be accessed from the console */
SimpleDisk *disk;
/** the system console (the terminal) is accessable from the console */
Terminal *terminal;
/** a pointer to the system we are running in */
AlphaSystem *system;
/** a pointer to the CPU boot cpu */
BaseCPU *cpu;
public:
typedef AlphaBackdoorParams Params;
AlphaBackdoor(const Params *p);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual void startup();
/**
* memory mapped reads and writes
*/
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* standard serialization routines for checkpointing
*/
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ALPHA_BACKDOOR_HH__

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Implementation of Tsunami platform.
*/
#include <deque>
#include <string>
#include <vector>
#include "arch/alpha/system.hh"
#include "config/the_isa.hh"
#include "cpu/intr_control.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/alpha/tsunami_pchip.hh"
#include "dev/terminal.hh"
using namespace std;
//Should this be AlphaISA?
using namespace TheISA;
Tsunami::Tsunami(const Params *p)
: Platform(p), system(p->system)
{
for (int i = 0; i < Tsunami::Max_CPUs; i++)
intr_sum_type[i] = 0;
}
void
Tsunami::init()
{
AlphaSystem *alphaSystem = dynamic_cast<AlphaSystem *>(system);
assert(alphaSystem);
alphaSystem->setIntrFreq(io->frequency());
}
void
Tsunami::postConsoleInt()
{
io->postPIC(0x10);
}
void
Tsunami::clearConsoleInt()
{
io->clearPIC(0x10);
}
void
Tsunami::postPciInt(int line)
{
cchip->postDRIR(line);
}
void
Tsunami::clearPciInt(int line)
{
cchip->clearDRIR(line);
}
Addr
Tsunami::pciToDma(Addr pciAddr) const
{
return pchip->translatePciToDma(pciAddr);
}
Addr
Tsunami::calcPciConfigAddr(int bus, int dev, int func)
{
return pchip->calcConfigAddr(bus, dev, func);
}
Addr
Tsunami::calcPciIOAddr(Addr addr)
{
return pchip->calcIOAddr(addr);
}
Addr
Tsunami::calcPciMemAddr(Addr addr)
{
return pchip->calcMemAddr(addr);
}
void
Tsunami::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
}
void
Tsunami::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
}
Tsunami *
TsunamiParams::create()
{
return new Tsunami(this);
}

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/**
* @file
* Declaration of top level class for the Tsunami chipset. This class just
* retains pointers to all its children so the children can communicate.
*/
#ifndef __DEV_TSUNAMI_HH__
#define __DEV_TSUNAMI_HH__
#include "dev/platform.hh"
#include "params/Tsunami.hh"
class IdeController;
class TsunamiCChip;
class TsunamiPChip;
class TsunamiIO;
class System;
/**
* Top level class for Tsunami Chipset emulation.
* This structure just contains pointers to all the
* children so the children can commnicate to do the
* read work
*/
class Tsunami : public Platform
{
public:
/** Max number of CPUs in a Tsunami */
static const int Max_CPUs = 64;
/** Pointer to the system */
System *system;
/** Pointer to the TsunamiIO device which has the RTC */
TsunamiIO *io;
/** Pointer to the Tsunami CChip.
* The chip contains some configuration information and
* all the interrupt mask and status registers
*/
TsunamiCChip *cchip;
/** Pointer to the Tsunami PChip.
* The pchip is the interface to the PCI bus, in our case
* it does not have to do much.
*/
TsunamiPChip *pchip;
int intr_sum_type[Tsunami::Max_CPUs];
int ipi_pending[Tsunami::Max_CPUs];
void init();
public:
typedef TsunamiParams Params;
Tsunami(const Params *p);
/**
* Cause the cpu to post a serial interrupt to the CPU.
*/
virtual void postConsoleInt();
/**
* Clear a posted CPU interrupt (id=55)
*/
virtual void clearConsoleInt();
/**
* Cause the chipset to post a cpi interrupt to the CPU.
*/
virtual void postPciInt(int line);
/**
* Clear a posted PCI->CPU interrupt
*/
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
/**
* Calculate the configuration address given a bus/dev/func.
*/
virtual Addr calcPciConfigAddr(int bus, int dev, int func);
/**
* Calculate the address for an IO location on the PCI bus.
*/
virtual Addr calcPciIOAddr(Addr addr);
/**
* Calculate the address for a memory location on the PCI bus.
*/
virtual Addr calcPciMemAddr(Addr addr);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_TSUNAMI_HH__

View File

@ -0,0 +1,536 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Ron Dreslinski
*/
/** @file
* Emulation of the Tsunami CChip CSRs
*/
#include <deque>
#include <string>
#include <vector>
#include "arch/alpha/ev5.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "cpu/intr_control.hh"
#include "cpu/thread_context.hh"
#include "debug/IPI.hh"
#include "debug/Tsunami.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunamireg.h"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/port.hh"
#include "params/TsunamiCChip.hh"
#include "sim/system.hh"
//Should this be AlphaISA?
using namespace TheISA;
TsunamiCChip::TsunamiCChip(const Params *p)
: BasicPioDevice(p), tsunami(p->tsunami)
{
pioSize = 0x10000000;
drir = 0;
ipint = 0;
itint = 0;
for (int x = 0; x < Tsunami::Max_CPUs; x++)
{
dim[x] = 0;
dir[x] = 0;
}
//Put back pointer in tsunami
tsunami->cchip = this;
}
Tick
TsunamiCChip::read(PacketPtr pkt)
{
DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr regnum = (pkt->getAddr() - pioAddr) >> 6;
Addr daddr = (pkt->getAddr() - pioAddr);
pkt->allocate();
switch (pkt->getSize()) {
case sizeof(uint64_t):
pkt->set<uint64_t>(0);
if (daddr & TSDEV_CC_BDIMS)
{
pkt->set(dim[(daddr >> 4) & 0x3F]);
break;
}
if (daddr & TSDEV_CC_BDIRS)
{
pkt->set(dir[(daddr >> 4) & 0x3F]);
break;
}
switch(regnum) {
case TSDEV_CC_CSR:
pkt->set(0x0);
break;
case TSDEV_CC_MTR:
panic("TSDEV_CC_MTR not implemeted\n");
break;
case TSDEV_CC_MISC:
pkt->set(((ipint << 8) & 0xF) | ((itint << 4) & 0xF) |
(pkt->req->contextId() & 0x3));
// currently, FS cannot handle MT so contextId and
// cpuId are effectively the same, don't know if it will
// matter if FS becomes MT enabled. I suspect no because
// we are currently able to boot up to 64 procs anyway
// which would render the CPUID of this register useless
// anyway
break;
case TSDEV_CC_AAR0:
case TSDEV_CC_AAR1:
case TSDEV_CC_AAR2:
case TSDEV_CC_AAR3:
pkt->set(0);
break;
case TSDEV_CC_DIM0:
pkt->set(dim[0]);
break;
case TSDEV_CC_DIM1:
pkt->set(dim[1]);
break;
case TSDEV_CC_DIM2:
pkt->set(dim[2]);
break;
case TSDEV_CC_DIM3:
pkt->set(dim[3]);
break;
case TSDEV_CC_DIR0:
pkt->set(dir[0]);
break;
case TSDEV_CC_DIR1:
pkt->set(dir[1]);
break;
case TSDEV_CC_DIR2:
pkt->set(dir[2]);
break;
case TSDEV_CC_DIR3:
pkt->set(dir[3]);
break;
case TSDEV_CC_DRIR:
pkt->set(drir);
break;
case TSDEV_CC_PRBEN:
panic("TSDEV_CC_PRBEN not implemented\n");
break;
case TSDEV_CC_IIC0:
case TSDEV_CC_IIC1:
case TSDEV_CC_IIC2:
case TSDEV_CC_IIC3:
panic("TSDEV_CC_IICx not implemented\n");
break;
case TSDEV_CC_MPR0:
case TSDEV_CC_MPR1:
case TSDEV_CC_MPR2:
case TSDEV_CC_MPR3:
panic("TSDEV_CC_MPRx not implemented\n");
break;
case TSDEV_CC_IPIR:
pkt->set(ipint);
break;
case TSDEV_CC_ITIR:
pkt->set(itint);
break;
default:
panic("default in cchip read reached, accessing 0x%x\n");
} // uint64_t
break;
case sizeof(uint32_t):
case sizeof(uint16_t):
case sizeof(uint8_t):
default:
panic("invalid access size(?) for tsunami register!\n");
}
DPRINTF(Tsunami, "Tsunami CChip: read regnum=%#x size=%d data=%lld\n",
regnum, pkt->getSize(), pkt->get<uint64_t>());
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
TsunamiCChip::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ;
assert(pkt->getSize() == sizeof(uint64_t));
DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->getAddr(), pkt->get<uint64_t>());
bool supportedWrite = false;
if (daddr & TSDEV_CC_BDIMS)
{
int number = (daddr >> 4) & 0x3F;
uint64_t bitvector;
uint64_t olddim;
uint64_t olddir;
olddim = dim[number];
olddir = dir[number];
dim[number] = pkt->get<uint64_t>();
dir[number] = dim[number] & drir;
for(int x = 0; x < Tsunami::Max_CPUs; x++)
{
bitvector = ULL(1) << x;
// Figure out which bits have changed
if ((dim[number] & bitvector) != (olddim & bitvector))
{
// The bit is now set and it wasn't before (set)
if((dim[number] & bitvector) && (dir[number] & bitvector))
{
tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
DPRINTF(Tsunami, "dim write resulting in posting dir"
" interrupt to cpu %d\n", number);
}
else if ((olddir & bitvector) &&
!(dir[number] & bitvector))
{
// The bit was set and now its now clear and
// we were interrupting on that bit before
tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
DPRINTF(Tsunami, "dim write resulting in clear"
" dir interrupt to cpu %d\n", number);
}
}
}
} else {
switch(regnum) {
case TSDEV_CC_CSR:
panic("TSDEV_CC_CSR write\n");
case TSDEV_CC_MTR:
panic("TSDEV_CC_MTR write not implemented\n");
case TSDEV_CC_MISC:
uint64_t ipreq;
ipreq = (pkt->get<uint64_t>() >> 12) & 0xF;
//If it is bit 12-15, this is an IPI post
if (ipreq) {
reqIPI(ipreq);
supportedWrite = true;
}
//If it is bit 8-11, this is an IPI clear
uint64_t ipintr;
ipintr = (pkt->get<uint64_t>() >> 8) & 0xF;
if (ipintr) {
clearIPI(ipintr);
supportedWrite = true;
}
//If it is the 4-7th bit, clear the RTC interrupt
uint64_t itintr;
itintr = (pkt->get<uint64_t>() >> 4) & 0xF;
if (itintr) {
clearITI(itintr);
supportedWrite = true;
}
// ignore NXMs
if (pkt->get<uint64_t>() & 0x10000000)
supportedWrite = true;
if(!supportedWrite)
panic("TSDEV_CC_MISC write not implemented\n");
break;
case TSDEV_CC_AAR0:
case TSDEV_CC_AAR1:
case TSDEV_CC_AAR2:
case TSDEV_CC_AAR3:
panic("TSDEV_CC_AARx write not implemeted\n");
case TSDEV_CC_DIM0:
case TSDEV_CC_DIM1:
case TSDEV_CC_DIM2:
case TSDEV_CC_DIM3:
int number;
if(regnum == TSDEV_CC_DIM0)
number = 0;
else if(regnum == TSDEV_CC_DIM1)
number = 1;
else if(regnum == TSDEV_CC_DIM2)
number = 2;
else
number = 3;
uint64_t bitvector;
uint64_t olddim;
uint64_t olddir;
olddim = dim[number];
olddir = dir[number];
dim[number] = pkt->get<uint64_t>();
dir[number] = dim[number] & drir;
for(int x = 0; x < 64; x++)
{
bitvector = ULL(1) << x;
// Figure out which bits have changed
if ((dim[number] & bitvector) != (olddim & bitvector))
{
// The bit is now set and it wasn't before (set)
if((dim[number] & bitvector) && (dir[number] & bitvector))
{
tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
}
else if ((olddir & bitvector) &&
!(dir[number] & bitvector))
{
// The bit was set and now its now clear and
// we were interrupting on that bit before
tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
DPRINTF(Tsunami, "dim write resulting in clear"
" dir interrupt to cpu %d\n",
x);
}
}
}
break;
case TSDEV_CC_DIR0:
case TSDEV_CC_DIR1:
case TSDEV_CC_DIR2:
case TSDEV_CC_DIR3:
panic("TSDEV_CC_DIR write not implemented\n");
case TSDEV_CC_DRIR:
panic("TSDEV_CC_DRIR write not implemented\n");
case TSDEV_CC_PRBEN:
panic("TSDEV_CC_PRBEN write not implemented\n");
case TSDEV_CC_IIC0:
case TSDEV_CC_IIC1:
case TSDEV_CC_IIC2:
case TSDEV_CC_IIC3:
panic("TSDEV_CC_IICx write not implemented\n");
case TSDEV_CC_MPR0:
case TSDEV_CC_MPR1:
case TSDEV_CC_MPR2:
case TSDEV_CC_MPR3:
panic("TSDEV_CC_MPRx write not implemented\n");
case TSDEV_CC_IPIR:
clearIPI(pkt->get<uint64_t>());
break;
case TSDEV_CC_ITIR:
clearITI(pkt->get<uint64_t>());
break;
case TSDEV_CC_IPIQ:
reqIPI(pkt->get<uint64_t>());
break;
default:
panic("default in cchip read reached, accessing 0x%x\n");
} // swtich(regnum)
} // not BIG_TSUNAMI write
pkt->makeAtomicResponse();
return pioDelay;
}
void
TsunamiCChip::clearIPI(uint64_t ipintr)
{
int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipintr) {
for (int cpunum=0; cpunum < numcpus; cpunum++) {
// Check each cpu bit
uint64_t cpumask = ULL(1) << cpunum;
if (ipintr & cpumask) {
// Check if there is a pending ipi
if (ipint & cpumask) {
ipint &= ~cpumask;
tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0);
DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum);
}
else
warn("clear IPI for CPU=%d, but NO IPI\n", cpunum);
}
}
}
else
panic("Big IPI Clear, but not processors indicated\n");
}
void
TsunamiCChip::clearITI(uint64_t itintr)
{
int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (itintr) {
for (int i=0; i < numcpus; i++) {
uint64_t cpumask = ULL(1) << i;
if (itintr & cpumask & itint) {
tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
itint &= ~cpumask;
DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
}
}
}
else
panic("Big ITI Clear, but not processors indicated\n");
}
void
TsunamiCChip::reqIPI(uint64_t ipreq)
{
int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipreq) {
for (int cpunum=0; cpunum < numcpus; cpunum++) {
// Check each cpu bit
uint64_t cpumask = ULL(1) << cpunum;
if (ipreq & cpumask) {
// Check if there is already an ipi (bits 8:11)
if (!(ipint & cpumask)) {
ipint |= cpumask;
tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0);
DPRINTF(IPI, "send IPI cpu=%d\n", cpunum);
}
else
warn("post IPI for CPU=%d, but IPI already\n", cpunum);
}
}
}
else
panic("Big IPI Request, but not processors indicated\n");
}
void
TsunamiCChip::postRTC()
{
int size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
for (int i = 0; i < size; i++) {
uint64_t cpumask = ULL(1) << i;
if (!(cpumask & itint)) {
itint |= cpumask;
tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d\n", i);
}
}
}
void
TsunamiCChip::postDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
uint64_t size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
drir |= bitvector;
for(int i=0; i < size; i++) {
dir[i] = dim[i] & drir;
if (dim[i] & bitvector) {
tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
"interrupt %d\n",i, interrupt);
}
}
}
void
TsunamiCChip::clearDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
uint64_t size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
if (drir & bitvector)
{
drir &= ~bitvector;
for(int i=0; i < size; i++) {
if (dir[i] & bitvector) {
tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
"interrupt %d\n",i, interrupt);
}
dir[i] = dim[i] & drir;
}
}
else
DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
}
void
TsunamiCChip::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
SERIALIZE_SCALAR(ipint);
SERIALIZE_SCALAR(itint);
SERIALIZE_SCALAR(drir);
}
void
TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
UNSERIALIZE_SCALAR(ipint);
UNSERIALIZE_SCALAR(itint);
UNSERIALIZE_SCALAR(drir);
}
TsunamiCChip *
TsunamiCChipParams::create()
{
return new TsunamiCChip(this);
}

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Emulation of the Tsunami CChip CSRs
*/
#ifndef __TSUNAMI_CCHIP_HH__
#define __TSUNAMI_CCHIP_HH__
#include "base/range.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/io_device.hh"
#include "params/TsunamiCChip.hh"
/**
* Tsunami CChip CSR Emulation. This device includes all the interrupt
* handling code for the chipset.
*/
class TsunamiCChip : public BasicPioDevice
{
protected:
/**
* pointer to the tsunami object.
* This is our access to all the other tsunami
* devices.
*/
Tsunami *tsunami;
/**
* The dims are device interrupt mask registers.
* One exists for each CPU, the DRIR X DIM = DIR
*/
uint64_t dim[Tsunami::Max_CPUs];
/**
* The dirs are device interrupt registers.
* One exists for each CPU, the DRIR X DIM = DIR
*/
uint64_t dir[Tsunami::Max_CPUs];
/**
* This register contains bits for each PCI interrupt
* that can occur.
*/
uint64_t drir;
/** Indicator of which CPUs have an IPI interrupt */
uint64_t ipint;
/** Indicator of which CPUs have an RTC interrupt */
uint64_t itint;
public:
typedef TsunamiCChipParams Params;
/**
* Initialize the Tsunami CChip by setting all of the
* device register to 0.
* @param p params struct
*/
TsunamiCChip(const Params *p);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* post an RTC interrupt to the CPU
*/
void postRTC();
/**
* post an interrupt to the CPU.
* @param interrupt the interrupt number to post (0-64)
*/
void postDRIR(uint32_t interrupt);
/**
* clear an interrupt previously posted to the CPU.
* @param interrupt the interrupt number to post (0-64)
*/
void clearDRIR(uint32_t interrupt);
/**
* post an ipi interrupt to the CPU.
* @param ipintr the cpu number to clear(bitvector)
*/
void clearIPI(uint64_t ipintr);
/**
* clear a timer interrupt previously posted to the CPU.
* @param itintr the cpu number to clear(bitvector)
*/
void clearITI(uint64_t itintr);
/**
* request an interrupt be posted to the CPU.
* @param ipreq the cpu number to interrupt(bitvector)
*/
void reqIPI(uint64_t ipreq);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __TSUNAMI_CCHIP_HH__

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Andrew Schultz
* Miguel Serrano
*/
/** @file
* Tsunami I/O including PIC, PIT, RTC, DMA
*/
#include <sys/time.h>
#include <deque>
#include <string>
#include <vector>
#include "base/time.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "debug/Tsunami.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/alpha/tsunamireg.h"
#include "dev/rtcreg.h"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/port.hh"
#include "sim/system.hh"
// clang complains about std::set being overloaded with Packet::set if
// we open up the entire namespace std
using std::string;
using std::ostream;
//Should this be AlphaISA?
using namespace TheISA;
TsunamiIO::RTC::RTC(const string &n, const TsunamiIOParams *p)
: MC146818(p->tsunami, n, p->time, p->year_is_bcd, p->frequency),
tsunami(p->tsunami)
{
}
TsunamiIO::TsunamiIO(const Params *p)
: BasicPioDevice(p), tsunami(p->tsunami),
pitimer(this, p->name + "pitimer"), rtc(p->name + ".rtc", p)
{
pioSize = 0x100;
// set the back pointer from tsunami to myself
tsunami->io = this;
timerData = 0;
picr = 0;
picInterrupting = false;
}
Tick
TsunamiIO::frequency() const
{
return SimClock::Frequency / params()->frequency;
}
Tick
TsunamiIO::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
pkt->getSize(), daddr);
pkt->allocate();
if (pkt->getSize() == sizeof(uint8_t)) {
switch(daddr) {
// PIC1 mask read
case TSDEV_PIC1_MASK:
pkt->set(~mask1);
break;
case TSDEV_PIC2_MASK:
pkt->set(~mask2);
break;
case TSDEV_PIC1_ISR:
// !!! If this is modified 64bit case needs to be too
// Pal code has to do a 64 bit physical read because there is
// no load physical byte instruction
pkt->set(picr);
break;
case TSDEV_PIC2_ISR:
// PIC2 not implemnted... just return 0
pkt->set(0x00);
break;
case TSDEV_TMR0_DATA:
pkt->set(pitimer.readCounter(0));
break;
case TSDEV_TMR1_DATA:
pkt->set(pitimer.readCounter(1));
break;
case TSDEV_TMR2_DATA:
pkt->set(pitimer.readCounter(2));
break;
case TSDEV_RTC_DATA:
pkt->set(rtc.readData(rtcAddr));
break;
case TSDEV_CTRL_PORTB:
if (pitimer.outputHigh(2))
pkt->set(PORTB_SPKR_HIGH);
else
pkt->set(0x00);
break;
default:
panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize());
}
} else if (pkt->getSize() == sizeof(uint64_t)) {
if (daddr == TSDEV_PIC1_ISR)
pkt->set<uint64_t>(picr);
else
panic("I/O Read - invalid addr - va %#x size %d\n",
pkt->getAddr(), pkt->getSize());
} else {
panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize());
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
TsunamiIO::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>());
assert(pkt->getSize() == sizeof(uint8_t));
switch(daddr) {
case TSDEV_PIC1_MASK:
mask1 = ~(pkt->get<uint8_t>());
if ((picr & mask1) && !picInterrupting) {
picInterrupting = true;
tsunami->cchip->postDRIR(55);
DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
}
if ((!(picr & mask1)) && picInterrupting) {
picInterrupting = false;
tsunami->cchip->clearDRIR(55);
DPRINTF(Tsunami, "clearing pic interrupt\n");
}
break;
case TSDEV_PIC2_MASK:
mask2 = pkt->get<uint8_t>();
//PIC2 Not implemented to interrupt
break;
case TSDEV_PIC1_ACK:
// clear the interrupt on the PIC
picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
if (!(picr & mask1))
tsunami->cchip->clearDRIR(55);
break;
case TSDEV_DMA1_MODE:
mode1 = pkt->get<uint8_t>();
break;
case TSDEV_DMA2_MODE:
mode2 = pkt->get<uint8_t>();
break;
case TSDEV_TMR0_DATA:
pitimer.writeCounter(0, pkt->get<uint8_t>());
break;
case TSDEV_TMR1_DATA:
pitimer.writeCounter(1, pkt->get<uint8_t>());
break;
case TSDEV_TMR2_DATA:
pitimer.writeCounter(2, pkt->get<uint8_t>());
break;
case TSDEV_TMR_CTRL:
pitimer.writeControl(pkt->get<uint8_t>());
break;
case TSDEV_RTC_ADDR:
rtcAddr = pkt->get<uint8_t>();
break;
case TSDEV_RTC_DATA:
rtc.writeData(rtcAddr, pkt->get<uint8_t>());
break;
case TSDEV_KBD:
case TSDEV_DMA1_CMND:
case TSDEV_DMA2_CMND:
case TSDEV_DMA1_MMASK:
case TSDEV_DMA2_MMASK:
case TSDEV_PIC2_ACK:
case TSDEV_DMA1_RESET:
case TSDEV_DMA2_RESET:
case TSDEV_DMA1_MASK:
case TSDEV_DMA2_MASK:
case TSDEV_CTRL_PORTB:
break;
default:
panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>());
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
TsunamiIO::postPIC(uint8_t bitvector)
{
//PIC2 Is not implemented, because nothing of interest there
picr |= bitvector;
if (picr & mask1) {
tsunami->cchip->postDRIR(55);
DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
}
}
void
TsunamiIO::clearPIC(uint8_t bitvector)
{
//PIC2 Is not implemented, because nothing of interest there
picr &= ~bitvector;
if (!(picr & mask1)) {
tsunami->cchip->clearDRIR(55);
DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
}
}
void
TsunamiIO::serialize(ostream &os)
{
SERIALIZE_SCALAR(rtcAddr);
SERIALIZE_SCALAR(timerData);
SERIALIZE_SCALAR(mask1);
SERIALIZE_SCALAR(mask2);
SERIALIZE_SCALAR(mode1);
SERIALIZE_SCALAR(mode2);
SERIALIZE_SCALAR(picr);
SERIALIZE_SCALAR(picInterrupting);
// Serialize the timers
pitimer.serialize("pitimer", os);
rtc.serialize("rtc", os);
}
void
TsunamiIO::unserialize(Checkpoint *cp, const string &section)
{
UNSERIALIZE_SCALAR(rtcAddr);
UNSERIALIZE_SCALAR(timerData);
UNSERIALIZE_SCALAR(mask1);
UNSERIALIZE_SCALAR(mask2);
UNSERIALIZE_SCALAR(mode1);
UNSERIALIZE_SCALAR(mode2);
UNSERIALIZE_SCALAR(picr);
UNSERIALIZE_SCALAR(picInterrupting);
// Unserialize the timers
pitimer.unserialize("pitimer", cp, section);
rtc.unserialize("rtc", cp, section);
}
TsunamiIO *
TsunamiIOParams::create()
{
return new TsunamiIO(this);
}

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Andrew Schultz
* Miguel Serrano
*/
/** @file
* Tsunami I/O Space mapping including RTC/timer interrupts
*/
#ifndef __DEV_TSUNAMI_IO_HH__
#define __DEV_TSUNAMI_IO_HH__
#include "base/range.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/intel_8254_timer.hh"
#include "dev/io_device.hh"
#include "dev/mc146818.hh"
#include "params/TsunamiIO.hh"
#include "sim/eventq.hh"
/**
* Tsunami I/O device is a catch all for all the south bridge stuff we care
* to implement.
*/
class TsunamiIO : public BasicPioDevice
{
private:
struct tm tm;
protected:
class RTC : public MC146818
{
public:
Tsunami *tsunami;
RTC(const std::string &n, const TsunamiIOParams *p);
protected:
void handleEvent()
{
//Actually interrupt the processor here
tsunami->cchip->postRTC();
}
};
/** Mask of the PIC1 */
uint8_t mask1;
/** Mask of the PIC2 */
uint8_t mask2;
/** Mode of PIC1. Not used for anything */
uint8_t mode1;
/** Mode of PIC2. Not used for anything */
uint8_t mode2;
/** Raw PIC interrupt register before masking */
uint8_t picr; //Raw PIC interrput register
/** Is the pic interrupting right now or not. */
bool picInterrupting;
/** A pointer to the Tsunami device which be belong to */
Tsunami *tsunami;
/** Intel 8253 Periodic Interval Timer */
Intel8254Timer pitimer;
RTC rtc;
uint8_t rtcAddr;
/** The interval is set via two writes to the PIT.
* This variable contains a flag as to how many writes have happened, and
* the time so far.
*/
uint16_t timerData;
public:
/**
* Return the freqency of the RTC
* @return interrupt rate of the RTC
*/
Tick frequency() const;
public:
typedef TsunamiIOParams Params;
/**
* Initialize all the data for devices supported by Tsunami I/O.
* @param p pointer to Params struct
*/
TsunamiIO(const Params *p);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* Post an PIC interrupt to the CPU via the CChip
* @param bitvector interrupt to post.
*/
void postPIC(uint8_t bitvector);
/**
* Clear a posted interrupt
* @param bitvector interrupt to clear
*/
void clearPIC(uint8_t bitvector);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_TSUNAMI_IO_HH__

View File

@ -0,0 +1,352 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Andrew Schultz
*/
/** @file
* Tsunami PChip (pci)
*/
#include <deque>
#include <string>
#include <vector>
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "debug/Tsunami.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/alpha/tsunami_pchip.hh"
#include "dev/alpha/tsunamireg.h"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "sim/system.hh"
using namespace std;
//Should this be AlphaISA?
using namespace TheISA;
TsunamiPChip::TsunamiPChip(const Params *p)
: BasicPioDevice(p)
{
pioSize = 0x1000;
for (int i = 0; i < 4; i++) {
wsba[i] = 0;
wsm[i] = 0;
tba[i] = 0;
}
// initialize pchip control register
pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
//Set back pointer in tsunami
p->tsunami->pchip = this;
}
Tick
TsunamiPChip::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
pkt->allocate();
Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
assert(pkt->getSize() == sizeof(uint64_t));
DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
switch(daddr) {
case TSDEV_PC_WSBA0:
pkt->set(wsba[0]);
break;
case TSDEV_PC_WSBA1:
pkt->set(wsba[1]);
break;
case TSDEV_PC_WSBA2:
pkt->set(wsba[2]);
break;
case TSDEV_PC_WSBA3:
pkt->set(wsba[3]);
break;
case TSDEV_PC_WSM0:
pkt->set(wsm[0]);
break;
case TSDEV_PC_WSM1:
pkt->set(wsm[1]);
break;
case TSDEV_PC_WSM2:
pkt->set(wsm[2]);
break;
case TSDEV_PC_WSM3:
pkt->set(wsm[3]);
break;
case TSDEV_PC_TBA0:
pkt->set(tba[0]);
break;
case TSDEV_PC_TBA1:
pkt->set(tba[1]);
break;
case TSDEV_PC_TBA2:
pkt->set(tba[2]);
break;
case TSDEV_PC_TBA3:
pkt->set(tba[3]);
break;
case TSDEV_PC_PCTL:
pkt->set(pctl);
break;
case TSDEV_PC_PLAT:
panic("PC_PLAT not implemented\n");
case TSDEV_PC_RES:
panic("PC_RES not implemented\n");
case TSDEV_PC_PERROR:
pkt->set((uint64_t)0x00);
break;
case TSDEV_PC_PERRMASK:
pkt->set((uint64_t)0x00);
break;
case TSDEV_PC_PERRSET:
panic("PC_PERRSET not implemented\n");
case TSDEV_PC_TLBIV:
panic("PC_TLBIV not implemented\n");
case TSDEV_PC_TLBIA:
pkt->set((uint64_t)0x00); // shouldn't be readable, but linux
break;
case TSDEV_PC_PMONCTL:
panic("PC_PMONCTL not implemented\n");
case TSDEV_PC_PMONCNT:
panic("PC_PMONCTN not implemented\n");
default:
panic("Default in PChip Read reached reading 0x%x\n", daddr);
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
TsunamiPChip::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
assert(pkt->getSize() == sizeof(uint64_t));
DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize());
switch(daddr) {
case TSDEV_PC_WSBA0:
wsba[0] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSBA1:
wsba[1] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSBA2:
wsba[2] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSBA3:
wsba[3] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSM0:
wsm[0] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSM1:
wsm[1] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSM2:
wsm[2] = pkt->get<uint64_t>();
break;
case TSDEV_PC_WSM3:
wsm[3] = pkt->get<uint64_t>();
break;
case TSDEV_PC_TBA0:
tba[0] = pkt->get<uint64_t>();
break;
case TSDEV_PC_TBA1:
tba[1] = pkt->get<uint64_t>();
break;
case TSDEV_PC_TBA2:
tba[2] = pkt->get<uint64_t>();
break;
case TSDEV_PC_TBA3:
tba[3] = pkt->get<uint64_t>();
break;
case TSDEV_PC_PCTL:
pctl = pkt->get<uint64_t>();
break;
case TSDEV_PC_PLAT:
panic("PC_PLAT not implemented\n");
case TSDEV_PC_RES:
panic("PC_RES not implemented\n");
case TSDEV_PC_PERROR:
break;
case TSDEV_PC_PERRMASK:
panic("PC_PERRMASK not implemented\n");
case TSDEV_PC_PERRSET:
panic("PC_PERRSET not implemented\n");
case TSDEV_PC_TLBIV:
panic("PC_TLBIV not implemented\n");
case TSDEV_PC_TLBIA:
break; // value ignored, supposted to invalidate SG TLB
case TSDEV_PC_PMONCTL:
panic("PC_PMONCTL not implemented\n");
case TSDEV_PC_PMONCNT:
panic("PC_PMONCTN not implemented\n");
default:
panic("Default in PChip write reached reading 0x%x\n", daddr);
} // uint64_t
pkt->makeAtomicResponse();
return pioDelay;
}
#define DMA_ADDR_MASK ULL(0x3ffffffff)
Addr
TsunamiPChip::translatePciToDma(Addr busAddr)
{
// compare the address to the window base registers
uint64_t tbaMask = 0;
uint64_t baMask = 0;
uint64_t windowMask = 0;
uint64_t windowBase = 0;
uint64_t pteEntry = 0;
Addr pteAddr;
Addr dmaAddr;
#if 0
DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
for (int i = 0; i < 4; i++) {
DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
i, wsba[i], wsm[i]);
windowBase = wsba[i];
windowMask = ~wsm[i] & (ULL(0xfff) << 20);
if ((busAddr & windowMask) == (windowBase & windowMask)) {
DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
i, windowBase, windowMask, (busAddr & windowMask),
(windowBase & windowMask));
}
}
#endif
for (int i = 0; i < 4; i++) {
windowBase = wsba[i];
windowMask = ~wsm[i] & (ULL(0xfff) << 20);
if ((busAddr & windowMask) == (windowBase & windowMask)) {
if (wsba[i] & 0x1) { // see if enabled
if (wsba[i] & 0x2) { // see if SG bit is set
/** @todo
This currently is faked by just doing a direct
read from memory, however, to be realistic, this
needs to actually do a bus transaction. The process
is explained in the tsunami documentation on page
10-12 and basically munges the address to look up a
PTE from a table in memory and then uses that mapping
to create an address for the SG page
*/
tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
sys->physProxy.readBlob(pteAddr, (uint8_t*)&pteEntry,
sizeof(uint64_t));
dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
} else {
baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
tbaMask = ~baMask;
dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
}
return (dmaAddr & DMA_ADDR_MASK);
}
}
}
// 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);
}
Addr
TsunamiPChip::calcIOAddr(Addr addr)
{
return TSUNAMI_PCI0_IO + addr;
}
Addr
TsunamiPChip::calcMemAddr(Addr addr)
{
return TSUNAMI_PCI0_MEMORY + addr;
}
void
TsunamiPChip::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(pctl);
SERIALIZE_ARRAY(wsba, 4);
SERIALIZE_ARRAY(wsm, 4);
SERIALIZE_ARRAY(tba, 4);
}
void
TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(pctl);
UNSERIALIZE_ARRAY(wsba, 4);
UNSERIALIZE_ARRAY(wsm, 4);
UNSERIALIZE_ARRAY(tba, 4);
}
TsunamiPChip *
TsunamiPChipParams::create()
{
return new TsunamiPChip(this);
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Tsunami PCI interface CSRs
*/
#ifndef __TSUNAMI_PCHIP_HH__
#define __TSUNAMI_PCHIP_HH__
#include "base/range.hh"
#include "dev/alpha/tsunami.hh"
#include "dev/io_device.hh"
#include "params/TsunamiPChip.hh"
/**
* A very simple implementation of the Tsunami PCI interface chips.
*/
class TsunamiPChip : public BasicPioDevice
{
protected:
static const Addr TsunamiPciBus0Config = ULL(0x801fe000000);
/** Pchip control register */
uint64_t pctl;
/** Window Base addresses */
uint64_t wsba[4];
/** Window masks */
uint64_t wsm[4];
/** Translated Base Addresses */
uint64_t tba[4];
public:
typedef TsunamiPChipParams Params;
/**
* Register the PChip with the mmu and init all wsba, wsm, and tba to 0
* @param p pointer to the parameters struct
*/
TsunamiPChip(const Params *p);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* Translate a PCI bus address to a memory address for DMA.
* @todo Andrew says this needs to be fixed. What's wrong with it?
* @param busAddr PCI address to translate.
* @return memory system address
*/
Addr translatePciToDma(Addr busAddr);
Addr calcConfigAddr(int bus, int dev, int func);
Addr calcIOAddr(Addr addr);
Addr calcMemAddr(Addr addr);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __TSUNAMI_PCHIP_HH__

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* List of Tsunami CSRs
*/
#ifndef __TSUNAMIREG_H__
#define __TSUNAMIREG_H__
#define ALPHA_K0SEG_BASE ULL(0xfffffc0000000000)
// CChip Registers
#define TSDEV_CC_CSR 0x00
#define TSDEV_CC_MTR 0x01
#define TSDEV_CC_MISC 0x02
#define TSDEV_CC_AAR0 0x04
#define TSDEV_CC_AAR1 0x05
#define TSDEV_CC_AAR2 0x06
#define TSDEV_CC_AAR3 0x07
#define TSDEV_CC_DIM0 0x08
#define TSDEV_CC_DIM1 0x09
#define TSDEV_CC_DIR0 0x0A
#define TSDEV_CC_DIR1 0x0B
#define TSDEV_CC_DRIR 0x0C
#define TSDEV_CC_PRBEN 0x0D
#define TSDEV_CC_IIC0 0x0E
#define TSDEV_CC_IIC1 0x0F
#define TSDEV_CC_MPR0 0x10
#define TSDEV_CC_MPR1 0x11
#define TSDEV_CC_MPR2 0x12
#define TSDEV_CC_MPR3 0x13
#define TSDEV_CC_DIM2 0x18
#define TSDEV_CC_DIM3 0x19
#define TSDEV_CC_DIR2 0x1A
#define TSDEV_CC_DIR3 0x1B
#define TSDEV_CC_IIC2 0x1C
#define TSDEV_CC_IIC3 0x1D
// BigTsunami Registers
#define TSDEV_CC_BDIMS 0x1000000
#define TSDEV_CC_BDIRS 0x2000000
#define TSDEV_CC_IPIQ 0x20 //0xf01a000800
#define TSDEV_CC_IPIR 0x21 //0xf01a000840
#define TSDEV_CC_ITIR 0x22 //0xf01a000880
// PChip Registers
#define TSDEV_PC_WSBA0 0x00
#define TSDEV_PC_WSBA1 0x01
#define TSDEV_PC_WSBA2 0x02
#define TSDEV_PC_WSBA3 0x03
#define TSDEV_PC_WSM0 0x04
#define TSDEV_PC_WSM1 0x05
#define TSDEV_PC_WSM2 0x06
#define TSDEV_PC_WSM3 0x07
#define TSDEV_PC_TBA0 0x08
#define TSDEV_PC_TBA1 0x09
#define TSDEV_PC_TBA2 0x0A
#define TSDEV_PC_TBA3 0x0B
#define TSDEV_PC_PCTL 0x0C
#define TSDEV_PC_PLAT 0x0D
#define TSDEV_PC_RES 0x0E
#define TSDEV_PC_PERROR 0x0F
#define TSDEV_PC_PERRMASK 0x10
#define TSDEV_PC_PERRSET 0x11
#define TSDEV_PC_TLBIV 0x12
#define TSDEV_PC_TLBIA 0x13
#define TSDEV_PC_PMONCTL 0x14
#define TSDEV_PC_PMONCNT 0x15
#define TSDEV_PC_SPST 0x20
// DChip Registers
#define TSDEV_DC_DSC 0x20
#define TSDEV_DC_STR 0x21
#define TSDEV_DC_DREV 0x22
#define TSDEV_DC_DSC2 0x23
// I/O Ports
#define TSDEV_PIC1_MASK 0x21
#define TSDEV_PIC2_MASK 0xA1
#define TSDEV_PIC1_ISR 0x20
#define TSDEV_PIC2_ISR 0xA0
#define TSDEV_PIC1_ACK 0x20
#define TSDEV_PIC2_ACK 0xA0
#define TSDEV_DMA1_RESET 0x0D
#define TSDEV_DMA2_RESET 0xDA
#define TSDEV_DMA1_MODE 0x0B
#define TSDEV_DMA2_MODE 0xD6
#define TSDEV_DMA1_MASK 0x0A
#define TSDEV_DMA2_MASK 0xD4
#define TSDEV_CTRL_PORTB 0x61
#define TSDEV_TMR0_DATA 0x40
#define TSDEV_TMR1_DATA 0x41
#define TSDEV_TMR2_DATA 0x42
#define TSDEV_TMR_CTRL 0x43
#define TSDEV_KBD 0x64
#define TSDEV_DMA1_CMND 0x08
#define TSDEV_DMA1_STAT TSDEV_DMA1_CMND
#define TSDEV_DMA2_CMND 0xD0
#define TSDEV_DMA2_STAT TSDEV_DMA2_CMND
#define TSDEV_DMA1_MMASK 0x0F
#define TSDEV_DMA2_MMASK 0xDE
/* Added for keyboard accesses */
#define TSDEV_KBD 0x64
#define TSDEV_RTC_ADDR 0x70
#define TSDEV_RTC_DATA 0x71
#define PCHIP_PCI0_MEMORY ULL(0x00000000000)
#define PCHIP_PCI0_IO ULL(0x001FC000000)
#define TSUNAMI_UNCACHABLE_BIT ULL(0x80000000000)
#define TSUNAMI_PCI0_MEMORY TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_MEMORY
#define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO
// System Control PortB Status Bits
#define PORTB_SPKR_HIGH 0x20
#endif // __TSUNAMIREG_H__

View File

@ -0,0 +1,418 @@
# Copyright (c) 2009-2012 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2006-2007 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: Ali Saidi
# Gabe Black
# William Wang
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr, DmaDevice
from Pci import PciConfigAll
from Ethernet import NSGigE, IGbE_e1000, IGbE_igb
from Ide import *
from Platform import Platform
from Terminal import Terminal
from Uart import Uart
from SimpleMemory import SimpleMemory
class AmbaDevice(BasicPioDevice):
type = 'AmbaDevice'
abstract = True
amba_id = Param.UInt32("ID of AMBA device for kernel detection")
class AmbaIntDevice(AmbaDevice):
type = 'AmbaIntDevice'
abstract = True
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
int_delay = Param.Latency("100ns",
"Time between action and interrupt generation by device")
class AmbaDmaDevice(DmaDevice):
type = 'AmbaDmaDevice'
abstract = True
pio_addr = Param.Addr("Address for AMBA slave interface")
pio_latency = Param.Latency("10ns", "Time between action and write/read result by AMBA DMA Device")
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
amba_id = Param.UInt32("ID of AMBA device for kernel detection")
class A9SCU(BasicPioDevice):
type = 'A9SCU'
class RealViewCtrl(BasicPioDevice):
type = 'RealViewCtrl'
proc_id0 = Param.UInt32(0x0C000000, "Processor ID, SYS_PROCID")
proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1")
idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID")
class Gic(PioDevice):
type = 'Gic'
platform = Param.Platform(Parent.any, "Platform this device is part of.")
dist_addr = Param.Addr(0x1f001000, "Address for distributor")
cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface")
int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU")
it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)")
class AmbaFake(AmbaDevice):
type = 'AmbaFake'
ignore_access = Param.Bool(False, "Ignore reads/writes to this device, (e.g. IsaFake + AMBA)")
amba_id = 0;
class Pl011(Uart):
type = 'Pl011'
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
end_on_eot = Param.Bool(False, "End the simulation when a EOT is received on the UART")
int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART")
class Sp804(AmbaDevice):
type = 'Sp804'
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num0 = Param.UInt32("Interrupt number that connects to GIC")
clock0 = Param.Clock('1MHz', "Clock speed of the input")
int_num1 = Param.UInt32("Interrupt number that connects to GIC")
clock1 = Param.Clock('1MHz', "Clock speed of the input")
amba_id = 0x00141804
class CpuLocalTimer(BasicPioDevice):
type = 'CpuLocalTimer'
gic = Param.Gic(Parent.any, "Gic to use for interrupting")
int_num_timer = Param.UInt32("Interrrupt number used per-cpu to GIC")
int_num_watchdog = Param.UInt32("Interrupt number for per-cpu watchdog to GIC")
clock = Param.Clock('1GHz', "Clock speed at which the timer counts")
class PL031(AmbaIntDevice):
type = 'PL031'
time = Param.Time('01/01/2009', "System time to use ('Now' for actual time)")
amba_id = 0x00341031
class Pl050(AmbaIntDevice):
type = 'Pl050'
vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display")
is_mouse = Param.Bool(False, "Is this interface a mouse, if not a keyboard")
int_delay = '1us'
amba_id = 0x00141050
class Pl111(AmbaDmaDevice):
type = 'Pl111'
clock = Param.Clock('24MHz', "Clock speed of the input")
vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display")
amba_id = 0x00141111
class RealView(Platform):
type = 'RealView'
system = Param.System(Parent.any, "system")
pci_cfg_base = Param.Addr(0, "Base address of PCI Configuraiton Space")
mem_start_addr = Param.Addr(0, "Start address of main memory")
max_mem_size = Param.Addr('256MB', "Maximum amount of RAM supported by platform")
def setupBootLoader(self, mem_bus, cur_sys, loc):
self.nvmem = SimpleMemory(range = AddrRange(Addr('2GB'),
size = '64MB'),
zero = True)
self.nvmem.port = mem_bus.master
cur_sys.boot_loader = loc('boot.arm')
# Reference for memory map and interrupt number
# RealView Platform Baseboard Explore for Cortex-A9 User Guide(ARM DUI 0440A)
# Chapter 4: Programmer's Reference
class RealViewPBX(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
gic = Gic()
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x1f000600)
clcd = Pl111(pio_addr=0x10020000, int_num=55)
kmi0 = Pl050(pio_addr=0x10006000, int_num=52)
kmi1 = Pl050(pio_addr=0x10007000, int_num=53, is_mouse=True)
a9scu = A9SCU(pio_addr=0x1f000000)
cf_ctrl = IdeController(disks=[], pci_func=0, pci_dev=7, pci_bus=2,
io_shift = 1, ctrl_offset = 2, Command = 0x1,
BAR0 = 0x18000000, BAR0Size = '16B',
BAR1 = 0x18000100, BAR1Size = '1B',
BAR0LegacyIO = True, BAR1LegacyIO = True)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff)
flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x20000000,
fake_mem=True)
dmac_fake = AmbaFake(pio_addr=0x10030000)
uart1_fake = AmbaFake(pio_addr=0x1000a000)
uart2_fake = AmbaFake(pio_addr=0x1000b000)
uart3_fake = AmbaFake(pio_addr=0x1000c000)
smc_fake = AmbaFake(pio_addr=0x100e1000)
sp810_fake = AmbaFake(pio_addr=0x10001000, ignore_access=True)
watchdog_fake = AmbaFake(pio_addr=0x10010000)
gpio0_fake = AmbaFake(pio_addr=0x10013000)
gpio1_fake = AmbaFake(pio_addr=0x10014000)
gpio2_fake = AmbaFake(pio_addr=0x10015000)
ssp_fake = AmbaFake(pio_addr=0x1000d000)
sci_fake = AmbaFake(pio_addr=0x1000e000)
aaci_fake = AmbaFake(pio_addr=0x10004000)
mmc_fake = AmbaFake(pio_addr=0x10005000)
rtc = PL031(pio_addr=0x10017000, int_num=42)
# Attach I/O devices that are on chip and also set the appropriate
# ranges for the bridge
def attachOnChipIO(self, bus, bridge):
self.gic.pio = bus.master
self.l2x0_fake.pio = bus.master
self.a9scu.pio = bus.master
self.local_cpu_timer.pio = bus.master
# Bridge ranges based on excluding what is part of on-chip I/O
# (gic, l2x0, a9scu, local_cpu_timer)
bridge.ranges = [AddrRange(self.realview_io.pio_addr,
self.a9scu.pio_addr - 1),
AddrRange(self.flash_fake.pio_addr,
self.flash_fake.pio_addr + \
self.flash_fake.pio_size - 1)]
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
self.clcd.dma = bus.slave
self.kmi0.pio = bus.master
self.kmi1.pio = bus.master
self.cf_ctrl.pio = bus.master
self.cf_ctrl.config = bus.master
self.cf_ctrl.dma = bus.slave
self.dmac_fake.pio = bus.master
self.uart1_fake.pio = bus.master
self.uart2_fake.pio = bus.master
self.uart3_fake.pio = bus.master
self.smc_fake.pio = bus.master
self.sp810_fake.pio = bus.master
self.watchdog_fake.pio = bus.master
self.gpio0_fake.pio = bus.master
self.gpio1_fake.pio = bus.master
self.gpio2_fake.pio = bus.master
self.ssp_fake.pio = bus.master
self.sci_fake.pio = bus.master
self.aaci_fake.pio = bus.master
self.mmc_fake.pio = bus.master
self.rtc.pio = bus.master
self.flash_fake.pio = bus.master
# Reference for memory map and interrupt number
# RealView Emulation Baseboard User Guide (ARM DUI 0143B)
# Chapter 4: Programmer's Reference
class RealViewEB(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
gic = Gic(dist_addr=0x10041000, cpu_addr=0x10040000)
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
clcd = Pl111(pio_addr=0x10020000, int_num=23)
kmi0 = Pl050(pio_addr=0x10006000, int_num=20)
kmi1 = Pl050(pio_addr=0x10007000, int_num=21, is_mouse=True)
l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff, warn_access="1")
flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x20000000-1,
fake_mem=True)
dmac_fake = AmbaFake(pio_addr=0x10030000)
uart1_fake = AmbaFake(pio_addr=0x1000a000)
uart2_fake = AmbaFake(pio_addr=0x1000b000)
uart3_fake = AmbaFake(pio_addr=0x1000c000)
smcreg_fake = IsaFake(pio_addr=0x10080000, pio_size=0x10000-1)
smc_fake = AmbaFake(pio_addr=0x100e1000)
sp810_fake = AmbaFake(pio_addr=0x10001000, ignore_access=True)
watchdog_fake = AmbaFake(pio_addr=0x10010000)
gpio0_fake = AmbaFake(pio_addr=0x10013000)
gpio1_fake = AmbaFake(pio_addr=0x10014000)
gpio2_fake = AmbaFake(pio_addr=0x10015000)
ssp_fake = AmbaFake(pio_addr=0x1000d000)
sci_fake = AmbaFake(pio_addr=0x1000e000)
aaci_fake = AmbaFake(pio_addr=0x10004000)
mmc_fake = AmbaFake(pio_addr=0x10005000)
rtc_fake = AmbaFake(pio_addr=0x10017000, amba_id=0x41031)
# Attach I/O devices that are on chip and also set the appropriate
# ranges for the bridge
def attachOnChipIO(self, bus, bridge):
self.gic.pio = bus.master
self.l2x0_fake.pio = bus.master
# Bridge ranges based on excluding what is part of on-chip I/O
# (gic, l2x0)
bridge.ranges = [AddrRange(self.realview_io.pio_addr,
self.gic.cpu_addr - 1),
AddrRange(self.flash_fake.pio_addr, Addr.max)]
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
self.clcd.dma = bus.slave
self.kmi0.pio = bus.master
self.kmi1.pio = bus.master
self.dmac_fake.pio = bus.master
self.uart1_fake.pio = bus.master
self.uart2_fake.pio = bus.master
self.uart3_fake.pio = bus.master
self.smc_fake.pio = bus.master
self.sp810_fake.pio = bus.master
self.watchdog_fake.pio = bus.master
self.gpio0_fake.pio = bus.master
self.gpio1_fake.pio = bus.master
self.gpio2_fake.pio = bus.master
self.ssp_fake.pio = bus.master
self.sci_fake.pio = bus.master
self.aaci_fake.pio = bus.master
self.mmc_fake.pio = bus.master
self.rtc_fake.pio = bus.master
self.flash_fake.pio = bus.master
self.smcreg_fake.pio = bus.master
class VExpress_EMM(RealView):
mem_start_addr = '2GB'
max_mem_size = '2GB'
pci_cfg_base = 0x30000000
uart = Pl011(pio_addr=0x1c090000, int_num=37)
realview_io = RealViewCtrl(proc_id0=0x14000000, proc_id1=0x14000000, pio_addr=0x1C010000)
gic = Gic(dist_addr=0x2C001000, cpu_addr=0x2C002000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000)
timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='50MHz', clock1='50MHz')
timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='50MHz', clock1='50MHz')
clcd = Pl111(pio_addr=0x1c1f0000, int_num=46)
kmi0 = Pl050(pio_addr=0x1c060000, int_num=44)
kmi1 = Pl050(pio_addr=0x1c070000, int_num=45)
cf_ctrl = IdeController(disks=[], pci_func=0, pci_dev=0, pci_bus=2,
io_shift = 2, ctrl_offset = 2, Command = 0x1,
BAR0 = 0x1C1A0000, BAR0Size = '256B',
BAR1 = 0x1C1A0100, BAR1Size = '4096B',
BAR0LegacyIO = True, BAR1LegacyIO = True)
pciconfig = PciConfigAll(size='256MB')
ethernet = IGbE_e1000(pci_bus=0, pci_dev=0, pci_func=0,
InterruptLine=1, InterruptPin=1)
ide = IdeController(disks = [], pci_bus=0, pci_dev=1, pci_func=0,
InterruptLine=2, InterruptPin=2)
vram = SimpleMemory(range = AddrRange(0x18000000, size='32MB'),
zero = True)
rtc = PL031(pio_addr=0x1C170000, int_num=36)
l2x0_fake = IsaFake(pio_addr=0x2C100000, pio_size=0xfff)
uart1_fake = AmbaFake(pio_addr=0x1C0A0000)
uart2_fake = AmbaFake(pio_addr=0x1C0B0000)
uart3_fake = AmbaFake(pio_addr=0x1C0C0000)
sp810_fake = AmbaFake(pio_addr=0x1C020000, ignore_access=True)
watchdog_fake = AmbaFake(pio_addr=0x1C0F0000)
aaci_fake = AmbaFake(pio_addr=0x1C040000)
lan_fake = IsaFake(pio_addr=0x1A000000, pio_size=0xffff)
usb_fake = IsaFake(pio_addr=0x1B000000, pio_size=0x1ffff)
mmc_fake = AmbaFake(pio_addr=0x1c050000)
def setupBootLoader(self, mem_bus, cur_sys, loc):
self.nvmem = SimpleMemory(range = AddrRange(0, size = '64MB'),
zero = True)
self.nvmem.port = mem_bus.master
cur_sys.boot_loader = loc('boot_emm.arm')
cur_sys.atags_addr = 0x80000100
# Attach I/O devices that are on chip and also set the appropriate
# ranges for the bridge
def attachOnChipIO(self, bus, bridge):
self.gic.pio = bus.master
self.local_cpu_timer.pio = bus.master
# Bridge ranges based on excluding what is part of on-chip I/O
# (gic, a9scu)
bridge.ranges = [AddrRange(0x2F000000, size='16MB'),
AddrRange(0x30000000, size='256MB'),
AddrRange(0x40000000, size='512MB'),
AddrRange(0x18000000, size='64MB'),
AddrRange(0x1C000000, size='64MB')]
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
self.uart.pio = bus.master
self.realview_io.pio = bus.master
self.timer0.pio = bus.master
self.timer1.pio = bus.master
self.clcd.pio = bus.master
self.clcd.dma = bus.slave
self.kmi0.pio = bus.master
self.kmi1.pio = bus.master
self.cf_ctrl.pio = bus.master
self.cf_ctrl.dma = bus.slave
self.cf_ctrl.config = bus.master
self.rtc.pio = bus.master
bus.use_default_range = True
self.vram.port = bus.master
self.ide.pio = bus.master
self.ide.config = bus.master
self.ide.dma = bus.slave
self.ethernet.pio = bus.master
self.ethernet.config = bus.master
self.ethernet.dma = bus.slave
self.pciconfig.pio = bus.default
self.l2x0_fake.pio = bus.master
self.uart1_fake.pio = bus.master
self.uart2_fake.pio = bus.master
self.uart3_fake.pio = bus.master
self.sp810_fake.pio = bus.master
self.watchdog_fake.pio = bus.master
self.aaci_fake.pio = bus.master
self.lan_fake.pio = bus.master
self.usb_fake.pio = bus.master
self.mmc_fake.pio = bus.master

View File

@ -0,0 +1,61 @@
# -*- mode:python -*-
# Copyright (c) 2009 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# 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: Ali Saidi
Import('*')
if env['TARGET_ISA'] == 'arm':
SimObject('RealView.py')
Source('a9scu.cc')
Source('amba_device.cc')
Source('amba_fake.cc')
Source('gic.cc')
Source('pl011.cc')
Source('pl111.cc')
Source('kmi.cc')
Source('timer_sp804.cc')
Source('rv_ctrl.cc')
Source('realview.cc')
Source('rtc_pl031.cc')
Source('timer_cpulocal.cc')
DebugFlag('AMBA')
DebugFlag('PL111')
DebugFlag('Pl050')
DebugFlag('GIC')

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#include "base/intmath.hh"
#include "base/trace.hh"
#include "dev/arm/a9scu.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "sim/system.hh"
A9SCU::A9SCU(Params *p)
: BasicPioDevice(p)
{
pioSize = 0x60;
}
Tick
A9SCU::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
switch(daddr) {
case Control:
pkt->set(1); // SCU already enabled
break;
case Config:
assert(sys->numContexts() <= 4);
int smp_bits, core_cnt;
smp_bits = power(2,sys->numContexts()) - 1;
core_cnt = sys->numContexts() - 1;
pkt->set(smp_bits << 4 | core_cnt);
break;
default:
// Only configuration register is implemented
panic("Tried to read SCU at offset %#x\n", daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
A9SCU::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
switch (daddr) {
default:
// Nothing implemented at this point
panic("Tried to write SCU at offset %#x\n", daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
A9SCU *
A9SCUParams::create()
{
return new A9SCU(this);
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#ifndef __DEV_ARM_A9SCU_HH__
#define __DEV_ARM_A9SCU_HH__
#include "base/range.hh"
#include "dev/io_device.hh"
#include "params/A9SCU.hh"
/** @file
* This defines the snoop control unit register on an A9
*/
class A9SCU : public BasicPioDevice
{
protected:
enum {
Control = 0x00,
Config = 0x04,
};
public:
typedef A9SCUParams Params;
/**
* The constructor for RealView just registers itself with the MMU.
* @param p params structure
*/
A9SCU(Params *p);
/**
* Handle a read to the device
* @param pkt The memory request.
* @param data Where to put the data.
*/
virtual Tick read(PacketPtr pkt);
/**
* All writes are panic.
* @param pkt The memory request.
* @param data the data
*/
virtual Tick write(PacketPtr pkt);
};
#endif // __DEV_ARM_A9SCU_HH__

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
#include "base/trace.hh"
#include "debug/AMBA.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/amba_fake.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
const uint64_t AmbaVendor = ULL(0xb105f00d00000000);
AmbaDevice::AmbaDevice(const Params *p)
: BasicPioDevice(p), ambaId(AmbaVendor | p->amba_id)
{
}
AmbaIntDevice::AmbaIntDevice(const Params *p)
: AmbaDevice(p), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay)
{
}
AmbaDmaDevice::AmbaDmaDevice(const Params *p)
: DmaDevice(p), ambaId(AmbaVendor | p->amba_id),
pioAddr(p->pio_addr), pioSize(0),
pioDelay(p->pio_latency),intNum(p->int_num), gic(p->gic)
{
}
namespace AmbaDev {
bool
readId(PacketPtr pkt, uint64_t amba_id, Addr pio_addr)
{
Addr daddr = pkt->getAddr() - pio_addr;
if (daddr < AMBA_PER_ID0 || daddr > AMBA_CEL_ID3)
return false;
pkt->allocate();
int byte = (daddr - AMBA_PER_ID0) << 1;
// Too noisy right now
DPRINTF(AMBA, "Returning %#x for offset %#x(%d)\n", (amba_id >> byte) & 0xFF,
pkt->getAddr() - pio_addr, byte);
assert(pkt->getSize() == 4);
pkt->set<uint32_t>((amba_id >> byte) & 0xFF);
return true;
}
} // namespace AmbaDev

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* This is a base class for AMBA devices that have to respond to Device and
* Implementer ID calls.
*/
#ifndef __DEV_ARM_AMBA_DEVICE_HH__
#define __DEV_ARM_AMBA_DEVICE_HH__
#include "base/range.hh"
#include "dev/arm/gic.hh"
#include "dev/dma_device.hh"
#include "dev/io_device.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/AmbaDevice.hh"
#include "params/AmbaDmaDevice.hh"
#include "params/AmbaIntDevice.hh"
namespace AmbaDev {
const int AMBA_PER_ID0 = 0xFE0;
const int AMBA_PER_ID1 = 0xFE4;
const int AMBA_PER_ID2 = 0xFE8;
const int AMBA_PER_ID3 = 0xFEC;
const int AMBA_CEL_ID0 = 0xFF0;
const int AMBA_CEL_ID1 = 0xFF4;
const int AMBA_CEL_ID2 = 0xFF8;
const int AMBA_CEL_ID3 = 0xFFC;
bool readId(PacketPtr pkt, uint64_t amba_id, Addr pio_addr);
}
class AmbaDevice : public BasicPioDevice
{
protected:
uint64_t ambaId;
public:
typedef AmbaDeviceParams Params;
AmbaDevice(const Params *p);
};
class AmbaIntDevice : public AmbaDevice
{
protected:
int intNum;
Gic *gic;
Tick intDelay;
public:
typedef AmbaIntDeviceParams Params;
AmbaIntDevice(const Params *p);
};
class AmbaDmaDevice : public DmaDevice
{
protected:
uint64_t ambaId;
Addr pioAddr;
Addr pioSize;
Tick pioDelay;
int intNum;
Gic *gic;
public:
typedef AmbaDmaDeviceParams Params;
AmbaDmaDevice(const Params *p);
};
#endif //__DEV_ARM_AMBA_DEVICE_HH__

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
#include "base/trace.hh"
#include "debug/AMBA.hh"
#include "dev/arm/amba_fake.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
using namespace AmbaDev;
AmbaFake::AmbaFake(const Params *p)
: AmbaDevice(p)
{
pioSize = 0xfff;
}
Tick
AmbaFake::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(AMBA, " read register %#x\n", daddr);
pkt->set<uint32_t>(0);
if (!readId(pkt, ambaId, pioAddr) && !params()->ignore_access)
panic("Tried to read AmbaFake at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
AmbaFake::write(PacketPtr pkt)
{
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
if (!params()->ignore_access)
panic("Tried to write AmbaFake at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
AmbaFake *
AmbaFakeParams::create()
{
return new AmbaFake(this);
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* This device sits in memory and reponds appropriately so the linux kernel
* ignores the device it is trying to talk to. It is used so the kernel doesn't
* need to be modified and devices that we are not interested in will simply be
* skipped.
*/
#ifndef __DEV_ARM_AMBA_FAKE_H__
#define __DEV_ARM_AMBA_FAKE_H__
#include "base/range.hh"
#include "dev/arm/amba_device.hh"
#include "params/AmbaFake.hh"
class AmbaFake : public AmbaDevice
{
public:
typedef AmbaFakeParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
AmbaFake(const Params *p);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
};
#endif //__DEV_ARM_AMBA_FAKE_H__

View File

@ -0,0 +1,843 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Prakash Ramrakhyani
*/
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/GIC.hh"
#include "debug/IPI.hh"
#include "debug/Interrupt.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/realview.hh"
#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
Gic::Gic(const Params *p)
: PioDevice(p), platform(p->platform), distAddr(p->dist_addr),
cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
enabled(false), itLines(p->it_lines)
{
itLinesLog2 = ceilLog2(itLines);
for (int x = 0; x < CPU_MAX; x++) {
cpuEnabled[x] = false;
cpuPriority[x] = 0xff;
cpuBpr[x] = 0;
// Initialize cpu highest int
cpuHighestInt[x] = SPURIOUS_INT;
postIntEvent[x] = new PostIntEvent(x, p->platform);
}
DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
cpuEnabled[1]);
for (int x = 0; x < INT_BITS_MAX; x++) {
intEnabled[x] = 0;
pendingInt[x] = 0;
activeInt[x] = 0;
}
for (int x = 0; x < INT_LINES_MAX; x++) {
intPriority[x] = 0;
cpuTarget[x] = 0;
}
for (int x = 0; x < INT_BITS_MAX*2; x++) {
intConfig[x] = 0;
}
for (int x = 0; x < SGI_MAX; x++) {
cpuSgiActive[x] = 0;
cpuSgiPending[x] = 0;
}
for (int x = 0; x < CPU_MAX; x++) {
cpuPpiActive[x] = 0;
cpuPpiPending[x] = 0;
}
for (int i = 0; i < CPU_MAX; i++) {
for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
bankedIntPriority[i][j] = 0;
}
}
RealView *rv = dynamic_cast<RealView*>(p->platform);
assert(rv);
rv->setGic(this);
}
Tick
Gic::read(PacketPtr pkt)
{
Addr addr = pkt->getAddr();
if (addr >= distAddr && addr < distAddr + DIST_SIZE)
return readDistributor(pkt);
else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
return readCpu(pkt);
else
panic("Read to unknown address %#x\n", pkt->getAddr());
}
Tick
Gic::write(PacketPtr pkt)
{
Addr addr = pkt->getAddr();
if (addr >= distAddr && addr < distAddr + DIST_SIZE)
return writeDistributor(pkt);
else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
return writeCpu(pkt);
else
panic("Write to unknown address %#x\n", pkt->getAddr());
}
Tick
Gic::readDistributor(PacketPtr pkt)
{
Addr daddr = pkt->getAddr() - distAddr;
pkt->allocate();
int ctx_id = pkt->req->contextId();
DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
assert((daddr-ICDISER_ST) >> 2 < 32);
pkt->set<uint32_t>(intEnabled[(daddr-ICDISER_ST)>>2]);
goto done;
}
if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
assert((daddr-ICDICER_ST) >> 2 < 32);
pkt->set<uint32_t>(intEnabled[(daddr-ICDICER_ST)>>2]);
goto done;
}
if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
assert((daddr-ICDISPR_ST) >> 2 < 32);
pkt->set<uint32_t>(pendingInt[(daddr-ICDISPR_ST)>>2]);
goto done;
}
if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
assert((daddr-ICDICPR_ST) >> 2 < 32);
pkt->set<uint32_t>(pendingInt[(daddr-ICDICPR_ST)>>2]);
goto done;
}
if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) {
assert((daddr-ICDABR_ST) >> 2 < 32);
pkt->set<uint32_t>(activeInt[(daddr-ICDABR_ST)>>2]);
goto done;
}
if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
Addr int_num;
int_num = daddr - ICDIPR_ST;
assert(int_num < INT_LINES_MAX);
DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
uint8_t* int_p;
if (int_num < (SGI_MAX + PPI_MAX))
int_p = bankedIntPriority[ctx_id];
else
int_p = intPriority;
switch (pkt->getSize()) {
case 1:
pkt->set<uint8_t>(int_p[int_num]);
break;
case 2:
assert((int_num + 1) < INT_LINES_MAX);
pkt->set<uint16_t>(int_p[int_num] |
int_p[int_num+1] << 8);
break;
case 4:
assert((int_num + 3) < INT_LINES_MAX);
pkt->set<uint32_t>(int_p[int_num] |
int_p[int_num+1] << 8 |
int_p[int_num+2] << 16 |
int_p[int_num+3] << 24);
break;
default:
panic("Invalid size while reading priority regs in GIC: %d\n",
pkt->getSize());
}
goto done;
}
if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
Addr int_num;
int_num = (daddr-ICDIPTR_ST) ;
DPRINTF(GIC, "Reading processor target register for int# %#x \n",
int_num);
assert(int_num < INT_LINES_MAX);
// First 31 interrupts only target single processor (SGI)
if (int_num > 31) {
if (pkt->getSize() == 1) {
pkt->set<uint8_t>(cpuTarget[int_num]);
} else {
assert(pkt->getSize() == 4);
int_num = mbits(int_num, 31, 2);
pkt->set<uint32_t>(cpuTarget[int_num] |
cpuTarget[int_num+1] << 8 |
cpuTarget[int_num+2] << 16 |
cpuTarget[int_num+3] << 24) ;
}
} else {
int ctx_id = pkt->req->contextId();
assert(ctx_id < sys->numRunningContexts());
pkt->set<uint32_t>(ctx_id);
}
goto done;
}
if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
assert((daddr-ICDICFR_ST) >> 2 < 64);
/** @todo software generated interrutps and PPIs
* can't be configured in some ways
*/
pkt->set<uint32_t>(intConfig[(daddr-ICDICFR_ST)>>2]);
goto done;
}
switch(daddr) {
case ICDDCR:
pkt->set<uint32_t>(enabled);
break;
case ICDICTR:
uint32_t tmp;
tmp = ((sys->numRunningContexts() - 1) << 5) |
(itLines/INT_BITS_MAX -1);
pkt->set<uint32_t>(tmp);
break;
default:
panic("Tried to read Gic distributor at offset %#x\n", daddr);
break;
}
done:
pkt->makeAtomicResponse();
return distPioDelay;
}
Tick
Gic::readCpu(PacketPtr pkt)
{
Addr daddr = pkt->getAddr() - cpuAddr;
pkt->allocate();
assert(pkt->req->hasContextId());
int ctx_id = pkt->req->contextId();
assert(ctx_id < sys->numRunningContexts());
DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
ctx_id);
switch(daddr) {
case ICCICR:
pkt->set<uint32_t>(cpuEnabled[ctx_id]);
break;
case ICCPMR:
pkt->set<uint32_t>(cpuPriority[ctx_id]);
break;
case ICCBPR:
pkt->set<uint32_t>(cpuBpr[ctx_id]);
break;
case ICCIAR:
if (enabled && cpuEnabled[ctx_id]) {
int active_int = cpuHighestInt[ctx_id];
IAR iar = 0;
iar.ack_id = active_int;
iar.cpu_id = 0;
if (active_int < SGI_MAX) {
// this is a software interrupt from another CPU
if (!cpuSgiPending[active_int])
panic("Interrupt %d active but no CPU generated it?\n",
active_int);
for (int x = 0; x < CPU_MAX; x++) {
// See which CPU generated the interrupt
uint8_t cpugen =
bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
if (cpugen & (1 << ctx_id)) {
iar.cpu_id = x;
break;
}
}
uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id);
cpuSgiActive[iar.ack_id] |= sgi_num;
cpuSgiPending[iar.ack_id] &= ~sgi_num;
} else if (active_int < (SGI_MAX + PPI_MAX) ) {
uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX);
cpuPpiActive[ctx_id] |= int_num;
updateRunPri();
cpuPpiPending[ctx_id] &= ~int_num;
} else {
uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
updateRunPri();
pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
}
DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
ctx_id, iar.ack_id, iar.cpu_id, iar);
cpuHighestInt[ctx_id] = SPURIOUS_INT;
updateIntState(-1);
pkt->set<uint32_t>(iar);
platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
} else {
pkt->set<uint32_t>(SPURIOUS_INT);
}
break;
case ICCRPR:
pkt->set<uint32_t>(iccrpr[0]);
break;
case ICCHPIR:
pkt->set<uint32_t>(0);
panic("Need to implement HPIR");
break;
default:
panic("Tried to read Gic cpu at offset %#x\n", daddr);
break;
}
pkt->makeAtomicResponse();
return cpuPioDelay;
}
Tick
Gic::writeDistributor(PacketPtr pkt)
{
Addr daddr = pkt->getAddr() - distAddr;
pkt->allocate();
assert(pkt->req->hasContextId());
int ctx_id = pkt->req->contextId();
DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
daddr, pkt->getSize(), pkt->get<uint32_t>());
if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
assert((daddr-ICDISER_ST) >> 2 < 32);
intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>();
goto done;
}
if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
assert((daddr-ICDICER_ST) >> 2 < 32);
intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>();
goto done;
}
if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
assert((daddr-ICDISPR_ST) >> 2 < 32);
pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>();
pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
updateIntState((daddr-ICDISPR_ST) >> 2);
goto done;
}
if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
assert((daddr-ICDICPR_ST) >> 2 < 32);
pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>();
pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
updateIntState((daddr-ICDICPR_ST) >> 2);
goto done;
}
if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
Addr int_num = daddr - ICDIPR_ST;
assert(int_num < INT_LINES_MAX);
uint8_t* int_p;
if (int_num < (SGI_MAX + PPI_MAX))
int_p = bankedIntPriority[ctx_id];
else
int_p = intPriority;
uint32_t tmp;
switch(pkt->getSize()) {
case 1:
tmp = pkt->get<uint8_t>();
int_p[int_num] = bits(tmp, 7, 0);
break;
case 2:
tmp = pkt->get<uint16_t>();
int_p[int_num] = bits(tmp, 7, 0);
int_p[int_num + 1] = bits(tmp, 15, 8);
break;
case 4:
tmp = pkt->get<uint32_t>();
int_p[int_num] = bits(tmp, 7, 0);
int_p[int_num + 1] = bits(tmp, 15, 8);
int_p[int_num + 2] = bits(tmp, 23, 16);
int_p[int_num + 3] = bits(tmp, 31, 24);
break;
default:
panic("Invalid size when writing to priority regs in Gic: %d\n",
pkt->getSize());
}
updateIntState(-1);
updateRunPri();
goto done;
}
if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
Addr int_num = (daddr-ICDIPTR_ST) ;
assert(int_num < INT_LINES_MAX);
// First 31 interrupts only target single processor
if (int_num >= SGI_MAX) {
if (pkt->getSize() == 1) {
uint8_t tmp = pkt->get<uint8_t>();
cpuTarget[int_num] = tmp & 0xff;
} else {
assert (pkt->getSize() == 4);
int_num = mbits(int_num, 31, 2);
uint32_t tmp = pkt->get<uint32_t>();
cpuTarget[int_num] = bits(tmp, 7, 0);
cpuTarget[int_num+1] = bits(tmp, 15, 8);
cpuTarget[int_num+2] = bits(tmp, 23, 16);
cpuTarget[int_num+3] = bits(tmp, 31, 24);
}
updateIntState((daddr-ICDIPTR_ST)>>2);
}
goto done;
}
if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
assert((daddr-ICDICFR_ST) >> 2 < 64);
intConfig[(daddr-ICDICFR_ST)>>2] = pkt->get<uint32_t>();
if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
warn("GIC N:N mode selected and not supported at this time\n");
goto done;
}
switch(daddr) {
case ICDDCR:
enabled = pkt->get<uint32_t>();
DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
break;
case ICDSGIR:
softInt(ctx_id, pkt->get<uint32_t>());
break;
default:
panic("Tried to write Gic distributor at offset %#x\n", daddr);
break;
}
done:
pkt->makeAtomicResponse();
return distPioDelay;
}
Tick
Gic::writeCpu(PacketPtr pkt)
{
Addr daddr = pkt->getAddr() - cpuAddr;
pkt->allocate();
assert(pkt->req->hasContextId());
int ctx_id = pkt->req->contextId();
IAR iar;
DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
ctx_id, daddr, pkt->get<uint32_t>());
switch(daddr) {
case ICCICR:
cpuEnabled[ctx_id] = pkt->get<uint32_t>();
break;
case ICCPMR:
cpuPriority[ctx_id] = pkt->get<uint32_t>();
break;
case ICCBPR:
cpuBpr[ctx_id] = pkt->get<uint32_t>();
break;
case ICCEOIR:
iar = pkt->get<uint32_t>();
if (iar.ack_id < SGI_MAX) {
// Clear out the bit that corrseponds to the cleared int
uint64_t clr_int = ULL(1) << (ctx_id + 8 * iar.cpu_id);
if (!(cpuSgiActive[iar.ack_id] & clr_int))
panic("Done handling a SGI that isn't active?\n");
cpuSgiActive[iar.ack_id] &= ~clr_int;
} else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
if (!(cpuPpiActive[ctx_id] & int_num))
panic("CPU %d Done handling a PPI interrupt that isn't active?\n", ctx_id);
cpuPpiActive[ctx_id] &= ~int_num;
} else {
uint32_t int_num = 1 << intNumToBit(iar.ack_id);
if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
panic("Done handling interrupt that isn't active?\n");
activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
}
updateRunPri();
DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
ctx_id, iar.ack_id, iar.cpu_id);
break;
default:
panic("Tried to write Gic cpu at offset %#x\n", daddr);
break;
}
if (cpuEnabled[ctx_id]) updateIntState(-1);
pkt->makeAtomicResponse();
return cpuPioDelay;
}
void
Gic::softInt(int ctx_id, SWI swi)
{
switch (swi.list_type) {
case 1:
// interrupt all
uint8_t cpu_list;
cpu_list = 0;
for (int x = 0; x < CPU_MAX; x++)
cpu_list |= cpuEnabled[x] ? 1 << x : 0;
swi.cpu_list = cpu_list;
break;
case 2:
// interrupt requesting cpu only
swi.cpu_list = 1 << ctx_id;
break;
// else interrupt cpus specified
}
DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id,
swi.cpu_list);
for (int i = 0; i < CPU_MAX; i++) {
DPRINTF(IPI, "Processing CPU %d\n", i);
if (!cpuEnabled[i])
continue;
if (swi.cpu_list & (1 << i))
cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx_id);
DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, cpuSgiPending[swi.sgi_id]);
}
updateIntState(-1);
}
uint64_t
Gic::genSwiMask(int cpu)
{
if (cpu > 7)
panic("Invalid CPU ID\n");
return ULL(0x0101010101010101) << cpu;
}
void
Gic::updateIntState(int hint)
{
for (int cpu = 0; cpu < CPU_MAX; cpu++) {
if (!cpuEnabled[cpu])
continue;
if (cpu >= sys->numContexts())
break;
/*@todo use hint to do less work. */
int highest_int = SPURIOUS_INT;
// Priorities below that set in ICCPMR can be ignored
uint8_t highest_pri = cpuPriority[cpu];
// Check SGIs
for (int swi = 0; swi < SGI_MAX; swi++) {
if (!cpuSgiPending[swi])
continue;
if (cpuSgiPending[swi] & genSwiMask(cpu))
if (highest_pri > bankedIntPriority[cpu][swi]) {
highest_pri = bankedIntPriority[cpu][swi];
highest_int = swi;
}
}
// Check PPIs
if (cpuPpiPending[cpu]) {
for (int ppi = 0; ppi < PPI_MAX; ppi++) {
if (cpuPpiPending[cpu] & (1 << ppi))
if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
highest_int = SGI_MAX + ppi;
}
}
}
bool mp_sys = sys->numRunningContexts() > 1;
// Check other ints
for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
if (intEnabled[x] & pendingInt[x]) {
for (int y = 0; y < INT_BITS_MAX; y++) {
uint32_t int_nm = x * INT_BITS_MAX + y;
DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
/* Set current pending int as highest int for current cpu
if the interrupt's priority higher than current prioirty
and if currrent cpu is the target (for mp configs only)
*/
if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
(intPriority[int_nm] < highest_pri))
if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) {
highest_pri = intPriority[int_nm];
highest_int = int_nm;
}
}
}
}
cpuHighestInt[cpu] = highest_int;
if (highest_int == SPURIOUS_INT)
continue;
/* @todo make this work for more than one cpu, need to handle 1:N, N:N
* models */
if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
!(activeInt[intNumToWord(highest_int)]
& (1 << intNumToBit(highest_int)))) {
DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
cpu);
postInt(cpu, curTick() + intLatency);
}
}
}
void
Gic::updateRunPri()
{
for (int cpu = 0; cpu < CPU_MAX; cpu++) {
if (!cpuEnabled[cpu])
continue;
uint8_t maxPriority = 0xff;
for (int i = 0; i < itLines; i++){
if (i < SGI_MAX) {
if ((cpuSgiActive[i] & genSwiMask(cpu)) &&
(bankedIntPriority[cpu][i] < maxPriority))
maxPriority = bankedIntPriority[cpu][i];
} else if (i < (SGI_MAX + PPI_MAX)) {
if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
(bankedIntPriority[cpu][i] < maxPriority))
maxPriority = bankedIntPriority[cpu][i];
} else {
if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
if (intPriority[i] < maxPriority)
maxPriority = intPriority[i];
}
}
iccrpr[cpu] = maxPriority;
}
}
void
Gic::sendInt(uint32_t num)
{
DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n",
num, cpuTarget[num]);
if (cpuTarget[num] & (cpuTarget[num] - 1))
panic("Multiple targets for peripheral interrupts is not supported\n");
pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
updateIntState(intNumToWord(num));
}
void
Gic::sendPPInt(uint32_t num, uint32_t cpu)
{
DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n",
num, cpu);
cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
updateIntState(intNumToWord(num));
}
void
Gic::clearInt(uint32_t number)
{
/* @todo assume edge triggered only at the moment. Nothing to do. */
}
void
Gic::postInt(uint32_t cpu, Tick when)
{
if (!(postIntEvent[cpu]->scheduled()))
eventq->schedule(postIntEvent[cpu], when);
}
AddrRangeList
Gic::getAddrRanges()
{
AddrRangeList ranges;
ranges.push_back(RangeSize(distAddr, DIST_SIZE));
ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
return ranges;
}
void
Gic::serialize(std::ostream &os)
{
DPRINTF(Checkpoint, "Serializing Arm GIC\n");
SERIALIZE_SCALAR(distAddr);
SERIALIZE_SCALAR(cpuAddr);
SERIALIZE_SCALAR(distPioDelay);
SERIALIZE_SCALAR(cpuPioDelay);
SERIALIZE_SCALAR(enabled);
SERIALIZE_SCALAR(itLines);
SERIALIZE_SCALAR(itLinesLog2);
SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
SERIALIZE_ARRAY(iccrpr, CPU_MAX);
SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
SERIALIZE_SCALAR(irqEnable);
Tick interrupt_time[CPU_MAX];
for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
interrupt_time[cpu] = 0;
if (postIntEvent[cpu]->scheduled()) {
interrupt_time[cpu] = postIntEvent[cpu]->when();
}
}
SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
}
void
Gic::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
UNSERIALIZE_SCALAR(distAddr);
UNSERIALIZE_SCALAR(cpuAddr);
UNSERIALIZE_SCALAR(distPioDelay);
UNSERIALIZE_SCALAR(cpuPioDelay);
UNSERIALIZE_SCALAR(enabled);
UNSERIALIZE_SCALAR(itLines);
UNSERIALIZE_SCALAR(itLinesLog2);
UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
UNSERIALIZE_SCALAR(irqEnable);
Tick interrupt_time[CPU_MAX];
UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
if (interrupt_time[cpu])
schedule(postIntEvent[cpu], interrupt_time[cpu]);
}
}
Gic *
GicParams::create()
{
return new Gic(this);
}
/* Functions for debugging and testing */
void
Gic::driveSPI(unsigned int spiVect)
{
DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
pendingInt[1] |= spiVect;
if (irqEnable && enabled) {
updateIntState(-1);
}
}
void
Gic::driveIrqEn( bool state)
{
irqEnable = state;
DPRINTF(GIC, " Enabling Irq\n");
updateIntState(-1);
}
void
Gic::driveLegIRQ(bool state)
{
if (irqEnable && !(!enabled && cpuEnabled[0])) {
if (state) {
DPRINTF(GIC, "Driving Legacy Irq\n");
platform->intrctrl->post(0, ArmISA::INT_IRQ, 0);
}
else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
}
}
void
Gic::driveLegFIQ(bool state)
{
if (state)
platform->intrctrl->post(0, ArmISA::INT_FIQ, 0);
else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0);
}

View File

@ -0,0 +1,321 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Implementiation of a PL390 GIC
*/
#ifndef __DEV_ARM_GIC_H__
#define __DEV_ARM_GIC_H__
#include "base/bitunion.hh"
#include "base/range.hh"
#include "dev/io_device.hh"
#include "dev/platform.hh"
#include "cpu/intr_control.hh"
#include "params/Gic.hh"
/** @todo this code only assumes one processor for now. Low word
* of intEnabled and pendingInt need to be replicated per CPU.
* bottom 31 interrupts (7 words) need to be replicated for
* for interrupt priority register, processor target registers
* interrupt config registers */
class Gic : public PioDevice
{
protected:
// distributor memory addresses
static const int ICDDCR = 0x000; // control register
static const int ICDICTR = 0x004; // controller type
static const int ICDIIDR = 0x008; // implementer id
static const int ICDISER_ST = 0x100; // interrupt set enable
static const int ICDISER_ED = 0x17c;
static const int ICDICER_ST = 0x180; // interrupt clear enable
static const int ICDICER_ED = 0x1fc;
static const int ICDISPR_ST = 0x200; // set pending interrupt
static const int ICDISPR_ED = 0x27c;
static const int ICDICPR_ST = 0x280; // clear pending interrupt
static const int ICDICPR_ED = 0x2fc;
static const int ICDABR_ST = 0x300; // active bit registers
static const int ICDABR_ED = 0x37c;
static const int ICDIPR_ST = 0x400; // interrupt priority registers
static const int ICDIPR_ED = 0x7f8;
static const int ICDIPTR_ST = 0x800; // processor target registers
static const int ICDIPTR_ED = 0xbf8;
static const int ICDICFR_ST = 0xc00; // interrupt config registers
static const int ICDICFR_ED = 0xcfc;
static const int ICDSGIR = 0xf00; // software generated interrupt
static const int DIST_SIZE = 0xfff;
// cpu memory addressesa
static const int ICCICR = 0x00; // CPU control register
static const int ICCPMR = 0x04; // Interrupt priority mask
static const int ICCBPR = 0x08; // binary point register
static const int ICCIAR = 0x0C; // interrupt ack register
static const int ICCEOIR = 0x10; // end of interrupt
static const int ICCRPR = 0x14; // runing priority
static const int ICCHPIR = 0x18; // highest pending interrupt
static const int ICCABPR = 0x1c; // aliased binary point
static const int ICCIIDR = 0xfc; // cpu interface id register
static const int CPU_SIZE = 0xff;
static const int SGI_MAX = 16; // Number of Software Gen Interrupts
static const int PPI_MAX = 16; // Number of Private Peripheral Interrupts
/** Mask off SGI's when setting/clearing pending bits */
static const int SGI_MASK = 0xFFFF0000;
/** Mask for bits that config N:N mode in ICDICFR's */
static const int NN_CONFIG_MASK = 0x55555555;
static const int CPU_MAX = 8; // Max number of supported CPU interfaces
static const int SPURIOUS_INT = 1023;
static const int INT_BITS_MAX = 32;
static const int INT_LINES_MAX = 1020;
BitUnion32(SWI)
Bitfield<3,0> sgi_id;
Bitfield<23,16> cpu_list;
Bitfield<25,24> list_type;
EndBitUnion(SWI)
BitUnion32(IAR)
Bitfield<9,0> ack_id;
Bitfield<12,10> cpu_id;
EndBitUnion(IAR)
Platform *platform;
/** Distributor address GIC listens at */
Addr distAddr;
/** CPU address GIC listens at */
/** @todo is this one per cpu? */
Addr cpuAddr;
/** Latency for a distributor operation */
Tick distPioDelay;
/** Latency for a cpu operation */
Tick cpuPioDelay;
/** Latency for a interrupt to get to CPU */
Tick intLatency;
/** Gic enabled */
bool enabled;
/** Number of itLines enabled */
uint32_t itLines;
uint32_t itLinesLog2;
/** interrupt enable bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t intEnabled[INT_BITS_MAX];
/** interrupt pending bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t pendingInt[INT_BITS_MAX];
/** interrupt active bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t activeInt[INT_BITS_MAX];
/** read only running priroity register, 1 per cpu*/
uint32_t iccrpr[CPU_MAX];
/** an 8 bit priority (lower is higher priority) for each
* of the 1020 possible supported interrupts.
*/
uint8_t intPriority[INT_LINES_MAX];
/** an 8 bit cpu target id for each shared peripheral interrupt
* of the 1020 possible supported interrupts.
*/
uint8_t cpuTarget[INT_LINES_MAX];
/** 2 bit per interrupt signaling if it's level or edge sensitive
* and if it is 1:N or N:N */
uint32_t intConfig[INT_BITS_MAX*2];
/** CPU enabled */
bool cpuEnabled[CPU_MAX];
/** CPU priority */
uint8_t cpuPriority[CPU_MAX];
/** Binary point registers */
uint8_t cpuBpr[CPU_MAX];
/** highest interrupt that is interrupting CPU */
uint32_t cpuHighestInt[CPU_MAX];
/** One bit per cpu per software interrupt that is pending for each possible
* sgi source. Indexed by SGI number. Each byte in generating cpu id and
* bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt
* for CPU 2. */
uint64_t cpuSgiPending[SGI_MAX];
uint64_t cpuSgiActive[SGI_MAX];
/** One bit per private peripheral interrupt. Only upper 16 bits
* will be used since PPI interrupts are numberred from 16 to 32 */
uint32_t cpuPpiPending[CPU_MAX];
uint32_t cpuPpiActive[CPU_MAX];
/** Banked interrupt prioirty registers for SGIs and PPIs */
uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];
/** IRQ Enable Used for debug */
bool irqEnable;
/** software generated interrupt
* @param data data to decode that indicates which cpus to interrupt
*/
void softInt(int ctx_id, SWI swi);
/** See if some processor interrupt flags need to be enabled/disabled
* @param hint which set of interrupts needs to be checked
*/
void updateIntState(int hint);
/** Update the register that records priority of the highest priority
* active interrupt*/
void updateRunPri();
/** generate a bit mask to check cpuSgi for an interrupt. */
uint64_t genSwiMask(int cpu);
int intNumToWord(int num) const { return num >> 5; }
int intNumToBit(int num) const { return num % 32; }
/** Post an interrupt to a CPU
*/
void postInt(uint32_t cpu, Tick when);
/** Event definition to post interrupt to CPU after a delay
*/
class PostIntEvent : public Event
{
private:
uint32_t cpu;
Platform *platform;
public:
PostIntEvent( uint32_t c, Platform* p)
: cpu(c), platform(p)
{ }
void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
const char *description() const { return "Post Interrupt to CPU"; }
};
PostIntEvent *postIntEvent[CPU_MAX];
public:
typedef GicParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Gic(const Params *p);
/** Return the address ranges used by the Gic
* This is the distributor address + all cpu addresses
*/
virtual AddrRangeList getAddrRanges();
/** A PIO read to the device, immediately split up into
* readDistributor() or readCpu()
*/
virtual Tick read(PacketPtr pkt);
/** A PIO read to the device, immediately split up into
* writeDistributor() or writeCpu()
*/
virtual Tick write(PacketPtr pkt);
/** Handle a read to the distributor poriton of the GIC
* @param pkt packet to respond to
*/
Tick readDistributor(PacketPtr pkt);
/** Handle a read to the cpu poriton of the GIC
* @param pkt packet to respond to
*/
Tick readCpu(PacketPtr pkt);
/** Handle a write to the distributor poriton of the GIC
* @param pkt packet to respond to
*/
Tick writeDistributor(PacketPtr pkt);
/** Handle a write to the cpu poriton of the GIC
* @param pkt packet to respond to
*/
Tick writeCpu(PacketPtr pkt);
/** Post an interrupt from a device that is connected to the Gic.
* Depending on the configuration, the gic will pass this interrupt
* on through to a CPU.
* @param number number of interrupt to send */
void sendInt(uint32_t number);
/** Interface call for private peripheral interrupts */
void sendPPInt(uint32_t num, uint32_t cpu);
/** Clear an interrupt from a device that is connected to the Gic
* Depending on the configuration, the gic may de-assert it's cpu line
* @param number number of interrupt to send */
void clearInt(uint32_t number);
/* Various functions fer testing and debugging */
void driveSPI(uint32_t spi);
void driveLegIRQ(bool state);
void driveLegFIQ(bool state);
void driveIrqEn(bool state);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif //__DEV_ARM_GIC_H__

View File

@ -0,0 +1,371 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* William Wang
*/
#include "base/vnc/vncserver.hh"
#include "base/trace.hh"
#include "debug/Pl050.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/kmi.hh"
#include "dev/ps2.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
Pl050::Pl050(const Params *p)
: AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0),
rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc),
driverInitialized(false), intEvent(this)
{
pioSize = 0xfff;
if (vnc) {
if (!p->is_mouse)
vnc->setKeyboard(this);
else
vnc->setMouse(this);
}
}
Tick
Pl050::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
uint32_t data = 0;
switch (daddr) {
case kmiCr:
DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control);
data = control;
break;
case kmiStat:
if (rxQueue.empty())
status.rxfull = 0;
else
status.rxfull = 1;
DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status);
data = status;
break;
case kmiData:
if (rxQueue.empty()) {
data = 0;
} else {
data = rxQueue.front();
rxQueue.pop_front();
}
DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data);
updateIntStatus();
break;
case kmiClkDiv:
data = clkdiv;
break;
case kmiISR:
data = interrupts;
DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts);
break;
default:
if (AmbaDev::readId(pkt, ambaId, pioAddr)) {
// Hack for variable size accesses
data = pkt->get<uint32_t>();
break;
}
warn("Tried to read PL050 at offset %#x that doesn't exist\n", daddr);
break;
}
switch(pkt->getSize()) {
case 1:
pkt->set<uint8_t>(data);
break;
case 2:
pkt->set<uint16_t>(data);
break;
case 4:
pkt->set<uint32_t>(data);
break;
default:
panic("KMI read size too big?\n");
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
Pl050::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
assert(pkt->getSize() == sizeof(uint8_t));
switch (daddr) {
case kmiCr:
DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get<uint8_t>());
control = pkt->get<uint8_t>();
updateIntStatus();
break;
case kmiData:
DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get<uint8_t>());
processCommand(pkt->get<uint8_t>());
updateIntStatus();
break;
case kmiClkDiv:
clkdiv = pkt->get<uint8_t>();
break;
default:
warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
Pl050::processCommand(uint8_t byte)
{
using namespace Ps2;
if (ackNext) {
ackNext--;
rxQueue.push_back(Ack);
updateIntStatus();
return;
}
switch (byte) {
case Ps2Reset:
rxQueue.push_back(Ack);
rxQueue.push_back(SelfTestPass);
break;
case SetResolution:
case SetRate:
case SetStatusLed:
case SetScaling1_1:
case SetScaling1_2:
rxQueue.push_back(Ack);
ackNext = 1;
break;
case ReadId:
rxQueue.push_back(Ack);
if (params()->is_mouse)
rxQueue.push_back(MouseId);
else
rxQueue.push_back(KeyboardId);
break;
case TpReadId:
if (!params()->is_mouse)
break;
// We're not a trackpoint device, this should make the probe go away
rxQueue.push_back(Ack);
rxQueue.push_back(0);
rxQueue.push_back(0);
// fall through
case Disable:
case Enable:
case SetDefaults:
rxQueue.push_back(Ack);
break;
case StatusRequest:
rxQueue.push_back(Ack);
rxQueue.push_back(0);
rxQueue.push_back(2); // default resolution
rxQueue.push_back(100); // default sample rate
break;
case TouchKitId:
ackNext = 2;
rxQueue.push_back(Ack);
rxQueue.push_back(TouchKitId);
rxQueue.push_back(1);
rxQueue.push_back('A');
driverInitialized = true;
break;
default:
panic("Unknown byte received: %d\n", byte);
}
updateIntStatus();
}
void
Pl050::updateIntStatus()
{
if (!rxQueue.empty())
rawInterrupts.rx = 1;
else
rawInterrupts.rx = 0;
interrupts.tx = rawInterrupts.tx & control.txint_enable;
interrupts.rx = rawInterrupts.rx & control.rxint_enable;
DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n",
(uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts);
if (interrupts && !intEvent.scheduled())
schedule(intEvent, curTick() + intDelay);
}
void
Pl050::generateInterrupt()
{
if (interrupts) {
gic->sendInt(intNum);
DPRINTF(Pl050, "Generated interrupt\n");
}
}
void
Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons)
{
using namespace Ps2;
// If the driver hasn't initialized the device yet, no need to try and send
// it anything. Similarly we can get vnc mouse events orders of maginture
// faster than m5 can process them. Only queue up two sets mouse movements
// and don't add more until those are processed.
if (!driverInitialized || rxQueue.size() > 10)
return;
// We shouldn't be here unless a vnc server called us in which case
// we should have a pointer to it
assert(vnc);
// Convert screen coordinates to touchpad coordinates
uint16_t _x = (2047.0/vnc->videoWidth()) * x;
uint16_t _y = (2047.0/vnc->videoHeight()) * y;
rxQueue.push_back(buttons);
rxQueue.push_back(_x >> 7);
rxQueue.push_back(_x & 0x7f);
rxQueue.push_back(_y >> 7);
rxQueue.push_back(_y & 0x7f);
updateIntStatus();
}
void
Pl050::keyPress(uint32_t key, bool down)
{
using namespace Ps2;
std::list<uint8_t> keys;
// convert the X11 keysym into ps2 codes
keySymToPs2(key, down, shiftDown, keys);
// Insert into our queue of charecters
rxQueue.splice(rxQueue.end(), keys);
updateIntStatus();
}
void
Pl050::serialize(std::ostream &os)
{
uint8_t ctrlreg = control;
SERIALIZE_SCALAR(ctrlreg);
uint8_t stsreg = status;
SERIALIZE_SCALAR(stsreg);
SERIALIZE_SCALAR(clkdiv);
uint8_t ints = interrupts;
SERIALIZE_SCALAR(ints);
uint8_t raw_ints = rawInterrupts;
SERIALIZE_SCALAR(raw_ints);
SERIALIZE_SCALAR(ackNext);
SERIALIZE_SCALAR(shiftDown);
SERIALIZE_SCALAR(driverInitialized);
arrayParamOut(os, "rxQueue", rxQueue);
}
void
Pl050::unserialize(Checkpoint *cp, const std::string &section)
{
uint8_t ctrlreg;
UNSERIALIZE_SCALAR(ctrlreg);
control = ctrlreg;
uint8_t stsreg;
UNSERIALIZE_SCALAR(stsreg);
status = stsreg;
UNSERIALIZE_SCALAR(clkdiv);
uint8_t ints;
UNSERIALIZE_SCALAR(ints);
interrupts = ints;
uint8_t raw_ints;
UNSERIALIZE_SCALAR(raw_ints);
rawInterrupts = raw_ints;
UNSERIALIZE_SCALAR(ackNext);
UNSERIALIZE_SCALAR(shiftDown);
UNSERIALIZE_SCALAR(driverInitialized);
arrayParamIn(cp, section, "rxQueue", rxQueue);
}
Pl050 *
Pl050Params::create()
{
return new Pl050(this);
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: William Wang
*/
/** @file
* Implementiation of a PL050 KMI
*/
#ifndef __DEV_ARM_PL050_HH__
#define __DEV_ARM_PL050_HH__
#include <list>
#include "base/vnc/vncserver.hh"
#include "base/range.hh"
#include "dev/arm/amba_device.hh"
#include "params/Pl050.hh"
class Gic;
class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse
{
protected:
static const int kmiCr = 0x000;
static const int kmiStat = 0x004;
static const int kmiData = 0x008;
static const int kmiClkDiv = 0x00C;
static const int kmiISR = 0x010;
BitUnion8(ControlReg)
Bitfield<0> force_clock_low;
Bitfield<1> force_data_low;
Bitfield<2> enable;
Bitfield<3> txint_enable;
Bitfield<4> rxint_enable;
Bitfield<5> type;
EndBitUnion(ControlReg)
/** control register
*/
ControlReg control;
/** KMI status register */
BitUnion8(StatusReg)
Bitfield<0> data_in;
Bitfield<1> clk_in;
Bitfield<2> rxparity;
Bitfield<3> rxbusy;
Bitfield<4> rxfull;
Bitfield<5> txbusy;
Bitfield<6> txempty;
EndBitUnion(StatusReg)
StatusReg status;
/** clock divisor register
* This register is just kept around to satisfy reads after driver does
* writes. The divsor does nothing, as we're not actually signaling ps2
* serial commands to anything.
*/
uint8_t clkdiv;
BitUnion8(InterruptReg)
Bitfield<0> rx;
Bitfield<1> tx;
EndBitUnion(InterruptReg)
/** interrupt status register. */
InterruptReg interrupts;
/** raw interrupt register (unmasked) */
InterruptReg rawInterrupts;
/** If the controller should ignore the next data byte and acknowledge it.
* The driver is attempting to setup some feature we don't care about
*/
int ackNext;
/** is the shift key currently down */
bool shiftDown;
/** The vnc server we're connected to (if any) */
VncServer *vnc;
/** If the linux driver has initialized the device yet and thus can we send
* mouse data */
bool driverInitialized;
/** Update the status of the interrupt registers and schedule an interrupt
* if required */
void updateIntStatus();
/** Function to generate interrupt */
void generateInterrupt();
/** Wrapper to create an event out of the thing */
EventWrapper<Pl050, &Pl050::generateInterrupt> intEvent;
/** Receive queue. This list contains all the pending commands that
* need to be sent to the driver
*/
std::list<uint8_t> rxQueue;
/** Handle a command sent to the kmi and respond appropriately
*/
void processCommand(uint8_t byte);
public:
typedef Pl050Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Pl050(const Params *p);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons);
virtual void keyPress(uint32_t key, bool down);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ARM_PL050_HH__

View File

@ -0,0 +1,331 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Uart.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/pl011.hh"
#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "sim/sim_exit.hh"
Pl011::Pl011(const Params *p)
: Uart(p), control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12), imsc(0),
rawInt(0), maskInt(0), intNum(p->int_num), gic(p->gic),
endOnEOT(p->end_on_eot), intDelay(p->int_delay), intEvent(this)
{
pioSize = 0xfff;
}
Tick
Pl011::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize());
// use a temporary data since the uart registers are read/written with
// different size operations
//
uint32_t data = 0;
switch(daddr) {
case UART_DR:
data = 0;
if (term->dataAvailable())
data = term->in();
break;
case UART_FR:
// For now we're infintely fast, so TX is never full, always empty,
// always clear to send
data = UART_FR_TXFE | UART_FR_CTS;
if (!term->dataAvailable())
data |= UART_FR_RXFE;
DPRINTF(Uart, "Reading FR register as %#x rawInt=0x%x imsc=0x%x maskInt=0x%x\n",
data, rawInt, imsc, maskInt);
break;
case UART_CR:
data = control;
break;
case UART_IBRD:
data = ibrd;
break;
case UART_FBRD:
data = fbrd;
break;
case UART_LCRH:
data = lcrh;
break;
case UART_IFLS:
data = ifls;
break;
case UART_IMSC:
data = imsc;
break;
case UART_RIS:
data = rawInt;
DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt);
break;
case UART_MIS:
DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", rawInt);
data = maskInt;
break;
default:
if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
// Hack for variable size accesses
data = pkt->get<uint32_t>();
break;
}
panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr);
break;
}
switch(pkt->getSize()) {
case 1:
pkt->set<uint8_t>(data);
break;
case 2:
pkt->set<uint16_t>(data);
break;
case 4:
pkt->set<uint32_t>(data);
break;
default:
panic("Uart read size too big?\n");
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
Pl011::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr,
pkt->get<uint8_t>(), pkt->getSize());
// use a temporary data since the uart registers are read/written with
// different size operations
//
uint32_t data = 0;
switch(pkt->getSize()) {
case 1:
data = pkt->get<uint8_t>();
break;
case 2:
data = pkt->get<uint16_t>();
break;
case 4:
data = pkt->get<uint32_t>();
break;
default:
panic("Uart write size too big?\n");
break;
}
switch (daddr) {
case UART_DR:
if ((data & 0xFF) == 0x04 && endOnEOT)
exitSimLoop("UART received EOT", 0);
term->out(data & 0xFF);
//raw interrupt is set regardless of imsc.txim
rawInt.txim = 1;
if (imsc.txim) {
DPRINTF(Uart, "TX int enabled, scheduling interruptt\n");
if (!intEvent.scheduled())
schedule(intEvent, curTick() + intDelay);
}
break;
case UART_CR:
control = data;
break;
case UART_IBRD:
ibrd = data;
break;
case UART_FBRD:
fbrd = data;
break;
case UART_LCRH:
lcrh = data;
break;
case UART_IFLS:
ifls = data;
break;
case UART_IMSC:
imsc = data;
if (imsc.rimim || imsc.ctsmim || imsc.dcdmim || imsc.dsrmim
|| imsc.feim || imsc.peim || imsc.beim || imsc.oeim || imsc.rsvd)
panic("Unknown interrupt enabled\n");
if (imsc.txim) {
DPRINTF(Uart, "Writing to IMSC: TX int enabled, scheduling interruptt\n");
rawInt.txim = 1;
if (!intEvent.scheduled())
schedule(intEvent, curTick() + intDelay);
}
break;
case UART_ICR:
DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
rawInt = rawInt & ~data;
maskInt = rawInt & imsc;
DPRINTF(Uart, " -- Masked interrupts 0x%x\n", maskInt);
if (!maskInt)
gic->clearInt(intNum);
break;
default:
panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
Pl011::dataAvailable()
{
/*@todo ignore the fifo, just say we have data now
* We might want to fix this, or we might not care */
rawInt.rxim = 1;
rawInt.rtim = 1;
DPRINTF(Uart, "Data available, scheduling interrupt\n");
if (!intEvent.scheduled())
schedule(intEvent, curTick() + intDelay);
}
void
Pl011::generateInterrupt()
{
DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n",
imsc, rawInt, maskInt);
maskInt = imsc & rawInt;
if (maskInt.rxim || maskInt.rtim || maskInt.txim) {
gic->sendInt(intNum);
DPRINTF(Uart, " -- Generated\n");
}
}
void
Pl011::serialize(std::ostream &os)
{
DPRINTF(Checkpoint, "Serializing Arm PL011\n");
SERIALIZE_SCALAR(control);
SERIALIZE_SCALAR(fbrd);
SERIALIZE_SCALAR(ibrd);
SERIALIZE_SCALAR(lcrh);
SERIALIZE_SCALAR(ifls);
uint16_t imsc_serial = imsc;
SERIALIZE_SCALAR(imsc_serial);
uint16_t rawInt_serial = rawInt;
SERIALIZE_SCALAR(rawInt_serial);
uint16_t maskInt_serial = maskInt;
SERIALIZE_SCALAR(maskInt_serial);
SERIALIZE_SCALAR(endOnEOT);
SERIALIZE_SCALAR(intDelay);
}
void
Pl011::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(Checkpoint, "Unserializing Arm PL011\n");
UNSERIALIZE_SCALAR(control);
UNSERIALIZE_SCALAR(fbrd);
UNSERIALIZE_SCALAR(ibrd);
UNSERIALIZE_SCALAR(lcrh);
UNSERIALIZE_SCALAR(ifls);
uint16_t imsc_serial;
UNSERIALIZE_SCALAR(imsc_serial);
imsc = imsc_serial;
uint16_t rawInt_serial;
UNSERIALIZE_SCALAR(rawInt_serial);
rawInt = rawInt_serial;
uint16_t maskInt_serial;
UNSERIALIZE_SCALAR(maskInt_serial);
maskInt = maskInt_serial;
UNSERIALIZE_SCALAR(endOnEOT);
UNSERIALIZE_SCALAR(intDelay);
}
Pl011 *
Pl011Params::create()
{
return new Pl011(this);
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Implementiation of a PL011 UART
*/
#ifndef __DEV_ARM_PL011_H__
#define __DEV_ARM_PL011_H__
#include "base/range.hh"
#include "dev/io_device.hh"
#include "dev/uart.hh"
#include "params/Pl011.hh"
class Gic;
class Pl011 : public Uart
{
protected:
static const uint64_t AMBA_ID = ULL(0xb105f00d00341011);
static const int UART_DR = 0x000;
static const int UART_FR = 0x018;
static const int UART_FR_CTS = 0x001;
static const int UART_FR_TXFE = 0x080;
static const int UART_FR_RXFE = 0x010;
static const int UART_IBRD = 0x024;
static const int UART_FBRD = 0x028;
static const int UART_LCRH = 0x02C;
static const int UART_CR = 0x030;
static const int UART_IFLS = 0x034;
static const int UART_IMSC = 0x038;
static const int UART_RIS = 0x03C;
static const int UART_MIS = 0x040;
static const int UART_ICR = 0x044;
uint16_t control;
/** fractional baud rate divisor. Not used for anything but reporting
* written value */
uint16_t fbrd;
/** integer baud rate divisor. Not used for anything but reporting
* written value */
uint16_t ibrd;
/** Line control register. Not used for anything but reporting
* written value */
uint16_t lcrh;
/** interrupt fifo level register. Not used for anything but reporting
* written value */
uint16_t ifls;
BitUnion16(INTREG)
Bitfield<0> rimim;
Bitfield<1> ctsmim;
Bitfield<2> dcdmim;
Bitfield<3> dsrmim;
Bitfield<4> rxim;
Bitfield<5> txim;
Bitfield<6> rtim;
Bitfield<7> feim;
Bitfield<8> peim;
Bitfield<9> beim;
Bitfield<10> oeim;
Bitfield<15,11> rsvd;
EndBitUnion(INTREG)
/** interrupt mask register. */
INTREG imsc;
/** raw interrupt status register */
INTREG rawInt;
/** Masked interrupt status register */
INTREG maskInt;
/** Interrupt number to generate */
int intNum;
/** Gic to use for interrupting */
Gic *gic;
/** Should the simulation end on an EOT */
bool endOnEOT;
/** Delay before interrupting */
Tick intDelay;
/** Function to generate interrupt */
void generateInterrupt();
/** Wrapper to create an event out of the thing */
EventWrapper<Pl011, &Pl011::generateInterrupt> intEvent;
public:
typedef Pl011Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Pl011(const Params *p);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
/**
* Inform the uart that there is data available.
*/
virtual void dataAvailable();
/**
* Return if we have an interrupt pending
* @return interrupt status
* @todo fix me when implementation improves
*/
virtual bool intStatus() { return false; }
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif //__DEV_ARM_PL011_H__

View File

@ -0,0 +1,757 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: William Wang
* Ali Saidi
*/
#include "base/vnc/vncserver.hh"
#include "base/bitmap.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "debug/PL111.hh"
#include "debug/Uart.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/pl111.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
// clang complains about std::set being overloaded with Packet::set if
// we open up the entire namespace std
using std::vector;
using namespace AmbaDev;
// initialize clcd registers
Pl111::Pl111(const Params *p)
: AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0),
lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0),
lcdRis(0), lcdMis(0),
clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0),
clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0),
clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p->clock),
vncserver(p->vnc), bmp(NULL), width(LcdMaxWidth), height(LcdMaxHeight),
bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0),
waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this),
dmaDoneEvent(maxOutstandingDma, this), intEvent(this)
{
pioSize = 0xFFFF;
pic = simout.create(csprintf("%s.framebuffer.bmp", sys->name()), true);
const int buffer_size = LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t);
dmaBuffer = new uint8_t[buffer_size];
memset(lcdPalette, 0, sizeof(lcdPalette));
memset(cursorImage, 0, sizeof(cursorImage));
memset(dmaBuffer, 0, buffer_size);
if (vncserver)
vncserver->setFramebufferAddr(dmaBuffer);
}
// read registers and frame buffer
Tick
Pl111::read(PacketPtr pkt)
{
// use a temporary data since the LCD registers are read/written with
// different size operations
uint32_t data = 0;
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize());
switch (daddr) {
case LcdTiming0:
data = lcdTiming0;
break;
case LcdTiming1:
data = lcdTiming1;
break;
case LcdTiming2:
data = lcdTiming2;
break;
case LcdTiming3:
data = lcdTiming3;
break;
case LcdUpBase:
data = lcdUpbase;
break;
case LcdLpBase:
data = lcdLpbase;
break;
case LcdControl:
data = lcdControl;
break;
case LcdImsc:
data = lcdImsc;
break;
case LcdRis:
data = lcdRis;
break;
case LcdMis:
data = lcdMis;
break;
case LcdIcr:
panic("LCD register at offset %#x is Write-Only\n", daddr);
break;
case LcdUpCurr:
data = curAddr;
break;
case LcdLpCurr:
data = curAddr;
break;
case ClcdCrsrCtrl:
data = clcdCrsrCtrl;
break;
case ClcdCrsrConfig:
data = clcdCrsrConfig;
break;
case ClcdCrsrPalette0:
data = clcdCrsrPalette0;
break;
case ClcdCrsrPalette1:
data = clcdCrsrPalette1;
break;
case ClcdCrsrXY:
data = clcdCrsrXY;
break;
case ClcdCrsrClip:
data = clcdCrsrClip;
break;
case ClcdCrsrImsc:
data = clcdCrsrImsc;
break;
case ClcdCrsrIcr:
panic("CLCD register at offset %#x is Write-Only\n", daddr);
break;
case ClcdCrsrRis:
data = clcdCrsrRis;
break;
case ClcdCrsrMis:
data = clcdCrsrMis;
break;
default:
if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
// Hack for variable size accesses
data = pkt->get<uint32_t>();
break;
} else if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
data= cursorImage[index];
break;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
data = lcdPalette[index];
break;
} else {
panic("Tried to read CLCD register at offset %#x that \
doesn't exist\n", daddr);
break;
}
}
switch(pkt->getSize()) {
case 1:
pkt->set<uint8_t>(data);
break;
case 2:
pkt->set<uint16_t>(data);
break;
case 4:
pkt->set<uint32_t>(data);
break;
default:
panic("CLCD controller read size too big?\n");
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
// write registers and frame buffer
Tick
Pl111::write(PacketPtr pkt)
{
// use a temporary data since the LCD registers are read/written with
// different size operations
//
uint32_t data = 0;
switch(pkt->getSize()) {
case 1:
data = pkt->get<uint8_t>();
break;
case 2:
data = pkt->get<uint16_t>();
break;
case 4:
data = pkt->get<uint32_t>();
break;
default:
panic("PL111 CLCD controller write size too big?\n");
break;
}
assert(pkt->getAddr() >= pioAddr &&
pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr,
pkt->get<uint8_t>(), pkt->getSize());
switch (daddr) {
case LcdTiming0:
lcdTiming0 = data;
// width = 16 * (PPL+1)
width = (lcdTiming0.ppl + 1) << 4;
break;
case LcdTiming1:
lcdTiming1 = data;
// height = LPP + 1
height = (lcdTiming1.lpp) + 1;
break;
case LcdTiming2:
lcdTiming2 = data;
break;
case LcdTiming3:
lcdTiming3 = data;
break;
case LcdUpBase:
lcdUpbase = data;
DPRINTF(PL111, "####### Upper panel base set to: %#x #######\n", lcdUpbase);
break;
case LcdLpBase:
warn_once("LCD dual screen mode not supported\n");
lcdLpbase = data;
DPRINTF(PL111, "###### Lower panel base set to: %#x #######\n", lcdLpbase);
break;
case LcdControl:
int old_lcdpwr;
old_lcdpwr = lcdControl.lcdpwr;
lcdControl = data;
DPRINTF(PL111, "LCD power is:%d\n", lcdControl.lcdpwr);
// LCD power enable
if (lcdControl.lcdpwr && !old_lcdpwr) {
updateVideoParams();
DPRINTF(PL111, " lcd size: height %d width %d\n", height, width);
waterMark = lcdControl.watermark ? 8 : 4;
startDma();
}
break;
case LcdImsc:
lcdImsc = data;
if (lcdImsc.vcomp)
panic("Interrupting on vcomp not supported\n");
lcdMis = lcdImsc & lcdRis;
if (!lcdMis)
gic->clearInt(intNum);
break;
case LcdRis:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdMis:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdIcr:
lcdRis = lcdRis & ~data;
lcdMis = lcdImsc & lcdRis;
if (!lcdMis)
gic->clearInt(intNum);
break;
case LcdUpCurr:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case LcdLpCurr:
panic("LCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrCtrl:
clcdCrsrCtrl = data;
break;
case ClcdCrsrConfig:
clcdCrsrConfig = data;
break;
case ClcdCrsrPalette0:
clcdCrsrPalette0 = data;
break;
case ClcdCrsrPalette1:
clcdCrsrPalette1 = data;
break;
case ClcdCrsrXY:
clcdCrsrXY = data;
break;
case ClcdCrsrClip:
clcdCrsrClip = data;
break;
case ClcdCrsrImsc:
clcdCrsrImsc = data;
break;
case ClcdCrsrIcr:
clcdCrsrIcr = data;
break;
case ClcdCrsrRis:
panic("CLCD register at offset %#x is Read-Only\n", daddr);
break;
case ClcdCrsrMis:
panic("CLCD register at offset %#x is Read-Only\n", daddr);
break;
default:
if (daddr >= CrsrImage && daddr <= 0xBFC) {
// CURSOR IMAGE
int index;
index = (daddr - CrsrImage) >> 2;
cursorImage[index] = data;
break;
} else if (daddr >= LcdPalette && daddr <= 0x3FC) {
// LCD Palette
int index;
index = (daddr - LcdPalette) >> 2;
lcdPalette[index] = data;
break;
} else {
panic("Tried to write PL111 register at offset %#x that \
doesn't exist\n", daddr);
break;
}
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
Pl111::updateVideoParams()
{
if (lcdControl.lcdbpp == bpp24) {
bytesPerPixel = 4;
} else if (lcdControl.lcdbpp == bpp16m565) {
bytesPerPixel = 2;
}
if (vncserver) {
if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::bgr8888, width,
height);
else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::rgb8888, width,
height);
else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::bgr565, width,
height);
else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
vncserver->setFrameBufferParams(VideoConvert::rgb565, width,
height);
else
panic("Unimplemented video mode\n");
}
if (bmp)
delete bmp;
if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr)
bmp = new Bitmap(VideoConvert::bgr8888, width, height, dmaBuffer);
else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr)
bmp = new Bitmap(VideoConvert::rgb8888, width, height, dmaBuffer);
else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr)
bmp = new Bitmap(VideoConvert::bgr565, width, height, dmaBuffer);
else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr)
bmp = new Bitmap(VideoConvert::rgb565, width, height, dmaBuffer);
else
panic("Unimplemented video mode\n");
}
void
Pl111::startDma()
{
if (dmaPendingNum != 0 || readEvent.scheduled())
return;
readFramebuffer();
}
void
Pl111::readFramebuffer()
{
// initialization for dma read from frame buffer to dma buffer
uint32_t length = height * width;
if (startAddr != lcdUpbase)
startAddr = lcdUpbase;
// Updating base address, interrupt if we're supposed to
lcdRis.baseaddr = 1;
if (!intEvent.scheduled())
schedule(intEvent, nextCycle());
curAddr = 0;
startTime = curTick();
maxAddr = static_cast<Addr>(length * bytesPerPixel);
DPRINTF(PL111, " lcd frame buffer size of %d bytes \n", maxAddr);
dmaPendingNum = 0;
fillFifo();
}
void
Pl111::fillFifo()
{
while ((dmaPendingNum < maxOutstandingDma) && (maxAddr >= curAddr + dmaSize )) {
// concurrent dma reads need different dma done events
// due to assertion in scheduling state
++dmaPendingNum;
assert(!dmaDoneEvent[dmaPendingNum-1].scheduled());
// We use a uncachable request here because the requests from the CPU
// will be uncacheable as well. If we have uncacheable and cacheable
// requests in the memory system for the same address it won't be
// pleased
dmaPort.dmaAction(MemCmd::ReadReq, curAddr + startAddr, dmaSize,
&dmaDoneEvent[dmaPendingNum-1], curAddr + dmaBuffer,
0, Request::UNCACHEABLE);
curAddr += dmaSize;
}
}
void
Pl111::dmaDone()
{
Tick maxFrameTime = lcdTiming2.cpl * height * clock;
--dmaPendingNum;
if (maxAddr == curAddr && !dmaPendingNum) {
if ((curTick() - startTime) > maxFrameTime) {
warn("CLCD controller buffer underrun, took %d cycles when should"
" have taken %d\n", curTick() - startTime, maxFrameTime);
lcdRis.underflow = 1;
if (!intEvent.scheduled())
schedule(intEvent, nextCycle());
}
assert(!readEvent.scheduled());
if (vncserver)
vncserver->setDirty();
DPRINTF(PL111, "-- write out frame buffer into bmp\n");
assert(bmp);
pic->seekp(0);
bmp->write(pic);
DPRINTF(PL111, "-- schedule next dma read event at %d tick \n",
maxFrameTime + curTick());
if (lcdControl.lcden)
schedule(readEvent, nextCycle(startTime + maxFrameTime));
}
if (dmaPendingNum > (maxOutstandingDma - waterMark))
return;
if (!fillFifoEvent.scheduled())
schedule(fillFifoEvent, nextCycle());
}
Tick
Pl111::nextCycle()
{
Tick nextTick = curTick() + clock - 1;
nextTick -= nextTick%clock;
return nextTick;
}
Tick
Pl111::nextCycle(Tick beginTick)
{
Tick nextTick = beginTick;
if (nextTick%clock!=0)
nextTick = nextTick - (nextTick%clock) + clock;
assert(nextTick >= curTick());
return nextTick;
}
void
Pl111::serialize(std::ostream &os)
{
DPRINTF(PL111, "Serializing ARM PL111\n");
uint32_t lcdTiming0_serial = lcdTiming0;
SERIALIZE_SCALAR(lcdTiming0_serial);
uint32_t lcdTiming1_serial = lcdTiming1;
SERIALIZE_SCALAR(lcdTiming1_serial);
uint32_t lcdTiming2_serial = lcdTiming2;
SERIALIZE_SCALAR(lcdTiming2_serial);
uint32_t lcdTiming3_serial = lcdTiming3;
SERIALIZE_SCALAR(lcdTiming3_serial);
SERIALIZE_SCALAR(lcdUpbase);
SERIALIZE_SCALAR(lcdLpbase);
uint32_t lcdControl_serial = lcdControl;
SERIALIZE_SCALAR(lcdControl_serial);
uint8_t lcdImsc_serial = lcdImsc;
SERIALIZE_SCALAR(lcdImsc_serial);
uint8_t lcdRis_serial = lcdRis;
SERIALIZE_SCALAR(lcdRis_serial);
uint8_t lcdMis_serial = lcdMis;
SERIALIZE_SCALAR(lcdMis_serial);
SERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
SERIALIZE_ARRAY(cursorImage, CrsrImageSize);
SERIALIZE_SCALAR(clcdCrsrCtrl);
SERIALIZE_SCALAR(clcdCrsrConfig);
SERIALIZE_SCALAR(clcdCrsrPalette0);
SERIALIZE_SCALAR(clcdCrsrPalette1);
SERIALIZE_SCALAR(clcdCrsrXY);
SERIALIZE_SCALAR(clcdCrsrClip);
uint8_t clcdCrsrImsc_serial = clcdCrsrImsc;
SERIALIZE_SCALAR(clcdCrsrImsc_serial);
uint8_t clcdCrsrIcr_serial = clcdCrsrIcr;
SERIALIZE_SCALAR(clcdCrsrIcr_serial);
uint8_t clcdCrsrRis_serial = clcdCrsrRis;
SERIALIZE_SCALAR(clcdCrsrRis_serial);
uint8_t clcdCrsrMis_serial = clcdCrsrMis;
SERIALIZE_SCALAR(clcdCrsrMis_serial);
SERIALIZE_SCALAR(clock);
SERIALIZE_SCALAR(height);
SERIALIZE_SCALAR(width);
SERIALIZE_SCALAR(bytesPerPixel);
SERIALIZE_ARRAY(dmaBuffer, height * width);
SERIALIZE_SCALAR(startTime);
SERIALIZE_SCALAR(startAddr);
SERIALIZE_SCALAR(maxAddr);
SERIALIZE_SCALAR(curAddr);
SERIALIZE_SCALAR(waterMark);
SERIALIZE_SCALAR(dmaPendingNum);
Tick int_event_time = 0;
Tick read_event_time = 0;
Tick fill_fifo_event_time = 0;
if (readEvent.scheduled())
read_event_time = readEvent.when();
if (fillFifoEvent.scheduled())
fill_fifo_event_time = fillFifoEvent.when();
if (intEvent.scheduled())
int_event_time = intEvent.when();
SERIALIZE_SCALAR(read_event_time);
SERIALIZE_SCALAR(fill_fifo_event_time);
SERIALIZE_SCALAR(int_event_time);
vector<Tick> dma_done_event_tick;
dma_done_event_tick.resize(maxOutstandingDma);
for (int x = 0; x < maxOutstandingDma; x++) {
dma_done_event_tick[x] = dmaDoneEvent[x].scheduled() ?
dmaDoneEvent[x].when() : 0;
}
arrayParamOut(os, "dma_done_event_tick", dma_done_event_tick);
}
void
Pl111::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(PL111, "Unserializing ARM PL111\n");
uint32_t lcdTiming0_serial;
UNSERIALIZE_SCALAR(lcdTiming0_serial);
lcdTiming0 = lcdTiming0_serial;
uint32_t lcdTiming1_serial;
UNSERIALIZE_SCALAR(lcdTiming1_serial);
lcdTiming1 = lcdTiming1_serial;
uint32_t lcdTiming2_serial;
UNSERIALIZE_SCALAR(lcdTiming2_serial);
lcdTiming2 = lcdTiming2_serial;
uint32_t lcdTiming3_serial;
UNSERIALIZE_SCALAR(lcdTiming3_serial);
lcdTiming3 = lcdTiming3_serial;
UNSERIALIZE_SCALAR(lcdUpbase);
UNSERIALIZE_SCALAR(lcdLpbase);
uint32_t lcdControl_serial;
UNSERIALIZE_SCALAR(lcdControl_serial);
lcdControl = lcdControl_serial;
uint8_t lcdImsc_serial;
UNSERIALIZE_SCALAR(lcdImsc_serial);
lcdImsc = lcdImsc_serial;
uint8_t lcdRis_serial;
UNSERIALIZE_SCALAR(lcdRis_serial);
lcdRis = lcdRis_serial;
uint8_t lcdMis_serial;
UNSERIALIZE_SCALAR(lcdMis_serial);
lcdMis = lcdMis_serial;
UNSERIALIZE_ARRAY(lcdPalette, LcdPaletteSize);
UNSERIALIZE_ARRAY(cursorImage, CrsrImageSize);
UNSERIALIZE_SCALAR(clcdCrsrCtrl);
UNSERIALIZE_SCALAR(clcdCrsrConfig);
UNSERIALIZE_SCALAR(clcdCrsrPalette0);
UNSERIALIZE_SCALAR(clcdCrsrPalette1);
UNSERIALIZE_SCALAR(clcdCrsrXY);
UNSERIALIZE_SCALAR(clcdCrsrClip);
uint8_t clcdCrsrImsc_serial;
UNSERIALIZE_SCALAR(clcdCrsrImsc_serial);
clcdCrsrImsc = clcdCrsrImsc_serial;
uint8_t clcdCrsrIcr_serial;
UNSERIALIZE_SCALAR(clcdCrsrIcr_serial);
clcdCrsrIcr = clcdCrsrIcr_serial;
uint8_t clcdCrsrRis_serial;
UNSERIALIZE_SCALAR(clcdCrsrRis_serial);
clcdCrsrRis = clcdCrsrRis_serial;
uint8_t clcdCrsrMis_serial;
UNSERIALIZE_SCALAR(clcdCrsrMis_serial);
clcdCrsrMis = clcdCrsrMis_serial;
UNSERIALIZE_SCALAR(clock);
UNSERIALIZE_SCALAR(height);
UNSERIALIZE_SCALAR(width);
UNSERIALIZE_SCALAR(bytesPerPixel);
UNSERIALIZE_ARRAY(dmaBuffer, height * width);
UNSERIALIZE_SCALAR(startTime);
UNSERIALIZE_SCALAR(startAddr);
UNSERIALIZE_SCALAR(maxAddr);
UNSERIALIZE_SCALAR(curAddr);
UNSERIALIZE_SCALAR(waterMark);
UNSERIALIZE_SCALAR(dmaPendingNum);
Tick int_event_time = 0;
Tick read_event_time = 0;
Tick fill_fifo_event_time = 0;
UNSERIALIZE_SCALAR(read_event_time);
UNSERIALIZE_SCALAR(fill_fifo_event_time);
UNSERIALIZE_SCALAR(int_event_time);
if (int_event_time)
schedule(intEvent, int_event_time);
if (read_event_time)
schedule(readEvent, read_event_time);
if (fill_fifo_event_time)
schedule(fillFifoEvent, fill_fifo_event_time);
vector<Tick> dma_done_event_tick;
dma_done_event_tick.resize(maxOutstandingDma);
arrayParamIn(cp, section, "dma_done_event_tick", dma_done_event_tick);
for (int x = 0; x < maxOutstandingDma; x++) {
if (dma_done_event_tick[x])
schedule(dmaDoneEvent[x], dma_done_event_tick[x]);
}
if (lcdControl.lcdpwr) {
updateVideoParams();
if (vncserver)
vncserver->setDirty();
}
}
void
Pl111::generateInterrupt()
{
DPRINTF(PL111, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n",
(uint32_t)lcdImsc, (uint32_t)lcdRis, (uint32_t)lcdMis);
lcdMis = lcdImsc & lcdRis;
if (lcdMis.underflow || lcdMis.baseaddr || lcdMis.vcomp || lcdMis.ahbmaster) {
gic->sendInt(intNum);
DPRINTF(PL111, " -- Generated\n");
}
}
AddrRangeList
Pl111::getAddrRanges()
{
AddrRangeList ranges;
ranges.push_back(RangeSize(pioAddr, pioSize));
return ranges;
}
Pl111 *
Pl111Params::create()
{
return new Pl111(this);
}

View File

@ -0,0 +1,334 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: William Wang
* Ali Saidi
*/
/** @file
* Implementiation of a PL111 CLCD controller
*/
#ifndef __DEV_ARM_PL111_HH__
#define __DEV_ARM_PL111_HH__
#include <fstream>
#include "base/range.hh"
#include "dev/arm/amba_device.hh"
#include "params/Pl111.hh"
#include "sim/serialize.hh"
class Gic;
class VncServer;
class Bitmap;
class Pl111: public AmbaDmaDevice
{
protected:
static const uint64_t AMBA_ID = ULL(0xb105f00d00141111);
/** ARM PL111 register map*/
static const int LcdTiming0 = 0x000;
static const int LcdTiming1 = 0x004;
static const int LcdTiming2 = 0x008;
static const int LcdTiming3 = 0x00C;
static const int LcdUpBase = 0x010;
static const int LcdLpBase = 0x014;
static const int LcdControl = 0x018;
static const int LcdImsc = 0x01C;
static const int LcdRis = 0x020;
static const int LcdMis = 0x024;
static const int LcdIcr = 0x028;
static const int LcdUpCurr = 0x02C;
static const int LcdLpCurr = 0x030;
static const int LcdPalette = 0x200;
static const int CrsrImage = 0x800;
static const int ClcdCrsrCtrl = 0xC00;
static const int ClcdCrsrConfig = 0xC04;
static const int ClcdCrsrPalette0 = 0xC08;
static const int ClcdCrsrPalette1 = 0xC0C;
static const int ClcdCrsrXY = 0xC10;
static const int ClcdCrsrClip = 0xC14;
static const int ClcdCrsrImsc = 0xC20;
static const int ClcdCrsrIcr = 0xC24;
static const int ClcdCrsrRis = 0xC28;
static const int ClcdCrsrMis = 0xC2C;
static const int LcdPaletteSize = 128;
static const int CrsrImageSize = 256;
static const int LcdMaxWidth = 1024; // pixels per line
static const int LcdMaxHeight = 768; // lines per panel
static const int dmaSize = 8; // 64 bits
static const int maxOutstandingDma = 16; // 16 deep FIFO of 64 bits
enum LcdMode {
bpp1 = 0,
bpp2,
bpp4,
bpp8,
bpp16,
bpp24,
bpp16m565,
bpp12
};
BitUnion8(InterruptReg)
Bitfield<1> underflow;
Bitfield<2> baseaddr;
Bitfield<3> vcomp;
Bitfield<4> ahbmaster;
EndBitUnion(InterruptReg)
BitUnion32(TimingReg0)
Bitfield<7,2> ppl;
Bitfield<15,8> hsw;
Bitfield<23,16> hfp;
Bitfield<31,24> hbp;
EndBitUnion(TimingReg0)
BitUnion32(TimingReg1)
Bitfield<9,0> lpp;
Bitfield<15,10> vsw;
Bitfield<23,16> vfp;
Bitfield<31,24> vbp;
EndBitUnion(TimingReg1)
BitUnion32(TimingReg2)
Bitfield<4,0> pcdlo;
Bitfield<5> clksel;
Bitfield<10,6> acb;
Bitfield<11> avs;
Bitfield<12> ihs;
Bitfield<13> ipc;
Bitfield<14> ioe;
Bitfield<25,16> cpl;
Bitfield<26> bcd;
Bitfield<31,27> pcdhi;
EndBitUnion(TimingReg2)
BitUnion32(TimingReg3)
Bitfield<6,0> led;
Bitfield<16> lee;
EndBitUnion(TimingReg3)
BitUnion32(ControlReg)
Bitfield<0> lcden;
Bitfield<3,1> lcdbpp;
Bitfield<4> lcdbw;
Bitfield<5> lcdtft;
Bitfield<6> lcdmono8;
Bitfield<7> lcddual;
Bitfield<8> bgr;
Bitfield<9> bebo;
Bitfield<10> bepo;
Bitfield<11> lcdpwr;
Bitfield<13,12> lcdvcomp;
Bitfield<16> watermark;
EndBitUnion(ControlReg)
/** Horizontal axis panel control register */
TimingReg0 lcdTiming0;
/** Vertical axis panel control register */
TimingReg1 lcdTiming1;
/** Clock and signal polarity control register */
TimingReg2 lcdTiming2;
/** Line end control register */
TimingReg3 lcdTiming3;
/** Upper panel frame base address register */
int lcdUpbase;
/** Lower panel frame base address register */
int lcdLpbase;
/** Control register */
ControlReg lcdControl;
/** Interrupt mask set/clear register */
InterruptReg lcdImsc;
/** Raw interrupt status register - const */
InterruptReg lcdRis;
/** Masked interrupt status register */
InterruptReg lcdMis;
/** 256x16-bit color palette registers
* 256 palette entries organized as 128 locations of two entries per word */
int lcdPalette[LcdPaletteSize];
/** Cursor image RAM register
* 256-word wide values defining images overlaid by the hw cursor mechanism */
int cursorImage[CrsrImageSize];
/** Cursor control register */
int clcdCrsrCtrl;
/** Cursor configuration register */
int clcdCrsrConfig;
/** Cursor palette registers */
int clcdCrsrPalette0;
int clcdCrsrPalette1;
/** Cursor XY position register */
int clcdCrsrXY;
/** Cursor clip position register */
int clcdCrsrClip;
/** Cursor interrupt mask set/clear register */
InterruptReg clcdCrsrImsc;
/** Cursor interrupt clear register */
InterruptReg clcdCrsrIcr;
/** Cursor raw interrupt status register - const */
InterruptReg clcdCrsrRis;
/** Cursor masked interrupt status register - const */
InterruptReg clcdCrsrMis;
/** Clock speed */
Tick clock;
/** VNC server */
VncServer *vncserver;
/** Helper to write out bitmaps */
Bitmap *bmp;
/** Picture of what the current frame buffer looks like */
std::ostream *pic;
/** Frame buffer width - pixels per line */
uint16_t width;
/** Frame buffer height - lines per panel */
uint16_t height;
/** Bytes per pixel */
uint8_t bytesPerPixel;
/** CLCDC supports up to 1024x768 */
uint8_t *dmaBuffer;
/** Start time for frame buffer dma read */
Tick startTime;
/** Frame buffer base address */
Addr startAddr;
/** Frame buffer max address */
Addr maxAddr;
/** Frame buffer current address */
Addr curAddr;
/** DMA FIFO watermark */
int waterMark;
/** Number of pending dma reads */
int dmaPendingNum;
/** Send updated parameters to the vnc server */
void updateVideoParams();
/** DMA framebuffer read */
void readFramebuffer();
/** Generate dma framebuffer read event */
void generateReadEvent();
/** Function to generate interrupt */
void generateInterrupt();
/** fillFIFO event */
void fillFifo();
/** start the dmas off after power is enabled */
void startDma();
/** DMA done event */
void dmaDone();
/** Next cycle event */
Tick nextCycle();
Tick nextCycle(Tick beginTick);
/** DMA framebuffer read event */
EventWrapper<Pl111, &Pl111::readFramebuffer> readEvent;
/** Fill fifo */
EventWrapper<Pl111, &Pl111::fillFifo> fillFifoEvent;
/** DMA done event */
std::vector<EventWrapper<Pl111, &Pl111::dmaDone> > dmaDoneEvent;
/** Wrapper to create an event out of the interrupt */
EventWrapper<Pl111, &Pl111::generateInterrupt> intEvent;
public:
typedef Pl111Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Pl111(const Params *p);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
/**
* Determine the address ranges that this device responds to.
*
* @return a list of non-overlapping address ranges
*/
AddrRangeList getAddrRanges();
};
#endif

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2009 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Implementation of RealView platform.
*/
#include <deque>
#include <string>
#include <vector>
#include "config/the_isa.hh"
#include "cpu/intr_control.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/realview.hh"
#include "dev/terminal.hh"
#include "sim/system.hh"
using namespace std;
using namespace TheISA;
RealView::RealView(const Params *p)
: Platform(p), system(p->system)
{}
void
RealView::postConsoleInt()
{
warn_once("Don't know what interrupt to post for console.\n");
//panic("Need implementation\n");
}
void
RealView::clearConsoleInt()
{
warn_once("Don't know what interrupt to clear for console.\n");
//panic("Need implementation\n");
}
void
RealView::postPciInt(int line)
{
gic->sendInt(line);
}
void
RealView::clearPciInt(int line)
{
gic->clearInt(line);
}
Addr
RealView::pciToDma(Addr pciAddr) const
{
return pciAddr;
}
Addr
RealView::calcPciConfigAddr(int bus, int dev, int func)
{
if (bus != 0)
return ULL(-1);
return params()->pci_cfg_base | ((func & 7) << 16) | ((dev & 0x1f) << 19);
}
Addr
RealView::calcPciIOAddr(Addr addr)
{
return addr;
}
Addr
RealView::calcPciMemAddr(Addr addr)
{
return addr;
}
RealView *
RealViewParams::create()
{
return new RealView(this);
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2009 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/**
* @file
* Declaration of top level class for the RealView platform chips. This class just
* retains pointers to all its children so the children can communicate.
*/
#ifndef __DEV_ARM_RealView_HH__
#define __DEV_ARM_RealView_HH__
#include "dev/platform.hh"
#include "params/RealView.hh"
class IdeController;
class System;
class RealView : public Platform
{
public:
/** Pointer to the system */
System *system;
Gic *gic;
public:
typedef RealViewParams Params;
const Params *
params() const {
return dynamic_cast<const Params *>(_params);
}
/**
* Constructor for the Tsunami Class.
* @param name name of the object
* @param s system the object belongs to
* @param intctrl pointer to the interrupt controller
*/
RealView(const Params *p);
/** Give platform a pointer to interrupt controller */
void setGic(Gic *_gic) { gic = _gic; }
/**
* Cause the cpu to post a serial interrupt to the CPU.
*/
virtual void postConsoleInt();
/**
* Clear a posted CPU interrupt
*/
virtual void clearConsoleInt();
/**
* Cause the chipset to post a cpi interrupt to the CPU.
*/
virtual void postPciInt(int line);
/**
* Clear a posted PCI->CPU interrupt
*/
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
/**
* Calculate the configuration address given a bus/dev/func.
*/
virtual Addr calcPciConfigAddr(int bus, int dev, int func);
/**
* Calculate the address for an IO location on the PCI bus.
*/
virtual Addr calcPciIOAddr(Addr addr);
/**
* Calculate the address for a memory location on the PCI bus.
*/
virtual Addr calcPciMemAddr(Addr addr);
};
#endif // __DEV_ARM_RealView_HH__

View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 2010-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#include "base/intmath.hh"
#include "base/time.hh"
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Timer.hh"
#include "dev/arm/amba_device.hh"
#include "dev/arm/rtc_pl031.hh"
#include "dev/mc146818.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
using namespace AmbaDev;
PL031::PL031(Params *p)
: AmbaIntDevice(p), timeVal(mkutctime(&p->time)), lastWrittenTick(0),
loadVal(0), matchVal(0), rawInt(false), maskInt(false),
pendingInt(false), matchEvent(this)
{
pioSize = 0xfff;
}
Tick
PL031::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
uint32_t data;
DPRINTF(Timer, "Reading from RTC at offset: %#x\n", daddr);
switch (daddr) {
case DataReg:
data = timeVal + ((curTick() - lastWrittenTick) / SimClock::Int::s);
break;
case MatchReg:
data = matchVal;
break;
case LoadReg:
data = loadVal;
break;
case ControlReg:
data = 1; // Always enabled otherwise there is no point
break;
case IntMask:
data = maskInt;
break;
case RawISR:
data = rawInt;
break;
case MaskedISR:
data = pendingInt;
break;
default:
if (AmbaDev::readId(pkt, ambaId, pioAddr)) {
// Hack for variable sized access
data = pkt->get<uint32_t>();
break;
}
panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr);
break;
}
switch(pkt->getSize()) {
case 1:
pkt->set<uint8_t>(data);
break;
case 2:
pkt->set<uint16_t>(data);
break;
case 4:
pkt->set<uint32_t>(data);
break;
default:
panic("Uart read size too big?\n");
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
PL031::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(Timer, "Writing to RTC at offset: %#x\n", daddr);
switch (daddr) {
case DataReg:
break;
case MatchReg:
matchVal = pkt->get<uint32_t>();
resyncMatch();
break;
case LoadReg:
lastWrittenTick = curTick();
timeVal = pkt->get<uint32_t>();
loadVal = timeVal;
resyncMatch();
break;
case ControlReg:
break; // Can't stop when started
case IntMask:
maskInt = pkt->get<uint32_t>();
break;
case IntClear:
if (pkt->get<uint32_t>()) {
rawInt = false;
pendingInt = false;
}
break;
default:
if (AmbaDev::readId(pkt, ambaId, pioAddr))
break;
panic("Tried to read PL031 at offset %#x that doesn't exist\n", daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
PL031::resyncMatch()
{
DPRINTF(Timer, "Setting up new match event match=%d time=%d\n", matchVal,
timeVal);
uint32_t seconds_until = matchVal - timeVal;
Tick ticks_until = SimClock::Int::s * seconds_until;
if (matchEvent.scheduled()) {
DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
deschedule(matchEvent);
}
schedule(matchEvent, curTick() + ticks_until);
DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + ticks_until);
}
void
PL031::counterMatch()
{
DPRINTF(Timer, "Counter reached zero\n");
rawInt = true;
bool old_pending = pendingInt;
pendingInt = maskInt & rawInt;
if (pendingInt && !old_pending) {
DPRINTF(Timer, "-- Causing interrupt\n");
gic->sendInt(intNum);
}
}
void
PL031::serialize(std::ostream &os)
{
DPRINTF(Checkpoint, "Serializing Arm PL031\n");
SERIALIZE_SCALAR(timeVal);
SERIALIZE_SCALAR(lastWrittenTick);
SERIALIZE_SCALAR(loadVal);
SERIALIZE_SCALAR(matchVal);
SERIALIZE_SCALAR(rawInt);
SERIALIZE_SCALAR(maskInt);
SERIALIZE_SCALAR(pendingInt);
bool is_in_event = matchEvent.scheduled();
SERIALIZE_SCALAR(is_in_event);
Tick event_time;
if (is_in_event){
event_time = matchEvent.when();
SERIALIZE_SCALAR(event_time);
}
}
void
PL031::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(Checkpoint, "Unserializing Arm PL031\n");
UNSERIALIZE_SCALAR(timeVal);
UNSERIALIZE_SCALAR(lastWrittenTick);
UNSERIALIZE_SCALAR(loadVal);
UNSERIALIZE_SCALAR(matchVal);
UNSERIALIZE_SCALAR(rawInt);
UNSERIALIZE_SCALAR(maskInt);
UNSERIALIZE_SCALAR(pendingInt);
bool is_in_event;
UNSERIALIZE_SCALAR(is_in_event);
Tick event_time;
if (is_in_event){
UNSERIALIZE_SCALAR(event_time);
schedule(matchEvent, event_time);
}
}
PL031 *
PL031Params::create()
{
return new PL031(this);
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2010-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#ifndef __DEV_ARM_RTC_PL310_HH__
#define __DEV_ARM_RTC_PL310_HH__
#include "base/range.hh"
#include "dev/arm/amba_device.hh"
#include "params/PL031.hh"
/** @file
* This implements the ARM Primecell 031 RTC
*/
class PL031 : public AmbaIntDevice
{
protected:
enum {
DataReg = 0x00,
MatchReg = 0x04,
LoadReg = 0x08,
ControlReg = 0x0C,
IntMask = 0x10,
RawISR = 0x14,
MaskedISR = 0x18,
IntClear = 0x1C,
};
/* Seconds since epoch that correspond to time simulation was started at the
* begining of simulation and is then updated if ever written. */
uint32_t timeVal;
/* Time when the timeVal register was written */
Tick lastWrittenTick;
/* Previous load value */
uint32_t loadVal;
/* RTC Match Value
* Cause an interrupt when this value hits counter
*/
uint32_t matchVal;
/** If timer has caused an interrupt. This is irrespective of
* interrupt enable */
bool rawInt;
/** If the timer interrupt mask that is anded with the raw interrupt to
* generate a pending interrupt
*/
bool maskInt;
/** If an interrupt is currently pending. Logical and of CTRL.intEnable
* and rawInt */
bool pendingInt;
/** Called when the counter reaches matches */
void counterMatch();
EventWrapper<PL031, &PL031::counterMatch> matchEvent;
/** Called to update the matchEvent when the load Value or match value are
* written.
*/
void resyncMatch();
public:
typedef PL031Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* The constructor for RealView just registers itself with the MMU.
* @param p params structure
*/
PL031(Params *p);
/**
* Handle a read to the device
* @param pkt The memory request.
* @param data Where to put the data.
*/
virtual Tick read(PacketPtr pkt);
/**
* Handle writes to the device
* @param pkt The memory request.
* @param data the data
*/
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ARM_RTC_PL031_HH__

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#include "base/trace.hh"
#include "dev/arm/rv_ctrl.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
RealViewCtrl::RealViewCtrl(Params *p)
: BasicPioDevice(p), flags(0)
{
pioSize = 0xD4;
}
Tick
RealViewCtrl::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
switch(daddr) {
case ProcId0:
pkt->set(params()->proc_id0);
break;
case ProcId1:
pkt->set(params()->proc_id1);
break;
case Clock24:
Tick clk;
clk = SimClock::Float::MHz * curTick() * 24;
pkt->set((uint32_t)(clk));
break;
case Clock100:
Tick clk100;
clk100 = SimClock::Float::MHz * curTick() * 100;
pkt->set((uint32_t)(clk100));
break;
case Flash:
pkt->set<uint32_t>(0);
break;
case Clcd:
pkt->set<uint32_t>(0x00001F00);
break;
case Osc0:
pkt->set<uint32_t>(0x00012C5C);
break;
case Osc1:
pkt->set<uint32_t>(0x00002CC0);
break;
case Osc2:
pkt->set<uint32_t>(0x00002C75);
break;
case Osc3:
pkt->set<uint32_t>(0x00020211);
break;
case Osc4:
pkt->set<uint32_t>(0x00002C75);
break;
case Lock:
pkt->set<uint32_t>(sysLock);
break;
case Flags:
pkt->set<uint32_t>(flags);
break;
case IdReg:
pkt->set<uint32_t>(params()->idreg);
break;
case CfgStat:
pkt->set<uint32_t>(1);
break;
default:
warn("Tried to read RealView I/O at offset %#x that doesn't exist\n",
daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
Tick
RealViewCtrl::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
switch (daddr) {
case Flash:
case Clcd:
case Osc0:
case Osc1:
case Osc2:
case Osc3:
case Osc4:
break;
case Lock:
sysLock.lockVal = pkt->get<uint16_t>();
break;
case Flags:
flags = pkt->get<uint32_t>();
break;
case FlagsClr:
flags = 0;
break;
default:
warn("Tried to write RVIO at offset %#x that doesn't exist\n",
daddr);
break;
}
pkt->makeAtomicResponse();
return pioDelay;
}
void
RealViewCtrl::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(flags);
}
void
RealViewCtrl::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(flags);
}
RealViewCtrl *
RealViewCtrlParams::create()
{
return new RealViewCtrl(this);
}

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#ifndef __DEV_ARM_RV_HH__
#define __DEV_ARM_RV_HH__
#include "base/bitunion.hh"
#include "base/range.hh"
#include "dev/io_device.hh"
#include "params/RealViewCtrl.hh"
/** @file
* This implements the simple real view registers on a PBXA9
*/
class RealViewCtrl : public BasicPioDevice
{
protected:
enum {
IdReg = 0x00,
SwReg = 0x04,
Led = 0x08,
Osc0 = 0x0C,
Osc1 = 0x10,
Osc2 = 0x14,
Osc3 = 0x18,
Osc4 = 0x1C,
Lock = 0x20,
Clock100 = 0x24,
CfgData1 = 0x28,
CfgData2 = 0x2C,
Flags = 0x30,
FlagsClr = 0x34,
NvFlags = 0x38,
NvFlagsClr = 0x3C,
ResetCtl = 0x40,
PciCtl = 0x44,
MciCtl = 0x48,
Flash = 0x4C,
Clcd = 0x50,
ClcdSer = 0x54,
Bootcs = 0x58,
Clock24 = 0x5C,
Misc = 0x60,
IoSel = 0x70,
ProcId0 = 0x84,
ProcId1 = 0x88,
CfgCtrl = 0xA0,
CfgData = 0xA4,
CfgStat = 0xA8,
TestOsc0 = 0xC0,
TestOsc1 = 0xC4,
TestOsc2 = 0xC8,
TestOsc3 = 0xCC,
TestOsc4 = 0xD0
};
// system lock value
BitUnion32(SysLockReg)
Bitfield<15,0> lockVal;
Bitfield<16> locked;
EndBitUnion(SysLockReg)
SysLockReg sysLock;
/** This register is used for smp booting.
* The primary cpu writes the secondary start address here before
* sends it a soft interrupt. The secondary cpu reads this register and if
* it's non-zero it jumps to the address
*/
uint32_t flags;
public:
typedef RealViewCtrlParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* The constructor for RealView just registers itself with the MMU.
* @param p params structure
*/
RealViewCtrl(Params *p);
/**
* Handle a read to the device
* @param pkt The memory request.
* @param data Where to put the data.
*/
virtual Tick read(PacketPtr pkt);
/**
* All writes are simply ignored.
* @param pkt The memory request.
* @param data the data
*/
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ARM_RV_HH__

View File

@ -0,0 +1,440 @@
/*
* Copyright (c) 2010-2011 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
* Geoffrey Blake
*/
#include "base/intmath.hh"
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Timer.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/timer_cpulocal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
CpuLocalTimer::CpuLocalTimer(Params *p)
: BasicPioDevice(p), gic(p->gic)
{
// Initialize the timer registers for each per cpu timer
for (int i = 0; i < CPU_MAX; i++) {
std::stringstream oss;
oss << name() << ".timer" << i;
localTimer[i]._name = oss.str();
localTimer[i].parent = this;
localTimer[i].intNumTimer = p->int_num_timer;
localTimer[i].intNumWatchdog = p->int_num_watchdog;
localTimer[i].clock = p->clock;
localTimer[i].cpuNum = i;
}
pioSize = 0x38;
}
CpuLocalTimer::Timer::Timer()
: timerControl(0x0), watchdogControl(0x0), rawIntTimer(false), rawIntWatchdog(false),
rawResetWatchdog(false), watchdogDisableReg(0x0), pendingIntTimer(false), pendingIntWatchdog(false),
timerLoadValue(0x0), watchdogLoadValue(0x0), timerZeroEvent(this), watchdogZeroEvent(this)
{
}
Tick
CpuLocalTimer::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
int cpu_id = pkt->req->contextId();
DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
assert(cpu_id >= 0);
assert(cpu_id < CPU_MAX);
if (daddr < Timer::Size)
localTimer[cpu_id].read(pkt, daddr);
else
panic("Tried to read CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
void
CpuLocalTimer::Timer::read(PacketPtr pkt, Addr daddr)
{
DPRINTF(Timer, "Reading from CpuLocalTimer at offset: %#x\n", daddr);
Tick time;
switch(daddr) {
case TimerLoadReg:
pkt->set<uint32_t>(timerLoadValue);
break;
case TimerCounterReg:
DPRINTF(Timer, "Event schedule for timer %d, clock=%d, prescale=%d\n",
timerZeroEvent.when(), clock, timerControl.prescalar);
time = timerZeroEvent.when() - curTick();
time = time / clock / power(16, timerControl.prescalar);
DPRINTF(Timer, "-- returning counter at %d\n", time);
pkt->set<uint32_t>(time);
break;
case TimerControlReg:
pkt->set<uint32_t>(timerControl);
break;
case TimerIntStatusReg:
pkt->set<uint32_t>(rawIntTimer);
break;
case WatchdogLoadReg:
pkt->set<uint32_t>(watchdogLoadValue);
break;
case WatchdogCounterReg:
DPRINTF(Timer, "Event schedule for watchdog %d, clock=%d, prescale=%d\n",
watchdogZeroEvent.when(), clock, watchdogControl.prescalar);
time = watchdogZeroEvent.when() - curTick();
time = time / clock / power(16, watchdogControl.prescalar);
DPRINTF(Timer, "-- returning counter at %d\n", time);
pkt->set<uint32_t>(time);
break;
case WatchdogControlReg:
pkt->set<uint32_t>(watchdogControl);
break;
case WatchdogIntStatusReg:
pkt->set<uint32_t>(rawIntWatchdog);
break;
case WatchdogResetStatusReg:
pkt->set<uint32_t>(rawResetWatchdog);
break;
case WatchdogDisableReg:
panic("Tried to read from WatchdogDisableRegister\n");
break;
default:
panic("Tried to read CpuLocalTimer at offset %#x\n", daddr);
break;
}
}
Tick
CpuLocalTimer::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
int cpu_id = pkt->req->contextId();
DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
assert(cpu_id >= 0);
assert(cpu_id < CPU_MAX);
if (daddr < Timer::Size)
localTimer[cpu_id].write(pkt, daddr);
else
panic("Tried to write CpuLocalTimer at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
void
CpuLocalTimer::Timer::write(PacketPtr pkt, Addr daddr)
{
DPRINTF(Timer, "Writing to CpuLocalTimer at offset: %#x\n", daddr);
bool old_enable;
bool old_wd_mode;
uint32_t old_val;
switch (daddr) {
case TimerLoadReg:
// Writing to this register also resets the counter register and
// starts decrementing if the counter is enabled.
timerLoadValue = pkt->get<uint32_t>();
restartTimerCounter(timerLoadValue);
break;
case TimerCounterReg:
// Can be written, doesn't start counting unless the timer is enabled
restartTimerCounter(pkt->get<uint32_t>());
break;
case TimerControlReg:
old_enable = timerControl.enable;
timerControl = pkt->get<uint32_t>();
if ((old_enable == 0) && timerControl.enable)
restartTimerCounter(timerLoadValue);
break;
case TimerIntStatusReg:
rawIntTimer = false;
if (pendingIntTimer) {
pendingIntTimer = false;
DPRINTF(Timer, "Clearing interrupt\n");
}
break;
case WatchdogLoadReg:
watchdogLoadValue = pkt->get<uint32_t>();
restartWatchdogCounter(watchdogLoadValue);
break;
case WatchdogCounterReg:
// Can't be written when in watchdog mode, but can in timer mode
if (!watchdogControl.watchdogMode) {
restartWatchdogCounter(pkt->get<uint32_t>());
}
break;
case WatchdogControlReg:
old_enable = watchdogControl.enable;
old_wd_mode = watchdogControl.watchdogMode;
watchdogControl = pkt->get<uint32_t>();
if ((old_enable == 0) && watchdogControl.enable)
restartWatchdogCounter(watchdogLoadValue);
// cannot disable watchdog using control register
if ((old_wd_mode == 1) && watchdogControl.watchdogMode == 0)
watchdogControl.watchdogMode = 1;
break;
case WatchdogIntStatusReg:
rawIntWatchdog = false;
if (pendingIntWatchdog) {
pendingIntWatchdog = false;
DPRINTF(Timer, "Clearing watchdog interrupt\n");
}
break;
case WatchdogResetStatusReg:
rawResetWatchdog = false;
DPRINTF(Timer, "Clearing watchdog reset flag\n");
break;
case WatchdogDisableReg:
old_val = watchdogDisableReg;
watchdogDisableReg = pkt->get<uint32_t>();
// if this sequence is observed, turn off watchdog mode
if (old_val == 0x12345678 && watchdogDisableReg == 0x87654321)
watchdogControl.watchdogMode = 0;
break;
default:
panic("Tried to write CpuLocalTimer timer at offset %#x\n", daddr);
break;
}
}
//XXX: Two functions are needed because the control registers are different types
void
CpuLocalTimer::Timer::restartTimerCounter(uint32_t val)
{
DPRINTF(Timer, "Resetting timer counter with value %#x\n", val);
if (!timerControl.enable)
return;
Tick time = clock * power(16, timerControl.prescalar);
time *= val;
if (timerZeroEvent.scheduled()) {
DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
parent->deschedule(timerZeroEvent);
}
parent->schedule(timerZeroEvent, curTick() + time);
DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
}
void
CpuLocalTimer::Timer::restartWatchdogCounter(uint32_t val)
{
DPRINTF(Timer, "Resetting watchdog counter with value %#x\n", val);
if (!watchdogControl.enable)
return;
Tick time = clock * power(16, watchdogControl.prescalar);
time *= val;
if (watchdogZeroEvent.scheduled()) {
DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
parent->deschedule(watchdogZeroEvent);
}
parent->schedule(watchdogZeroEvent, curTick() + time);
DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
}
//////
void
CpuLocalTimer::Timer::timerAtZero()
{
if (!timerControl.enable)
return;
DPRINTF(Timer, "Timer Counter reached zero\n");
rawIntTimer = true;
bool old_pending = pendingIntTimer;
if (timerControl.intEnable)
pendingIntTimer = true;
if (pendingIntTimer && !old_pending) {
DPRINTF(Timer, "-- Causing interrupt\n");
parent->gic->sendPPInt(intNumTimer, cpuNum);
}
if (!timerControl.autoReload)
return;
else
restartTimerCounter(timerLoadValue);
}
void
CpuLocalTimer::Timer::watchdogAtZero()
{
if (!watchdogControl.enable)
return;
DPRINTF(Timer, "Watchdog Counter reached zero\n");
rawIntWatchdog = true;
bool old_pending = pendingIntWatchdog;
// generates an interrupt only if the watchdog is in timer
// mode.
if (watchdogControl.intEnable && !watchdogControl.watchdogMode)
pendingIntWatchdog = true;
else if (watchdogControl.watchdogMode) {
rawResetWatchdog = true;
fatal("gem5 ARM Model does not support true watchdog operation!\n");
//XXX: Should we ever support a true watchdog reset?
}
if (pendingIntWatchdog && !old_pending) {
DPRINTF(Timer, "-- Causing interrupt\n");
parent->gic->sendPPInt(intNumWatchdog, cpuNum);
}
if (watchdogControl.watchdogMode)
return;
else if (watchdogControl.autoReload)
restartWatchdogCounter(watchdogLoadValue);
}
void
CpuLocalTimer::Timer::serialize(std::ostream &os)
{
DPRINTF(Checkpoint, "Serializing Arm CpuLocalTimer\n");
SERIALIZE_SCALAR(intNumTimer);
SERIALIZE_SCALAR(intNumWatchdog);
SERIALIZE_SCALAR(clock);
uint32_t timer_control_serial = timerControl;
uint32_t watchdog_control_serial = watchdogControl;
SERIALIZE_SCALAR(timer_control_serial);
SERIALIZE_SCALAR(watchdog_control_serial);
SERIALIZE_SCALAR(rawIntTimer);
SERIALIZE_SCALAR(rawIntWatchdog);
SERIALIZE_SCALAR(rawResetWatchdog);
SERIALIZE_SCALAR(watchdogDisableReg);
SERIALIZE_SCALAR(pendingIntTimer);
SERIALIZE_SCALAR(pendingIntWatchdog);
SERIALIZE_SCALAR(timerLoadValue);
SERIALIZE_SCALAR(watchdogLoadValue);
bool timer_is_in_event = timerZeroEvent.scheduled();
SERIALIZE_SCALAR(timer_is_in_event);
bool watchdog_is_in_event = watchdogZeroEvent.scheduled();
SERIALIZE_SCALAR(watchdog_is_in_event);
Tick timer_event_time;
if (timer_is_in_event){
timer_event_time = timerZeroEvent.when();
SERIALIZE_SCALAR(timer_event_time);
}
Tick watchdog_event_time;
if (watchdog_is_in_event){
watchdog_event_time = watchdogZeroEvent.when();
SERIALIZE_SCALAR(watchdog_event_time);
}
}
void
CpuLocalTimer::Timer::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(Checkpoint, "Unserializing Arm CpuLocalTimer\n");
UNSERIALIZE_SCALAR(intNumTimer);
UNSERIALIZE_SCALAR(intNumWatchdog);
UNSERIALIZE_SCALAR(clock);
uint32_t timer_control_serial;
UNSERIALIZE_SCALAR(timer_control_serial);
timerControl = timer_control_serial;
uint32_t watchdog_control_serial;
UNSERIALIZE_SCALAR(watchdog_control_serial);
watchdogControl = watchdog_control_serial;
UNSERIALIZE_SCALAR(rawIntTimer);
UNSERIALIZE_SCALAR(rawIntWatchdog);
UNSERIALIZE_SCALAR(rawResetWatchdog);
UNSERIALIZE_SCALAR(watchdogDisableReg);
UNSERIALIZE_SCALAR(pendingIntTimer);
UNSERIALIZE_SCALAR(pendingIntWatchdog);
UNSERIALIZE_SCALAR(timerLoadValue);
UNSERIALIZE_SCALAR(watchdogLoadValue);
bool timer_is_in_event;
UNSERIALIZE_SCALAR(timer_is_in_event);
bool watchdog_is_in_event;
UNSERIALIZE_SCALAR(watchdog_is_in_event);
Tick timer_event_time;
if (timer_is_in_event){
UNSERIALIZE_SCALAR(timer_event_time);
parent->schedule(timerZeroEvent, timer_event_time);
}
Tick watchdog_event_time;
if (watchdog_is_in_event) {
UNSERIALIZE_SCALAR(watchdog_event_time);
parent->schedule(watchdogZeroEvent, watchdog_event_time);
}
}
void
CpuLocalTimer::serialize(std::ostream &os)
{
for (int i = 0; i < CPU_MAX; i++) {
nameOut(os, csprintf("%s.timer%d", name(), i));
localTimer[i].serialize(os);
}
}
void
CpuLocalTimer::unserialize(Checkpoint *cp, const std::string &section)
{
for (int i = 0; i < CPU_MAX; i++) {
localTimer[i].unserialize(cp, csprintf("%s.timer%d", section, i));
}
}
CpuLocalTimer *
CpuLocalTimerParams::create()
{
return new CpuLocalTimer(this);
}

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2010-2011 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
* Geoffrey Blake
*/
#ifndef __DEV_ARM_LOCALTIMER_HH__
#define __DEV_ARM_LOCALTIMER_HH__
#include "base/range.hh"
#include "dev/io_device.hh"
#include "params/CpuLocalTimer.hh"
/** @file
* This implements the cpu local timer from the Cortex-A9 MPCore
* Technical Reference Manual rev r2p2 (ARM DDI 0407F)
*/
class Gic;
class CpuLocalTimer : public BasicPioDevice
{
protected:
class Timer
{
public:
enum {
TimerLoadReg = 0x00,
TimerCounterReg = 0x04,
TimerControlReg = 0x08,
TimerIntStatusReg = 0x0C,
WatchdogLoadReg = 0x20,
WatchdogCounterReg = 0x24,
WatchdogControlReg = 0x28,
WatchdogIntStatusReg = 0x2C,
WatchdogResetStatusReg = 0x30,
WatchdogDisableReg = 0x34,
Size = 0x38
};
BitUnion32(TimerCtrl)
Bitfield<0> enable;
Bitfield<1> autoReload;
Bitfield<2> intEnable;
Bitfield<3,7> reserved;
Bitfield<8,15> prescalar;
EndBitUnion(TimerCtrl)
BitUnion32(WatchdogCtrl)
Bitfield<0> enable;
Bitfield<1> autoReload;
Bitfield<2> intEnable;
Bitfield<3> watchdogMode;
Bitfield<4,7> reserved;
Bitfield<8,15> prescalar;
EndBitUnion(WatchdogCtrl)
protected:
std::string _name;
/** Pointer to parent class */
CpuLocalTimer *parent;
/** Number of interrupt to cause/clear */
uint32_t intNumTimer;
uint32_t intNumWatchdog;
/** Cpu this timer is attached to */
uint32_t cpuNum;
/** Number of ticks in a clock input */
Tick clock;
/** Control register as specified above */
TimerCtrl timerControl;
WatchdogCtrl watchdogControl;
/** If timer has caused an interrupt. This is irrespective of
* interrupt enable */
bool rawIntTimer;
bool rawIntWatchdog;
bool rawResetWatchdog;
uint32_t watchdogDisableReg;
/** If an interrupt is currently pending. Logical and of Timer or
* Watchdog Ctrl.enable and rawIntTimer or rawIntWatchdog */
bool pendingIntTimer;
bool pendingIntWatchdog;
/** Value to load into counters when periodic mode reaches 0 */
uint32_t timerLoadValue;
uint32_t watchdogLoadValue;
/** Called when the counter reaches 0 */
void timerAtZero();
EventWrapper<Timer, &Timer::timerAtZero> timerZeroEvent;
void watchdogAtZero();
EventWrapper<Timer, &Timer::watchdogAtZero> watchdogZeroEvent;
public:
/** Restart the counter ticking at val
* @param val the value to start at */
void restartTimerCounter(uint32_t val);
void restartWatchdogCounter(uint32_t val);
Timer();
std::string name() const { return _name; }
/** Handle read for a single timer */
void read(PacketPtr pkt, Addr daddr);
/** Handle write for a single timer */
void write(PacketPtr pkt, Addr daddr);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
friend class CpuLocalTimer;
};
static const int CPU_MAX = 8;
/** Pointer to the GIC for causing an interrupt */
Gic *gic;
/** Timers that do the actual work */
Timer localTimer[CPU_MAX];
public:
typedef CpuLocalTimerParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* The constructor for RealView just registers itself with the MMU.
* @param p params structure
*/
CpuLocalTimer(Params *p);
/**
* Handle a read to the device
* @param pkt The memory request.
* @return Returns latency of device read
*/
virtual Tick read(PacketPtr pkt);
/**
* Handle a write to the device.
* @param pkt The memory request.
* @return Returns latency of device write
*/
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ARM_SP804_HH__

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#include "base/intmath.hh"
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Timer.hh"
#include "dev/arm/gic.hh"
#include "dev/arm/timer_sp804.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
using namespace AmbaDev;
Sp804::Sp804(Params *p)
: AmbaDevice(p), gic(p->gic), timer0(name() + ".timer0", this, p->int_num0, p->clock0),
timer1(name() + ".timer1", this, p->int_num1, p->clock1)
{
pioSize = 0xfff;
}
Sp804::Timer::Timer(std::string __name, Sp804 *_parent, int int_num, Tick _clock)
: _name(__name), parent(_parent), intNum(int_num), clock(_clock), control(0x20),
rawInt(false), pendingInt(false), loadValue(0xffffffff), zeroEvent(this)
{
}
Tick
Sp804::read(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(Timer, "Reading from DualTimer at offset: %#x\n", daddr);
if (daddr < Timer::Size)
timer0.read(pkt, daddr);
else if ((daddr - Timer::Size) < Timer::Size)
timer1.read(pkt, daddr - Timer::Size);
else if (!readId(pkt, ambaId, pioAddr))
panic("Tried to read SP804 at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
void
Sp804::Timer::read(PacketPtr pkt, Addr daddr)
{
switch(daddr) {
case LoadReg:
pkt->set<uint32_t>(loadValue);
break;
case CurrentReg:
DPRINTF(Timer, "Event schedule for %d, clock=%d, prescale=%d\n",
zeroEvent.when(), clock, control.timerPrescale);
Tick time;
time = zeroEvent.when() - curTick();
time = time / clock / power(16, control.timerPrescale);
DPRINTF(Timer, "-- returning counter at %d\n", time);
pkt->set<uint32_t>(time);
break;
case ControlReg:
pkt->set<uint32_t>(control);
break;
case RawISR:
pkt->set<uint32_t>(rawInt);
break;
case MaskedISR:
pkt->set<uint32_t>(pendingInt);
break;
case BGLoad:
pkt->set<uint32_t>(loadValue);
break;
default:
panic("Tried to read SP804 timer at offset %#x\n", daddr);
break;
}
DPRINTF(Timer, "Reading %#x from Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
}
Tick
Sp804::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 4);
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
DPRINTF(Timer, "Writing to DualTimer at offset: %#x\n", daddr);
if (daddr < Timer::Size)
timer0.write(pkt, daddr);
else if ((daddr - Timer::Size) < Timer::Size)
timer1.write(pkt, daddr - Timer::Size);
else if (!readId(pkt, ambaId, pioAddr))
panic("Tried to write SP804 at offset %#x that doesn't exist\n", daddr);
pkt->makeAtomicResponse();
return pioDelay;
}
void
Sp804::Timer::write(PacketPtr pkt, Addr daddr)
{
DPRINTF(Timer, "Writing %#x to Timer at offset: %#x\n", pkt->get<uint32_t>(), daddr);
switch (daddr) {
case LoadReg:
loadValue = pkt->get<uint32_t>();
restartCounter(loadValue);
break;
case CurrentReg:
// Spec says this value can't be written, but linux writes it anyway
break;
case ControlReg:
bool old_enable;
old_enable = control.timerEnable;
control = pkt->get<uint32_t>();
if ((old_enable == 0) && control.timerEnable)
restartCounter(loadValue);
break;
case IntClear:
rawInt = false;
if (pendingInt) {
pendingInt = false;
DPRINTF(Timer, "Clearing interrupt\n");
parent->gic->clearInt(intNum);
}
break;
case BGLoad:
loadValue = pkt->get<uint32_t>();
break;
default:
panic("Tried to write SP804 timer at offset %#x\n", daddr);
break;
}
}
void
Sp804::Timer::restartCounter(uint32_t val)
{
DPRINTF(Timer, "Resetting counter with value %#x\n", val);
if (!control.timerEnable)
return;
Tick time = clock * power(16, control.timerPrescale);
if (control.timerSize)
time *= val;
else
time *= bits(val,15,0);
if (zeroEvent.scheduled()) {
DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n");
parent->deschedule(zeroEvent);
}
parent->schedule(zeroEvent, curTick() + time);
DPRINTF(Timer, "-- Scheduling new event for: %d\n", curTick() + time);
}
void
Sp804::Timer::counterAtZero()
{
if (!control.timerEnable)
return;
DPRINTF(Timer, "Counter reached zero\n");
rawInt = true;
bool old_pending = pendingInt;
if (control.intEnable)
pendingInt = true;
if (pendingInt && !old_pending) {
DPRINTF(Timer, "-- Causing interrupt\n");
parent->gic->sendInt(intNum);
}
if (control.oneShot)
return;
// Free-running
if (control.timerMode == 0)
restartCounter(0xffffffff);
else
restartCounter(loadValue);
}
void
Sp804::Timer::serialize(std::ostream &os)
{
DPRINTF(Checkpoint, "Serializing Arm Sp804\n");
SERIALIZE_SCALAR(intNum);
SERIALIZE_SCALAR(clock);
uint32_t control_serial = control;
SERIALIZE_SCALAR(control_serial);
SERIALIZE_SCALAR(rawInt);
SERIALIZE_SCALAR(pendingInt);
SERIALIZE_SCALAR(loadValue);
bool is_in_event = zeroEvent.scheduled();
SERIALIZE_SCALAR(is_in_event);
Tick event_time;
if (is_in_event){
event_time = zeroEvent.when();
SERIALIZE_SCALAR(event_time);
}
}
void
Sp804::Timer::unserialize(Checkpoint *cp, const std::string &section)
{
DPRINTF(Checkpoint, "Unserializing Arm Sp804\n");
UNSERIALIZE_SCALAR(intNum);
UNSERIALIZE_SCALAR(clock);
uint32_t control_serial;
UNSERIALIZE_SCALAR(control_serial);
control = control_serial;
UNSERIALIZE_SCALAR(rawInt);
UNSERIALIZE_SCALAR(pendingInt);
UNSERIALIZE_SCALAR(loadValue);
bool is_in_event;
UNSERIALIZE_SCALAR(is_in_event);
Tick event_time;
if (is_in_event){
UNSERIALIZE_SCALAR(event_time);
parent->schedule(zeroEvent, event_time);
}
}
void
Sp804::serialize(std::ostream &os)
{
nameOut(os, csprintf("%s.timer0", name()));
timer0.serialize(os);
nameOut(os, csprintf("%s.timer1", name()));
timer1.serialize(os);
}
void
Sp804::unserialize(Checkpoint *cp, const std::string &section)
{
timer0.unserialize(cp, csprintf("%s.timer0", section));
timer1.unserialize(cp, csprintf("%s.timer1", section));
}
Sp804 *
Sp804Params::create()
{
return new Sp804(this);
}

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
*/
#ifndef __DEV_ARM_SP804_HH__
#define __DEV_ARM_SP804_HH__
#include "base/range.hh"
#include "dev/arm/amba_device.hh"
#include "params/Sp804.hh"
/** @file
* This implements the dual Sp804 timer block
*/
class Gic;
class Sp804 : public AmbaDevice
{
protected:
class Timer
{
public:
enum {
LoadReg = 0x00,
CurrentReg = 0x04,
ControlReg = 0x08,
IntClear = 0x0C,
RawISR = 0x10,
MaskedISR = 0x14,
BGLoad = 0x18,
Size = 0x20
};
BitUnion32(CTRL)
Bitfield<0> oneShot;
Bitfield<1> timerSize;
Bitfield<3,2> timerPrescale;
Bitfield<5> intEnable;
Bitfield<6> timerMode;
Bitfield<7> timerEnable;
EndBitUnion(CTRL)
protected:
std::string _name;
/** Pointer to parent class */
Sp804 *parent;
/** Number of interrupt to cause/clear */
uint32_t intNum;
/** Number of ticks in a clock input */
Tick clock;
/** Control register as specified above */
CTRL control;
/** If timer has caused an interrupt. This is irrespective of
* interrupt enable */
bool rawInt;
/** If an interrupt is currently pending. Logical and of CTRL.intEnable
* and rawInt */
bool pendingInt;
/** Value to load into counter when periodic mode reaches 0 */
uint32_t loadValue;
/** Called when the counter reaches 0 */
void counterAtZero();
EventWrapper<Timer, &Timer::counterAtZero> zeroEvent;
public:
/** Restart the counter ticking at val
* @param val the value to start at (pre-16 bit masking if en) */
void restartCounter(uint32_t val);
Timer(std::string __name, Sp804 *parent, int int_num, Tick clock);
std::string name() const { return _name; }
/** Handle read for a single timer */
void read(PacketPtr pkt, Addr daddr);
/** Handle write for a single timer */
void write(PacketPtr pkt, Addr daddr);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
};
/** Pointer to the GIC for causing an interrupt */
Gic *gic;
/** Timers that do the actual work */
Timer timer0;
Timer timer1;
public:
typedef Sp804Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* The constructor for RealView just registers itself with the MMU.
* @param p params structure
*/
Sp804(Params *p);
/**
* Handle a read to the device
* @param pkt The memory request.
* @param data Where to put the data.
*/
virtual Tick read(PacketPtr pkt);
/**
* All writes are simply ignored.
* @param pkt The memory request.
* @param data the data
*/
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_ARM_SP804_HH__

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* BadDevice implemenation
*/
#include <deque>
#include <string>
#include <vector>
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "dev/baddev.hh"
#include "mem/port.hh"
#include "params/BadDevice.hh"
#include "sim/system.hh"
using namespace std;
BadDevice::BadDevice(Params *p)
: BasicPioDevice(p), devname(p->devicename)
{
pioSize = 0x10;
}
Tick
BadDevice::read(PacketPtr pkt)
{
panic("Device %s not imlpmented\n", devname);
M5_DUMMY_RETURN
}
Tick
BadDevice::write(PacketPtr pkt)
{
panic("Device %s not imlpmented\n", devname);
M5_DUMMY_RETURN
}
BadDevice *
BadDeviceParams::create()
{
return new BadDevice(this);
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* This devices just panics when touched. For example if you have a
* kernel that touches the frame buffer which isn't allowed.
*/
#ifndef __DEV_BADDEV_HH__
#define __DEV_BADDEV_HH__
#include "base/range.hh"
#include "dev/io_device.hh"
#include "params/BadDevice.hh"
/**
* BadDevice
* This device just panics when accessed. It is supposed to warn
* the user that the kernel they are running has unsupported
* options (i.e. frame buffer)
*/
class BadDevice : public BasicPioDevice
{
private:
std::string devname;
public:
typedef BadDeviceParams Params;
protected:
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
public:
/**
* Constructor for the Baddev Class.
* @param p object parameters
* @param a base address of the write
*/
BadDevice(Params *p);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
};
#endif // __DEV_BADDEV_HH__

View File

@ -0,0 +1,782 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2008 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: Ali Saidi
*/
/* @file
* Device model for Intel's I/O AT DMA copy engine.
*/
#include <algorithm>
#include "base/cp_annotate.hh"
#include "base/trace.hh"
#include "debug/DMACopyEngine.hh"
#include "dev/copy_engine.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/CopyEngine.hh"
#include "sim/stats.hh"
#include "sim/system.hh"
using namespace CopyEngineReg;
CopyEngine::CopyEngine(const Params *p)
: PciDev(p)
{
// All Reg regs are initialized to 0 by default
regs.chanCount = p->ChanCnt;
regs.xferCap = findMsbSet(p->XferCap);
regs.attnStatus = 0;
if (regs.chanCount > 64)
fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
for (int x = 0; x < regs.chanCount; x++) {
CopyEngineChannel *ch = new CopyEngineChannel(this, x);
chan.push_back(ch);
}
}
CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
: cePort(_ce, _ce->sys, _ce->params()->min_backoff_delay,
_ce->params()->max_backoff_delay),
ce(_ce), channelId(cid), busy(false), underReset(false),
refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
latAfterCompletion(ce->params()->latAfterCompletion),
completionDataReg(0), nextState(Idle), drainEvent(NULL),
fetchCompleteEvent(this), addrCompleteEvent(this),
readCompleteEvent(this), writeCompleteEvent(this),
statusCompleteEvent(this)
{
cr.status.dma_transfer_status(3);
cr.descChainAddr = 0;
cr.completionAddr = 0;
curDmaDesc = new DmaDesc;
memset(curDmaDesc, 0, sizeof(DmaDesc));
copyBuffer = new uint8_t[ce->params()->XferCap];
}
CopyEngine::~CopyEngine()
{
for (int x = 0; x < chan.size(); x++) {
delete chan[x];
}
}
CopyEngine::CopyEngineChannel::~CopyEngineChannel()
{
delete curDmaDesc;
delete [] copyBuffer;
}
MasterPort &
CopyEngine::getMasterPort(const std::string &if_name, int idx)
{
if (if_name != "dma") {
// pass it along to our super class
return PciDev::getMasterPort(if_name, idx);
} else {
if (idx >= static_cast<int>(chan.size())) {
panic("CopyEngine::getMasterPort: unknown index %d\n", idx);
}
return chan[idx]->getMasterPort();
}
}
MasterPort &
CopyEngine::CopyEngineChannel::getMasterPort()
{
return cePort;
}
void
CopyEngine::CopyEngineChannel::recvCommand()
{
if (cr.command.start_dma()) {
assert(!busy);
cr.status.dma_transfer_status(0);
nextState = DescriptorFetch;
fetchAddress = cr.descChainAddr;
if (ce->getState() == SimObject::Running)
fetchDescriptor(cr.descChainAddr);
} else if (cr.command.append_dma()) {
if (!busy) {
nextState = AddressFetch;
if (ce->getState() == SimObject::Running)
fetchNextAddr(lastDescriptorAddr);
} else
refreshNext = true;
} else if (cr.command.reset_dma()) {
if (busy)
underReset = true;
else {
cr.status.dma_transfer_status(3);
nextState = Idle;
}
} else if (cr.command.resume_dma() || cr.command.abort_dma() ||
cr.command.suspend_dma())
panic("Resume, Abort, and Suspend are not supported\n");
cr.command(0);
}
Tick
CopyEngine::read(PacketPtr pkt)
{
int bar;
Addr daddr;
if (!getBAR(pkt->getAddr(), bar, daddr))
panic("Invalid PCI memory access to unmapped memory.\n");
// Only Memory register BAR is allowed
assert(bar == 0);
int size = pkt->getSize();
if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
panic("Unknown size for MMIO access: %d\n", pkt->getSize());
}
DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
pkt->allocate();
///
/// Handle read of register here
///
if (daddr < 0x80) {
switch (daddr) {
case GEN_CHANCOUNT:
assert(size == sizeof(regs.chanCount));
pkt->set<uint8_t>(regs.chanCount);
break;
case GEN_XFERCAP:
assert(size == sizeof(regs.xferCap));
pkt->set<uint8_t>(regs.xferCap);
break;
case GEN_INTRCTRL:
assert(size == sizeof(uint8_t));
pkt->set<uint8_t>(regs.intrctrl());
regs.intrctrl.master_int_enable(0);
break;
case GEN_ATTNSTATUS:
assert(size == sizeof(regs.attnStatus));
pkt->set<uint32_t>(regs.attnStatus);
regs.attnStatus = 0;
break;
default:
panic("Read request to unknown register number: %#x\n", daddr);
}
pkt->makeAtomicResponse();
return pioDelay;
}
// Find which channel we're accessing
int chanid = 0;
daddr -= 0x80;
while (daddr >= 0x80) {
chanid++;
daddr -= 0x80;
}
if (chanid >= regs.chanCount)
panic("Access to channel %d (device only configured for %d channels)",
chanid, regs.chanCount);
///
/// Channel registers are handled here
///
chan[chanid]->channelRead(pkt, daddr, size);
pkt->makeAtomicResponse();
return pioDelay;
}
void
CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
{
switch (daddr) {
case CHAN_CONTROL:
assert(size == sizeof(uint16_t));
pkt->set<uint16_t>(cr.ctrl());
cr.ctrl.in_use(1);
break;
case CHAN_STATUS:
assert(size == sizeof(uint64_t));
pkt->set<uint64_t>(cr.status() | ~busy);
break;
case CHAN_CHAINADDR:
assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
if (size == sizeof(uint64_t))
pkt->set<uint64_t>(cr.descChainAddr);
else
pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
break;
case CHAN_CHAINADDR_HIGH:
assert(size == sizeof(uint32_t));
pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
break;
case CHAN_COMMAND:
assert(size == sizeof(uint8_t));
pkt->set<uint32_t>(cr.command());
break;
case CHAN_CMPLNADDR:
assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
if (size == sizeof(uint64_t))
pkt->set<uint64_t>(cr.completionAddr);
else
pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
break;
case CHAN_CMPLNADDR_HIGH:
assert(size == sizeof(uint32_t));
pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
break;
case CHAN_ERROR:
assert(size == sizeof(uint32_t));
pkt->set<uint32_t>(cr.error());
break;
default:
panic("Read request to unknown channel register number: (%d)%#x\n",
channelId, daddr);
}
}
Tick
CopyEngine::write(PacketPtr pkt)
{
int bar;
Addr daddr;
if (!getBAR(pkt->getAddr(), bar, daddr))
panic("Invalid PCI memory access to unmapped memory.\n");
// Only Memory register BAR is allowed
assert(bar == 0);
int size = pkt->getSize();
///
/// Handle write of register here
///
if (size == sizeof(uint64_t)) {
uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
} else if (size == sizeof(uint32_t)) {
uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
} else if (size == sizeof(uint16_t)) {
uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
} else if (size == sizeof(uint8_t)) {
uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
} else {
panic("Unknown size for MMIO access: %d\n", size);
}
if (daddr < 0x80) {
switch (daddr) {
case GEN_CHANCOUNT:
case GEN_XFERCAP:
case GEN_ATTNSTATUS:
DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
daddr);
break;
case GEN_INTRCTRL:
regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
break;
default:
panic("Read request to unknown register number: %#x\n", daddr);
}
pkt->makeAtomicResponse();
return pioDelay;
}
// Find which channel we're accessing
int chanid = 0;
daddr -= 0x80;
while (daddr >= 0x80) {
chanid++;
daddr -= 0x80;
}
if (chanid >= regs.chanCount)
panic("Access to channel %d (device only configured for %d channels)",
chanid, regs.chanCount);
///
/// Channel registers are handled here
///
chan[chanid]->channelWrite(pkt, daddr, size);
pkt->makeAtomicResponse();
return pioDelay;
}
void
CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
{
switch (daddr) {
case CHAN_CONTROL:
assert(size == sizeof(uint16_t));
int old_int_disable;
old_int_disable = cr.ctrl.interrupt_disable();
cr.ctrl(pkt->get<uint16_t>());
if (cr.ctrl.interrupt_disable())
cr.ctrl.interrupt_disable(0);
else
cr.ctrl.interrupt_disable(old_int_disable);
break;
case CHAN_STATUS:
assert(size == sizeof(uint64_t));
DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
daddr);
break;
case CHAN_CHAINADDR:
assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
if (size == sizeof(uint64_t))
cr.descChainAddr = pkt->get<uint64_t>();
else
cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() |
(cr.descChainAddr & ~mask(32));
DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
break;
case CHAN_CHAINADDR_HIGH:
assert(size == sizeof(uint32_t));
cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
(cr.descChainAddr & mask(32));
DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
break;
case CHAN_COMMAND:
assert(size == sizeof(uint8_t));
cr.command(pkt->get<uint8_t>());
recvCommand();
break;
case CHAN_CMPLNADDR:
assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
if (size == sizeof(uint64_t))
cr.completionAddr = pkt->get<uint64_t>();
else
cr.completionAddr = pkt->get<uint32_t>() |
(cr.completionAddr & ~mask(32));
break;
case CHAN_CMPLNADDR_HIGH:
assert(size == sizeof(uint32_t));
cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
(cr.completionAddr & mask(32));
break;
case CHAN_ERROR:
assert(size == sizeof(uint32_t));
cr.error(~pkt->get<uint32_t>() & cr.error());
break;
default:
panic("Read request to unknown channel register number: (%d)%#x\n",
channelId, daddr);
}
}
void
CopyEngine::regStats()
{
using namespace Stats;
bytesCopied
.init(regs.chanCount)
.name(name() + ".bytes_copied")
.desc("Number of bytes copied by each engine")
.flags(total)
;
copiesProcessed
.init(regs.chanCount)
.name(name() + ".copies_processed")
.desc("Number of copies processed by each engine")
.flags(total)
;
}
void
CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
{
anDq();
anBegin("FetchDescriptor");
DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
address, ce->platform->pciToDma(address));
assert(address);
busy = true;
DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
cePort.dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address),
sizeof(DmaDesc), &fetchCompleteEvent,
(uint8_t*)curDmaDesc, latBeforeBegin);
lastDescriptorAddr = address;
}
void
CopyEngine::CopyEngineChannel::fetchDescComplete()
{
DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
if ((curDmaDesc->command & DESC_CTRL_NULL)) {
DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
if (curDmaDesc->command & DESC_CTRL_CP_STS) {
panic("Shouldn't be able to get here\n");
nextState = CompletionWrite;
if (inDrain()) return;
writeCompletionStatus();
} else {
anBegin("Idle");
anWait();
busy = false;
nextState = Idle;
inDrain();
}
return;
}
if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
panic("Descriptor has flag other that completion status set\n");
nextState = DMARead;
if (inDrain()) return;
readCopyBytes();
}
void
CopyEngine::CopyEngineChannel::readCopyBytes()
{
anBegin("ReadCopyBytes");
DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
curDmaDesc->len, curDmaDesc->dest,
ce->platform->pciToDma(curDmaDesc->src));
cePort.dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src),
curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
}
void
CopyEngine::CopyEngineChannel::readCopyBytesComplete()
{
DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
nextState = DMAWrite;
if (inDrain()) return;
writeCopyBytes();
}
void
CopyEngine::CopyEngineChannel::writeCopyBytes()
{
anBegin("WriteCopyBytes");
DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
curDmaDesc->len, curDmaDesc->dest,
ce->platform->pciToDma(curDmaDesc->dest));
cePort.dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest),
curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
ce->bytesCopied[channelId] += curDmaDesc->len;
ce->copiesProcessed[channelId]++;
}
void
CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
{
DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
curDmaDesc->user1);
cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
completionDataReg = cr.status() | 1;
anQ("DMAUsedDescQ", channelId, 1);
anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
if (curDmaDesc->command & DESC_CTRL_CP_STS) {
nextState = CompletionWrite;
if (inDrain()) return;
writeCompletionStatus();
return;
}
continueProcessing();
}
void
CopyEngine::CopyEngineChannel::continueProcessing()
{
busy = false;
if (underReset) {
anBegin("Reset");
anWait();
underReset = false;
refreshNext = false;
busy = false;
nextState = Idle;
return;
}
if (curDmaDesc->next) {
nextState = DescriptorFetch;
fetchAddress = curDmaDesc->next;
if (inDrain()) return;
fetchDescriptor(curDmaDesc->next);
} else if (refreshNext) {
nextState = AddressFetch;
refreshNext = false;
if (inDrain()) return;
fetchNextAddr(lastDescriptorAddr);
} else {
inDrain();
nextState = Idle;
anWait();
anBegin("Idle");
}
}
void
CopyEngine::CopyEngineChannel::writeCompletionStatus()
{
anBegin("WriteCompletionStatus");
DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
completionDataReg, cr.completionAddr,
ce->platform->pciToDma(cr.completionAddr));
cePort.dmaAction(MemCmd::WriteReq,
ce->platform->pciToDma(cr.completionAddr),
sizeof(completionDataReg), &statusCompleteEvent,
(uint8_t*)&completionDataReg, latAfterCompletion);
}
void
CopyEngine::CopyEngineChannel::writeStatusComplete()
{
DPRINTF(DMACopyEngine, "Writing completion status complete\n");
continueProcessing();
}
void
CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
{
anBegin("FetchNextAddr");
DPRINTF(DMACopyEngine, "Fetching next address...\n");
busy = true;
cePort.dmaAction(MemCmd::ReadReq,
ce->platform->pciToDma(address + offsetof(DmaDesc, next)),
sizeof(Addr), &addrCompleteEvent,
(uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
}
void
CopyEngine::CopyEngineChannel::fetchAddrComplete()
{
DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
curDmaDesc->next);
if (!curDmaDesc->next) {
DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
busy = false;
nextState = Idle;
anWait();
anBegin("Idle");
inDrain();
return;
}
nextState = DescriptorFetch;
fetchAddress = curDmaDesc->next;
if (inDrain()) return;
fetchDescriptor(curDmaDesc->next);
}
bool
CopyEngine::CopyEngineChannel::inDrain()
{
if (ce->getState() == SimObject::Draining) {
DPRINTF(DMACopyEngine, "processing drain\n");
assert(drainEvent);
drainEvent->process();
drainEvent = NULL;
}
return ce->getState() != SimObject::Running;
}
unsigned int
CopyEngine::CopyEngineChannel::drain(Event *de)
{
if (nextState == Idle || ce->getState() != SimObject::Running)
return 0;
unsigned int count = 1;
count += cePort.drain(de);
DPRINTF(DMACopyEngine, "unable to drain, returning %d\n", count);
drainEvent = de;
return count;
}
unsigned int
CopyEngine::drain(Event *de)
{
unsigned int count;
count = pioPort.drain(de) + dmaPort.drain(de) + configPort.drain(de);
for (int x = 0;x < chan.size(); x++)
count += chan[x]->drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
DPRINTF(DMACopyEngine, "call to CopyEngine::drain() returning %d\n", count);
return count;
}
void
CopyEngine::serialize(std::ostream &os)
{
PciDev::serialize(os);
regs.serialize(os);
for (int x =0; x < chan.size(); x++) {
nameOut(os, csprintf("%s.channel%d", name(), x));
chan[x]->serialize(os);
}
}
void
CopyEngine::unserialize(Checkpoint *cp, const std::string &section)
{
PciDev::unserialize(cp, section);
regs.unserialize(cp, section);
for (int x = 0; x < chan.size(); x++)
chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x));
}
void
CopyEngine::CopyEngineChannel::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(channelId);
SERIALIZE_SCALAR(busy);
SERIALIZE_SCALAR(underReset);
SERIALIZE_SCALAR(refreshNext);
SERIALIZE_SCALAR(lastDescriptorAddr);
SERIALIZE_SCALAR(completionDataReg);
SERIALIZE_SCALAR(fetchAddress);
int nextState = this->nextState;
SERIALIZE_SCALAR(nextState);
arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
cr.serialize(os);
}
void
CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(channelId);
UNSERIALIZE_SCALAR(busy);
UNSERIALIZE_SCALAR(underReset);
UNSERIALIZE_SCALAR(refreshNext);
UNSERIALIZE_SCALAR(lastDescriptorAddr);
UNSERIALIZE_SCALAR(completionDataReg);
UNSERIALIZE_SCALAR(fetchAddress);
int nextState;
UNSERIALIZE_SCALAR(nextState);
this->nextState = (ChannelState)nextState;
arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
cr.unserialize(cp, section);
}
void
CopyEngine::CopyEngineChannel::restartStateMachine()
{
switch(nextState) {
case AddressFetch:
fetchNextAddr(lastDescriptorAddr);
break;
case DescriptorFetch:
fetchDescriptor(fetchAddress);
break;
case DMARead:
readCopyBytes();
break;
case DMAWrite:
writeCopyBytes();
break;
case CompletionWrite:
writeCompletionStatus();
break;
case Idle:
break;
default:
panic("Unknown state for CopyEngineChannel\n");
}
}
void
CopyEngine::resume()
{
SimObject::resume();
for (int x = 0;x < chan.size(); x++)
chan[x]->resume();
}
void
CopyEngine::CopyEngineChannel::resume()
{
DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
restartStateMachine();
}
CopyEngine *
CopyEngineParams::create()
{
return new CopyEngine(this);
}

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2008 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: Ali Saidi
*/
/* @file
* Device model for Intel's I/O Acceleration Technology (I/OAT).
* A DMA asyncronous copy engine
*/
#ifndef __DEV_COPY_ENGINE_HH__
#define __DEV_COPY_ENGINE_HH__
#include <vector>
#include "base/statistics.hh"
#include "dev/copy_engine_defs.hh"
#include "dev/pcidev.hh"
#include "params/CopyEngine.hh"
#include "sim/eventq.hh"
class CopyEngine : public PciDev
{
class CopyEngineChannel
{
private:
DmaPort cePort;
CopyEngine *ce;
CopyEngineReg::ChanRegs cr;
int channelId;
CopyEngineReg::DmaDesc *curDmaDesc;
uint8_t *copyBuffer;
bool busy;
bool underReset;
bool refreshNext;
Addr lastDescriptorAddr;
Addr fetchAddress;
Tick latBeforeBegin;
Tick latAfterCompletion;
uint64_t completionDataReg;
enum ChannelState {
Idle,
AddressFetch,
DescriptorFetch,
DMARead,
DMAWrite,
CompletionWrite
};
ChannelState nextState;
Event *drainEvent;
public:
CopyEngineChannel(CopyEngine *_ce, int cid);
virtual ~CopyEngineChannel();
MasterPort &getMasterPort();
std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
virtual Tick read(PacketPtr pkt)
{ panic("CopyEngineChannel has no I/O access\n");}
virtual Tick write(PacketPtr pkt)
{ panic("CopyEngineChannel has no I/O access\n"); }
void channelRead(PacketPtr pkt, Addr daddr, int size);
void channelWrite(PacketPtr pkt, Addr daddr, int size);
unsigned int drain(Event *de);
void resume();
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
private:
void fetchDescriptor(Addr address);
void fetchDescComplete();
EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchDescComplete>
fetchCompleteEvent;
void fetchNextAddr(Addr address);
void fetchAddrComplete();
EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchAddrComplete>
addrCompleteEvent;
void readCopyBytes();
void readCopyBytesComplete();
EventWrapper<CopyEngineChannel, &CopyEngineChannel::readCopyBytesComplete>
readCompleteEvent;
void writeCopyBytes();
void writeCopyBytesComplete();
EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeCopyBytesComplete>
writeCompleteEvent;
void writeCompletionStatus();
void writeStatusComplete();
EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeStatusComplete>
statusCompleteEvent;
void continueProcessing();
void recvCommand();
bool inDrain();
void restartStateMachine();
inline void anBegin(const char *s)
{
CPA::cpa()->hwBegin(CPA::FL_NONE, ce->sys,
channelId, "CopyEngine", s);
}
inline void anWait()
{
CPA::cpa()->hwWe(CPA::FL_NONE, ce->sys,
channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
}
inline void anDq()
{
CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
}
inline void anPq()
{
CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
}
inline void anQ(const char * s, uint64_t id, int size = 1)
{
CPA::cpa()->hwQ(CPA::FL_NONE, ce->sys, channelId,
"CopyEngine", s, id, NULL, size);
}
};
private:
Stats::Vector bytesCopied;
Stats::Vector copiesProcessed;
// device registers
CopyEngineReg::Regs regs;
// Array of channels each one with regs/dma port/etc
std::vector<CopyEngineChannel*> chan;
public:
typedef CopyEngineParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
CopyEngine(const Params *params);
~CopyEngine();
void regStats();
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual void resume();
};
#endif //__DEV_COPY_ENGINE_HH__

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2008 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: Ali Saidi
*/
/* @file
* Register and structure descriptions for Intel's I/O AT DMA Engine
*/
#include "base/bitfield.hh"
#include "sim/serialize.hh"
namespace CopyEngineReg {
// General Channel independant registers, 128 bytes starting at 0x00
const uint32_t GEN_CHANCOUNT = 0x00;
const uint32_t GEN_XFERCAP = 0x01;
const uint32_t GEN_INTRCTRL = 0x03;
const uint32_t GEN_ATTNSTATUS = 0x04;
// Channel specific registers, each block is 128 bytes, starting at 0x80
const uint32_t CHAN_CONTROL = 0x00;
const uint32_t CHAN_STATUS = 0x04;
const uint32_t CHAN_CHAINADDR = 0x0C;
const uint32_t CHAN_CHAINADDR_LOW = 0x0C;
const uint32_t CHAN_CHAINADDR_HIGH = 0x10;
const uint32_t CHAN_COMMAND = 0x14;
const uint32_t CHAN_CMPLNADDR = 0x18;
const uint32_t CHAN_CMPLNADDR_LOW = 0x18;
const uint32_t CHAN_CMPLNADDR_HIGH = 0x1C;
const uint32_t CHAN_ERROR = 0x28;
const uint32_t DESC_CTRL_INT_GEN = 0x00000001;
const uint32_t DESC_CTRL_SRC_SN = 0x00000002;
const uint32_t DESC_CTRL_DST_SN = 0x00000004;
const uint32_t DESC_CTRL_CP_STS = 0x00000008;
const uint32_t DESC_CTRL_FRAME = 0x00000010;
const uint32_t DESC_CTRL_NULL = 0x00000020;
struct DmaDesc {
uint32_t len;
uint32_t command;
Addr src;
Addr dest;
Addr next;
uint64_t reserved1;
uint64_t reserved2;
uint64_t user1;
uint64_t user2;
};
#define ADD_FIELD8(NAME, OFFSET, BITS) \
inline uint8_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint8_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
#define ADD_FIELD16(NAME, OFFSET, BITS) \
inline uint16_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint16_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
#define ADD_FIELD32(NAME, OFFSET, BITS) \
inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
#define ADD_FIELD64(NAME, OFFSET, BITS) \
inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
template<class T>
struct Reg {
T _data;
T operator()() { return _data; }
const Reg<T> &operator=(T d) { _data = d; return *this;}
bool operator==(T d) { return d == _data; }
void operator()(T d) { _data = d; }
Reg() { _data = 0; }
void serialize(std::ostream &os)
{
SERIALIZE_SCALAR(_data);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(_data);
}
};
struct Regs {
uint8_t chanCount;
uint8_t xferCap;
struct INTRCTRL : public Reg<uint8_t> { // 0x03
using Reg<uint8_t>::operator =;
ADD_FIELD8(master_int_enable,0,1);
ADD_FIELD8(interrupt_status,1,1);
ADD_FIELD8(interrupt,2,1);
};
INTRCTRL intrctrl;
uint32_t attnStatus; // Read clears
void serialize(std::ostream &os)
{
SERIALIZE_SCALAR(chanCount);
SERIALIZE_SCALAR(xferCap);
paramOut(os, "intrctrl", intrctrl._data);
SERIALIZE_SCALAR(attnStatus);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(chanCount);
UNSERIALIZE_SCALAR(xferCap);
paramIn(cp, section, "intrctrl", intrctrl._data);
UNSERIALIZE_SCALAR(attnStatus);
}
};
struct ChanRegs {
struct CHANCTRL : public Reg<uint16_t> { // channelX + 0x00
using Reg<uint16_t>::operator =;
ADD_FIELD16(interrupt_disable,0,1);
ADD_FIELD16(error_completion_enable, 2,1);
ADD_FIELD16(any_error_abort_enable,3,1);
ADD_FIELD16(error_int_enable,4,1);
ADD_FIELD16(desc_addr_snoop_control,5,1);
ADD_FIELD16(in_use, 8,1);
};
CHANCTRL ctrl;
struct CHANSTS : public Reg<uint64_t> { // channelX + 0x04
ADD_FIELD64(dma_transfer_status, 0, 3);
ADD_FIELD64(unaffiliated_error, 3, 1);
ADD_FIELD64(soft_error, 4, 1);
ADD_FIELD64(compl_desc_addr, 6, 58);
};
CHANSTS status;
uint64_t descChainAddr;
struct CHANCMD : public Reg<uint8_t> { // channelX + 0x14
ADD_FIELD8(start_dma,0,1);
ADD_FIELD8(append_dma,1,1);
ADD_FIELD8(suspend_dma,2,1);
ADD_FIELD8(abort_dma,3,1);
ADD_FIELD8(resume_dma,4,1);
ADD_FIELD8(reset_dma,5,1);
};
CHANCMD command;
uint64_t completionAddr;
struct CHANERR : public Reg<uint32_t> { // channel X + 0x28
ADD_FIELD32(source_addr_error,0,1);
ADD_FIELD32(dest_addr_error,1,1);
ADD_FIELD32(ndesc_addr_error,2,1);
ADD_FIELD32(desc_error,3,1);
ADD_FIELD32(chain_addr_error,4,1);
ADD_FIELD32(chain_cmd_error,5,1);
ADD_FIELD32(chipset_parity_error,6,1);
ADD_FIELD32(dma_parity_error,7,1);
ADD_FIELD32(read_data_error,8,1);
ADD_FIELD32(write_data_error,9,1);
ADD_FIELD32(desc_control_error,10,1);
ADD_FIELD32(desc_len_error,11,1);
ADD_FIELD32(completion_addr_error,12,1);
ADD_FIELD32(interrupt_config_error,13,1);
ADD_FIELD32(soft_error,14,1);
ADD_FIELD32(unaffiliated_error,15,1);
};
CHANERR error;
void serialize(std::ostream &os)
{
paramOut(os, "ctrl", ctrl._data);
paramOut(os, "status", status._data);
SERIALIZE_SCALAR(descChainAddr);
paramOut(os, "command", command._data);
SERIALIZE_SCALAR(completionAddr);
paramOut(os, "error", error._data);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
paramIn(cp, section, "ctrl", ctrl._data);
paramIn(cp, section, "status", status._data);
UNSERIALIZE_SCALAR(descChainAddr);
paramIn(cp, section, "command", command._data);
UNSERIALIZE_SCALAR(completionAddr);
paramIn(cp, section, "error", error._data);
}
};
} // namespace CopyEngineReg

View File

@ -0,0 +1,429 @@
/*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/** @file
* Disk Image Definitions
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <fstream>
#include <string>
#include "base/callback.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "debug/DiskImageRead.hh"
#include "debug/DiskImageWrite.hh"
#include "dev/disk_image.hh"
#include "sim/byteswap.hh"
#include "sim/sim_exit.hh"
using namespace std;
////////////////////////////////////////////////////////////////////////
//
// Raw Disk image
//
RawDiskImage::RawDiskImage(const Params* p)
: DiskImage(p), disk_size(0)
{ open(p->image_file, p->read_only); }
RawDiskImage::~RawDiskImage()
{ close(); }
void
RawDiskImage::open(const string &filename, bool rd_only)
{
if (!filename.empty()) {
initialized = true;
readonly = rd_only;
file = filename;
ios::openmode mode = ios::in | ios::binary;
if (!readonly)
mode |= ios::out;
stream.open(file.c_str(), mode);
if (!stream.is_open())
panic("Error opening %s", filename);
}
}
void
RawDiskImage::close()
{
stream.close();
}
off_t
RawDiskImage::size() const
{
if (disk_size == 0) {
if (!stream.is_open())
panic("file not open!\n");
stream.seekg(0, ios::end);
disk_size = stream.tellg();
}
return disk_size / SectorSize;
}
off_t
RawDiskImage::read(uint8_t *data, off_t offset) const
{
if (!initialized)
panic("RawDiskImage not initialized");
if (!stream.is_open())
panic("file not open!\n");
if (stream.seekg(offset * SectorSize, ios::beg) < 0)
panic("Could not seek to location in file");
streampos pos = stream.tellg();
stream.read((char *)data, SectorSize);
DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
DDUMP(DiskImageRead, data, SectorSize);
return stream.tellg() - pos;
}
off_t
RawDiskImage::write(const uint8_t *data, off_t offset)
{
if (!initialized)
panic("RawDiskImage not initialized");
if (readonly)
panic("Cannot write to a read only disk image");
if (!stream.is_open())
panic("file not open!\n");
if (stream.seekp(offset * SectorSize, ios::beg) < 0)
panic("Could not seek to location in file");
DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
DDUMP(DiskImageWrite, data, SectorSize);
streampos pos = stream.tellp();
stream.write((const char *)data, SectorSize);
return stream.tellp() - pos;
}
RawDiskImage *
RawDiskImageParams::create()
{
return new RawDiskImage(this);
}
////////////////////////////////////////////////////////////////////////
//
// Copy on Write Disk image
//
const uint32_t CowDiskImage::VersionMajor = 1;
const uint32_t CowDiskImage::VersionMinor = 0;
class CowDiskCallback : public Callback
{
private:
CowDiskImage *image;
public:
CowDiskCallback(CowDiskImage *i) : image(i) {}
void process() { image->save(); delete this; }
};
CowDiskImage::CowDiskImage(const Params *p)
: DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
{
if (filename.empty()) {
initSectorTable(p->table_size);
} else {
if (!open(filename)) {
if (p->read_only)
fatal("could not open read-only file");
initSectorTable(p->table_size);
}
if (!p->read_only)
registerExitCallback(new CowDiskCallback(this));
}
}
CowDiskImage::~CowDiskImage()
{
SectorTable::iterator i = table->begin();
SectorTable::iterator end = table->end();
while (i != end) {
delete (*i).second;
++i;
}
}
void
SafeRead(ifstream &stream, void *data, int count)
{
stream.read((char *)data, count);
if (!stream.is_open())
panic("file not open");
if (stream.eof())
panic("premature end-of-file");
if (stream.bad() || stream.fail())
panic("error reading cowdisk image");
}
template<class T>
void
SafeRead(ifstream &stream, T &data)
{
SafeRead(stream, &data, sizeof(data));
}
template<class T>
void
SafeReadSwap(ifstream &stream, T &data)
{
SafeRead(stream, &data, sizeof(data));
data = letoh(data); //is this the proper byte order conversion?
}
bool
CowDiskImage::open(const string &file)
{
ifstream stream(file.c_str());
if (!stream.is_open())
return false;
if (stream.fail() || stream.bad())
panic("Error opening %s", file);
uint64_t magic;
SafeRead(stream, magic);
if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
panic("Could not open %s: Invalid magic", file);
uint32_t major, minor;
SafeReadSwap(stream, major);
SafeReadSwap(stream, minor);
if (major != VersionMajor && minor != VersionMinor)
panic("Could not open %s: invalid version %d.%d != %d.%d",
file, major, minor, VersionMajor, VersionMinor);
uint64_t sector_count;
SafeReadSwap(stream, sector_count);
table = new SectorTable(sector_count);
for (uint64_t i = 0; i < sector_count; i++) {
uint64_t offset;
SafeReadSwap(stream, offset);
Sector *sector = new Sector;
SafeRead(stream, sector, sizeof(Sector));
assert(table->find(offset) == table->end());
(*table)[offset] = sector;
}
stream.close();
initialized = true;
return true;
}
void
CowDiskImage::initSectorTable(int hash_size)
{
table = new SectorTable(hash_size);
initialized = true;
}
void
SafeWrite(ofstream &stream, const void *data, int count)
{
stream.write((const char *)data, count);
if (!stream.is_open())
panic("file not open");
if (stream.eof())
panic("premature end-of-file");
if (stream.bad() || stream.fail())
panic("error reading cowdisk image");
}
template<class T>
void
SafeWrite(ofstream &stream, const T &data)
{
SafeWrite(stream, &data, sizeof(data));
}
template<class T>
void
SafeWriteSwap(ofstream &stream, const T &data)
{
T swappeddata = letoh(data); //is this the proper byte order conversion?
SafeWrite(stream, &swappeddata, sizeof(data));
}
void
CowDiskImage::save()
{
save(filename);
}
void
CowDiskImage::save(const string &file)
{
if (!initialized)
panic("RawDiskImage not initialized");
ofstream stream(file.c_str());
if (!stream.is_open() || stream.fail() || stream.bad())
panic("Error opening %s", file);
uint64_t magic;
memcpy(&magic, "COWDISK!", sizeof(magic));
SafeWrite(stream, magic);
SafeWriteSwap(stream, (uint32_t)VersionMajor);
SafeWriteSwap(stream, (uint32_t)VersionMinor);
SafeWriteSwap(stream, (uint64_t)table->size());
uint64_t size = table->size();
SectorTable::iterator iter = table->begin();
SectorTable::iterator end = table->end();
for (uint64_t i = 0; i < size; i++) {
if (iter == end)
panic("Incorrect Table Size during save of COW disk image");
SafeWriteSwap(stream, (uint64_t)(*iter).first);
SafeWrite(stream, (*iter).second->data, sizeof(Sector));
++iter;
}
stream.close();
}
void
CowDiskImage::writeback()
{
SectorTable::iterator i = table->begin();
SectorTable::iterator end = table->end();
while (i != end) {
child->write((*i).second->data, (*i).first);
++i;
}
}
off_t
CowDiskImage::size() const
{ return child->size(); }
off_t
CowDiskImage::read(uint8_t *data, off_t offset) const
{
if (!initialized)
panic("CowDiskImage not initialized");
if (offset > size())
panic("access out of bounds");
SectorTable::const_iterator i = table->find(offset);
if (i == table->end())
return child->read(data, offset);
else {
memcpy(data, (*i).second->data, SectorSize);
DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
DDUMP(DiskImageRead, data, SectorSize);
return SectorSize;
}
}
off_t
CowDiskImage::write(const uint8_t *data, off_t offset)
{
if (!initialized)
panic("RawDiskImage not initialized");
if (offset > size())
panic("access out of bounds");
SectorTable::iterator i = table->find(offset);
if (i == table->end()) {
Sector *sector = new Sector;
memcpy(sector, data, SectorSize);
table->insert(make_pair(offset, sector));
} else {
memcpy((*i).second->data, data, SectorSize);
}
DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
DDUMP(DiskImageWrite, data, SectorSize);
return SectorSize;
}
void
CowDiskImage::serialize(ostream &os)
{
string cowFilename = name() + ".cow";
SERIALIZE_SCALAR(cowFilename);
save(Checkpoint::dir() + "/" + cowFilename);
}
void
CowDiskImage::unserialize(Checkpoint *cp, const string &section)
{
string cowFilename;
UNSERIALIZE_SCALAR(cowFilename);
cowFilename = cp->cptDir + "/" + cowFilename;
open(cowFilename);
}
CowDiskImage *
CowDiskImageParams::create()
{
return new CowDiskImage(this);
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/** @file
* Disk Image Interfaces
*/
#ifndef __DISK_IMAGE_HH__
#define __DISK_IMAGE_HH__
#include <fstream>
#include "base/hashmap.hh"
#include "params/CowDiskImage.hh"
#include "params/DiskImage.hh"
#include "params/RawDiskImage.hh"
#include "sim/sim_object.hh"
#define SectorSize (512)
/**
* Basic interface for accessing a disk image.
*/
class DiskImage : public SimObject
{
protected:
bool initialized;
public:
typedef DiskImageParams Params;
DiskImage(const Params *p) : SimObject(p), initialized(false) {}
virtual ~DiskImage() {}
virtual off_t size() const = 0;
virtual off_t read(uint8_t *data, off_t offset) const = 0;
virtual off_t write(const uint8_t *data, off_t offset) = 0;
};
/**
* Specialization for accessing a raw disk image
*/
class RawDiskImage : public DiskImage
{
protected:
mutable std::fstream stream;
std::string file;
bool readonly;
mutable off_t disk_size;
public:
typedef RawDiskImageParams Params;
RawDiskImage(const Params *p);
~RawDiskImage();
void close();
void open(const std::string &filename, bool rd_only = false);
virtual off_t size() const;
virtual off_t read(uint8_t *data, off_t offset) const;
virtual off_t write(const uint8_t *data, off_t offset);
};
/**
* Specialization for accessing a copy-on-write disk image layer.
* A copy-on-write(COW) layer must be stacked on top of another disk
* image layer this layer can be another CowDiskImage, or a
* RawDiskImage.
*
* This object is designed to provide a mechanism for persistant
* changes to a main disk image, or to provide a place for temporary
* changes to the image to take place that later may be thrown away.
*/
class CowDiskImage : public DiskImage
{
public:
static const uint32_t VersionMajor;
static const uint32_t VersionMinor;
protected:
struct Sector {
uint8_t data[SectorSize];
};
typedef m5::hash_map<uint64_t, Sector *> SectorTable;
protected:
std::string filename;
DiskImage *child;
SectorTable *table;
public:
typedef CowDiskImageParams Params;
CowDiskImage(const Params *p);
~CowDiskImage();
void initSectorTable(int hash_size);
bool open(const std::string &file);
void save();
void save(const std::string &file);
void writeback();
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
virtual off_t size() const;
virtual off_t read(uint8_t *data, off_t offset) const;
virtual off_t write(const uint8_t *data, off_t offset);
};
#endif // __DISK_IMAGE_HH__

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
* Nathan Binkert
*/
#include "base/chunk_generator.hh"
#include "debug/DMA.hh"
#include "dev/dma_device.hh"
#include "sim/system.hh"
DmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff)
: MasterPort(dev->name() + "-dma", dev), device(dev), sys(s),
masterId(s->getMasterId(dev->name())),
pendingCount(0), actionInProgress(0), drainEvent(NULL),
backoffTime(0), minBackoffDelay(min_backoff),
maxBackoffDelay(max_backoff), inRetry(false),
backoffEvent(this)
{ }
bool
DmaPort::recvTimingResp(PacketPtr pkt)
{
if (pkt->wasNacked()) {
DPRINTF(DMA, "Received nacked %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
if (backoffTime < minBackoffDelay)
backoffTime = minBackoffDelay;
else if (backoffTime < maxBackoffDelay)
backoffTime <<= 1;
device->reschedule(backoffEvent, curTick() + backoffTime, true);
DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
pkt->reinitNacked();
queueDma(pkt, true);
} else if (pkt->senderState) {
DmaReqState *state;
backoffTime >>= 2;
DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
state = dynamic_cast<DmaReqState*>(pkt->senderState);
pendingCount--;
assert(pendingCount >= 0);
assert(state);
// We shouldn't ever get a block in ownership state
assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
state->numBytes += pkt->req->getSize();
assert(state->totBytes >= state->numBytes);
if (state->totBytes == state->numBytes) {
if (state->completionEvent) {
if (state->delay)
device->schedule(state->completionEvent,
curTick() + state->delay);
else
state->completionEvent->process();
}
delete state;
}
delete pkt->req;
delete pkt;
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} else {
panic("Got packet without sender state... huh?\n");
}
return true;
}
DmaDevice::DmaDevice(const Params *p)
: PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay,
params()->max_backoff_delay)
{ }
void
DmaDevice::init()
{
if (!dmaPort.isConnected())
panic("DMA port of %s not connected to anything!", name());
PioDevice::init();
}
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()
{
assert(transmitList.size());
bool result = true;
do {
PacketPtr pkt = transmitList.front();
DPRINTF(DMA, "Retry on %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
result = sendTimingReq(pkt);
if (result) {
DPRINTF(DMA, "-- Done\n");
transmitList.pop_front();
inRetry = false;
} else {
inRetry = true;
DPRINTF(DMA, "-- Failed, queued\n");
}
} while (!backoffTime && result && transmitList.size());
if (transmitList.size() && backoffTime && !inRetry) {
DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime);
if (!backoffEvent.scheduled())
device->schedule(backoffEvent, backoffTime + curTick());
}
DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
transmitList.size(), backoffTime, inRetry,
backoffEvent.scheduled());
}
void
DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data, Tick delay, Request::Flags flag)
{
assert(device->getState() == SimObject::Running);
DmaReqState *reqState = new DmaReqState(event, size, delay);
DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
event ? event->scheduled() : -1 );
for (ChunkGenerator gen(addr, size, peerBlockSize());
!gen.done(); gen.next()) {
Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
PacketPtr pkt = new Packet(req, cmd);
// Increment the data pointer on a write
if (data)
pkt->dataStatic(data + gen.complete());
pkt->senderState = reqState;
assert(pendingCount >= 0);
pendingCount++;
DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
gen.size());
queueDma(pkt);
}
}
void
DmaPort::queueDma(PacketPtr pkt, bool front)
{
if (front)
transmitList.push_front(pkt);
else
transmitList.push_back(pkt);
sendDma();
}
void
DmaPort::sendDma()
{
// some kind of selction between access methods
// more work is going to have to be done to make
// switching actually work
assert(transmitList.size());
PacketPtr pkt = transmitList.front();
Enums::MemoryMode state = sys->getMemoryMode();
if (state == Enums::timing) {
if (backoffEvent.scheduled() || inRetry) {
DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n");
return;
}
DPRINTF(DMA, "Attempting to send %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
bool result;
do {
result = sendTimingReq(pkt);
if (result) {
transmitList.pop_front();
DPRINTF(DMA, "-- Done\n");
} else {
inRetry = true;
DPRINTF(DMA, "-- Failed: queued\n");
}
} while (result && !backoffTime && transmitList.size());
if (transmitList.size() && backoffTime && !inRetry &&
!backoffEvent.scheduled()) {
DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
backoffTime+curTick());
device->schedule(backoffEvent, backoffTime + curTick());
}
} else if (state == Enums::atomic) {
transmitList.pop_front();
Tick lat;
DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n",
pkt->req->getPaddr(), pkt->req->getSize());
lat = sendAtomic(pkt);
assert(pkt->senderState);
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
assert(state);
state->numBytes += pkt->req->getSize();
DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
state->totBytes,
state->completionEvent ? state->completionEvent->scheduled() : 0 );
if (state->totBytes == state->numBytes) {
if (state->completionEvent) {
assert(!state->completionEvent->scheduled());
device->schedule(state->completionEvent,
curTick() + lat + state->delay);
}
delete state;
delete pkt->req;
}
pendingCount--;
assert(pendingCount >= 0);
delete pkt;
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
}
} else
panic("Unknown memory command state.");
}
DmaDevice::~DmaDevice()
{
}
MasterPort &
DmaDevice::getMasterPort(const std::string &if_name, int idx)
{
if (if_name == "dma") {
return dmaPort;
}
return PioDevice::getMasterPort(if_name, idx);
}

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Nathan Binkert
*/
#ifndef __DEV_DMA_DEVICE_HH__
#define __DEV_DMA_DEVICE_HH__
#include "dev/io_device.hh"
#include "params/DmaDevice.hh"
class DmaPort : public MasterPort
{
protected:
struct DmaReqState : public Packet::SenderState
{
/** Event to call on the device when this transaction (all packets)
* complete. */
Event *completionEvent;
/** Total number of bytes that this transaction involves. */
Addr totBytes;
/** Number of bytes that have been acked for this transaction. */
Addr numBytes;
/** Amount to delay completion of dma by */
Tick delay;
DmaReqState(Event *ce, Addr tb, Tick _delay)
: completionEvent(ce), totBytes(tb), numBytes(0), delay(_delay)
{}
};
MemObject *device;
std::list<PacketPtr> transmitList;
/** The system that device/port are in. This is used to select which mode
* we are currently operating in. */
System *sys;
/** Id for all requests */
MasterID masterId;
/** 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;
/** time to wait between sending another packet, increases as NACKs are
* recived, decreases as responses are recived. */
Tick backoffTime;
/** Minimum time that device should back off for after failed sendTiming */
Tick minBackoffDelay;
/** Maximum time that device should back off for after failed sendTiming */
Tick maxBackoffDelay;
/** If the port is currently waiting for a retry before it can send whatever
* it is that it's sending. */
bool inRetry;
virtual bool recvTimingResp(PacketPtr pkt);
virtual void recvRetry() ;
void queueDma(PacketPtr pkt, bool front = false);
void sendDma();
/** event to give us a kick every time we backoff time is reached. */
EventWrapper<DmaPort, &DmaPort::sendDma> backoffEvent;
public:
DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data, Tick delay, Request::Flags flag = 0);
bool dmaPending() { return pendingCount > 0; }
unsigned cacheBlockSize() const { return peerBlockSize(); }
unsigned int drain(Event *de);
};
class DmaDevice : public PioDevice
{
protected:
DmaPort dmaPort;
public:
typedef DmaDeviceParams Params;
DmaDevice(const Params *p);
virtual ~DmaDevice();
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
Tick delay = 0)
{
dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
}
void dmaRead(Addr addr, int size, Event *event, uint8_t *data,
Tick delay = 0)
{
dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
}
bool dmaPending() { return dmaPort.dmaPending(); }
virtual void init();
virtual unsigned int drain(Event *de);
unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }
virtual MasterPort &getMasterPort(const std::string &if_name,
int idx = -1);
friend class DmaPort;
};
#endif // __DEV_DMA_DEVICE_HH__

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Device module for modelling an ethernet hub
*/
#include <cmath>
#include <deque>
#include <string>
#include <vector>
#include "base/trace.hh"
#include "debug/Ethernet.hh"
#include "debug/EthernetData.hh"
#include "dev/etherbus.hh"
#include "dev/etherdump.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
#include "params/EtherBus.hh"
#include "sim/core.hh"
using namespace std;
EtherBus::EtherBus(const Params *p)
: EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback),
event(this), sender(0), dump(p->dump)
{
}
void
EtherBus::txDone()
{
devlist_t::iterator i = devlist.begin();
devlist_t::iterator end = devlist.end();
DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
while (i != end) {
if (loopback || *i != sender)
(*i)->sendPacket(packet);
++i;
}
sender->sendDone();
if (dump)
dump->dump(packet);
sender = 0;
packet = 0;
}
EtherInt*
EtherBus::getEthPort(const std::string &if_name, int idx)
{
panic("Etherbus doesn't work\n");
}
bool
EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
{
if (busy()) {
DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick());
return false;
}
DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length);
DDUMP(EthernetData, pkt->data, pkt->length);
packet = pkt;
sender = sndr;
int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0);
DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
delay, ticksPerByte);
schedule(event, curTick() + delay);
return true;
}
EtherBus *
EtherBusParams::create()
{
return new EtherBus(this);
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Device module for modelling an ethernet hub
*/
#ifndef __ETHERBUS_H__
#define __ETHERBUS_H__
#include "dev/etherobject.hh"
#include "dev/etherpkt.hh"
#include "params/EtherBus.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
class EtherDump;
class EtherInt;
class EtherBus : public EtherObject
{
protected:
typedef std::list<EtherInt *> devlist_t;
devlist_t devlist;
double ticksPerByte;
bool loopback;
protected:
class DoneEvent : public Event
{
protected:
EtherBus *bus;
public:
DoneEvent(EtherBus *b) : bus(b) {}
virtual void process() { bus->txDone(); }
virtual const char *description() const
{ return "ethernet bus completion"; }
};
DoneEvent event;
EthPacketPtr packet;
EtherInt *sender;
EtherDump *dump;
public:
typedef EtherBusParams Params;
EtherBus(const Params *p);
virtual ~EtherBus() {}
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
void txDone();
void reg(EtherInt *dev);
bool busy() const { return (bool)packet; }
bool send(EtherInt *sender, EthPacketPtr &packet);
virtual EtherInt *getEthPort(const std::string &if_name, int idx);
};
#endif // __ETHERBUS_H__

View File

@ -0,0 +1,368 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Lisa Hsu
*/
#include "dev/etherdevice.hh"
#include "sim/stats.hh"
void
EtherDevice::regStats()
{
txBytes
.name(name() + ".txBytes")
.desc("Bytes Transmitted")
.prereq(txBytes)
;
rxBytes
.name(name() + ".rxBytes")
.desc("Bytes Received")
.prereq(rxBytes)
;
txPackets
.name(name() + ".txPackets")
.desc("Number of Packets Transmitted")
.prereq(txBytes)
;
rxPackets
.name(name() + ".rxPackets")
.desc("Number of Packets Received")
.prereq(rxBytes)
;
txIpChecksums
.name(name() + ".txIpChecksums")
.desc("Number of tx IP Checksums done by device")
.precision(0)
.prereq(txBytes)
;
rxIpChecksums
.name(name() + ".rxIpChecksums")
.desc("Number of rx IP Checksums done by device")
.precision(0)
.prereq(rxBytes)
;
txTcpChecksums
.name(name() + ".txTcpChecksums")
.desc("Number of tx TCP Checksums done by device")
.precision(0)
.prereq(txBytes)
;
rxTcpChecksums
.name(name() + ".rxTcpChecksums")
.desc("Number of rx TCP Checksums done by device")
.precision(0)
.prereq(rxBytes)
;
txUdpChecksums
.name(name() + ".txUdpChecksums")
.desc("Number of tx UDP Checksums done by device")
.precision(0)
.prereq(txBytes)
;
rxUdpChecksums
.name(name() + ".rxUdpChecksums")
.desc("Number of rx UDP Checksums done by device")
.precision(0)
.prereq(rxBytes)
;
descDmaReads
.name(name() + ".descDMAReads")
.desc("Number of descriptors the device read w/ DMA")
.precision(0)
;
descDmaWrites
.name(name() + ".descDMAWrites")
.desc("Number of descriptors the device wrote w/ DMA")
.precision(0)
;
descDmaRdBytes
.name(name() + ".descDmaReadBytes")
.desc("number of descriptor bytes read w/ DMA")
.precision(0)
;
descDmaWrBytes
.name(name() + ".descDmaWriteBytes")
.desc("number of descriptor bytes write w/ DMA")
.precision(0)
;
txBandwidth
.name(name() + ".txBandwidth")
.desc("Transmit Bandwidth (bits/s)")
.precision(0)
.prereq(txBytes)
;
rxBandwidth
.name(name() + ".rxBandwidth")
.desc("Receive Bandwidth (bits/s)")
.precision(0)
.prereq(rxBytes)
;
totBandwidth
.name(name() + ".totBandwidth")
.desc("Total Bandwidth (bits/s)")
.precision(0)
.prereq(totBytes)
;
totPackets
.name(name() + ".totPackets")
.desc("Total Packets")
.precision(0)
.prereq(totBytes)
;
totBytes
.name(name() + ".totBytes")
.desc("Total Bytes")
.precision(0)
.prereq(totBytes)
;
totPacketRate
.name(name() + ".totPPS")
.desc("Total Tranmission Rate (packets/s)")
.precision(0)
.prereq(totBytes)
;
txPacketRate
.name(name() + ".txPPS")
.desc("Packet Tranmission Rate (packets/s)")
.precision(0)
.prereq(txBytes)
;
rxPacketRate
.name(name() + ".rxPPS")
.desc("Packet Reception Rate (packets/s)")
.precision(0)
.prereq(rxBytes)
;
postedSwi
.name(name() + ".postedSwi")
.desc("number of software interrupts posted to CPU")
.precision(0)
;
totalSwi
.name(name() + ".totalSwi")
.desc("total number of Swi written to ISR")
.precision(0)
;
coalescedSwi
.name(name() + ".coalescedSwi")
.desc("average number of Swi's coalesced into each post")
.precision(0)
;
postedRxIdle
.name(name() + ".postedRxIdle")
.desc("number of rxIdle interrupts posted to CPU")
.precision(0)
;
totalRxIdle
.name(name() + ".totalRxIdle")
.desc("total number of RxIdle written to ISR")
.precision(0)
;
coalescedRxIdle
.name(name() + ".coalescedRxIdle")
.desc("average number of RxIdle's coalesced into each post")
.precision(0)
;
postedRxOk
.name(name() + ".postedRxOk")
.desc("number of RxOk interrupts posted to CPU")
.precision(0)
;
totalRxOk
.name(name() + ".totalRxOk")
.desc("total number of RxOk written to ISR")
.precision(0)
;
coalescedRxOk
.name(name() + ".coalescedRxOk")
.desc("average number of RxOk's coalesced into each post")
.precision(0)
;
postedRxDesc
.name(name() + ".postedRxDesc")
.desc("number of RxDesc interrupts posted to CPU")
.precision(0)
;
totalRxDesc
.name(name() + ".totalRxDesc")
.desc("total number of RxDesc written to ISR")
.precision(0)
;
coalescedRxDesc
.name(name() + ".coalescedRxDesc")
.desc("average number of RxDesc's coalesced into each post")
.precision(0)
;
postedTxOk
.name(name() + ".postedTxOk")
.desc("number of TxOk interrupts posted to CPU")
.precision(0)
;
totalTxOk
.name(name() + ".totalTxOk")
.desc("total number of TxOk written to ISR")
.precision(0)
;
coalescedTxOk
.name(name() + ".coalescedTxOk")
.desc("average number of TxOk's coalesced into each post")
.precision(0)
;
postedTxIdle
.name(name() + ".postedTxIdle")
.desc("number of TxIdle interrupts posted to CPU")
.precision(0)
;
totalTxIdle
.name(name() + ".totalTxIdle")
.desc("total number of TxIdle written to ISR")
.precision(0)
;
coalescedTxIdle
.name(name() + ".coalescedTxIdle")
.desc("average number of TxIdle's coalesced into each post")
.precision(0)
;
postedTxDesc
.name(name() + ".postedTxDesc")
.desc("number of TxDesc interrupts posted to CPU")
.precision(0)
;
totalTxDesc
.name(name() + ".totalTxDesc")
.desc("total number of TxDesc written to ISR")
.precision(0)
;
coalescedTxDesc
.name(name() + ".coalescedTxDesc")
.desc("average number of TxDesc's coalesced into each post")
.precision(0)
;
postedRxOrn
.name(name() + ".postedRxOrn")
.desc("number of RxOrn posted to CPU")
.precision(0)
;
totalRxOrn
.name(name() + ".totalRxOrn")
.desc("total number of RxOrn written to ISR")
.precision(0)
;
coalescedRxOrn
.name(name() + ".coalescedRxOrn")
.desc("average number of RxOrn's coalesced into each post")
.precision(0)
;
coalescedTotal
.name(name() + ".coalescedTotal")
.desc("average number of interrupts coalesced into each post")
.precision(0)
;
postedInterrupts
.name(name() + ".postedInterrupts")
.desc("number of posts to CPU")
.precision(0)
;
droppedPackets
.name(name() + ".droppedPackets")
.desc("number of packets dropped")
.precision(0)
;
coalescedSwi = totalSwi / postedInterrupts;
coalescedRxIdle = totalRxIdle / postedInterrupts;
coalescedRxOk = totalRxOk / postedInterrupts;
coalescedRxDesc = totalRxDesc / postedInterrupts;
coalescedTxOk = totalTxOk / postedInterrupts;
coalescedTxIdle = totalTxIdle / postedInterrupts;
coalescedTxDesc = totalTxDesc / postedInterrupts;
coalescedRxOrn = totalRxOrn / postedInterrupts;
coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
totalTxOk + totalTxIdle + totalTxDesc +
totalRxOrn) / postedInterrupts;
txBandwidth = txBytes * Stats::constant(8) / simSeconds;
rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
totBandwidth = txBandwidth + rxBandwidth;
totBytes = txBytes + rxBytes;
totPackets = txPackets + rxPackets;
txPacketRate = txPackets / simSeconds;
rxPacketRate = rxPackets / simSeconds;
totPacketRate = totPackets / simSeconds;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2007 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: Ali Saidi
*/
/**
* @file
* Base Ethernet Device declaration.
*/
#ifndef __DEV_ETHERDEVICE_HH__
#define __DEV_ETHERDEVICE_HH__
#include "base/statistics.hh"
#include "dev/pcidev.hh"
#include "params/EtherDevice.hh"
#include "sim/sim_object.hh"
class EtherInt;
/**
* The base EtherObject class, allows for an accesor function to a
* simobj that returns the Port.
*/
class EtherDevice : public PciDev
{
public:
typedef EtherDeviceParams Params;
EtherDevice(const Params *params)
: PciDev(params)
{}
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
public:
/** Additional function to return the Port of a memory object. */
virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
public:
void regStats();
protected:
Stats::Scalar txBytes;
Stats::Scalar rxBytes;
Stats::Scalar txPackets;
Stats::Scalar rxPackets;
Stats::Scalar txIpChecksums;
Stats::Scalar rxIpChecksums;
Stats::Scalar txTcpChecksums;
Stats::Scalar rxTcpChecksums;
Stats::Scalar txUdpChecksums;
Stats::Scalar rxUdpChecksums;
Stats::Scalar descDmaReads;
Stats::Scalar descDmaWrites;
Stats::Scalar descDmaRdBytes;
Stats::Scalar descDmaWrBytes;
Stats::Formula totBandwidth;
Stats::Formula totPackets;
Stats::Formula totBytes;
Stats::Formula totPacketRate;
Stats::Formula txBandwidth;
Stats::Formula rxBandwidth;
Stats::Formula txPacketRate;
Stats::Formula rxPacketRate;
Stats::Scalar postedSwi;
Stats::Formula coalescedSwi;
Stats::Scalar totalSwi;
Stats::Scalar postedRxIdle;
Stats::Formula coalescedRxIdle;
Stats::Scalar totalRxIdle;
Stats::Scalar postedRxOk;
Stats::Formula coalescedRxOk;
Stats::Scalar totalRxOk;
Stats::Scalar postedRxDesc;
Stats::Formula coalescedRxDesc;
Stats::Scalar totalRxDesc;
Stats::Scalar postedTxOk;
Stats::Formula coalescedTxOk;
Stats::Scalar totalTxOk;
Stats::Scalar postedTxIdle;
Stats::Formula coalescedTxIdle;
Stats::Scalar totalTxIdle;
Stats::Scalar postedTxDesc;
Stats::Formula coalescedTxDesc;
Stats::Scalar totalTxDesc;
Stats::Scalar postedRxOrn;
Stats::Formula coalescedRxOrn;
Stats::Scalar totalRxOrn;
Stats::Formula coalescedTotal;
Stats::Scalar postedInterrupts;
Stats::Scalar droppedPackets;
};
#endif //__DEV_ETHERDEVICE_HH__

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Simple object for creating a simple pcap style packet trace
*/
#include <sys/time.h>
#include <algorithm>
#include <string>
#include "base/misc.hh"
#include "base/output.hh"
#include "dev/etherdump.hh"
#include "sim/core.hh"
using std::string;
EtherDump::EtherDump(const Params *p)
: SimObject(p), stream(simout.create(p->file, true)),
maxlen(p->maxlen)
{
}
#define DLT_EN10MB 1 // Ethernet (10Mb)
#define TCPDUMP_MAGIC 0xa1b2c3d4
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
struct pcap_file_header {
uint32_t magic;
uint16_t version_major;
uint16_t version_minor;
int32_t thiszone; // gmt to local correction
uint32_t sigfigs; // accuracy of timestamps
uint32_t snaplen; // max length saved portion of each pkt
uint32_t linktype; // data link type (DLT_*)
};
struct pcap_pkthdr {
uint32_t seconds;
uint32_t microseconds;
uint32_t caplen; // length of portion present
uint32_t len; // length this packet (off wire)
};
void
EtherDump::init()
{
struct pcap_file_header hdr;
hdr.magic = TCPDUMP_MAGIC;
hdr.version_major = PCAP_VERSION_MAJOR;
hdr.version_minor = PCAP_VERSION_MINOR;
hdr.thiszone = 0;
hdr.snaplen = 1500;
hdr.sigfigs = 0;
hdr.linktype = DLT_EN10MB;
stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
stream->flush();
}
void
EtherDump::dumpPacket(EthPacketPtr &packet)
{
pcap_pkthdr pkthdr;
pkthdr.seconds = curTick() / SimClock::Int::s;
pkthdr.microseconds = (curTick() / SimClock::Int::us) % ULL(1000000);
pkthdr.caplen = std::min(packet->length, maxlen);
pkthdr.len = packet->length;
stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
stream->flush();
}
EtherDump *
EtherDumpParams::create()
{
return new EtherDump(this);
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Simple object for creating a simple pcap style packet trace
*/
#ifndef __ETHERDUMP_H__
#define __ETHERDUMP_H__
#include <fstream>
#include "dev/etherpkt.hh"
#include "params/EtherDump.hh"
#include "sim/sim_object.hh"
/*
* Simple object for creating a simple pcap style packet trace
*/
class EtherDump : public SimObject
{
private:
std::ostream *stream;
const unsigned maxlen;
void dumpPacket(EthPacketPtr &packet);
void init();
public:
typedef EtherDumpParams Params;
EtherDump(const Params *p);
inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); }
};
#endif // __ETHERDUMP_H__

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
#include "base/misc.hh"
#include "dev/etherint.hh"
#include "sim/sim_object.hh"
void
EtherInt::setPeer(EtherInt *p)
{
if (peer && peer != p)
panic("You cannot change the peer once it is set.\n"
"Current peer=%s Desired peer=%s", peer->name(), p->name());
peer = p;
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Class representing the actual interface between two ethernet
* components.
*/
#ifndef __DEV_ETHERINT_HH__
#define __DEV_ETHERINT_HH__
#include <string>
#include "dev/etherpkt.hh"
/*
* Class representing the actual interface between two ethernet
* components. These components are intended to attach to another
* ethernet interface on one side and whatever device on the other.
*/
class EtherInt
{
protected:
mutable std::string portName;
EtherInt *peer;
public:
EtherInt(const std::string &name)
: portName(name), peer(NULL) {}
virtual ~EtherInt() {}
/** Return port name (for DPRINTF). */
const std::string &name() const { return portName; }
void setPeer(EtherInt *p);
EtherInt* getPeer() { return peer; }
void recvDone() { peer->sendDone(); }
virtual void sendDone() = 0;
bool sendPacket(EthPacketPtr packet)
{ return peer ? peer->recvPacket(packet) : true; }
virtual bool recvPacket(EthPacketPtr packet) = 0;
bool askBusy() {return peer->isBusy(); }
virtual bool isBusy() { return false; }
};
#endif // __DEV_ETHERINT_HH__

View File

@ -0,0 +1,290 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Ron Dreslinski
*/
/* @file
* Device module for modelling a fixed bandwidth full duplex ethernet link
*/
#include <cmath>
#include <deque>
#include <string>
#include <vector>
#include "base/random.hh"
#include "base/trace.hh"
#include "debug/Ethernet.hh"
#include "debug/EthernetData.hh"
#include "dev/etherdump.hh"
#include "dev/etherint.hh"
#include "dev/etherlink.hh"
#include "dev/etherpkt.hh"
#include "params/EtherLink.hh"
#include "sim/core.hh"
#include "sim/serialize.hh"
#include "sim/system.hh"
using namespace std;
EtherLink::EtherLink(const Params *p)
: EtherObject(p)
{
link[0] = new Link(name() + ".link0", this, 0, p->speed,
p->delay, p->delay_var, p->dump);
link[1] = new Link(name() + ".link1", this, 1, p->speed,
p->delay, p->delay_var, p->dump);
interface[0] = new Interface(name() + ".int0", link[0], link[1]);
interface[1] = new Interface(name() + ".int1", link[1], link[0]);
}
EtherLink::~EtherLink()
{
delete link[0];
delete link[1];
delete interface[0];
delete interface[1];
}
EtherInt*
EtherLink::getEthPort(const std::string &if_name, int idx)
{
Interface *i;
if (if_name == "int0")
i = interface[0];
else if (if_name == "int1")
i = interface[1];
else
return NULL;
if (i->getPeer())
panic("interface already connected to\n");
return i;
}
EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
: EtherInt(name), txlink(tx)
{
tx->setTxInt(this);
rx->setRxInt(this);
}
EtherLink::Link::Link(const string &name, EtherLink *p, int num,
double rate, Tick delay, Tick delay_var, EtherDump *d)
: objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
doneEvent(this)
{ }
void
EtherLink::serialize(ostream &os)
{
link[0]->serialize("link0", os);
link[1]->serialize("link1", os);
}
void
EtherLink::unserialize(Checkpoint *cp, const string &section)
{
link[0]->unserialize("link0", cp, section);
link[1]->unserialize("link1", cp, section);
}
void
EtherLink::Link::txComplete(EthPacketPtr packet)
{
DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
rxint->sendPacket(packet);
}
class LinkDelayEvent : public Event
{
protected:
EtherLink::Link *link;
EthPacketPtr packet;
public:
// non-scheduling version for createForUnserialize()
LinkDelayEvent();
LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt);
void process();
virtual void serialize(ostream &os);
virtual void unserialize(Checkpoint *cp, const string &section);
static Serializable *createForUnserialize(Checkpoint *cp,
const string &section);
};
void
EtherLink::Link::txDone()
{
if (dump)
dump->dump(packet);
if (linkDelay > 0) {
DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
Event *event = new LinkDelayEvent(this, packet);
parent->schedule(event, curTick() + linkDelay);
} else {
txComplete(packet);
}
packet = 0;
assert(!busy());
txint->sendDone();
}
bool
EtherLink::Link::transmit(EthPacketPtr pkt)
{
if (busy()) {
DPRINTF(Ethernet, "packet not sent, link busy\n");
return false;
}
DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
DDUMP(EthernetData, pkt->data, pkt->length);
packet = pkt;
Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
if (delayVar != 0)
delay += random_mt.random<Tick>(0, delayVar);
DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
delay, ticksPerByte);
parent->schedule(doneEvent, curTick() + delay);
return true;
}
void
EtherLink::Link::serialize(const string &base, ostream &os)
{
bool packet_exists = packet;
paramOut(os, base + ".packet_exists", packet_exists);
if (packet_exists)
packet->serialize(base + ".packet", os);
bool event_scheduled = doneEvent.scheduled();
paramOut(os, base + ".event_scheduled", event_scheduled);
if (event_scheduled) {
Tick event_time = doneEvent.when();
paramOut(os, base + ".event_time", event_time);
}
}
void
EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
bool packet_exists;
paramIn(cp, section, base + ".packet_exists", packet_exists);
if (packet_exists) {
packet = new EthPacketData(16384);
packet->unserialize(base + ".packet", cp, section);
}
bool event_scheduled;
paramIn(cp, section, base + ".event_scheduled", event_scheduled);
if (event_scheduled) {
Tick event_time;
paramIn(cp, section, base + ".event_time", event_time);
parent->schedule(doneEvent, event_time);
}
}
LinkDelayEvent::LinkDelayEvent()
: Event(Default_Pri, AutoSerialize | AutoDelete), link(NULL)
{
}
LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p)
: Event(Default_Pri, AutoSerialize | AutoDelete), link(l), packet(p)
{
}
void
LinkDelayEvent::process()
{
link->txComplete(packet);
}
void
LinkDelayEvent::serialize(ostream &os)
{
paramOut(os, "type", string("LinkDelayEvent"));
Event::serialize(os);
EtherLink *parent = link->parent;
bool number = link->number;
SERIALIZE_OBJPTR(parent);
SERIALIZE_SCALAR(number);
packet->serialize("packet", os);
}
void
LinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
{
Event::unserialize(cp, section);
EtherLink *parent;
bool number;
UNSERIALIZE_OBJPTR(parent);
UNSERIALIZE_SCALAR(number);
link = parent->link[number];
packet = new EthPacketData(16384);
packet->unserialize("packet", cp, section);
}
Serializable *
LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
{
return new LinkDelayEvent();
}
REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
EtherLink *
EtherLinkParams::create()
{
return new EtherLink(this);
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Device module for modelling a fixed bandwidth full duplex ethernet link
*/
#ifndef __DEV_ETHERLINK_HH__
#define __DEV_ETHERLINK_HH__
#include "base/types.hh"
#include "dev/etherint.hh"
#include "dev/etherobject.hh"
#include "dev/etherpkt.hh"
#include "params/EtherLink.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
class EtherDump;
class Checkpoint;
/*
* Model for a fixed bandwidth full duplex ethernet link
*/
class EtherLink : public EtherObject
{
protected:
class Interface;
friend class LinkDelayEvent;
/*
* Model for a single uni-directional link
*/
class Link
{
protected:
std::string objName;
EtherLink *parent;
int number;
Interface *txint;
Interface *rxint;
double ticksPerByte;
Tick linkDelay;
Tick delayVar;
EtherDump *dump;
protected:
/*
* Transfer is complete
*/
EthPacketPtr packet;
void txDone();
typedef EventWrapper<Link, &Link::txDone> DoneEvent;
friend void DoneEvent::process();
DoneEvent doneEvent;
friend class LinkDelayEvent;
void txComplete(EthPacketPtr packet);
public:
Link(const std::string &name, EtherLink *p, int num,
double rate, Tick delay, Tick delay_var, EtherDump *dump);
~Link() {}
const std::string name() const { return objName; }
bool busy() const { return (bool)packet; }
bool transmit(EthPacketPtr packet);
void setTxInt(Interface *i) { assert(!txint); txint = i; }
void setRxInt(Interface *i) { assert(!rxint); rxint = i; }
void serialize(const std::string &base, std::ostream &os);
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
/*
* Interface at each end of the link
*/
class Interface : public EtherInt
{
private:
Link *txlink;
public:
Interface(const std::string &name, Link *txlink, Link *rxlink);
bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); }
void sendDone() { peer->sendDone(); }
bool isBusy() { return txlink->busy(); }
};
Link *link[2];
Interface *interface[2];
public:
typedef EtherLinkParams Params;
EtherLink(const Params *p);
virtual ~EtherLink();
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual EtherInt *getEthPort(const std::string &if_name, int idx);
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __ETHERLINK_HH__

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2007 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: Ali Saidi
*/
/**
* @file
* Base Ethernet Object declaration.
*/
#ifndef __DEV_ETHEROBJECT_HH__
#define __DEV_ETHEROBJECT_HH__
#include "params/EtherObject.hh"
#include "sim/sim_object.hh"
class EtherInt;
/**
* The base EtherObject class, allows for an accesor function to a
* simobj that returns the Port.
*/
class EtherObject : public SimObject
{
public:
typedef EtherObjectParams Params;
EtherObject(const Params *params)
: SimObject(params) {}
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
public:
/** Additional function to return the Port of a memory object. */
virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
};
#endif //__MEM_MEM_OBJECT_HH__

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
#include <iostream>
#include "base/misc.hh"
#include "dev/etherpkt.hh"
#include "sim/serialize.hh"
using namespace std;
void
EthPacketData::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".length", length);
arrayParamOut(os, base + ".data", data, length);
}
void
EthPacketData::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
paramIn(cp, section, base + ".length", length);
if (length)
arrayParamIn(cp, section, base + ".data", data, length);
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Lisa Hsu
*/
/* @file
* Reference counted class containing ethernet packet data
*/
#ifndef __ETHERPKT_HH__
#define __ETHERPKT_HH__
#include <cassert>
#include <iosfwd>
#include <memory>
#include "base/refcnt.hh"
#include "base/types.hh"
/*
* Reference counted class containing ethernet packet data
*/
class Checkpoint;
class EthPacketData : public RefCounted
{
public:
/*
* Pointer to packet data will be deleted
*/
uint8_t *data;
/*
* Length of the current packet
*/
unsigned length;
public:
EthPacketData()
: data(NULL), length(0)
{ }
explicit EthPacketData(unsigned size)
: data(new uint8_t[size]), length(0)
{ }
EthPacketData(std::auto_ptr<uint8_t> d, int l)
: data(d.release()), length(l)
{ }
~EthPacketData() { if (data) delete [] data; }
public:
void serialize(const std::string &base, std::ostream &os);
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
typedef RefCountingPtr<EthPacketData> EthPacketPtr;
#endif // __ETHERPKT_HH__

View File

@ -0,0 +1,340 @@
/*
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Interface to connect a simulated ethernet device to the real world
*/
#if defined(__OpenBSD__) || defined(__APPLE__)
#include <sys/param.h>
#endif
#include <netinet/in.h>
#include <unistd.h>
#include <deque>
#include <string>
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "base/trace.hh"
#include "debug/Ethernet.hh"
#include "debug/EthernetData.hh"
#include "dev/etherdump.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
#include "dev/ethertap.hh"
using namespace std;
/**
*/
class TapListener
{
protected:
/**
*/
class Event : public PollEvent
{
protected:
TapListener *listener;
public:
Event(TapListener *l, int fd, int e)
: PollEvent(fd, e), listener(l) {}
virtual void process(int revent) { listener->accept(); }
};
friend class Event;
Event *event;
protected:
ListenSocket listener;
EtherTap *tap;
int port;
public:
TapListener(EtherTap *t, int p)
: event(NULL), tap(t), port(p) {}
~TapListener() { if (event) delete event; }
void accept();
void listen();
};
void
TapListener::listen()
{
while (!listener.listen(port, true)) {
DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
port++;
}
ccprintf(cerr, "Listening for tap connection on port %d\n", port);
event = new Event(this, listener.getfd(), POLLIN|POLLERR);
pollQueue.schedule(event);
}
void
TapListener::accept()
{
if (!listener.islistening())
panic("TapListener(accept): cannot accept if we're not listening!");
int sfd = listener.accept(true);
if (sfd != -1)
tap->attach(sfd);
}
/**
*/
class TapEvent : public PollEvent
{
protected:
EtherTap *tap;
public:
TapEvent(EtherTap *_tap, int fd, int e)
: PollEvent(fd, e), tap(_tap) {}
virtual void process(int revent) { tap->process(revent); }
};
EtherTap::EtherTap(const Params *p)
: EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump),
interface(NULL), txEvent(this)
{
if (ListenSocket::allDisabled())
fatal("All listeners are disabled! EtherTap can't work!");
buffer = new char[buflen];
listener = new TapListener(this, p->port);
listener->listen();
interface = new EtherTapInt(name() + ".interface", this);
}
EtherTap::~EtherTap()
{
if (event)
delete event;
if (buffer)
delete [] buffer;
delete listener;
}
void
EtherTap::attach(int fd)
{
if (socket != -1)
close(fd);
buffer_offset = 0;
data_len = 0;
socket = fd;
DPRINTF(Ethernet, "EtherTap attached\n");
event = new TapEvent(this, socket, POLLIN|POLLERR);
pollQueue.schedule(event);
}
void
EtherTap::detach()
{
DPRINTF(Ethernet, "EtherTap detached\n");
delete event;
event = 0;
close(socket);
socket = -1;
}
bool
EtherTap::recvPacket(EthPacketPtr packet)
{
if (dump)
dump->dump(packet);
DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
uint32_t len = htonl(packet->length);
ssize_t ret = write(socket, &len, sizeof(len));
if (ret != sizeof(len))
return false;
ret = write(socket, packet->data, packet->length);
if (ret != packet->length)
return false;
interface->recvDone();
return true;
}
void
EtherTap::sendDone()
{}
void
EtherTap::process(int revent)
{
if (revent & POLLERR) {
detach();
return;
}
char *data = buffer + sizeof(uint32_t);
if (!(revent & POLLIN))
return;
if (buffer_offset < data_len + sizeof(uint32_t)) {
int len = read(socket, buffer + buffer_offset, buflen - buffer_offset);
if (len == 0) {
detach();
return;
}
buffer_offset += len;
if (data_len == 0)
data_len = ntohl(*(uint32_t *)buffer);
DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d "
"data_len=%d\n", len, buffer_offset, data_len);
}
while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) {
EthPacketPtr packet;
packet = new EthPacketData(data_len);
packet->length = data_len;
memcpy(packet->data, data, data_len);
buffer_offset -= data_len + sizeof(uint32_t);
assert(buffer_offset >= 0);
if (buffer_offset > 0) {
memmove(buffer, data + data_len, buffer_offset);
data_len = ntohl(*(uint32_t *)buffer);
} else
data_len = 0;
DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
packetBuffer.push(packet);
if (!txEvent.scheduled())
schedule(txEvent, curTick() + retryTime);
} else if (dump) {
dump->dump(packet);
}
}
}
void
EtherTap::retransmit()
{
if (packetBuffer.empty())
return;
EthPacketPtr packet = packetBuffer.front();
if (interface->sendPacket(packet)) {
if (dump)
dump->dump(packet);
DPRINTF(Ethernet, "EtherTap retransmit\n");
packetBuffer.front() = NULL;
packetBuffer.pop();
}
if (!packetBuffer.empty() && !txEvent.scheduled())
schedule(txEvent, curTick() + retryTime);
}
EtherInt*
EtherTap::getEthPort(const std::string &if_name, int idx)
{
if (if_name == "tap") {
if (interface->getPeer())
panic("Interface already connected to\n");
return interface;
}
return NULL;
}
//=====================================================================
void
EtherTap::serialize(ostream &os)
{
SERIALIZE_SCALAR(socket);
SERIALIZE_SCALAR(buflen);
uint8_t *buffer = (uint8_t *)this->buffer;
SERIALIZE_ARRAY(buffer, buflen);
SERIALIZE_SCALAR(buffer_offset);
SERIALIZE_SCALAR(data_len);
bool tapevent_present = false;
if (event) {
tapevent_present = true;
SERIALIZE_SCALAR(tapevent_present);
event->serialize(os);
}
else {
SERIALIZE_SCALAR(tapevent_present);
}
}
void
EtherTap::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(socket);
UNSERIALIZE_SCALAR(buflen);
uint8_t *buffer = (uint8_t *)this->buffer;
UNSERIALIZE_ARRAY(buffer, buflen);
UNSERIALIZE_SCALAR(buffer_offset);
UNSERIALIZE_SCALAR(data_len);
bool tapevent_present;
UNSERIALIZE_SCALAR(tapevent_present);
if (tapevent_present) {
event = new TapEvent(this, socket, POLLIN|POLLERR);
event->unserialize(cp,section);
if (event->queued()) {
pollQueue.schedule(event);
}
}
}
//=====================================================================
EtherTap *
EtherTapParams::create()
{
return new EtherTap(this);
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
/* @file
* Interface to connect a simulated ethernet device to the real world
*/
#ifndef __ETHERTAP_HH__
#define __ETHERTAP_HH__
#include <queue>
#include <string>
#include "base/pollevent.hh"
#include "dev/etherint.hh"
#include "dev/etherobject.hh"
#include "dev/etherpkt.hh"
#include "params/EtherTap.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
class TapEvent;
class TapListener;
class EtherTapInt;
/*
* Interface to connect a simulated ethernet device to the real world
*/
class EtherTap : public EtherObject
{
protected:
friend class TapEvent;
TapEvent *event;
protected:
friend class TapListener;
TapListener *listener;
int socket;
char *buffer;
int buflen;
uint32_t buffer_offset;
uint32_t data_len;
EtherDump *dump;
void attach(int fd);
void detach();
protected:
std::string device;
std::queue<EthPacketPtr> packetBuffer;
EtherTapInt *interface;
void process(int revent);
void enqueue(EthPacketData *packet);
void retransmit();
/*
*/
class TxEvent : public Event
{
protected:
EtherTap *tap;
public:
TxEvent(EtherTap *_tap) : tap(_tap) {}
void process() { tap->retransmit(); }
virtual const char *description() const
{ return "EtherTap retransmit"; }
};
friend class TxEvent;
TxEvent txEvent;
public:
typedef EtherTapParams Params;
EtherTap(const Params *p);
virtual ~EtherTap();
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual EtherInt *getEthPort(const std::string &if_name, int idx);
virtual bool recvPacket(EthPacketPtr packet);
virtual void sendDone();
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
class EtherTapInt : public EtherInt
{
private:
EtherTap *tap;
public:
EtherTapInt(const std::string &name, EtherTap *t)
: EtherInt(name), tap(t)
{ }
virtual bool recvPacket(EthPacketPtr pkt) { return tap->recvPacket(pkt); }
virtual void sendDone() { tap->sendDone(); }
};
#endif // __ETHERTAP_HH__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,559 @@
/*
* 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: Ali Saidi
*/
/* @file
* Device model for Intel's 8254x line of gigabit ethernet controllers.
*/
#ifndef __DEV_I8254XGBE_HH__
#define __DEV_I8254XGBE_HH__
#include <deque>
#include <string>
#include "base/cp_annotate.hh"
#include "base/inet.hh"
#include "debug/EthernetDesc.hh"
#include "debug/EthernetIntr.hh"
#include "dev/etherdevice.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
#include "dev/i8254xGBe_defs.hh"
#include "dev/pcidev.hh"
#include "dev/pktfifo.hh"
#include "params/IGbE.hh"
#include "sim/eventq.hh"
class IGbEInt;
class IGbE : public EtherDevice
{
private:
IGbEInt *etherInt;
CPA *cpa;
// device registers
iGbReg::Regs regs;
// eeprom data, status and control bits
int eeOpBits, eeAddrBits, eeDataBits;
uint8_t eeOpcode, eeAddr;
uint16_t flash[iGbReg::EEPROM_SIZE];
// The drain event if we have one
Event *drainEvent;
// cached parameters from params struct
bool useFlowControl;
// packet fifos
PacketFifo rxFifo;
PacketFifo txFifo;
// Packet that we are currently putting into the txFifo
EthPacketPtr txPacket;
// Should to Rx/Tx State machine tick?
bool rxTick;
bool txTick;
bool txFifoTick;
bool rxDmaPacket;
// Number of bytes copied from current RX packet
unsigned pktOffset;
// Delays in managaging descriptors
Tick fetchDelay, wbDelay;
Tick fetchCompDelay, wbCompDelay;
Tick rxWriteDelay, txReadDelay;
// Event and function to deal with RDTR timer expiring
void rdtrProcess() {
rxDescCache.writeback(0);
DPRINTF(EthernetIntr,
"Posting RXT interrupt because RDTR timer expired\n");
postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
// Event and function to deal with RADV timer expiring
void radvProcess() {
rxDescCache.writeback(0);
DPRINTF(EthernetIntr,
"Posting RXT interrupt because RADV timer expired\n");
postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::radvProcess>;
EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
// Event and function to deal with TADV timer expiring
void tadvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr,
"Posting TXDW interrupt because TADV timer expired\n");
postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
// Event and function to deal with TIDV timer expiring
void tidvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr,
"Posting TXDW interrupt because TIDV timer expired\n");
postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
// Main event to tick the device
void tick();
//friend class EventWrapper<IGbE, &IGbE::tick>;
EventWrapper<IGbE, &IGbE::tick> tickEvent;
uint64_t macAddr;
void rxStateMachine();
void txStateMachine();
void txWire();
/** Write an interrupt into the interrupt pending register and check mask
* and interrupt limit timer before sending interrupt to CPU
* @param t the type of interrupt we are posting
* @param now should we ignore the interrupt limiting timer
*/
void postInterrupt(iGbReg::IntTypes t, bool now = false);
/** Check and see if changes to the mask register have caused an interrupt
* to need to be sent or perhaps removed an interrupt cause.
*/
void chkInterrupt();
/** Send an interrupt to the cpu
*/
void delayIntEvent();
void cpuPostInt();
// Event to moderate interrupts
EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
/** Clear the interupt line to the cpu
*/
void cpuClearInt();
Tick intClock() { return SimClock::Int::ns * 1024; }
/** This function is used to restart the clock so it can handle things like
* draining and resume in one place. */
void restartClock();
/** Check if all the draining things that need to occur have occured and
* handle the drain event if so.
*/
void checkDrain();
void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
}
void anQ(std::string sm, std::string q) {
cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
}
void anDq(std::string sm, std::string q) {
cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
}
void anPq(std::string sm, std::string q, int num = 1) {
cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
}
void anRq(std::string sm, std::string q, int num = 1) {
cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
}
void anWe(std::string sm, std::string q) {
cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
}
void anWf(std::string sm, std::string q) {
cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
}
template<class T>
class DescCache
{
protected:
virtual Addr descBase() const = 0;
virtual long descHead() const = 0;
virtual long descTail() const = 0;
virtual long descLen() const = 0;
virtual void updateHead(long h) = 0;
virtual void enableSm() = 0;
virtual void actionAfterWb() {}
virtual void fetchAfterWb() = 0;
typedef std::deque<T *> CacheType;
CacheType usedCache;
CacheType unusedCache;
T *fetchBuf;
T *wbBuf;
// Pointer to the device we cache for
IGbE *igbe;
// Name of this descriptor cache
std::string _name;
// How far we've cached
int cachePnt;
// The size of the descriptor cache
int size;
// How many descriptors we are currently fetching
int curFetching;
// How many descriptors we are currently writing back
int wbOut;
// if the we wrote back to the end of the descriptor ring and are going
// to have to wrap and write more
bool moreToWb;
// What the alignment is of the next descriptor writeback
Addr wbAlignment;
/** The packet that is currently being dmad to memory if any */
EthPacketPtr pktPtr;
/** Shortcut for DMA address translation */
Addr pciToDma(Addr a) { return igbe->platform->pciToDma(a); }
public:
/** Annotate sm*/
std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
annUsedDescQ, annUnusedCacheQ, annDescQ;
DescCache(IGbE *i, const std::string n, int s);
virtual ~DescCache();
std::string name() { return _name; }
/** If the address/len/head change when we've got descriptors that are
* dirty that is very bad. This function checks that we don't and if we
* do panics.
*/
void areaChanged();
void writeback(Addr aMask);
void writeback1();
EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
/** Fetch a chunk of descriptors into the descriptor cache.
* Calls fetchComplete when the memory system returns the data
*/
void fetchDescriptors();
void fetchDescriptors1();
EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
/** Called by event when dma to read descriptors is completed
*/
void fetchComplete();
EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
/** Called by event when dma to writeback descriptors is completed
*/
void wbComplete();
EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
/* Return the number of descriptors left in the ring, so the device has
* a way to figure out if it needs to interrupt.
*/
unsigned
descLeft() const
{
unsigned left = unusedCache.size();
if (cachePnt > descTail())
left += (descLen() - cachePnt + descTail());
else
left += (descTail() - cachePnt);
return left;
}
/* Return the number of descriptors used and not written back.
*/
unsigned descUsed() const { return usedCache.size(); }
/* Return the number of cache unused descriptors we have. */
unsigned descUnused() const { return unusedCache.size(); }
/* Get into a state where the descriptor address/head/etc colud be
* changed */
void reset();
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual bool hasOutstandingEvents() {
return wbEvent.scheduled() || fetchEvent.scheduled();
}
};
class RxDescCache : public DescCache<iGbReg::RxDesc>
{
protected:
virtual Addr descBase() const { return igbe->regs.rdba(); }
virtual long descHead() const { return igbe->regs.rdh(); }
virtual long descLen() const { return igbe->regs.rdlen() >> 4; }
virtual long descTail() const { return igbe->regs.rdt(); }
virtual void updateHead(long h) { igbe->regs.rdh(h); }
virtual void enableSm();
virtual void fetchAfterWb() {
if (!igbe->rxTick && igbe->getState() == SimObject::Running)
fetchDescriptors();
}
bool pktDone;
/** Variable to head with header/data completion events */
int splitCount;
/** Bytes of packet that have been copied, so we know when to
set EOP */
unsigned bytesCopied;
public:
RxDescCache(IGbE *i, std::string n, int s);
/** Write the given packet into the buffer(s) pointed to by the
* descriptor and update the book keeping. Should only be called when
* there are no dma's pending.
* @param packet ethernet packet to write
* @param pkt_offset bytes already copied from the packet to memory
* @return pkt_offset + number of bytes copied during this call
*/
int writePacket(EthPacketPtr packet, int pkt_offset);
/** Called by event when dma to write packet is completed
*/
void pktComplete();
/** Check if the dma on the packet has completed and RX state machine
* can continue
*/
bool packetDone();
EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
// Event to handle issuing header and data write at the same time
// and only callking pktComplete() when both are completed
void pktSplitDone();
EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
virtual bool hasOutstandingEvents();
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
friend class RxDescCache;
RxDescCache rxDescCache;
class TxDescCache : public DescCache<iGbReg::TxDesc>
{
protected:
virtual Addr descBase() const { return igbe->regs.tdba(); }
virtual long descHead() const { return igbe->regs.tdh(); }
virtual long descTail() const { return igbe->regs.tdt(); }
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
virtual void updateHead(long h) { igbe->regs.tdh(h); }
virtual void enableSm();
virtual void actionAfterWb();
virtual void fetchAfterWb() {
if (!igbe->txTick && igbe->getState() == SimObject::Running)
fetchDescriptors();
}
bool pktDone;
bool isTcp;
bool pktWaiting;
bool pktMultiDesc;
Addr completionAddress;
bool completionEnabled;
uint32_t descEnd;
// tso variables
bool useTso;
Addr tsoHeaderLen;
Addr tsoMss;
Addr tsoTotalLen;
Addr tsoUsedLen;
Addr tsoPrevSeq;
Addr tsoPktPayloadBytes;
bool tsoLoadedHeader;
bool tsoPktHasHeader;
uint8_t tsoHeader[256];
Addr tsoDescBytesUsed;
Addr tsoCopyBytes;
int tsoPkts;
public:
TxDescCache(IGbE *i, std::string n, int s);
/** Tell the cache to DMA a packet from main memory into its buffer and
* return the size the of the packet to reserve space in tx fifo.
* @return size of the packet
*/
unsigned getPacketSize(EthPacketPtr p);
void getPacketData(EthPacketPtr p);
void processContextDesc();
/** Return the number of dsecriptors in a cache block for threshold
* operations.
*/
unsigned
descInBlock(unsigned num_desc)
{
return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc);
}
/** Ask if the packet has been transfered so the state machine can give
* it to the fifo.
* @return packet available in descriptor cache
*/
bool packetAvailable();
/** Ask if we are still waiting for the packet to be transfered.
* @return packet still in transit.
*/
bool packetWaiting() { return pktWaiting; }
/** Ask if this packet is composed of multiple descriptors
* so even if we've got data, we need to wait for more before
* we can send it out.
* @return packet can't be sent out because it's a multi-descriptor
* packet
*/
bool packetMultiDesc() { return pktMultiDesc;}
/** Called by event when dma to write packet is completed
*/
void pktComplete();
EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
void headerComplete();
EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
void completionWriteback(Addr a, bool enabled) {
DPRINTF(EthernetDesc,
"Completion writeback Addr: %#x enabled: %d\n",
a, enabled);
completionAddress = a;
completionEnabled = enabled;
}
virtual bool hasOutstandingEvents();
void nullCallback() {
DPRINTF(EthernetDesc, "Completion writeback complete\n");
}
EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
friend class TxDescCache;
TxDescCache txDescCache;
public:
typedef IGbEParams Params;
const Params *
params() const {
return dynamic_cast<const Params *>(_params);
}
IGbE(const Params *params);
~IGbE() {}
virtual void init();
virtual EtherInt *getEthPort(const std::string &if_name, int idx);
Tick clock;
Tick lastInterrupt;
inline Tick ticks(int numCycles) const { return numCycles * clock; }
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
virtual Tick writeConfig(PacketPtr pkt);
bool ethRxPkt(EthPacketPtr packet);
void ethTxDone();
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual void resume();
};
class IGbEInt : public EtherInt
{
private:
IGbE *dev;
public:
IGbEInt(const std::string &name, IGbE *d)
: EtherInt(name), dev(d)
{ }
virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
virtual void sendDone() { dev->ethTxDone(); }
};
#endif //__DEV_I8254XGBE_HH__

View File

@ -0,0 +1,854 @@
/*
* 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: Ali Saidi
*/
/* @file
* Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers.
*/
#include "base/bitfield.hh"
namespace iGbReg {
// Registers used by the Intel GbE NIC
const uint32_t REG_CTRL = 0x00000;
const uint32_t REG_STATUS = 0x00008;
const uint32_t REG_EECD = 0x00010;
const uint32_t REG_EERD = 0x00014;
const uint32_t REG_CTRL_EXT = 0x00018;
const uint32_t REG_MDIC = 0x00020;
const uint32_t REG_FCAL = 0x00028;
const uint32_t REG_FCAH = 0x0002C;
const uint32_t REG_FCT = 0x00030;
const uint32_t REG_VET = 0x00038;
const uint32_t REG_PBA = 0x01000;
const uint32_t REG_ICR = 0x000C0;
const uint32_t REG_ITR = 0x000C4;
const uint32_t REG_ICS = 0x000C8;
const uint32_t REG_IMS = 0x000D0;
const uint32_t REG_IMC = 0x000D8;
const uint32_t REG_IAM = 0x000E0;
const uint32_t REG_RCTL = 0x00100;
const uint32_t REG_FCTTV = 0x00170;
const uint32_t REG_TIPG = 0x00410;
const uint32_t REG_AIFS = 0x00458;
const uint32_t REG_LEDCTL = 0x00e00;
const uint32_t REG_EICR = 0x01580;
const uint32_t REG_IVAR0 = 0x01700;
const uint32_t REG_FCRTL = 0x02160;
const uint32_t REG_FCRTH = 0x02168;
const uint32_t REG_RDBAL = 0x02800;
const uint32_t REG_RDBAH = 0x02804;
const uint32_t REG_RDLEN = 0x02808;
const uint32_t REG_SRRCTL = 0x0280C;
const uint32_t REG_RDH = 0x02810;
const uint32_t REG_RDT = 0x02818;
const uint32_t REG_RDTR = 0x02820;
const uint32_t REG_RXDCTL = 0x02828;
const uint32_t REG_RADV = 0x0282C;
const uint32_t REG_TCTL = 0x00400;
const uint32_t REG_TDBAL = 0x03800;
const uint32_t REG_TDBAH = 0x03804;
const uint32_t REG_TDLEN = 0x03808;
const uint32_t REG_TDH = 0x03810;
const uint32_t REG_TXDCA_CTL = 0x03814;
const uint32_t REG_TDT = 0x03818;
const uint32_t REG_TIDV = 0x03820;
const uint32_t REG_TXDCTL = 0x03828;
const uint32_t REG_TADV = 0x0382C;
const uint32_t REG_TDWBAL = 0x03838;
const uint32_t REG_TDWBAH = 0x0383C;
const uint32_t REG_CRCERRS = 0x04000;
const uint32_t REG_RXCSUM = 0x05000;
const uint32_t REG_RLPML = 0x05004;
const uint32_t REG_RFCTL = 0x05008;
const uint32_t REG_MTA = 0x05200;
const uint32_t REG_RAL = 0x05400;
const uint32_t REG_RAH = 0x05404;
const uint32_t REG_VFTA = 0x05600;
const uint32_t REG_WUC = 0x05800;
const uint32_t REG_MANC = 0x05820;
const uint32_t REG_SWSM = 0x05B50;
const uint32_t REG_FWSM = 0x05B54;
const uint32_t REG_SWFWSYNC = 0x05B5C;
const uint8_t EEPROM_READ_OPCODE_SPI = 0x03;
const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05;
const uint8_t EEPROM_SIZE = 64;
const uint16_t EEPROM_CSUM = 0xBABA;
const uint8_t VLAN_FILTER_TABLE_SIZE = 128;
const uint8_t RCV_ADDRESS_TABLE_SIZE = 24;
const uint8_t MULTICAST_TABLE_SIZE = 128;
const uint32_t STATS_REGS_SIZE = 0x228;
// Registers in that are accessed in the PHY
const uint8_t PHY_PSTATUS = 0x1;
const uint8_t PHY_PID = 0x2;
const uint8_t PHY_EPID = 0x3;
const uint8_t PHY_GSTATUS = 10;
const uint8_t PHY_EPSTATUS = 15;
const uint8_t PHY_AGC = 18;
// Receive Descriptor Status Flags
const uint16_t RXDS_DYNINT = 0x800;
const uint16_t RXDS_UDPV = 0x400;
const uint16_t RXDS_CRCV = 0x100;
const uint16_t RXDS_PIF = 0x080;
const uint16_t RXDS_IPCS = 0x040;
const uint16_t RXDS_TCPCS = 0x020;
const uint16_t RXDS_UDPCS = 0x010;
const uint16_t RXDS_VP = 0x008;
const uint16_t RXDS_IXSM = 0x004;
const uint16_t RXDS_EOP = 0x002;
const uint16_t RXDS_DD = 0x001;
// Receive Descriptor Error Flags
const uint8_t RXDE_RXE = 0x80;
const uint8_t RXDE_IPE = 0x40;
const uint8_t RXDE_TCPE = 0x20;
const uint8_t RXDE_SEQ = 0x04;
const uint8_t RXDE_SE = 0x02;
const uint8_t RXDE_CE = 0x01;
// Receive Descriptor Extended Error Flags
const uint16_t RXDEE_HBO = 0x008;
const uint16_t RXDEE_CE = 0x010;
const uint16_t RXDEE_LE = 0x020;
const uint16_t RXDEE_PE = 0x080;
const uint16_t RXDEE_OSE = 0x100;
const uint16_t RXDEE_USE = 0x200;
const uint16_t RXDEE_TCPE = 0x400;
const uint16_t RXDEE_IPE = 0x800;
// Receive Descriptor Types
const uint8_t RXDT_LEGACY = 0x00;
const uint8_t RXDT_ADV_ONEBUF = 0x01;
const uint8_t RXDT_ADV_SPLIT_A = 0x05;
// Receive Descriptor Packet Types
const uint16_t RXDP_IPV4 = 0x001;
const uint16_t RXDP_IPV4E = 0x002;
const uint16_t RXDP_IPV6 = 0x004;
const uint16_t RXDP_IPV6E = 0x008;
const uint16_t RXDP_TCP = 0x010;
const uint16_t RXDP_UDP = 0x020;
const uint16_t RXDP_SCTP = 0x040;
const uint16_t RXDP_NFS = 0x080;
// Interrupt types
enum IntTypes
{
IT_NONE = 0x00000, //dummy value
IT_TXDW = 0x00001,
IT_TXQE = 0x00002,
IT_LSC = 0x00004,
IT_RXSEQ = 0x00008,
IT_RXDMT = 0x00010,
IT_RXO = 0x00040,
IT_RXT = 0x00080,
IT_MADC = 0x00200,
IT_RXCFG = 0x00400,
IT_GPI0 = 0x02000,
IT_GPI1 = 0x04000,
IT_TXDLOW = 0x08000,
IT_SRPD = 0x10000,
IT_ACK = 0x20000
};
// Receive Descriptor struct
struct RxDesc {
union {
struct {
Addr buf;
uint16_t len;
uint16_t csum;
uint8_t status;
uint8_t errors;
uint16_t vlan;
} legacy;
struct {
Addr pkt;
Addr hdr;
} adv_read;
struct {
uint16_t rss_type:4;
uint16_t pkt_type:12;
uint16_t __reserved1:5;
uint16_t header_len:10;
uint16_t sph:1;
union {
struct {
uint16_t id;
uint16_t csum;
};
uint32_t rss_hash;
};
uint32_t status:20;
uint32_t errors:12;
uint16_t pkt_len;
uint16_t vlan_tag;
} adv_wb ;
};
};
struct TxDesc {
uint64_t d1;
uint64_t d2;
};
namespace TxdOp {
const uint8_t TXD_CNXT = 0x0;
const uint8_t TXD_DATA = 0x1;
const uint8_t TXD_ADVCNXT = 0x2;
const uint8_t TXD_ADVDATA = 0x3;
bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); }
uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); }
bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; }
bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); }
bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT); }
bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); }
bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); }
Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
bool ide(TxDesc *d) { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); }
bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
bool rs(TxDesc *d) { return bits(d->d2, 27,27); }
bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
bool tse(TxDesc *d) {
if (isTypes(d, TXD_CNXT, TXD_DATA))
return bits(d->d2, 26,26);
if (isType(d, TXD_ADVDATA))
return bits(d->d2, 31, 31);
return false;
}
bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
bool tcp(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 24,24); }
uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
bool ixsm(TxDesc *d) { return isData(d) && bits(d->d2, 40,40); }
bool txsm(TxDesc *d) { return isData(d) && bits(d->d2, 41,41); }
int tucse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,63,48); }
int tucso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,47,40); }
int tucss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,39,32); }
int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
int hdrlen(TxDesc *d) {
assert(isContext(d));
if (!isAdvDesc(d))
return bits(d->d2,47,40);
return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9);
}
int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); }
int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); }
} // namespace TxdOp
#define ADD_FIELD32(NAME, OFFSET, BITS) \
inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
#define ADD_FIELD64(NAME, OFFSET, BITS) \
inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
struct Regs {
template<class T>
struct Reg {
T _data;
T operator()() { return _data; }
const Reg<T> &operator=(T d) { _data = d; return *this;}
bool operator==(T d) { return d == _data; }
void operator()(T d) { _data = d; }
Reg() { _data = 0; }
void serialize(std::ostream &os)
{
SERIALIZE_SCALAR(_data);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(_data);
}
};
struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(fd,0,1); // full duplex
ADD_FIELD32(bem,1,1); // big endian mode
ADD_FIELD32(pcipr,2,1); // PCI priority
ADD_FIELD32(lrst,3,1); // link reset
ADD_FIELD32(tme,4,1); // test mode enable
ADD_FIELD32(asde,5,1); // Auto-speed detection
ADD_FIELD32(slu,6,1); // Set link up
ADD_FIELD32(ilos,7,1); // invert los-of-signal
ADD_FIELD32(speed,8,2); // speed selection bits
ADD_FIELD32(be32,10,1); // big endian mode 32
ADD_FIELD32(frcspd,11,1); // force speed
ADD_FIELD32(frcdpx,12,1); // force duplex
ADD_FIELD32(duden,13,1); // dock/undock enable
ADD_FIELD32(dudpol,14,1); // dock/undock polarity
ADD_FIELD32(fphyrst,15,1); // force phy reset
ADD_FIELD32(extlen,16,1); // external link status enable
ADD_FIELD32(rsvd,17,1); // reserved
ADD_FIELD32(sdp0d,18,1); // software controlled pin data
ADD_FIELD32(sdp1d,19,1); // software controlled pin data
ADD_FIELD32(sdp2d,20,1); // software controlled pin data
ADD_FIELD32(sdp3d,21,1); // software controlled pin data
ADD_FIELD32(sdp0i,22,1); // software controlled pin dir
ADD_FIELD32(sdp1i,23,1); // software controlled pin dir
ADD_FIELD32(sdp2i,24,1); // software controlled pin dir
ADD_FIELD32(sdp3i,25,1); // software controlled pin dir
ADD_FIELD32(rst,26,1); // reset
ADD_FIELD32(rfce,27,1); // receive flow control enable
ADD_FIELD32(tfce,28,1); // transmit flow control enable
ADD_FIELD32(rte,29,1); // routing tag enable
ADD_FIELD32(vme,30,1); // vlan enable
ADD_FIELD32(phyrst,31,1); // phy reset
};
CTRL ctrl;
struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(fd,0,1); // full duplex
ADD_FIELD32(lu,1,1); // link up
ADD_FIELD32(func,2,2); // function id
ADD_FIELD32(txoff,4,1); // transmission paused
ADD_FIELD32(tbimode,5,1); // tbi mode
ADD_FIELD32(speed,6,2); // link speed
ADD_FIELD32(asdv,8,2); // auto speed detection value
ADD_FIELD32(mtxckok,10,1); // mtx clock running ok
ADD_FIELD32(pci66,11,1); // In 66Mhz pci slot
ADD_FIELD32(bus64,12,1); // in 64 bit slot
ADD_FIELD32(pcix,13,1); // Pci mode
ADD_FIELD32(pcixspd,14,2); // pci x speed
};
STATUS sts;
struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(sk,0,1); // clack input to the eeprom
ADD_FIELD32(cs,1,1); // chip select to eeprom
ADD_FIELD32(din,2,1); // data input to eeprom
ADD_FIELD32(dout,3,1); // data output bit
ADD_FIELD32(fwe,4,2); // flash write enable
ADD_FIELD32(ee_req,6,1); // request eeprom access
ADD_FIELD32(ee_gnt,7,1); // grant eeprom access
ADD_FIELD32(ee_pres,8,1); // eeprom present
ADD_FIELD32(ee_size,9,1); // eeprom size
ADD_FIELD32(ee_sz1,10,1); // eeprom size
ADD_FIELD32(rsvd,11,2); // reserved
ADD_FIELD32(ee_type,13,1); // type of eeprom
} ;
EECD eecd;
struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(start,0,1); // start read
ADD_FIELD32(done,1,1); // done read
ADD_FIELD32(addr,2,14); // address
ADD_FIELD32(data,16,16); // data
};
EERD eerd;
struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(gpi_en,0,4); // enable interrupts from gpio
ADD_FIELD32(phyint,5,1); // reads the phy internal int status
ADD_FIELD32(sdp2_data,6,1); // data from gpio sdp
ADD_FIELD32(spd3_data,7,1); // data frmo gpio sdp
ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2
ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2
ADD_FIELD32(asdchk,12,1); // initiate auto-speed-detection
ADD_FIELD32(eerst,13,1); // reset the eeprom
ADD_FIELD32(spd_byps,15,1); // bypass speed select
ADD_FIELD32(ro_dis,17,1); // disable relaxed memory ordering
ADD_FIELD32(vreg,21,1); // power down the voltage regulator
ADD_FIELD32(link_mode,22,2); // interface to talk to the link
ADD_FIELD32(iame, 27,1); // interrupt acknowledge auto-mask ??
ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device
ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ??
};
CTRL_EXT ctrl_ext;
struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(data,0,16); // data
ADD_FIELD32(regadd,16,5); // register address
ADD_FIELD32(phyadd,21,5); // phy addresses
ADD_FIELD32(op,26,2); // opcode
ADD_FIELD32(r,28,1); // ready
ADD_FIELD32(i,29,1); // interrupt
ADD_FIELD32(e,30,1); // error
};
MDIC mdic;
struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(txdw,0,1) // tx descr witten back
ADD_FIELD32(txqe,1,1) // tx queue empty
ADD_FIELD32(lsc,2,1) // link status change
ADD_FIELD32(rxseq,3,1) // rcv sequence error
ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh
ADD_FIELD32(rsvd1,5,1) // reserved
ADD_FIELD32(rxo,6,1) // receive overrunn
ADD_FIELD32(rxt0,7,1) // receiver timer interrupt
ADD_FIELD32(mdac,9,1) // mdi/o access complete
ADD_FIELD32(rxcfg,10,1) // recv /c/ ordered sets
ADD_FIELD32(phyint,12,1) // phy interrupt
ADD_FIELD32(gpi1,13,1) // gpi int 1
ADD_FIELD32(gpi2,14,1) // gpi int 2
ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
ADD_FIELD32(srpd,16,1) // small receive packet detected
ADD_FIELD32(ack,17,1); // receive ack frame
ADD_FIELD32(int_assert, 31,1); // interrupt caused a system interrupt
};
ICR icr;
uint32_t imr; // register that contains the current interrupt mask
struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval
// specified in 256ns interrupts
};
ITR itr;
// When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write
// causes the IAM register contents to be written into the IMC
// automatically clearing all interrupts that have a bit in the IAM set
uint32_t iam;
struct RCTL : public Reg<uint32_t> { // 0x0100 RCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rst,0,1); // Reset
ADD_FIELD32(en,1,1); // Enable
ADD_FIELD32(sbp,2,1); // Store bad packets
ADD_FIELD32(upe,3,1); // Unicast Promiscuous enabled
ADD_FIELD32(mpe,4,1); // Multicast promiscuous enabled
ADD_FIELD32(lpe,5,1); // long packet reception enabled
ADD_FIELD32(lbm,6,2); //
ADD_FIELD32(rdmts,8,2); //
ADD_FIELD32(mo,12,2); //
ADD_FIELD32(mdr,14,1); //
ADD_FIELD32(bam,15,1); //
ADD_FIELD32(bsize,16,2); //
ADD_FIELD32(vfe,18,1); //
ADD_FIELD32(cfien,19,1); //
ADD_FIELD32(cfi,20,1); //
ADD_FIELD32(dpf,22,1); // discard pause frames
ADD_FIELD32(pmcf,23,1); // pass mac control frames
ADD_FIELD32(bsex,25,1); // buffer size extension
ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet
unsigned descSize()
{
switch(bsize()) {
case 0: return bsex() == 0 ? 2048 : 0;
case 1: return bsex() == 0 ? 1024 : 16384;
case 2: return bsex() == 0 ? 512 : 8192;
case 3: return bsex() == 0 ? 256 : 4096;
default:
return 0;
}
}
};
RCTL rctl;
struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV
using Reg<uint32_t>::operator=;
ADD_FIELD32(ttv,0,16); // Transmit Timer Value
};
FCTTV fcttv;
struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rst,0,1); // Reset
ADD_FIELD32(en,1,1); // Enable
ADD_FIELD32(bce,2,1); // busy check enable
ADD_FIELD32(psp,3,1); // pad short packets
ADD_FIELD32(ct,4,8); // collision threshold
ADD_FIELD32(cold,12,10); // collision distance
ADD_FIELD32(swxoff,22,1); // software xoff transmission
ADD_FIELD32(pbe,23,1); // packet burst enable
ADD_FIELD32(rtlc,24,1); // retransmit late collisions
ADD_FIELD32(nrtu,25,1); // on underrun no TX
ADD_FIELD32(mulr,26,1); // multiple request
};
TCTL tctl;
struct PBA : public Reg<uint32_t> { // 0x1000 PBA Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rxa,0,16);
ADD_FIELD32(txa,16,16);
};
PBA pba;
struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have
// a larger buffer
ADD_FIELD32(xone, 31,1);
};
FCRTL fcrtl;
struct FCRTH : public Reg<uint32_t> { // 0x2168 FCRTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have
//a larger buffer
ADD_FIELD32(xfce, 31,1);
};
FCRTH fcrth;
struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
using Reg<uint64_t>::operator=;
ADD_FIELD64(rdbal,0,32); // base address of rx descriptor ring
ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
};
RDBA rdba;
struct RDLEN : public Reg<uint32_t> { // 0x2808 RDLEN Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
};
RDLEN rdlen;
struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pktlen, 0, 8);
ADD_FIELD32(hdrlen, 8, 8); // guess based on header, not documented
ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv,
//101 hdr split
unsigned bufLen() { return pktlen() << 10; }
unsigned hdrLen() { return hdrlen() << 6; }
};
SRRCTL srrctl;
struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rdh,0,16); // head of the descriptor ring
};
RDH rdh;
struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rdt,0,16); // tail of the descriptor ring
};
RDT rdt;
struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(delay,0,16); // receive delay timer
ADD_FIELD32(fpd, 31,1); // flush partial descriptor block ??
};
RDTR rdtr;
struct RXDCTL : public Reg<uint32_t> { // 0x2828 RXDCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pthresh,0,6); // prefetch threshold, less that this
// consider prefetch
ADD_FIELD32(hthresh,8,6); // number of descriptors in host mem to
// consider prefetch
ADD_FIELD32(wthresh,16,6); // writeback threshold
ADD_FIELD32(gran,24,1); // granularity 0 = desc, 1 = cacheline
};
RXDCTL rxdctl;
struct RADV : public Reg<uint32_t> { // 0x282C RADV Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(idv,0,16); // absolute interrupt delay
};
RADV radv;
struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(idv,0,12); // size to interrutp on small packets
};
RSRPD rsrpd;
struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
using Reg<uint64_t>::operator=;
ADD_FIELD64(tdbal,0,32); // base address of transmit descriptor ring
ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
};
TDBA tdba;
struct TDLEN : public Reg<uint32_t> { // 0x3808 TDLEN Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
};
TDLEN tdlen;
struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(tdh,0,16); // head of the descriptor ring
};
TDH tdh;
struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(cpu_mask, 0, 5);
ADD_FIELD32(enabled, 5,1);
ADD_FIELD32(relax_ordering, 6, 1);
};
TXDCA_CTL txdca_ctl;
struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
};
TDT tdt;
struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(idv,0,16); // interrupt delay
};
TIDV tidv;
struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pthresh, 0,6); // if number of descriptors control has is
// below this number, a prefetch is considered
ADD_FIELD32(hthresh,8,8); // number of valid descriptors is host memory
// before a prefetch is considered
ADD_FIELD32(wthresh,16,6); // number of descriptors to keep until
// writeback is considered
ADD_FIELD32(gran, 24,1); // granulatiry of above values (0 = cacheline,
// 1 == desscriptor)
ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt
// below this level
};
TXDCTL txdctl;
struct TADV : public Reg<uint32_t> { // 0x382C TADV Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(idv,0,16); // absolute interrupt delay
};
TADV tadv;
/*
struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register
using Reg<uint64_t>::operator=;
ADD_FIELD64(en,0,1); // enable transmit description ring address writeback
ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback
ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring
};
TDWBA tdwba;*/
uint64_t tdwba;
struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pcss,0,8);
ADD_FIELD32(ipofld,8,1);
ADD_FIELD32(tuofld,9,1);
ADD_FIELD32(pcsd, 13,1);
};
RXCSUM rxcsum;
uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size
struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(iscsi_dis,0,1);
ADD_FIELD32(iscsi_dwc,1,5);
ADD_FIELD32(nfsw_dis,6,1);
ADD_FIELD32(nfsr_dis,7,1);
ADD_FIELD32(nfs_ver,8,2);
ADD_FIELD32(ipv6_dis,10,1);
ADD_FIELD32(ipv6xsum_dis,11,1);
ADD_FIELD32(ackdis,13,1);
ADD_FIELD32(ipfrsp_dis,14,1);
ADD_FIELD32(exsten,15,1);
};
RFCTL rfctl;
struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(smbus,0,1); // SMBus enabled #####
ADD_FIELD32(asf,1,1); // ASF enabled #####
ADD_FIELD32(ronforce,2,1); // reset of force
ADD_FIELD32(rsvd,3,5); // reserved
ADD_FIELD32(rmcp1,8,1); // rcmp1 filtering
ADD_FIELD32(rmcp2,9,1); // rcmp2 filtering
ADD_FIELD32(ipv4,10,1); // enable ipv4
ADD_FIELD32(ipv6,11,1); // enable ipv6
ADD_FIELD32(snap,12,1); // accept snap
ADD_FIELD32(arp,13,1); // filter arp #####
ADD_FIELD32(neighbor,14,1); // neighbor discovery
ADD_FIELD32(arp_resp,15,1); // arp response
ADD_FIELD32(tcorst,16,1); // tco reset happened
ADD_FIELD32(rcvtco,17,1); // receive tco enabled ######
ADD_FIELD32(blkphyrst,18,1);// block phy resets ########
ADD_FIELD32(rcvall,19,1); // receive all
ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ######
ADD_FIELD32(mng2host,21,1); // mng2 host packets #######
ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering
ADD_FIELD32(xsumfilter,23,1); // checksum filtering
ADD_FIELD32(brfilter,24,1); // broadcast filtering
ADD_FIELD32(smbreq,25,1); // smb request
ADD_FIELD32(smbgnt,26,1); // smb grant
ADD_FIELD32(smbclkin,27,1); // smbclkin
ADD_FIELD32(smbdatain,28,1); // smbdatain
ADD_FIELD32(smbdataout,29,1); // smb data out
ADD_FIELD32(smbclkout,30,1); // smb clock out
};
MANC manc;
struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register
using Reg<uint32_t>::operator=;
ADD_FIELD32(smbi,0,1); // Semaphone bit
ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore
ADD_FIELD32(wmng, 2,1); // Wake MNG clock
ADD_FIELD32(reserved, 3, 29);
};
SWSM swsm;
struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register
using Reg<uint32_t>::operator=;
ADD_FIELD32(eep_fw_semaphore,0,1);
ADD_FIELD32(fw_mode, 1,3);
ADD_FIELD32(ide, 4,1);
ADD_FIELD32(sol, 5,1);
ADD_FIELD32(eep_roload, 6,1);
ADD_FIELD32(reserved, 7,8);
ADD_FIELD32(fw_val_bit, 15, 1);
ADD_FIELD32(reset_cnt, 16, 3);
ADD_FIELD32(ext_err_ind, 19, 6);
ADD_FIELD32(reserved2, 25, 7);
};
FWSM fwsm;
uint32_t sw_fw_sync;
void serialize(std::ostream &os)
{
paramOut(os, "ctrl", ctrl._data);
paramOut(os, "sts", sts._data);
paramOut(os, "eecd", eecd._data);
paramOut(os, "eerd", eerd._data);
paramOut(os, "ctrl_ext", ctrl_ext._data);
paramOut(os, "mdic", mdic._data);
paramOut(os, "icr", icr._data);
SERIALIZE_SCALAR(imr);
paramOut(os, "itr", itr._data);
SERIALIZE_SCALAR(iam);
paramOut(os, "rctl", rctl._data);
paramOut(os, "fcttv", fcttv._data);
paramOut(os, "tctl", tctl._data);
paramOut(os, "pba", pba._data);
paramOut(os, "fcrtl", fcrtl._data);
paramOut(os, "fcrth", fcrth._data);
paramOut(os, "rdba", rdba._data);
paramOut(os, "rdlen", rdlen._data);
paramOut(os, "srrctl", srrctl._data);
paramOut(os, "rdh", rdh._data);
paramOut(os, "rdt", rdt._data);
paramOut(os, "rdtr", rdtr._data);
paramOut(os, "rxdctl", rxdctl._data);
paramOut(os, "radv", radv._data);
paramOut(os, "rsrpd", rsrpd._data);
paramOut(os, "tdba", tdba._data);
paramOut(os, "tdlen", tdlen._data);
paramOut(os, "tdh", tdh._data);
paramOut(os, "txdca_ctl", txdca_ctl._data);
paramOut(os, "tdt", tdt._data);
paramOut(os, "tidv", tidv._data);
paramOut(os, "txdctl", txdctl._data);
paramOut(os, "tadv", tadv._data);
//paramOut(os, "tdwba", tdwba._data);
SERIALIZE_SCALAR(tdwba);
paramOut(os, "rxcsum", rxcsum._data);
SERIALIZE_SCALAR(rlpml);
paramOut(os, "rfctl", rfctl._data);
paramOut(os, "manc", manc._data);
paramOut(os, "swsm", swsm._data);
paramOut(os, "fwsm", fwsm._data);
SERIALIZE_SCALAR(sw_fw_sync);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
paramIn(cp, section, "ctrl", ctrl._data);
paramIn(cp, section, "sts", sts._data);
paramIn(cp, section, "eecd", eecd._data);
paramIn(cp, section, "eerd", eerd._data);
paramIn(cp, section, "ctrl_ext", ctrl_ext._data);
paramIn(cp, section, "mdic", mdic._data);
paramIn(cp, section, "icr", icr._data);
UNSERIALIZE_SCALAR(imr);
paramIn(cp, section, "itr", itr._data);
UNSERIALIZE_SCALAR(iam);
paramIn(cp, section, "rctl", rctl._data);
paramIn(cp, section, "fcttv", fcttv._data);
paramIn(cp, section, "tctl", tctl._data);
paramIn(cp, section, "pba", pba._data);
paramIn(cp, section, "fcrtl", fcrtl._data);
paramIn(cp, section, "fcrth", fcrth._data);
paramIn(cp, section, "rdba", rdba._data);
paramIn(cp, section, "rdlen", rdlen._data);
paramIn(cp, section, "srrctl", srrctl._data);
paramIn(cp, section, "rdh", rdh._data);
paramIn(cp, section, "rdt", rdt._data);
paramIn(cp, section, "rdtr", rdtr._data);
paramIn(cp, section, "rxdctl", rxdctl._data);
paramIn(cp, section, "radv", radv._data);
paramIn(cp, section, "rsrpd", rsrpd._data);
paramIn(cp, section, "tdba", tdba._data);
paramIn(cp, section, "tdlen", tdlen._data);
paramIn(cp, section, "tdh", tdh._data);
paramIn(cp, section, "txdca_ctl", txdca_ctl._data);
paramIn(cp, section, "tdt", tdt._data);
paramIn(cp, section, "tidv", tidv._data);
paramIn(cp, section, "txdctl", txdctl._data);
paramIn(cp, section, "tadv", tadv._data);
UNSERIALIZE_SCALAR(tdwba);
//paramIn(cp, section, "tdwba", tdwba._data);
paramIn(cp, section, "rxcsum", rxcsum._data);
UNSERIALIZE_SCALAR(rlpml);
paramIn(cp, section, "rfctl", rfctl._data);
paramIn(cp, section, "manc", manc._data);
paramIn(cp, section, "swsm", swsm._data);
paramIn(cp, section, "fwsm", fwsm._data);
UNSERIALIZE_SCALAR(sw_fw_sync);
}
};
} // namespace iGbReg

View File

@ -0,0 +1,290 @@
/* $OpenBSD: atareg.h,v 1.12 2004/09/24 07:15:22 grange Exp $ */
/* $NetBSD: atareg.h,v 1.5 1999/01/18 20:06:24 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Manuel Bouyer.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _DEV_ATA_ATAREG_H_
#define _DEV_ATA_ATAREG_H_
#if defined(__linux__)
#include <endian.h>
#elif defined(__sun)
#include <sys/isa_defs.h>
#else
#include <machine/endian.h>
#endif
#ifdef LITTLE_ENDIAN
#define ATA_BYTE_ORDER LITTLE_ENDIAN
#elif defined(BIG_ENDIAN)
#define ATA_BYTE_ORDER BIG_ENDIAN
#elif defined(_LITTLE_ENDIAN)
#define ATA_BYTE_ORDER 1
#define LITTLE_ENDIAN 1
#elif defined(_BIG_ENDIAN)
#define ATA_BYTE_ORDER 0
#define LITTLE_ENDIAN 1
#else
#error "No endianess defined"
#endif
/*
* Drive parameter structure for ATA/ATAPI.
* Bit fields: WDC_* : common to ATA/ATAPI
* ATA_* : ATA only
* ATAPI_* : ATAPI only.
*/
struct ataparams {
/* drive info */
uint16_t atap_config; /* 0: general configuration */
#define WDC_CFG_ATAPI_MASK 0xc000
#define WDC_CFG_ATAPI 0x8000
#define ATA_CFG_REMOVABLE 0x0080
#define ATA_CFG_FIXED 0x0040
#define ATAPI_CFG_TYPE_MASK 0x1f00
#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8)
#define ATAPI_CFG_TYPE_DIRECT 0x00
#define ATAPI_CFG_TYPE_SEQUENTIAL 0x01
#define ATAPI_CFG_TYPE_CDROM 0x05
#define ATAPI_CFG_TYPE_OPTICAL 0x07
#define ATAPI_CFG_TYPE_NODEVICE 0x1F
#define ATAPI_CFG_REMOV 0x0080
#define ATAPI_CFG_DRQ_MASK 0x0060
#define ATAPI_CFG_STD_DRQ 0x0000
#define ATAPI_CFG_IRQ_DRQ 0x0020
#define ATAPI_CFG_ACCEL_DRQ 0x0040
#define ATAPI_CFG_CMD_MASK 0x0003
#define ATAPI_CFG_CMD_12 0x0000
#define ATAPI_CFG_CMD_16 0x0001
/* words 1-9 are ATA only */
uint16_t atap_cylinders; /* 1: # of non-removable cylinders */
uint16_t __reserved1;
uint16_t atap_heads; /* 3: # of heads */
uint16_t __retired1[2]; /* 4-5: # of unform. bytes/track */
uint16_t atap_sectors; /* 6: # of sectors */
uint16_t __retired2[3];
uint8_t atap_serial[20]; /* 10-19: serial number */
uint16_t __retired3[2];
uint16_t __obsolete1;
uint8_t atap_revision[8]; /* 23-26: firmware revision */
uint8_t atap_model[40]; /* 27-46: model number */
uint16_t atap_multi; /* 47: maximum sectors per irq (ATA) */
uint16_t __reserved2;
uint8_t atap_vendor; /* 49: vendor */
uint8_t atap_capabilities1; /* 49: capability flags */
#define WDC_CAP_IORDY 0x0800
#define WDC_CAP_IORDY_DSBL 0x0400
#define WDC_CAP_LBA 0x0200
#define WDC_CAP_DMA 0x0100
#define ATA_CAP_STBY 0x2000
#define ATAPI_CAP_INTERL_DMA 0x8000
#define ATAPI_CAP_CMD_QUEUE 0x4000
#define ATAPI_CAP_OVERLP 0x2000
#define ATAPI_CAP_ATA_RST 0x1000
uint16_t atap_capabilities2; /* 50: capability flags (ATA) */
#if ATA_BYTE_ORDER == LITTLE_ENDIAN
uint8_t __junk2;
uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
uint8_t __junk3;
uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
#else
uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
uint8_t __junk2;
uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
uint8_t __junk3;
#endif
uint16_t atap_extensions; /* 53: extensions supported */
#define WDC_EXT_UDMA_MODES 0x0004
#define WDC_EXT_MODES 0x0002
#define WDC_EXT_GEOM 0x0001
/* words 54-62 are ATA only */
uint16_t atap_curcylinders; /* 54: current logical cylinders */
uint16_t atap_curheads; /* 55: current logical heads */
uint16_t atap_cursectors; /* 56: current logical sectors/tracks */
uint16_t atap_curcapacity[2]; /* 57-58: current capacity */
uint8_t atap_curmulti; /* 59: current multi-sector setting */
uint8_t atap_curmulti_valid; /* 59: current multi-sector setting */
#define WDC_MULTI_VALID 0x0100
#define WDC_MULTI_MASK 0x00ff
uint32_t atap_capacity; /* 60-61: total capacity (LBA only) */
uint16_t __retired4;
#if ATA_BYTE_ORDER == LITTLE_ENDIAN
uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
uint8_t atap_dmamode_act; /* multiword DMA mode active */
uint8_t atap_piomode_supp; /* 64: PIO mode supported */
uint8_t __junk4;
#else
uint8_t atap_dmamode_act; /* multiword DMA mode active */
uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
uint8_t __junk4;
uint8_t atap_piomode_supp; /* 64: PIO mode supported */
#endif
uint16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */
uint16_t atap_dmatiming_recom; /* 66: recommended DMA cycle time */
uint16_t atap_piotiming; /* 67: mini PIO cycle time without FC */
uint16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */
uint16_t __reserved3[2];
/* words 71-72 are ATAPI only */
uint16_t atap_pkt_br; /* 71: time (ns) to bus release */
uint16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */
uint16_t __reserved4[2];
uint16_t atap_queuedepth; /* 75: */
#define WDC_QUEUE_DEPTH_MASK 0x1f
uint16_t atap_sata_caps; /* 76: SATA capabilities */
#define SATA_SIGNAL_GEN1 0x0002 /* SATA Gen-1 signaling speed */
#define SATA_SIGNAL_GEN2 0x0004 /* SATA Gen-2 signaling speed */
#define SATA_NATIVE_CMDQ 0x0100 /* native command queuing */
#define SATA_HOST_PWR_MGMT 0x0200 /* power management (host) */
uint16_t atap_sata_reserved; /* 77: reserved */
uint16_t atap_sata_features_supp;/* 78: SATA features supported */
#define SATA_NONZERO_OFFSETS 0x0002 /* non-zero buffer offsets */
#define SATA_DMA_SETUP_AUTO 0x0004 /* DMA setup auto-activate */
#define SATA_DRIVE_PWR_MGMT 0x0008 /* power management (device) */
uint16_t atap_sata_features_en; /* 79: SATA features enabled */
uint16_t atap_ata_major; /* 80: Major version number */
#define WDC_VER_ATA1 0x0002
#define WDC_VER_ATA2 0x0004
#define WDC_VER_ATA3 0x0008
#define WDC_VER_ATA4 0x0010
#define WDC_VER_ATA5 0x0020
#define WDC_VER_ATA6 0x0040
#define WDC_VER_ATA7 0x0080
#define WDC_VER_ATA8 0x0100
#define WDC_VER_ATA9 0x0200
#define WDC_VER_ATA10 0x0400
#define WDC_VER_ATA11 0x0800
#define WDC_VER_ATA12 0x1000
#define WDC_VER_ATA13 0x2000
#define WDC_VER_ATA14 0x4000
uint16_t atap_ata_minor; /* 81: Minor version number */
uint16_t atap_cmd_set1; /* 82: command set supported */
#define WDC_CMD1_NOP 0x4000
#define WDC_CMD1_RB 0x2000
#define WDC_CMD1_WB 0x1000
#define WDC_CMD1_HPA 0x0400
#define WDC_CMD1_DVRST 0x0200
#define WDC_CMD1_SRV 0x0100
#define WDC_CMD1_RLSE 0x0080
#define WDC_CMD1_AHEAD 0x0040
#define WDC_CMD1_CACHE 0x0020
#define WDC_CMD1_PKT 0x0010
#define WDC_CMD1_PM 0x0008
#define WDC_CMD1_REMOV 0x0004
#define WDC_CMD1_SEC 0x0002
#define WDC_CMD1_SMART 0x0001
uint16_t atap_cmd_set2; /* 83: command set supported */
#define ATAPI_CMD2_FCE 0x2000 /* Flush Cache Ext supported */
#define ATAPI_CMD2_FC 0x1000 /* Flush Cache supported */
#define ATAPI_CMD2_DCO 0x0800 /* Device Configuration Overlay supported */
#define ATAPI_CMD2_48AD 0x0400 /* 48bit address supported */
#define ATAPI_CMD2_AAM 0x0200 /* Automatic Acoustic Management supported */
#define ATAPI_CMD2_SM 0x0100 /* Set Max security extension supported */
#define ATAPI_CMD2_SF 0x0040 /* Set Features subcommand required */
#define ATAPI_CMD2_PUIS 0x0020 /* Power up in standby supported */
#define WDC_CMD2_RMSN 0x0010
#define ATA_CMD2_APM 0x0008
#define ATA_CMD2_CFA 0x0004
#define ATA_CMD2_RWQ 0x0002
#define WDC_CMD2_DM 0x0001 /* Download Microcode supported */
uint16_t atap_cmd_ext; /* 84: command/features supp. ext. */
#define ATAPI_CMDE_MSER 0x0004 /* Media serial number supported */
#define ATAPI_CMDE_TEST 0x0002 /* SMART self-test supported */
#define ATAPI_CMDE_SLOG 0x0001 /* SMART error logging supported */
uint16_t atap_cmd1_en; /* 85: cmd/features enabled */
/* bits are the same as atap_cmd_set1 */
uint16_t atap_cmd2_en; /* 86: cmd/features enabled */
/* bits are the same as atap_cmd_set2 */
uint16_t atap_cmd_def; /* 87: cmd/features default */
/* bits are NOT the same as atap_cmd_ext */
#if ATA_BYTE_ORDER == LITTLE_ENDIAN
uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
#else
uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
#endif
/* 89-92 are ATA-only */
uint16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */
uint16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */
uint16_t atap_apm_val; /* 91: current APM value */
uint16_t atap_mpasswd_rev; /* 92: Master Password revision */
uint16_t atap_hwreset_res; /* 93: Hardware reset value */
#define ATA_HWRES_CBLID 0x2000 /* CBLID above Vih */
#define ATA_HWRES_D1_PDIAG 0x0800 /* Device 1 PDIAG detect OK */
#define ATA_HWRES_D1_CSEL 0x0400 /* Device 1 used CSEL for address */
#define ATA_HWRES_D1_JUMP 0x0200 /* Device 1 jumpered to address */
#define ATA_HWRES_D0_SEL 0x0040 /* Device 0 responds when Dev 1 selected */
#define ATA_HWRES_D0_DASP 0x0020 /* Device 0 DASP detect OK */
#define ATA_HWRES_D0_PDIAG 0x0010 /* Device 0 PDIAG detect OK */
#define ATA_HWRES_D0_DIAG 0x0008 /* Device 0 diag OK */
#define ATA_HWRES_D0_CSEL 0x0004 /* Device 0 used CSEL for address */
#define ATA_HWRES_D0_JUMP 0x0002 /* Device 0 jumpered to address */
#if ATA_BYTE_ORDER == LITTLE_ENDIAN
uint8_t atap_acoustic_val; /* 94: Current acoustic level */
uint8_t atap_acoustic_def; /* recommended level */
#else
uint8_t atap_acoustic_def; /* recommended level */
uint8_t atap_acoustic_val; /* 94: Current acoustic level */
#endif
uint16_t __reserved6[5]; /* 95-99: reserved */
uint16_t atap_max_lba[4]; /* 100-103: Max. user LBA add */
uint16_t __reserved7[23]; /* 104-126: reserved */
uint16_t atap_rmsn_supp; /* 127: remov. media status notif. */
#define WDC_RMSN_SUPP_MASK 0x0003
#define WDC_RMSN_SUPP 0x0001
uint16_t atap_sec_st; /* 128: security status */
#define WDC_SEC_LEV_MAX 0x0100
#define WDC_SEC_ESE_SUPP 0x0020
#define WDC_SEC_EXP 0x0010
#define WDC_SEC_FROZEN 0x0008
#define WDC_SEC_LOCKED 0x0004
#define WDC_SEC_EN 0x0002
#define WDC_SEC_SUPP 0x0001
uint16_t __reserved8[31]; /* 129-159: vendor specific */
uint16_t atap_cfa_power; /* 160: CFA powermode */
#define ATAPI_CFA_MAX_MASK 0x0FFF
#define ATAPI_CFA_MODE1_DIS 0x1000 /* CFA Mode 1 Disabled */
#define ATAPI_CFA_MODE1_REQ 0x2000 /* CFA Mode 1 Required */
#define ATAPI_CFA_WORD160 0x8000 /* Word 160 supported */
uint16_t __reserved9[15]; /* 161-175: reserved for CFA */
uint8_t atap_media_serial[60]; /* 176-205: media serial number */
uint16_t __reserved10[49]; /* 206-254: reserved */
#if ATA_BYTE_ORDER == LITTLE_ENDIAN
uint8_t atap_signature; /* 255: Signature */
uint8_t atap_checksum; /* Checksum */
#else
uint8_t atap_checksum; /* Checksum */
uint8_t atap_signature; /* 255: Signature */
#endif
};
#undef ATA_BYTE_ORDER
#endif /* !_DEV_ATA_ATAREG_H_ */

View File

@ -0,0 +1,615 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Andrew Schultz
* Ali Saidi
* Miguel Serrano
*/
#include <string>
#include "cpu/intr_control.hh"
#include "debug/IdeCtrl.hh"
#include "dev/ide_ctrl.hh"
#include "dev/ide_disk.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/IdeController.hh"
#include "sim/byteswap.hh"
// clang complains about std::set being overloaded with Packet::set if
// we open up the entire namespace std
using std::string;
// Bus master IDE registers
enum BMIRegOffset {
BMICommand = 0x0,
BMIStatus = 0x2,
BMIDescTablePtr = 0x4
};
// PCI config space registers
enum ConfRegOffset {
PrimaryTiming = 0x40,
SecondaryTiming = 0x42,
DeviceTiming = 0x44,
UDMAControl = 0x48,
UDMATiming = 0x4A,
IDEConfig = 0x54
};
static const uint16_t timeRegWithDecodeEn = 0x8000;
IdeController::Channel::Channel(
string newName, Addr _cmdSize, Addr _ctrlSize) :
_name(newName),
cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
master(NULL), slave(NULL), selected(NULL)
{
memset(&bmiRegs, 0, sizeof(bmiRegs));
bmiRegs.status.dmaCap0 = 1;
bmiRegs.status.dmaCap1 = 1;
}
IdeController::Channel::~Channel()
{
}
IdeController::IdeController(Params *p)
: PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
secondary(name() + ".secondary", BARSize[2], BARSize[3]),
bmiAddr(0), bmiSize(BARSize[4]),
primaryTiming(htole(timeRegWithDecodeEn)),
secondaryTiming(htole(timeRegWithDecodeEn)),
deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
ioEnabled(false), bmEnabled(false),
ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
{
if (params()->disks.size() > 3)
panic("IDE controllers support a maximum of 4 devices attached!\n");
// Assign the disks to channels
int numDisks = params()->disks.size();
if (numDisks > 0)
primary.master = params()->disks[0];
if (numDisks > 1)
primary.slave = params()->disks[1];
if (numDisks > 2)
secondary.master = params()->disks[2];
if (numDisks > 3)
secondary.slave = params()->disks[3];
for (int i = 0; i < params()->disks.size(); i++) {
params()->disks[i]->setController(this);
}
primary.select(false);
secondary.select(false);
if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0];
primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARAddrs[1];
}
if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2];
secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARAddrs[3];
}
ioEnabled = (config.command & htole(PCI_CMD_IOSE));
bmEnabled = (config.command & htole(PCI_CMD_BME));
}
bool
IdeController::isDiskSelected(IdeDisk *diskPtr)
{
return (primary.selected == diskPtr || secondary.selected == diskPtr);
}
void
IdeController::intrPost()
{
primary.bmiRegs.status.intStatus = 1;
PciDev::intrPost();
}
void
IdeController::setDmaComplete(IdeDisk *disk)
{
Channel *channel;
if (disk == primary.master || disk == primary.slave) {
channel = &primary;
} else if (disk == secondary.master || disk == secondary.slave) {
channel = &secondary;
} else {
panic("Unable to find disk based on pointer %#x\n", disk);
}
channel->bmiRegs.command.startStop = 0;
channel->bmiRegs.status.active = 0;
channel->bmiRegs.status.intStatus = 1;
}
Tick
IdeController::readConfig(PacketPtr pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset < PCI_DEVICE_SPECIFIC) {
return PciDev::readConfig(pkt);
}
pkt->allocate();
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
case DeviceTiming:
pkt->set<uint8_t>(deviceTiming);
break;
case UDMAControl:
pkt->set<uint8_t>(udmaControl);
break;
case PrimaryTiming + 1:
pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
break;
case SecondaryTiming + 1:
pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
break;
case IDEConfig:
pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
break;
case IDEConfig + 1:
pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
break;
default:
panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
offset);
}
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 PrimaryTiming:
pkt->set<uint16_t>(primaryTiming);
break;
case SecondaryTiming:
pkt->set<uint16_t>(secondaryTiming);
break;
case UDMATiming:
pkt->set<uint16_t>(udmaTiming);
break;
case IDEConfig:
pkt->set<uint16_t>(ideConfig);
break;
default:
panic("Invalid PCI configuration read for size 2 offset: %#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):
if (offset == IDEConfig)
pkt->set<uint32_t>(ideConfig);
else
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");
}
pkt->makeAtomicResponse();
return configDelay;
}
Tick
IdeController::writeConfig(PacketPtr pkt)
{
int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(pkt);
} else {
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
case DeviceTiming:
deviceTiming = pkt->get<uint8_t>();
break;
case UDMAControl:
udmaControl = pkt->get<uint8_t>();
break;
case IDEConfig:
replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
break;
case IDEConfig + 1:
replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
break;
default:
panic("Invalid PCI configuration write "
"for size 1 offset: %#x!\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
offset, (uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
switch (offset) {
case PrimaryTiming:
primaryTiming = pkt->get<uint16_t>();
break;
case SecondaryTiming:
secondaryTiming = pkt->get<uint16_t>();
break;
case UDMATiming:
udmaTiming = pkt->get<uint16_t>();
break;
case IDEConfig:
ideConfig = pkt->get<uint16_t>();
break;
default:
panic("Invalid PCI configuration write "
"for size 2 offset: %#x!\n",
offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
offset, (uint32_t)pkt->get<uint16_t>());
break;
case sizeof(uint32_t):
if (offset == IDEConfig)
ideConfig = pkt->get<uint32_t>();
else
panic("Write of unimplemented PCI config. register: %x\n", offset);
break;
default:
panic("invalid access size(?) for PCI configspace!\n");
}
pkt->makeAtomicResponse();
}
/* Trap command register writes and enable IO/BM as appropriate as well as
* BARs. */
switch(offset) {
case PCI0_BASE_ADDR0:
if (BARAddrs[0] != 0)
primary.cmdAddr = BARAddrs[0];
break;
case PCI0_BASE_ADDR1:
if (BARAddrs[1] != 0)
primary.ctrlAddr = BARAddrs[1];
break;
case PCI0_BASE_ADDR2:
if (BARAddrs[2] != 0)
secondary.cmdAddr = BARAddrs[2];
break;
case PCI0_BASE_ADDR3:
if (BARAddrs[3] != 0)
secondary.ctrlAddr = BARAddrs[3];
break;
case PCI0_BASE_ADDR4:
if (BARAddrs[4] != 0)
bmiAddr = BARAddrs[4];
break;
case PCI_COMMAND:
DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
ioEnabled = (config.command & htole(PCI_CMD_IOSE));
bmEnabled = (config.command & htole(PCI_CMD_BME));
break;
}
return configDelay;
}
void
IdeController::Channel::accessCommand(Addr offset,
int size, uint8_t *data, bool read)
{
const Addr SelectOffset = 6;
const uint8_t SelectDevBit = 0x10;
if (!read && offset == SelectOffset)
select(*data & SelectDevBit);
if (selected == NULL) {
assert(size == sizeof(uint8_t));
*data = 0;
} else if (read) {
selected->readCommand(offset, size, data);
} else {
selected->writeCommand(offset, size, data);
}
}
void
IdeController::Channel::accessControl(Addr offset,
int size, uint8_t *data, bool read)
{
if (selected == NULL) {
assert(size == sizeof(uint8_t));
*data = 0;
} else if (read) {
selected->readControl(offset, size, data);
} else {
selected->writeControl(offset, size, data);
}
}
void
IdeController::Channel::accessBMI(Addr offset,
int size, uint8_t *data, bool read)
{
assert(offset + size <= sizeof(BMIRegs));
if (read) {
memcpy(data, (uint8_t *)&bmiRegs + offset, size);
} else {
switch (offset) {
case BMICommand:
{
if (size != sizeof(uint8_t))
panic("Invalid BMIC write size: %x\n", size);
BMICommandReg oldVal = bmiRegs.command;
BMICommandReg newVal = *data;
// if a DMA transfer is in progress, R/W control cannot change
if (oldVal.startStop && oldVal.rw != newVal.rw)
oldVal.rw = newVal.rw;
if (oldVal.startStop != newVal.startStop) {
if (selected == NULL)
panic("DMA start for disk which does not exist\n");
if (oldVal.startStop) {
DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
bmiRegs.status.active = 0;
selected->abortDma();
} else {
DPRINTF(IdeCtrl, "Starting DMA transfer\n");
bmiRegs.status.active = 1;
selected->startDma(letoh(bmiRegs.bmidtp));
}
}
bmiRegs.command = newVal;
}
break;
case BMIStatus:
{
if (size != sizeof(uint8_t))
panic("Invalid BMIS write size: %x\n", size);
BMIStatusReg oldVal = bmiRegs.status;
BMIStatusReg newVal = *data;
// the BMIDEA bit is read only
newVal.active = oldVal.active;
// to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
if (oldVal.intStatus && newVal.intStatus)
newVal.intStatus = 0; // clear the interrupt?
else
newVal.intStatus = oldVal.intStatus;
if (oldVal.dmaError && newVal.dmaError)
newVal.dmaError = 0;
else
newVal.dmaError = oldVal.dmaError;
bmiRegs.status = newVal;
}
break;
case BMIDescTablePtr:
if (size != sizeof(uint32_t))
panic("Invalid BMIDTP write size: %x\n", size);
bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
break;
default:
if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
size != sizeof(uint32_t))
panic("IDE controller write of invalid write size: %x\n", size);
memcpy((uint8_t *)&bmiRegs + offset, data, size);
}
}
}
void
IdeController::dispatchAccess(PacketPtr pkt, bool read)
{
pkt->allocate();
if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
panic("Bad IDE read size: %d\n", pkt->getSize());
if (!ioEnabled) {
pkt->makeAtomicResponse();
DPRINTF(IdeCtrl, "io not enabled\n");
return;
}
Addr addr = pkt->getAddr();
int size = pkt->getSize();
uint8_t *dataPtr = pkt->getPtr<uint8_t>();
if (addr >= primary.cmdAddr &&
addr < (primary.cmdAddr + primary.cmdSize)) {
addr -= primary.cmdAddr;
// linux may have shifted the address by ioShift,
// here we shift it back, similarly for ctrlOffset.
addr >>= ioShift;
primary.accessCommand(addr, size, dataPtr, read);
} else if (addr >= primary.ctrlAddr &&
addr < (primary.ctrlAddr + primary.ctrlSize)) {
addr -= primary.ctrlAddr;
addr += ctrlOffset;
primary.accessControl(addr, size, dataPtr, read);
} else if (addr >= secondary.cmdAddr &&
addr < (secondary.cmdAddr + secondary.cmdSize)) {
addr -= secondary.cmdAddr;
secondary.accessCommand(addr, size, dataPtr, read);
} else if (addr >= secondary.ctrlAddr &&
addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
addr -= secondary.ctrlAddr;
secondary.accessControl(addr, size, dataPtr, read);
} else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
if (!read && !bmEnabled)
return;
addr -= bmiAddr;
if (addr < sizeof(Channel::BMIRegs)) {
primary.accessBMI(addr, size, dataPtr, read);
} else {
addr -= sizeof(Channel::BMIRegs);
secondary.accessBMI(addr, size, dataPtr, read);
}
} else {
panic("IDE controller access to invalid address: %#x\n", addr);
}
#ifndef NDEBUG
uint32_t data;
if (pkt->getSize() == 1)
data = pkt->get<uint8_t>();
else if (pkt->getSize() == 2)
data = pkt->get<uint16_t>();
else
data = pkt->get<uint32_t>();
DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
#endif
pkt->makeAtomicResponse();
}
Tick
IdeController::read(PacketPtr pkt)
{
dispatchAccess(pkt, true);
return pioDelay;
}
Tick
IdeController::write(PacketPtr pkt)
{
dispatchAccess(pkt, false);
return pioDelay;
}
void
IdeController::serialize(std::ostream &os)
{
// Serialize the PciDev base class
PciDev::serialize(os);
// Serialize channels
primary.serialize("primary", os);
secondary.serialize("secondary", os);
// Serialize config registers
SERIALIZE_SCALAR(primaryTiming);
SERIALIZE_SCALAR(secondaryTiming);
SERIALIZE_SCALAR(deviceTiming);
SERIALIZE_SCALAR(udmaControl);
SERIALIZE_SCALAR(udmaTiming);
SERIALIZE_SCALAR(ideConfig);
// Serialize internal state
SERIALIZE_SCALAR(ioEnabled);
SERIALIZE_SCALAR(bmEnabled);
SERIALIZE_SCALAR(bmiAddr);
SERIALIZE_SCALAR(bmiSize);
}
void
IdeController::Channel::serialize(const std::string &base, std::ostream &os)
{
paramOut(os, base + ".cmdAddr", cmdAddr);
paramOut(os, base + ".cmdSize", cmdSize);
paramOut(os, base + ".ctrlAddr", ctrlAddr);
paramOut(os, base + ".ctrlSize", ctrlSize);
uint8_t command = bmiRegs.command;
paramOut(os, base + ".bmiRegs.command", command);
paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
uint8_t status = bmiRegs.status;
paramOut(os, base + ".bmiRegs.status", status);
paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
paramOut(os, base + ".selectBit", selectBit);
}
void
IdeController::unserialize(Checkpoint *cp, const std::string &section)
{
// Unserialize the PciDev base class
PciDev::unserialize(cp, section);
// Unserialize channels
primary.unserialize("primary", cp, section);
secondary.unserialize("secondary", cp, section);
// Unserialize config registers
UNSERIALIZE_SCALAR(primaryTiming);
UNSERIALIZE_SCALAR(secondaryTiming);
UNSERIALIZE_SCALAR(deviceTiming);
UNSERIALIZE_SCALAR(udmaControl);
UNSERIALIZE_SCALAR(udmaTiming);
UNSERIALIZE_SCALAR(ideConfig);
// Unserialize internal state
UNSERIALIZE_SCALAR(ioEnabled);
UNSERIALIZE_SCALAR(bmEnabled);
UNSERIALIZE_SCALAR(bmiAddr);
UNSERIALIZE_SCALAR(bmiSize);
}
void
IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp,
const std::string &section)
{
paramIn(cp, section, base + ".cmdAddr", cmdAddr);
paramIn(cp, section, base + ".cmdSize", cmdSize);
paramIn(cp, section, base + ".ctrlAddr", ctrlAddr);
paramIn(cp, section, base + ".ctrlSize", ctrlSize);
uint8_t command;
paramIn(cp, section, base +".bmiRegs.command", command);
bmiRegs.command = command;
paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
uint8_t status;
paramIn(cp, section, base + ".bmiRegs.status", status);
bmiRegs.status = status;
paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
paramIn(cp, section, base + ".selectBit", selectBit);
select(selectBit);
}
IdeController *
IdeControllerParams::create()
{
return new IdeController(this);
}

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Andrew Schultz
* Miguel Serrano
*/
/** @file
* Simple PCI IDE controller with bus mastering capability and UDMA
* modeled after controller in the Intel PIIX4 chip
*/
#ifndef __IDE_CTRL_HH__
#define __IDE_CTRL_HH__
#include "base/bitunion.hh"
#include "dev/io_device.hh"
#include "dev/pcidev.hh"
#include "dev/pcireg.h"
#include "params/IdeController.hh"
class IdeDisk;
/**
* Device model for an Intel PIIX4 IDE controller
*/
class IdeController : public PciDev
{
private:
// Bus master IDE status register bit fields
BitUnion8(BMIStatusReg)
Bitfield<6> dmaCap0;
Bitfield<5> dmaCap1;
Bitfield<2> intStatus;
Bitfield<1> dmaError;
Bitfield<0> active;
EndBitUnion(BMIStatusReg)
BitUnion8(BMICommandReg)
Bitfield<3> rw;
Bitfield<0> startStop;
EndBitUnion(BMICommandReg)
struct Channel
{
std::string _name;
const std::string
name()
{
return _name;
}
/** Command and control block registers */
Addr cmdAddr, cmdSize, ctrlAddr, ctrlSize;
/** Registers used for bus master interface */
struct BMIRegs
{
BMICommandReg command;
uint8_t reserved0;
BMIStatusReg status;
uint8_t reserved1;
uint32_t bmidtp;
} bmiRegs;
/** IDE disks connected to this controller */
IdeDisk *master, *slave;
/** Currently selected disk */
IdeDisk *selected;
bool selectBit;
void
select(bool selSlave)
{
selectBit = selSlave;
selected = selectBit ? slave : master;
}
void accessCommand(Addr offset, int size, uint8_t *data, bool read);
void accessControl(Addr offset, int size, uint8_t *data, bool read);
void accessBMI(Addr offset, int size, uint8_t *data, bool read);
Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize);
~Channel();
void serialize(const std::string &base, std::ostream &os);
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
Channel primary;
Channel secondary;
/** Bus master interface (BMI) registers */
Addr bmiAddr, bmiSize;
/** Registers used in device specific PCI configuration */
uint16_t primaryTiming, secondaryTiming;
uint8_t deviceTiming;
uint8_t udmaControl;
uint16_t udmaTiming;
uint16_t ideConfig;
// Internal management variables
bool ioEnabled;
bool bmEnabled;
uint32_t ioShift, ctrlOffset;
void dispatchAccess(PacketPtr pkt, bool read);
public:
typedef IdeControllerParams Params;
const Params *params() const { return (const Params *)_params; }
IdeController(Params *p);
/** See if a disk is selected based on its pointer */
bool isDiskSelected(IdeDisk *diskPtr);
void intrPost();
Tick writeConfig(PacketPtr pkt);
Tick readConfig(PacketPtr pkt);
void setDmaComplete(IdeDisk *disk);
Tick read(PacketPtr pkt);
Tick write(PacketPtr pkt);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __IDE_CTRL_HH_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,368 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Andrew Schultz
*/
/** @file
* Device model for an IDE disk
*/
#ifndef __IDE_DISK_HH__
#define __IDE_DISK_HH__
#include "base/statistics.hh"
#include "dev/disk_image.hh"
#include "dev/ide_atareg.h"
#include "dev/ide_ctrl.hh"
#include "dev/ide_wdcreg.h"
#include "dev/io_device.hh"
#include "params/IdeDisk.hh"
#include "sim/eventq.hh"
class ChunkGenerator;
#define DMA_BACKOFF_PERIOD 200
#define MAX_DMA_SIZE 0x20000 // 128K
#define MAX_SINGLE_DMA_SIZE 0x10000
#define MAX_MULTSECT (128)
#define PRD_BASE_MASK 0xfffffffe
#define PRD_COUNT_MASK 0xfffe
#define PRD_EOT_MASK 0x8000
typedef struct PrdEntry {
uint32_t baseAddr;
uint16_t byteCount;
uint16_t endOfTable;
} PrdEntry_t;
class PrdTableEntry {
public:
PrdEntry_t entry;
uint32_t getBaseAddr()
{
return (entry.baseAddr & PRD_BASE_MASK);
}
uint32_t getByteCount()
{
return ((entry.byteCount == 0) ? MAX_SINGLE_DMA_SIZE :
(entry.byteCount & PRD_COUNT_MASK));
}
uint16_t getEOT()
{
return (entry.endOfTable & PRD_EOT_MASK);
}
};
#define DATA_OFFSET (0)
#define ERROR_OFFSET (1)
#define FEATURES_OFFSET (1)
#define NSECTOR_OFFSET (2)
#define SECTOR_OFFSET (3)
#define LCYL_OFFSET (4)
#define HCYL_OFFSET (5)
#define SELECT_OFFSET (6)
#define DRIVE_OFFSET (6)
#define STATUS_OFFSET (7)
#define COMMAND_OFFSET (7)
#define CONTROL_OFFSET (2)
#define ALTSTAT_OFFSET (2)
#define SELECT_DEV_BIT 0x10
#define CONTROL_RST_BIT 0x04
#define CONTROL_IEN_BIT 0x02
#define STATUS_BSY_BIT 0x80
#define STATUS_DRDY_BIT 0x40
#define STATUS_DRQ_BIT 0x08
#define STATUS_SEEK_BIT 0x10
#define STATUS_DF_BIT 0x20
#define DRIVE_LBA_BIT 0x40
#define DEV0 (0)
#define DEV1 (1)
typedef struct CommandReg {
uint16_t data;
uint8_t error;
uint8_t sec_count;
uint8_t sec_num;
uint8_t cyl_low;
uint8_t cyl_high;
union {
uint8_t drive;
uint8_t head;
};
uint8_t command;
} CommandReg_t;
typedef enum Events {
None = 0,
Transfer,
ReadWait,
WriteWait,
PrdRead,
DmaRead,
DmaWrite
} Events_t;
typedef enum DevAction {
ACT_NONE = 0,
ACT_CMD_WRITE,
ACT_CMD_COMPLETE,
ACT_CMD_ERROR,
ACT_SELECT_WRITE,
ACT_STAT_READ,
ACT_DATA_READY,
ACT_DATA_READ_BYTE,
ACT_DATA_READ_SHORT,
ACT_DATA_WRITE_BYTE,
ACT_DATA_WRITE_SHORT,
ACT_DMA_READY,
ACT_DMA_DONE,
ACT_SRST_SET,
ACT_SRST_CLEAR
} DevAction_t;
typedef enum DevState {
// Device idle
Device_Idle_S = 0,
Device_Idle_SI,
Device_Idle_NS,
// Software reset
Device_Srst,
// Non-data commands
Command_Execution,
// PIO data-in (data to host)
Prepare_Data_In,
Data_Ready_INTRQ_In,
Transfer_Data_In,
// PIO data-out (data from host)
Prepare_Data_Out,
Data_Ready_INTRQ_Out,
Transfer_Data_Out,
// DMA protocol
Prepare_Data_Dma,
Transfer_Data_Dma
} DevState_t;
typedef enum DmaState {
Dma_Idle = 0,
Dma_Start,
Dma_Transfer
} DmaState_t;
class IdeController;
/**
* IDE Disk device model
*/
class IdeDisk : public SimObject
{
protected:
/** The IDE controller for this disk. */
IdeController *ctrl;
/** The image that contains the data of this disk. */
DiskImage *image;
protected:
/** The disk delay in microseconds. */
int diskDelay;
private:
/** Drive identification structure for this disk */
struct ataparams driveID;
/** Data buffer for transfers */
uint8_t *dataBuffer;
/** Number of bytes in command data transfer */
uint32_t cmdBytes;
/** Number of bytes left in command data transfer */
uint32_t cmdBytesLeft;
/** Number of bytes left in DRQ block */
uint32_t drqBytesLeft;
/** Current sector in access */
uint32_t curSector;
/** Command block registers */
CommandReg_t cmdReg;
/** Status register */
uint8_t status;
/** Interrupt enable bit */
bool nIENBit;
/** Device state */
DevState_t devState;
/** Dma state */
DmaState_t dmaState;
/** Dma transaction is a read */
bool dmaRead;
/** PRD table base address */
uint32_t curPrdAddr;
/** PRD entry */
PrdTableEntry curPrd;
/** Device ID (master=0/slave=1) */
int devID;
/** Interrupt pending */
bool intrPending;
Stats::Scalar dmaReadFullPages;
Stats::Scalar dmaReadBytes;
Stats::Scalar dmaReadTxs;
Stats::Scalar dmaWriteFullPages;
Stats::Scalar dmaWriteBytes;
Stats::Scalar dmaWriteTxs;
public:
typedef IdeDiskParams Params;
IdeDisk(const Params *p);
/**
* Delete the data buffer.
*/
~IdeDisk();
/**
* Reset the device state
*/
void reset(int id);
/**
* Register Statistics
*/
void regStats();
/**
* Set the controller for this device
* @param c The IDE controller
*/
void setController(IdeController *c) {
if (ctrl) panic("Cannot change the controller once set!\n");
ctrl = c;
}
// Device register read/write
void readCommand(const Addr offset, int size, uint8_t *data);
void readControl(const Addr offset, int size, uint8_t *data);
void writeCommand(const Addr offset, int size, const uint8_t *data);
void writeControl(const Addr offset, int size, const uint8_t *data);
// Start/abort functions
void startDma(const uint32_t &prdTableBase);
void abortDma();
private:
void startCommand();
// Interrupt management
void intrPost();
void intrClear();
// DMA stuff
void doDmaTransfer();
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
void doDmaDataRead();
void doDmaRead();
ChunkGenerator *dmaReadCG;
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
void doDmaDataWrite();
void doDmaWrite();
ChunkGenerator *dmaWriteCG;
friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
void dmaPrdReadDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
void dmaReadDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
void dmaWriteDone();
friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
// Disk image read/write
void readDisk(uint32_t sector, uint8_t *data);
void writeDisk(uint32_t sector, uint8_t *data);
// State machine management
void updateState(DevAction_t action);
// Utility functions
bool isBSYSet() { return (status & STATUS_BSY_BIT); }
bool isIENSet() { return nIENBit; }
bool isDEVSelect();
void setComplete()
{
// clear out the status byte
status = 0;
// set the DRDY bit
status |= STATUS_DRDY_BIT;
// set the SEEK bit
status |= STATUS_SEEK_BIT;
}
uint32_t getLBABase()
{
return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
(cmdReg.cyl_low << 8) | (cmdReg.sec_num));
}
inline Addr pciToDma(Addr pciAddr);
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint to use.
* @param section The section name describing this object.
*/
void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __IDE_DISK_HH__

View File

@ -0,0 +1,197 @@
/* $OpenBSD: wdcreg.h,v 1.13 2004/09/24 07:05:44 grange Exp $ */
/* $NetBSD: wdcreg.h,v 1.22 1999/03/07 14:02:54 bouyer Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California
* All rights reserved
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)wdreg.h 7.1 (Berkeley) 5/9/91
*/
#ifndef _DEV_IC_WDCREG_H_
#define _DEV_IC_WDCREG_H_
/*
* Controller register (wdr_ctlr)
*/
#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */
#define WDCTL_RST 0x04 /* reset the controller */
#define WDCTL_IDS 0x02 /* disable controller interrupts */
/*
* Status bits.
*/
#define WDCS_BSY 0x80 /* busy */
#define WDCS_DRDY 0x40 /* drive ready */
#define WDCS_DWF 0x20 /* drive write fault */
#define WDCS_DSC 0x10 /* drive seek complete */
#define WDCS_DRQ 0x08 /* data request */
#define WDCS_CORR 0x04 /* corrected data */
#define WDCS_IDX 0x02 /* index */
#define WDCS_ERR 0x01 /* error */
#define WDCS_BITS "\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR"
/*
* Error bits.
*/
#define WDCE_BBK 0x80 /* bad block detected */
#define WDCE_CRC 0x80 /* CRC error (Ultra-DMA only) */
#define WDCE_UNC 0x40 /* uncorrectable data error */
#define WDCE_MC 0x20 /* media changed */
#define WDCE_IDNF 0x10 /* id not found */
#define WDCE_MCR 0x08 /* media change requested */
#define WDCE_ABRT 0x04 /* aborted command */
#define WDCE_TK0NF 0x02 /* track 0 not found */
#define WDCE_AMNF 0x01 /* address mark not found */
/*
* Commands for Disk Controller.
*/
#define WDCC_NOP 0x00 /* NOP - Always fail with "aborted command" */
#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
#define WDCC_READ 0x20 /* disk read code */
#define WDCC_WRITE 0x30 /* disk write code */
#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
#define WDCC_FORMAT 0x50 /* disk format code */
#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
#define WDCC_IDP 0x91 /* initialize drive parameters */
#define WDCC_READMULTI 0xc4 /* read multiple */
#define WDCC_WRITEMULTI 0xc5 /* write multiple */
#define WDCC_SETMULTI 0xc6 /* set multiple mode */
#define WDCC_READDMA 0xc8 /* read with DMA */
#define WDCC_WRITEDMA 0xca /* write with DMA */
#define WDCC_ACKMC 0xdb /* acknowledge media change */
#define WDCC_LOCK 0xde /* lock drawer */
#define WDCC_UNLOCK 0xdf /* unlock drawer */
#define WDCC_FLUSHCACHE 0xe7 /* Flush cache */
#define WDCC_IDENTIFY 0xec /* read parameters from controller */
#define SET_FEATURES 0xef /* set features */
#define WDCC_IDLE 0xe3 /* set idle timer & enter idle mode */
#define WDCC_IDLE_IMMED 0xe1 /* enter idle mode */
#define WDCC_SLEEP 0xe6 /* enter sleep mode */
#define WDCC_STANDBY 0xe2 /* set standby timer & enter standby mode */
#define WDCC_STANDBY_IMMED 0xe0 /* enter standby mode */
#define WDCC_CHECK_PWR 0xe5 /* check power mode */
#define WDCC_READ_EXT 0x24 /* read 48-bit addressing */
#define WDCC_WRITE_EXT 0x34 /* write 48-bit addressing */
#define WDCC_READMULTI_EXT 0x29 /* read multiple 48-bit addressing */
#define WDCC_WRITEMULTI_EXT 0x39 /* write multiple 48-bit addressing */
#define WDCC_READDMA_EXT 0x25 /* read 48-bit addressing with DMA */
#define WDCC_WRITEDMA_EXT 0x35 /* write 48-bit addressing with DMA */
#define WDCC_FLUSHCACHE_EXT 0xea /* 48-bit addressing flush cache */
/* Subcommands for SET_FEATURES (features register ) */
#define WDSF_8BIT_PIO_EN 0x01 /* Enable 8bit PIO (CFA featureset) */
#define WDSF_EN_WR_CACHE 0x02
#define WDSF_SET_MODE 0x03
#define WDSF_REASSIGN_EN 0x04 /* Obsolete in ATA-6 */
#define WDSF_APM_EN 0x05 /* Enable Adv. Power Management */
#define WDSF_PUIS_EN 0x06 /* Enable Power-Up In Standby */
#define WDSF_PUIS_SPINUP 0x07 /* Power-Up In Standby spin-up */
#define WDSF_CFA_MODE1_EN 0x0A /* Enable CFA power mode 1 */
#define WDSF_RMSN_DS 0x31 /* Disable Removable Media Status */
#define WDSF_RETRY_DS 0x33 /* Obsolete in ATA-6 */
#define WDSF_AAM_EN 0x42 /* Enable Autom. Acoustic Management */
#define WDSF_SET_CACHE_SGMT 0x54 /* Obsolete in ATA-6 */
#define WDSF_READAHEAD_DS 0x55 /* Disable read look-ahead */
#define WDSF_RLSE_EN 0x5D /* Enable release interrupt */
#define WDSF_SRV_EN 0x5E /* Enable SERVICE interrupt */
#define WDSF_POD_DS 0x66
#define WDSF_ECC_DS 0x77
#define WDSF_8BIT_PIO_DS 0x81 /* Disable 8bit PIO (CFA featureset) */
#define WDSF_WRITE_CACHE_DS 0x82
#define WDSF_REASSIGN_DS 0x84
#define WDSF_APM_DS 0x85 /* Disable Adv. Power Management */
#define WDSF_PUIS_DS 0x86 /* Disable Power-Up In Standby */
#define WDSF_ECC_EN 0x88
#define WDSF_CFA_MODE1_DS 0x8A /* Disable CFA power mode 1 */
#define WDSF_RMSN_EN 0x95 /* Enable Removable Media Status */
#define WDSF_RETRY_EN 0x99 /* Obsolete in ATA-6 */
#define WDSF_SET_CURRENT 0x9A /* Obsolete in ATA-6 */
#define WDSF_READAHEAD_EN 0xAA
#define WDSF_PREFETCH_SET 0xAB /* Obsolete in ATA-6 */
#define WDSF_AAM_DS 0xC2 /* Disable Autom. Acoustic Management */
#define WDSF_POD_EN 0xCC
#define WDSF_RLSE_DS 0xDD /* Disable release interrupt */
#define WDSF_SRV_DS 0xDE /* Disable SERVICE interrupt */
#define WDSF_READ_NATIVE_MAX 0xF8
#define WDSF_SEEK 0x70
#define WDSF_VERIFY 0x40
/* parameters uploaded to device/heads register */
#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
#define WDSD_LBA 0x40 /* logical block addressing */
/* Commands for ATAPI devices */
#define ATAPI_CHECK_POWER_MODE 0xe5
#define ATAPI_EXEC_DRIVE_DIAGS 0x90
#define ATAPI_IDLE_IMMEDIATE 0xe1
#define ATAPI_NOP 0x00
#define ATAPI_PKT_CMD 0xa0
#define ATAPI_IDENTIFY_DEVICE 0xa1
#define ATAPI_SOFT_RESET 0x08
#define ATAPI_DEVICE_RESET 0x08 /* ATA/ATAPI-5 name for soft reset */
#define ATAPI_SLEEP 0xe6
#define ATAPI_STANDBY_IMMEDIATE 0xe0
#define ATAPI_SMART 0xB0 /* SMART operations */
#define ATAPI_SETMAX 0xF9 /* Set Max Address */
#define ATAPI_WRITEEXT 0x34 /* Write sectors Ext */
#define ATAPI_SETMAXEXT 0x37 /* Set Max Address Ext */
#define ATAPI_WRITEMULTIEXT 0x39 /* Write Multi Ext */
/* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */
#define ATAPI_PKT_CMD_FTRE_DMA 0x01
#define ATAPI_PKT_CMD_FTRE_OVL 0x02
/* ireason */
#define WDCI_CMD 0x01 /* command(1) or data(0) */
#define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */
#define WDCI_RELEASE 0x04 /* bus released until completion */
#define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD)
#define PHASE_DATAIN (WDCS_DRQ | WDCI_IN)
#define PHASE_DATAOUT WDCS_DRQ
#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
#define PHASE_ABORTED 0
#endif /* !_DEV_IC_WDCREG_H_ */

View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2004, 2005
* The Regents of The University of Michigan
* All Rights Reserved
*
* This code is part of the M5 simulator.
*
* Permission is granted to use, copy, create derivative works and
* redistribute this software and such derivative works for any
* purpose, so long as the copyright notice above, this grant of
* permission, and the disclaimer below appear in all copies made; and
* so long as the name of The University of Michigan is not used in
* any advertising or publicity pertaining to the use or distribution
* of this software without specific, written prior authorization.
*
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
* UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
* WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
* LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
* ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGES.
*
* Authors: Ali G. Saidi
* Andrew L. Schultz
* Miguel J. Serrano
*/
#include "base/misc.hh"
#include "debug/Intel8254Timer.hh"
#include "dev/intel_8254_timer.hh"
using namespace std;
Intel8254Timer::Intel8254Timer(EventManager *em, const string &name,
Counter *counter0, Counter *counter1, Counter *counter2) :
EventManager(em), _name(name)
{
counter[0] = counter0;
counter[1] = counter1;
counter[2] = counter2;
}
Intel8254Timer::Intel8254Timer(EventManager *em, const string &name) :
EventManager(em), _name(name)
{
counter[0] = new Counter(this, name + ".counter0", 0);
counter[1] = new Counter(this, name + ".counter1", 1);
counter[2] = new Counter(this, name + ".counter2", 2);
}
void
Intel8254Timer::writeControl(const CtrlReg data)
{
int sel = data.sel;
if (sel == ReadBackCommand)
panic("PITimer Read-Back Command is not implemented.\n");
if (data.rw == LatchCommand)
counter[sel]->latchCount();
else {
counter[sel]->setRW(data.rw);
counter[sel]->setMode(data.mode);
counter[sel]->setBCD(data.bcd);
}
}
void
Intel8254Timer::serialize(const string &base, ostream &os)
{
// serialize the counters
counter[0]->serialize(base + ".counter0", os);
counter[1]->serialize(base + ".counter1", os);
counter[2]->serialize(base + ".counter2", os);
}
void
Intel8254Timer::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
// unserialze the counters
counter[0]->unserialize(base + ".counter0", cp, section);
counter[1]->unserialize(base + ".counter1", cp, section);
counter[2]->unserialize(base + ".counter2", cp, section);
}
Intel8254Timer::Counter::Counter(Intel8254Timer *p,
const string &name, unsigned int _num)
: _name(name), num(_num), event(this), initial_count(0),
latched_count(0), period(0), mode(0), output_high(false),
latch_on(false), read_byte(LSB), write_byte(LSB), parent(p)
{
}
void
Intel8254Timer::Counter::latchCount()
{
// behave like a real latch
if(!latch_on) {
latch_on = true;
read_byte = LSB;
latched_count = currentCount();
}
}
int
Intel8254Timer::Counter::currentCount()
{
int clocks = event.clocksLeft();
if (clocks == -1) {
warn_once("Reading current count from inactive timer.\n");
return 0;
}
if (mode == RateGen || mode == SquareWave)
return clocks + 1;
else
return clocks;
}
uint8_t
Intel8254Timer::Counter::read()
{
if (latch_on) {
switch (read_byte) {
case LSB:
read_byte = MSB;
return (uint8_t)latched_count;
break;
case MSB:
read_byte = LSB;
latch_on = false;
return latched_count >> 8;
break;
default:
panic("Shouldn't be here");
}
} else {
uint16_t count = currentCount();
switch (read_byte) {
case LSB:
read_byte = MSB;
return (uint8_t)count;
break;
case MSB:
read_byte = LSB;
return count >> 8;
break;
default:
panic("Shouldn't be here");
}
}
}
void
Intel8254Timer::Counter::write(const uint8_t data)
{
switch (write_byte) {
case LSB:
initial_count = (initial_count & 0xFF00) | data;
if (event.scheduled())
parent->deschedule(event);
output_high = false;
write_byte = MSB;
break;
case MSB:
initial_count = (initial_count & 0x00FF) | (data << 8);
// In the RateGen or SquareWave modes, the timer wraps around and
// triggers on a value of 1, not 0.
if (mode == RateGen || mode == SquareWave)
period = initial_count - 1;
else
period = initial_count;
if (period > 0)
event.setTo(period);
write_byte = LSB;
break;
}
}
void
Intel8254Timer::Counter::setRW(int rw_val)
{
if (rw_val != TwoPhase)
panic("Only LSB/MSB read/write is implemented.\n");
}
void
Intel8254Timer::Counter::setMode(int mode_val)
{
if(mode_val != InitTc && mode_val != RateGen &&
mode_val != SquareWave)
panic("PIT mode %#x is not implemented: \n", mode_val);
mode = mode_val;
}
void
Intel8254Timer::Counter::setBCD(int bcd_val)
{
if (bcd_val)
panic("PITimer does not implement BCD counts.\n");
}
bool
Intel8254Timer::Counter::outputHigh()
{
return output_high;
}
void
Intel8254Timer::Counter::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".initial_count", initial_count);
paramOut(os, base + ".latched_count", latched_count);
paramOut(os, base + ".period", period);
paramOut(os, base + ".mode", mode);
paramOut(os, base + ".output_high", output_high);
paramOut(os, base + ".latch_on", latch_on);
paramOut(os, base + ".read_byte", read_byte);
paramOut(os, base + ".write_byte", write_byte);
Tick event_tick = 0;
if (event.scheduled())
event_tick = event.when();
paramOut(os, base + ".event_tick", event_tick);
}
void
Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
paramIn(cp, section, base + ".initial_count", initial_count);
paramIn(cp, section, base + ".latched_count", latched_count);
paramIn(cp, section, base + ".period", period);
paramIn(cp, section, base + ".mode", mode);
paramIn(cp, section, base + ".output_high", output_high);
paramIn(cp, section, base + ".latch_on", latch_on);
paramIn(cp, section, base + ".read_byte", read_byte);
paramIn(cp, section, base + ".write_byte", write_byte);
Tick event_tick = 0;
if (event.scheduled())
parent->deschedule(event);
paramIn(cp, section, base + ".event_tick", event_tick);
if (event_tick)
parent->schedule(event, event_tick);
}
Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
{
interval = (Tick)(SimClock::Float::s / 1193180.0);
counter = c_ptr;
}
void
Intel8254Timer::Counter::CounterEvent::process()
{
switch (counter->mode) {
case InitTc:
counter->output_high = true;
break;
case RateGen:
case SquareWave:
setTo(counter->period);
break;
default:
panic("Unimplemented PITimer mode.\n");
}
counter->parent->counterInterrupt(counter->num);
}
void
Intel8254Timer::Counter::CounterEvent::setTo(int clocks)
{
if (clocks == 0)
panic("Timer can't be set to go off instantly.\n");
DPRINTF(Intel8254Timer, "Timer set to curTick() + %d\n",
clocks * interval);
counter->parent->schedule(this, curTick() + clocks * interval);
}
int
Intel8254Timer::Counter::CounterEvent::clocksLeft()
{
if (!scheduled())
return -1;
return (when() - curTick() + interval - 1) / interval;
}
const char *
Intel8254Timer::Counter::CounterEvent::description() const
{
return "Intel 8254 Interval timer";
}

View File

@ -0,0 +1,250 @@
/*
* Copyright (c) 2004, 2005
* The Regents of The University of Michigan
* All Rights Reserved
*
* This code is part of the M5 simulator.
*
* Permission is granted to use, copy, create derivative works and
* redistribute this software and such derivative works for any
* purpose, so long as the copyright notice above, this grant of
* permission, and the disclaimer below appear in all copies made; and
* so long as the name of The University of Michigan is not used in
* any advertising or publicity pertaining to the use or distribution
* of this software without specific, written prior authorization.
*
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
* UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
* WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
* LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
* ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGES.
*
* Authors: Ali G. Saidi
* Andrew L. Schultz
* Miguel J. Serrano
*/
#ifndef __DEV_8254_HH__
#define __DEV_8254_HH__
#include <iostream>
#include <string>
#include "base/bitunion.hh"
#include "base/types.hh"
#include "debug/Intel8254Timer.hh"
#include "sim/eventq.hh"
#include "sim/serialize.hh"
/** Programmable Interval Timer (Intel 8254) */
class Intel8254Timer : public EventManager
{
protected:
BitUnion8(CtrlReg)
Bitfield<7, 6> sel;
Bitfield<5, 4> rw;
Bitfield<3, 1> mode;
Bitfield<0> bcd;
EndBitUnion(CtrlReg)
enum SelectVal {
SelectCounter0,
SelectCounter1,
SelectCounter2,
ReadBackCommand
};
enum ReadWriteVal {
LatchCommand,
LsbOnly,
MsbOnly,
TwoPhase
};
enum ModeVal {
InitTc,
OneShot,
RateGen,
SquareWave,
SoftwareStrobe,
HardwareStrobe
};
/** Counter element for PIT */
class Counter
{
/** Event for counter interrupt */
class CounterEvent : public Event
{
private:
/** Pointer back to Counter */
Counter* counter;
Tick interval;
public:
CounterEvent(Counter*);
/** Event process */
void process();
/** Event description */
virtual const char *description() const;
friend class Counter;
void setTo(int clocks);
int clocksLeft();
};
private:
std::string _name;
const std::string &name() const { return _name; }
unsigned int num;
CounterEvent event;
/** Initial count value */
uint16_t initial_count;
/** Latched count */
uint16_t latched_count;
/** Interrupt period */
uint16_t period;
/** Current mode of operation */
uint8_t mode;
/** Output goes high when the counter reaches zero */
bool output_high;
/** State of the count latch */
bool latch_on;
/** Set of values for read_byte and write_byte */
enum {LSB, MSB};
/** Determine which byte of a 16-bit count value to read/write */
uint8_t read_byte, write_byte;
/** Pointer to container */
Intel8254Timer *parent;
public:
Counter(Intel8254Timer *p, const std::string &name, unsigned int num);
/** Latch the current count (if one is not already latched) */
void latchCount();
/** Get the current count for this counter */
int currentCount();
/** Set the read/write mode */
void setRW(int rw_val);
/** Set operational mode */
void setMode(int mode_val);
/** Set count encoding */
void setBCD(int bcd_val);
/** Read a count byte */
uint8_t read();
/** Write a count byte */
void write(const uint8_t data);
/** Is the output high? */
bool outputHigh();
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.
* @param os The stream to serialize to.
*/
void serialize(const std::string &base, std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param base The base name of the counter object.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
protected:
std::string _name;
const std::string &name() const { return _name; }
/** PIT has three seperate counters */
Counter *counter[3];
virtual void
counterInterrupt(unsigned int num)
{
DPRINTF(Intel8254Timer, "Timer interrupt from counter %d.\n", num);
}
public:
virtual
~Intel8254Timer()
{}
Intel8254Timer(EventManager *em, const std::string &name,
Counter *counter0, Counter *counter1, Counter *counter2);
Intel8254Timer(EventManager *em, const std::string &name);
/** Write control word */
void writeControl(const CtrlReg data);
uint8_t
readCounter(unsigned int num)
{
assert(num < 3);
return counter[num]->read();
}
void
writeCounter(unsigned int num, const uint8_t data)
{
assert(num < 3);
counter[num]->write(data);
}
bool
outputHigh(unsigned int num)
{
assert(num < 3);
return counter[num]->outputHigh();
}
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.
* @param os The stream to serialize to.
*/
void serialize(const std::string &base, std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param base The base name of the counter object.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
#endif // __DEV_8254_HH__

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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: Ali Saidi
* Nathan Binkert
*/
#include "base/trace.hh"
#include "debug/BusAddrRanges.hh"
#include "dev/io_device.hh"
#include "sim/system.hh"
PioPort::PioPort(PioDevice *dev)
: SimpleTimingPort(dev->name() + "-pio", dev), device(dev)
{
}
Tick
PioPort::recvAtomic(PacketPtr pkt)
{
return pkt->isRead() ? device->read(pkt) : device->write(pkt);
}
AddrRangeList
PioPort::getAddrRanges()
{
return device->getAddrRanges();
}
PioDevice::PioDevice(const Params *p)
: MemObject(p), sys(p->system), pioPort(this)
{}
PioDevice::~PioDevice()
{
}
void
PioDevice::init()
{
if (!pioPort.isConnected())
panic("Pio port of %s not connected to anything!", name());
pioPort.sendRangeChange();
}
SlavePort &
PioDevice::getSlavePort(const std::string &if_name, int idx)
{
if (if_name == "pio") {
return pioPort;
}
return MemObject::getSlavePort(if_name, idx);
}
unsigned int
PioDevice::drain(Event *de)
{
unsigned int count;
count = pioPort.drain(de);
if (count)
changeState(Draining);
else
changeState(Drained);
return count;
}
BasicPioDevice::BasicPioDevice(const Params *p)
: PioDevice(p), pioAddr(p->pio_addr), pioSize(0),
pioDelay(p->pio_latency)
{}
AddrRangeList
BasicPioDevice::getAddrRanges()
{
assert(pioSize != 0);
AddrRangeList ranges;
DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize);
ranges.push_back(RangeSize(pioAddr, pioSize));
return ranges;
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Nathan Binkert
*/
#ifndef __DEV_IO_DEVICE_HH__
#define __DEV_IO_DEVICE_HH__
#include "mem/mem_object.hh"
#include "mem/tport.hh"
#include "params/BasicPioDevice.hh"
#include "params/PioDevice.hh"
class PioDevice;
class System;
/**
* The PioPort class is a programmed i/o port that all devices that are
* sensitive to an address range use. The port takes all the memory
* access types and roles them into one read() and write() call that the device
* must respond to. The device must also provide getAddrRanges() function
* with which it returns the address ranges it is interested in.
*/
class PioPort : public SimpleTimingPort
{
protected:
/** The device that this port serves. */
PioDevice *device;
virtual Tick recvAtomic(PacketPtr pkt);
virtual AddrRangeList getAddrRanges();
public:
PioPort(PioDevice *dev);
};
/**
* This device is the base class which all devices senstive to an address range
* inherit from. There are three pure virtual functions which all devices must
* implement getAddrRanges(), read(), and write(). The magic do choose which
* mode we are in, etc is handled by the PioPort so the device doesn't have to
* bother.
*/
class PioDevice : public MemObject
{
protected:
System *sys;
/** The pioPort that handles the requests for us and provides us requests
* that it sees. */
PioPort pioPort;
/**
* Every PIO device is obliged to provide an implementation that
* returns the address ranges the device responds to.
*
* @return a list of non-overlapping address ranges
*/
virtual AddrRangeList getAddrRanges() = 0;
/** Pure virtual function that the device must implement. Called
* when a read command is recieved by the port.
* @param pkt Packet describing this request
* @return number of ticks it took to complete
*/
virtual Tick read(PacketPtr pkt) = 0;
/** Pure virtual function that the device must implement. Called when a
* write command is recieved by the port.
* @param pkt Packet describing this request
* @return number of ticks it took to complete
*/
virtual Tick write(PacketPtr pkt) = 0;
public:
typedef PioDeviceParams Params;
PioDevice(const Params *p);
virtual ~PioDevice();
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual void init();
virtual unsigned int drain(Event *de);
virtual SlavePort &getSlavePort(const std::string &if_name, int idx = -1);
friend class PioPort;
};
class BasicPioDevice : public PioDevice
{
protected:
/** Address that the device listens to. */
Addr pioAddr;
/** Size that the device's address range. */
Addr pioSize;
/** Delay that the device experinces on an access. */
Tick pioDelay;
public:
typedef BasicPioDeviceParams Params;
BasicPioDevice(const Params *p);
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* Determine the address ranges that this device responds to.
*
* @return a list of non-overlapping address ranges
*/
virtual AddrRangeList getAddrRanges();
};
#endif // __DEV_IO_DEVICE_HH__

View File

@ -0,0 +1,155 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Isa Fake Device implementation
*/
#include "base/trace.hh"
#include "debug/IsaFake.hh"
#include "dev/isa_fake.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "sim/system.hh"
using namespace std;
IsaFake::IsaFake(Params *p)
: BasicPioDevice(p)
{
if (!p->ret_bad_addr)
pioSize = p->pio_size;
retData8 = p->ret_data8;
retData16 = p->ret_data16;
retData32 = p->ret_data32;
retData64 = p->ret_data64;
}
Tick
IsaFake::read(PacketPtr pkt)
{
pkt->allocate();
pkt->makeAtomicResponse();
if (params()->warn_access != "")
warn("Device %s accessed by read to address %#x size=%d\n",
name(), pkt->getAddr(), pkt->getSize());
if (params()->ret_bad_addr) {
DPRINTF(IsaFake, "read to bad address va=%#x size=%d\n",
pkt->getAddr(), pkt->getSize());
pkt->setBadAddress();
} else {
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
DPRINTF(IsaFake, "read va=%#x size=%d\n",
pkt->getAddr(), pkt->getSize());
switch (pkt->getSize()) {
case sizeof(uint64_t):
pkt->set(retData64);
break;
case sizeof(uint32_t):
pkt->set(retData32);
break;
case sizeof(uint16_t):
pkt->set(retData16);
break;
case sizeof(uint8_t):
pkt->set(retData8);
break;
default:
if (params()->fake_mem)
std::memset(pkt->getPtr<uint8_t>(), 0, pkt->getSize());
else
panic("invalid access size! Device being accessed by cache?\n");
}
}
return pioDelay;
}
Tick
IsaFake::write(PacketPtr pkt)
{
pkt->makeAtomicResponse();
if (params()->warn_access != "") {
uint64_t data;
switch (pkt->getSize()) {
case sizeof(uint64_t):
data = pkt->get<uint64_t>();
break;
case sizeof(uint32_t):
data = pkt->get<uint32_t>();
break;
case sizeof(uint16_t):
data = pkt->get<uint16_t>();
break;
case sizeof(uint8_t):
data = pkt->get<uint8_t>();
break;
default:
panic("invalid access size!\n");
}
warn("Device %s accessed by write to address %#x size=%d data=%#x\n",
name(), pkt->getAddr(), pkt->getSize(), data);
}
if (params()->ret_bad_addr) {
DPRINTF(IsaFake, "write to bad address va=%#x size=%d \n",
pkt->getAddr(), pkt->getSize());
pkt->setBadAddress();
} else {
DPRINTF(IsaFake, "write - va=%#x size=%d \n",
pkt->getAddr(), pkt->getSize());
if (params()->update_data) {
switch (pkt->getSize()) {
case sizeof(uint64_t):
retData64 = pkt->get<uint64_t>();
break;
case sizeof(uint32_t):
retData32 = pkt->get<uint32_t>();
break;
case sizeof(uint16_t):
retData16 = pkt->get<uint16_t>();
break;
case sizeof(uint8_t):
retData8 = pkt->get<uint8_t>();
break;
default:
panic("invalid access size!\n");
}
}
}
return pioDelay;
}
IsaFake *
IsaFakeParams::create()
{
return new IsaFake(this);
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
/** @file
* Declaration of a fake device.
*/
#ifndef __ISA_FAKE_HH__
#define __ISA_FAKE_HH__
#include <string>
#include "base/range.hh"
#include "dev/io_device.hh"
// #include "dev/alpha/tsunami.hh"
#include "mem/packet.hh"
#include "params/IsaFake.hh"
/**
* IsaFake is a device that returns, BadAddr, 1 or 0 on all reads and
* rites. It is meant to be placed at an address range
* so that an mcheck doesn't occur when an os probes a piece of hw
* that doesn't exist (e.g. UARTs1-3), or catch requests in the memory system
* that have no responders..
*/
class IsaFake : public BasicPioDevice
{
protected:
uint8_t retData8;
uint16_t retData16;
uint32_t retData32;
uint64_t retData64;
public:
typedef IsaFakeParams Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
/**
* The constructor for Isa Fake just registers itself with the MMU.
* @param p params structure
*/
IsaFake(Params *p);
/**
* This read always returns -1.
* @param pkt The memory request.
* @param data Where to put the data.
*/
virtual Tick read(PacketPtr pkt);
/**
* All writes are simply ignored.
* @param pkt The memory request.
* @param data the data to not write.
*/
virtual Tick write(PacketPtr pkt);
};
#endif // __ISA_FAKE_HH__

View File

@ -0,0 +1,265 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Andrew Schultz
* Miguel Serrano
*/
#include <sys/time.h>
#include <ctime>
#include <string>
#include "base/bitfield.hh"
#include "base/time.hh"
#include "base/trace.hh"
#include "debug/MC146818.hh"
#include "dev/mc146818.hh"
#include "dev/rtcreg.h"
using namespace std;
static uint8_t
bcdize(uint8_t val)
{
uint8_t result;
result = val % 10;
result += (val / 10) << 4;
return result;
}
static uint8_t
unbcdize(uint8_t val)
{
uint8_t result;
result = val & 0xf;
result += (val >> 4) * 10;
return result;
}
void
MC146818::setTime(const struct tm time)
{
curTime = time;
year = time.tm_year;
// Unix is 0-11 for month, data seet says start at 1
mon = time.tm_mon + 1;
mday = time.tm_mday;
hour = time.tm_hour;
min = time.tm_min;
sec = time.tm_sec;
// Datasheet says 1 is sunday
wday = time.tm_wday + 1;
if (!(stat_regB & RTCB_BIN)) {
// The datasheet says that the year field can be either BCD or
// years since 1900. Linux seems to be happy with years since
// 1900.
year = bcdize(year % 100);
mon = bcdize(mon);
mday = bcdize(mday);
hour = bcdize(hour);
min = bcdize(min);
sec = bcdize(sec);
}
}
MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
bool bcd, Tick frequency)
: EventManager(em), _name(n), event(this, frequency), tickEvent(this)
{
memset(clock_data, 0, sizeof(clock_data));
stat_regA = RTCA_32768HZ | RTCA_1024HZ;
stat_regB = RTCB_PRDC_IE | RTCB_24HR;
if (!bcd)
stat_regB |= RTCB_BIN;
setTime(time);
DPRINTFN("Real-time clock set to %s", asctime(&time));
}
MC146818::~MC146818()
{
deschedule(tickEvent);
deschedule(event);
}
void
MC146818::writeData(const uint8_t addr, const uint8_t data)
{
if (addr < RTC_STAT_REGA) {
clock_data[addr] = data;
curTime.tm_sec = unbcdize(sec);
curTime.tm_min = unbcdize(min);
curTime.tm_hour = unbcdize(hour);
curTime.tm_mday = unbcdize(mday);
curTime.tm_mon = unbcdize(mon) - 1;
curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
curTime.tm_wday = unbcdize(wday) - 1;
} else {
switch (addr) {
case RTC_STAT_REGA:
// The "update in progress" bit is read only.
if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ))
panic("Unimplemented RTC register A value write!\n");
replaceBits(stat_regA, data, 6, 0);
break;
case RTC_STAT_REGB:
if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != RTCB_24HR)
panic("Write to RTC reg B bits that are not implemented!\n");
if (data & RTCB_PRDC_IE) {
if (!event.scheduled())
event.scheduleIntr();
} else {
if (event.scheduled())
deschedule(event);
}
stat_regB = data;
break;
case RTC_STAT_REGC:
case RTC_STAT_REGD:
panic("RTC status registers C and D are not implemented.\n");
break;
}
}
}
uint8_t
MC146818::readData(uint8_t addr)
{
if (addr < RTC_STAT_REGA)
return clock_data[addr];
else {
switch (addr) {
case RTC_STAT_REGA:
// toggle UIP bit for linux
stat_regA ^= RTCA_UIP;
return stat_regA;
break;
case RTC_STAT_REGB:
return stat_regB;
break;
case RTC_STAT_REGC:
case RTC_STAT_REGD:
return 0x00;
break;
default:
panic("Shouldn't be here");
}
}
}
void
MC146818::tickClock()
{
if (stat_regB & RTCB_NO_UPDT)
return;
time_t calTime = mkutctime(&curTime);
calTime++;
setTime(*gmtime(&calTime));
}
void
MC146818::serialize(const string &base, ostream &os)
{
arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
paramOut(os, base + ".stat_regA", stat_regA);
paramOut(os, base + ".stat_regB", stat_regB);
//
// save the timer tick and rtc clock tick values to correctly reschedule
// them during unserialize
//
Tick rtcTimerInterruptTickOffset = event.when() - curTick();
SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
Tick rtcClockTickOffset = tickEvent.when() - curTick();
SERIALIZE_SCALAR(rtcClockTickOffset);
}
void
MC146818::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
arrayParamIn(cp, section, base + ".clock_data", clock_data,
sizeof(clock_data));
paramIn(cp, section, base + ".stat_regA", stat_regA);
paramIn(cp, section, base + ".stat_regB", stat_regB);
//
// properly schedule the timer and rtc clock events
//
Tick rtcTimerInterruptTickOffset;
UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
reschedule(event, curTick() + rtcTimerInterruptTickOffset);
Tick rtcClockTickOffset;
UNSERIALIZE_SCALAR(rtcClockTickOffset);
reschedule(tickEvent, curTick() + rtcClockTickOffset);
}
MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
: parent(_parent), interval(i)
{
DPRINTF(MC146818, "RTC Event Initilizing\n");
parent->schedule(this, curTick() + interval);
}
void
MC146818::RTCEvent::scheduleIntr()
{
parent->schedule(this, curTick() + interval);
}
void
MC146818::RTCEvent::process()
{
DPRINTF(MC146818, "RTC Timer Interrupt\n");
parent->schedule(this, curTick() + interval);
parent->handleEvent();
}
const char *
MC146818::RTCEvent::description() const
{
return "RTC interrupt";
}
void
MC146818::RTCTickEvent::process()
{
DPRINTF(MC146818, "RTC clock tick\n");
parent->schedule(this, curTick() + SimClock::Int::s);
parent->tickClock();
}
const char *
MC146818::RTCTickEvent::description() const
{
return "RTC clock tick";
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Andrew Schultz
* Miguel Serrano
*/
#ifndef __DEV_MC146818_HH__
#define __DEV_MC146818_HH__
#include "base/range.hh"
#include "sim/eventq.hh"
/** Real-Time Clock (MC146818) */
class MC146818 : public EventManager
{
protected:
virtual void handleEvent()
{
warn("No RTC event handler defined.\n");
}
private:
/** Event for RTC periodic interrupt */
struct RTCEvent : public Event
{
MC146818 * parent;
Tick interval;
RTCEvent(MC146818 * _parent, Tick i);
/** Schedule the RTC periodic interrupt */
void scheduleIntr();
/** Event process to occur at interrupt*/
virtual void process();
/** Event description */
virtual const char *description() const;
};
/** Event for RTC periodic interrupt */
struct RTCTickEvent : public Event
{
MC146818 * parent;
RTCTickEvent(MC146818 * _parent) : parent(_parent)
{
parent->schedule(this, curTick() + SimClock::Int::s);
}
/** Event process to occur at interrupt*/
void process();
/** Event description */
const char *description() const;
};
private:
std::string _name;
const std::string &name() const { return _name; }
/** RTC periodic interrupt event */
RTCEvent event;
/** RTC tick event */
RTCTickEvent tickEvent;
/** Data for real-time clock function */
union {
uint8_t clock_data[10];
struct {
uint8_t sec;
uint8_t sec_alrm;
uint8_t min;
uint8_t min_alrm;
uint8_t hour;
uint8_t hour_alrm;
uint8_t wday;
uint8_t mday;
uint8_t mon;
uint8_t year;
};
};
struct tm curTime;
void setTime(const struct tm time);
/** RTC status register A */
uint8_t stat_regA;
/** RTC status register B */
uint8_t stat_regB;
public:
MC146818(EventManager *em, const std::string &name, const struct tm time,
bool bcd, Tick frequency);
virtual ~MC146818();
/** RTC write data */
void writeData(const uint8_t addr, const uint8_t data);
/** RTC read data */
uint8_t readData(const uint8_t addr);
void tickClock();
/**
* Serialize this object to the given output stream.
* @param base The base name of the counter object.
* @param os The stream to serialize to.
*/
void serialize(const std::string &base, std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param base The base name of the counter object.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
};
#endif // __DEV_MC146818_HH__

View File

@ -0,0 +1,68 @@
# Copyright (c) 2007 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
from m5.params import *
from m5.proxy import *
from BadDevice import BadDevice
from Device import BasicPioDevice
from Pci import PciConfigAll
from Platform import Platform
from Uart import Uart8250
class MaltaCChip(BasicPioDevice):
type = 'MaltaCChip'
malta = Param.Malta(Parent.any, "Malta")
class MaltaIO(BasicPioDevice):
type = 'MaltaIO'
time = Param.Time('01/01/2009',
"System time to use (0 for actual time, default is 1/1/06)")
year_is_bcd = Param.Bool(False,
"The RTC should interpret the year as a BCD value")
malta = Param.Malta(Parent.any, "Malta")
frequency = Param.Frequency('1024Hz', "frequency of interrupts")
class MaltaPChip(BasicPioDevice):
type = 'MaltaPChip'
malta = Param.Malta(Parent.any, "Malta")
class Malta(Platform):
type = 'Malta'
system = Param.System(Parent.any, "system")
cchip = MaltaCChip(pio_addr=0x801a0000000)
io = MaltaIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0xBFD003F8)
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
self.cchip.pio = bus.master
self.io.pio = bus.master
self.uart.pio = bus.master

View File

@ -0,0 +1,42 @@
# -*- mode:python -*-
# 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: Steve Reinhardt
# Gabe Black
Import('*')
if env['TARGET_ISA'] == 'mips':
SimObject('Malta.py')
DebugFlag('Malta')
Source('malta.cc')
Source('malta_cchip.cc')
Source('malta_io.cc')
Source('malta_pchip.cc')

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
#ifndef __MIPS_ACCESS_H__
#define __MIPS_ACCESS_H__
/** @file
* System Console Memory Mapped Register Definition
*/
#define MIPS_ACCESS_VERSION (1305)
#define CONSOLE_START_ADDRESS 0xBFD00F00
#define REG_OFFSET 1
#define UART8250_BASE 0xBFD003F8
#define UART8250_END 7*REG_OFFSET
#ifdef CONSOLE
typedef unsigned uint32_t;
typedef unsigned long uint64_t;
#endif
// This structure hacked up from simos
struct MipsAccess
{
uint32_t inputChar; // 00: Placeholder for input
uint32_t last_offset; // 04: must be first field
uint32_t version; // 08:
uint32_t numCPUs; // 0C:
uint32_t intrClockFrequency; // 10: Hz
// Loaded kernel
uint32_t kernStart; // 14:
uint32_t kernEnd; // 18:
uint32_t entryPoint; // 1c:
// console simple output stuff
uint32_t outputChar; // 20: Placeholder for output
// console disk stuff
uint32_t diskUnit; // 24:
uint32_t diskCount; // 28:
uint32_t diskPAddr; // 2c:
uint32_t diskBlock; // 30:
uint32_t diskOperation; // 34:
// MP boot
uint32_t cpuStack[64]; // 70:
/* XXX There appears to be a problem in accessing
* unit64_t in the console.c file. They are treated
* like uint32_int and result in the wrong address for
* everything below. This problem should be investigated.
*/
uint64_t cpuClock; // 38: MHz
uint64_t mem_size; // 40:
};
#endif // __MIPS_ACCESS_H__

Binary file not shown.

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Rick Strong
*/
/** @file
* Implementation of Malta platform.
*/
#include <deque>
#include <string>
#include <vector>
#include "config/the_isa.hh"
#include "cpu/intr_control.hh"
#include "debug/Malta.hh"
#include "dev/mips/malta.hh"
#include "dev/mips/malta_cchip.hh"
#include "dev/mips/malta_io.hh"
#include "dev/mips/malta_pchip.hh"
#include "dev/terminal.hh"
#include "params/Malta.hh"
#include "sim/system.hh"
using namespace std;
using namespace TheISA;
Malta::Malta(const Params *p)
: Platform(p), system(p->system)
{
for (int i = 0; i < Malta::Max_CPUs; i++)
intr_sum_type[i] = 0;
}
void
Malta::postConsoleInt()
{
//see {Linux-src}/arch/mips/mips-boards/sim/sim_setup.c
io->postIntr(0x10/*HW4*/);
}
void
Malta::clearConsoleInt()
{
//FIXME: implement clearConsoleInt()
io->clearIntr(0x10/*HW4*/);
}
void
Malta::postPciInt(int line)
{
panic("Malta::postPciInt() has not been implemented.");
}
void
Malta::clearPciInt(int line)
{
panic("Malta::clearPciInt() has not been implemented.");
}
Addr
Malta::pciToDma(Addr pciAddr) const
{
panic("Malta::pciToDma() has not been implemented.");
}
void
Malta::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(intr_sum_type, Malta::Max_CPUs);
}
void
Malta::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(intr_sum_type, Malta::Max_CPUs);
}
Malta *
MaltaParams::create()
{
return new Malta(this);
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
* Rick Strong
*/
/**
* @file
* Declaration of top level class for the Malta chipset. This class just
* retains pointers to all its children so the children can communicate.
*/
#ifndef __DEV_MALTA_HH__
#define __DEV_MALTA_HH__
#include "dev/platform.hh"
#include "params/Malta.hh"
class IdeController;
class MaltaCChip;
class MaltaPChip;
class MaltaIO;
class System;
/**
* Top level class for Malta Chipset emulation.
* This structure just contains pointers to all the
* children so the children can commnicate to do the
* read work
*/
class Malta : public Platform
{
public:
/** Max number of CPUs in a Malta */
static const int Max_CPUs = 64;
/** Pointer to the system */
System *system;
/** Pointer to the MaltaIO device which has the RTC */
MaltaIO *io;
/** Pointer to the Malta CChip.
* The chip contains some configuration information and
* all the interrupt mask and status registers
*/
MaltaCChip *cchip;
/** Pointer to the Malta PChip.
* The pchip is the interface to the PCI bus, in our case
* it does not have to do much.
*/
MaltaPChip *pchip;
int intr_sum_type[Malta::Max_CPUs];
int ipi_pending[Malta::Max_CPUs];
public:
/**
* Constructor for the Malta Class.
* @param name name of the object
* @param s system the object belongs to
* @param intctrl pointer to the interrupt controller
*/
typedef MaltaParams Params;
Malta(const Params *p);
/**
* Cause the cpu to post a serial interrupt to the CPU.
*/
virtual void postConsoleInt();
/**
* Clear a posted CPU interrupt (id=55)
*/
virtual void clearConsoleInt();
/**
* Cause the chipset to post a cpi interrupt to the CPU.
*/
virtual void postPciInt(int line);
/**
* Clear a posted PCI->CPU interrupt
*/
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
Addr
calcPciConfigAddr(int bus, int dev, int func)
{
panic("Need implementation\n");
M5_DUMMY_RETURN
}
Addr
calcPciIOAddr(Addr addr)
{
panic("Need implementation\n");
M5_DUMMY_RETURN
}
Addr
calcPciMemAddr(Addr addr)
{
panic("Need implementation\n");
M5_DUMMY_RETURN
}
/**
* Serialize this object to the given output stream.
* @param os The stream to serialize to.
*/
virtual void serialize(std::ostream &os);
/**
* Reconstruct the state of this object from a checkpoint.
* @param cp The checkpoint use.
* @param section The section name of this object
*/
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __DEV_MALTA_HH__

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