summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/CopyEngine.py59
-rw-r--r--src/dev/DiskImage.py1
-rw-r--r--src/dev/Ethernet.py30
-rw-r--r--src/dev/Pci.py6
-rw-r--r--src/dev/SConscript18
-rw-r--r--src/dev/Terminal.py (renamed from src/dev/SimConsole.py)9
-rw-r--r--src/dev/Uart.py2
-rw-r--r--src/dev/alpha/AlphaBackdoor.py (renamed from src/dev/alpha/AlphaConsole.py)6
-rw-r--r--src/dev/alpha/SConscript7
-rw-r--r--src/dev/alpha/Tsunami.py10
-rw-r--r--src/dev/alpha/access.h34
-rw-r--r--src/dev/alpha/backdoor.cc (renamed from src/dev/alpha/console.cc)42
-rw-r--r--src/dev/alpha/backdoor.hh (renamed from src/dev/alpha/console.hh)22
-rw-r--r--src/dev/alpha/tsunami.cc16
-rw-r--r--src/dev/alpha/tsunami.hh12
-rw-r--r--src/dev/alpha/tsunami_cchip.cc10
-rw-r--r--src/dev/alpha/tsunami_io.cc404
-rw-r--r--src/dev/alpha/tsunami_io.hh228
-rw-r--r--src/dev/alpha/tsunami_pchip.cc11
-rw-r--r--src/dev/alpha/tsunami_pchip.hh2
-rw-r--r--src/dev/copy_engine.cc764
-rw-r--r--src/dev/copy_engine.hh199
-rw-r--r--src/dev/copy_engine_defs.hh225
-rw-r--r--src/dev/etherbus.cc4
-rw-r--r--src/dev/etherbus.hh3
-rw-r--r--src/dev/etherdevice.cc367
-rw-r--r--src/dev/etherdevice.hh54
-rw-r--r--src/dev/etherdump.cc49
-rw-r--r--src/dev/etherdump.hh4
-rw-r--r--src/dev/etherlink.cc16
-rw-r--r--src/dev/etherpkt.cc2
-rw-r--r--src/dev/etherpkt.hh17
-rw-r--r--src/dev/ethertap.cc15
-rw-r--r--src/dev/ethertap.hh3
-rw-r--r--src/dev/i8254xGBe.cc850
-rw-r--r--src/dev/i8254xGBe.hh293
-rw-r--r--src/dev/i8254xGBe_defs.hh227
-rw-r--r--src/dev/ide_ctrl.cc832
-rw-r--r--src/dev/ide_ctrl.hh246
-rw-r--r--src/dev/ide_disk.cc224
-rw-r--r--src/dev/ide_disk.hh18
-rw-r--r--src/dev/intel_8254_timer.cc278
-rw-r--r--src/dev/intel_8254_timer.hh244
-rw-r--r--src/dev/io_device.cc19
-rw-r--r--src/dev/io_device.hh30
-rw-r--r--src/dev/mc146818.cc192
-rw-r--r--src/dev/mc146818.hh126
-rwxr-xr-xsrc/dev/mips/Malta.py11
-rw-r--r--src/dev/mips/MipsBackdoor.py (renamed from src/dev/mips/MipsConsole.py)6
-rwxr-xr-xsrc/dev/mips/SConscript4
-rwxr-xr-xsrc/dev/mips/access.h34
-rwxr-xr-xsrc/dev/mips/backdoor.cc (renamed from src/dev/mips/console.cc)38
-rwxr-xr-xsrc/dev/mips/backdoor.hh (renamed from src/dev/mips/console.hh)24
-rwxr-xr-xsrc/dev/mips/malta.cc2
-rwxr-xr-xsrc/dev/mips/malta_cchip.cc2
-rw-r--r--src/dev/ns_gige.cc395
-rw-r--r--src/dev/ns_gige.hh63
-rw-r--r--src/dev/pciconfigall.cc2
-rw-r--r--src/dev/pcidev.cc79
-rw-r--r--src/dev/pcidev.hh3
-rw-r--r--src/dev/pcireg.h120
-rw-r--r--src/dev/pktfifo.cc55
-rw-r--r--src/dev/pktfifo.hh108
-rw-r--r--src/dev/platform.hh6
-rw-r--r--src/dev/rtcreg.h50
-rw-r--r--src/dev/sinic.cc242
-rw-r--r--src/dev/sinic.hh79
-rw-r--r--src/dev/sinicreg.hh91
-rw-r--r--src/dev/sparc/T1000.py12
-rw-r--r--src/dev/sparc/iob.cc6
-rw-r--r--src/dev/sparc/t1000.cc18
-rw-r--r--src/dev/sparc/t1000.hh12
-rw-r--r--src/dev/terminal.cc (renamed from src/dev/simconsole.cc)116
-rw-r--r--src/dev/terminal.hh (renamed from src/dev/simconsole.hh)36
-rw-r--r--src/dev/uart.cc8
-rw-r--r--src/dev/uart.hh4
-rw-r--r--src/dev/uart8250.cc30
-rw-r--r--src/dev/uart8250.hh2
-rw-r--r--src/dev/x86/Cmos.py41
-rw-r--r--src/dev/x86/I8042.py45
-rw-r--r--src/dev/x86/I82094AA.py43
-rw-r--r--src/dev/x86/I8237.py36
-rw-r--r--src/dev/x86/I8254.py39
-rw-r--r--src/dev/x86/I8259.py50
-rw-r--r--src/dev/x86/Opteron.py18
-rw-r--r--src/dev/x86/Pc.py83
-rw-r--r--src/dev/x86/PcSpeaker.py37
-rw-r--r--src/dev/x86/SConscript40
-rw-r--r--src/dev/x86/SouthBridge.py122
-rw-r--r--src/dev/x86/X86IntPin.py51
-rw-r--r--src/dev/x86/cmos.cc118
-rw-r--r--src/dev/x86/cmos.hh89
-rw-r--r--src/dev/x86/i8042.cc446
-rw-r--r--src/dev/x86/i8042.hh259
-rw-r--r--src/dev/x86/i82094aa.cc236
-rw-r--r--src/dev/x86/i82094aa.hh127
-rw-r--r--src/dev/x86/i8237.cc132
-rw-r--r--src/dev/x86/i8237.hh66
-rw-r--r--src/dev/x86/i8254.cc (renamed from src/dev/x86/opteron.cc)108
-rw-r--r--src/dev/x86/i8254.hh116
-rw-r--r--src/dev/x86/i8259.cc310
-rw-r--r--src/dev/x86/i8259.hh105
-rw-r--r--src/dev/x86/intdev.cc49
-rw-r--r--src/dev/x86/intdev.hh216
-rw-r--r--src/dev/x86/pc.cc176
-rw-r--r--src/dev/x86/pc.hh (renamed from src/dev/x86/opteron.hh)37
-rw-r--r--src/dev/x86/south_bridge.cc52
-rw-r--r--src/dev/x86/south_bridge.hh70
-rw-r--r--src/dev/x86/speaker.cc79
-rw-r--r--src/dev/x86/speaker.hh (renamed from src/dev/pitreg.h)76
110 files changed, 8597 insertions, 2763 deletions
diff --git a/src/dev/CopyEngine.py b/src/dev/CopyEngine.py
new file mode 100644
index 000000000..29d9a23dd
--- /dev/null
+++ b/src/dev/CopyEngine.py
@@ -0,0 +1,59 @@
+# 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'
+ 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")
+
+
diff --git a/src/dev/DiskImage.py b/src/dev/DiskImage.py
index af2407458..92eb0553c 100644
--- a/src/dev/DiskImage.py
+++ b/src/dev/DiskImage.py
@@ -42,3 +42,4 @@ class CowDiskImage(DiskImage):
child = Param.DiskImage(RawDiskImage(read_only=True),
"child image")
table_size = Param.Int(65536, "initial table size")
+ image_file = ""
diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py
index 2beb0d537..d73d56d03 100644
--- a/src/dev/Ethernet.py
+++ b/src/dev/Ethernet.py
@@ -67,6 +67,7 @@ class EtherDevice(PciDevice):
interface = Port("Ethernet Interrface")
class IGbE(EtherDevice):
+ # Base class for two IGbE adapters listed above
type = 'IGbE'
hardware_address = Param.EthernetAddr(NextEthernetAddr,
"Ethernet Hardware Address")
@@ -80,7 +81,6 @@ class IGbE(EtherDevice):
"Number of enteries in the rx descriptor cache")
clock = Param.Clock('500MHz', "Clock speed of the device")
VendorID = 0x8086
- DeviceID = 0x1075
SubsystemID = 0x1008
SubsystemVendorID = 0x8086
Status = 0x0000
@@ -98,6 +98,28 @@ class IGbE(EtherDevice):
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'
@@ -153,8 +175,7 @@ class NSGigE(EtherDevBase):
class Sinic(EtherDevBase):
type = 'Sinic'
- cxx_namespace = 'Sinic'
- cxx_class = 'Device'
+ cxx_class = 'Sinic::Device'
rx_max_copy = Param.MemorySize('1514B', "rx max copy")
tx_max_copy = Param.MemorySize('16kB', "tx max copy")
@@ -164,6 +185,9 @@ class Sinic(EtherDevBase):
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")
diff --git a/src/dev/Pci.py b/src/dev/Pci.py
index b50e1b15c..bd67d82fb 100644
--- a/src/dev/Pci.py
+++ b/src/dev/Pci.py
@@ -73,6 +73,12 @@ class PciDevice(DmaDevice):
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")
diff --git a/src/dev/SConscript b/src/dev/SConscript
index 0aba8ac35..c09ec3dcd 100644
--- a/src/dev/SConscript
+++ b/src/dev/SConscript
@@ -33,19 +33,22 @@ Import('*')
if env['FULL_SYSTEM']:
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('SimConsole.py')
SimObject('SimpleDisk.py')
+ SimObject('Terminal.py')
SimObject('Uart.py')
Source('baddev.cc')
+ Source('copy_engine.cc')
Source('disk_image.cc')
Source('etherbus.cc')
+ Source('etherdevice.cc')
Source('etherdump.cc')
Source('etherint.cc')
Source('etherlink.cc')
@@ -54,24 +57,25 @@ if env['FULL_SYSTEM']:
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('simconsole.cc')
Source('simple_disk.cc')
Source('sinic.cc')
+ Source('terminal.cc')
Source('uart.cc')
Source('uart8250.cc')
- TraceFlag('Console')
- TraceFlag('ConsoleVerbose')
TraceFlag('DiskImageRead')
TraceFlag('DiskImageWrite')
TraceFlag('DMA')
+ TraceFlag('DMACopyEngine')
TraceFlag('Ethernet')
TraceFlag('EthernetCksum')
TraceFlag('EthernetDMA')
@@ -83,17 +87,21 @@ if env['FULL_SYSTEM']:
TraceFlag('EthernetSM')
TraceFlag('IdeCtrl')
TraceFlag('IdeDisk')
+ TraceFlag('Intel8254Timer')
TraceFlag('IsaFake')
+ TraceFlag('MC146818')
TraceFlag('PCIDEV')
TraceFlag('PciConfigAll')
TraceFlag('SimpleDisk')
TraceFlag('SimpleDiskData')
+ TraceFlag('Terminal')
+ TraceFlag('TerminalVerbose')
TraceFlag('Uart')
CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
- 'EthernetCksum' ])
+ 'EthernetCksum', 'EthernetEEPROM' ])
CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])
diff --git a/src/dev/SimConsole.py b/src/dev/Terminal.py
index bb8420527..d67019198 100644
--- a/src/dev/SimConsole.py
+++ b/src/dev/Terminal.py
@@ -30,10 +30,9 @@ from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
-class SimConsole(SimObject):
- type = 'SimConsole'
- append_name = Param.Bool(True, "append name() to filename")
+class Terminal(SimObject):
+ type = 'Terminal'
intr_control = Param.IntrControl(Parent.any, "interrupt controller")
port = Param.TcpPort(3456, "listen port")
- number = Param.Int(0, "console number")
- output = Param.String('console', "file to dump output to")
+ number = Param.Int(0, "terminal number")
+ output = Param.Bool(True, "Enable output dump to file")
diff --git a/src/dev/Uart.py b/src/dev/Uart.py
index e32517a4c..c5db3c42f 100644
--- a/src/dev/Uart.py
+++ b/src/dev/Uart.py
@@ -34,7 +34,7 @@ from Device import BasicPioDevice
class Uart(BasicPioDevice):
type = 'Uart'
abstract = True
- sim_console = Param.SimConsole(Parent.any, "The console")
+ terminal = Param.Terminal(Parent.any, "The terminal")
class Uart8250(Uart):
type = 'Uart8250'
diff --git a/src/dev/alpha/AlphaConsole.py b/src/dev/alpha/AlphaBackdoor.py
index 43c7ef954..fa9627164 100644
--- a/src/dev/alpha/AlphaConsole.py
+++ b/src/dev/alpha/AlphaBackdoor.py
@@ -30,9 +30,9 @@ from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
-class AlphaConsole(BasicPioDevice):
- type = 'AlphaConsole'
+class AlphaBackdoor(BasicPioDevice):
+ type = 'AlphaBackdoor'
cpu = Param.BaseCPU(Parent.cpu[0], "Processor")
disk = Param.SimpleDisk("Simple Disk")
- sim_console = Param.SimConsole(Parent.any, "The Simulator Console")
+ terminal = Param.Terminal(Parent.any, "The console terminal")
system = Param.AlphaSystem(Parent.any, "system object")
diff --git a/src/dev/alpha/SConscript b/src/dev/alpha/SConscript
index 2292c3c57..4dbb73903 100644
--- a/src/dev/alpha/SConscript
+++ b/src/dev/alpha/SConscript
@@ -32,15 +32,14 @@
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'alpha':
- SimObject('AlphaConsole.py')
+ SimObject('AlphaBackdoor.py')
SimObject('Tsunami.py')
- Source('console.cc')
+ Source('backdoor.cc')
Source('tsunami.cc')
Source('tsunami_cchip.cc')
Source('tsunami_io.cc')
Source('tsunami_pchip.cc')
- TraceFlag('AlphaConsole')
- TraceFlag('MC146818')
+ TraceFlag('AlphaBackdoor')
TraceFlag('Tsunami')
diff --git a/src/dev/alpha/Tsunami.py b/src/dev/alpha/Tsunami.py
index 484976c09..5440486b6 100644
--- a/src/dev/alpha/Tsunami.py
+++ b/src/dev/alpha/Tsunami.py
@@ -28,12 +28,12 @@
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 AlphaConsole import AlphaConsole
from Uart import Uart8250
-from Pci import PciConfigAll
-from BadDevice import BadDevice
class TsunamiCChip(BasicPioDevice):
type = 'TsunamiCChip'
@@ -87,7 +87,7 @@ class Tsunami(Platform):
fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer')
io = TsunamiIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0x801fc0003f8)
- console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk)
+ 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
@@ -120,4 +120,4 @@ class Tsunami(Platform):
self.fb.pio = bus.port
self.io.pio = bus.port
self.uart.pio = bus.port
- self.console.pio = bus.port
+ self.backdoor.pio = bus.port
diff --git a/src/dev/alpha/access.h b/src/dev/alpha/access.h
index 4adeaf84b..72eb4950a 100644
--- a/src/dev/alpha/access.h
+++ b/src/dev/alpha/access.h
@@ -45,31 +45,31 @@ typedef unsigned long uint64_t;
// 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:
+ 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:
+ 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:
+ 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
+ uint64_t outputChar; // 60: Placeholder for output
+ uint64_t inputChar; // 68: Placeholder for input
// MP boot
- uint64_t cpuStack[64]; // 70:
+ uint64_t cpuStack[64]; // 70:
};
#endif // __ALPHA_ACCESS_H__
diff --git a/src/dev/alpha/console.cc b/src/dev/alpha/backdoor.cc
index 493a21f99..66f682e66 100644
--- a/src/dev/alpha/console.cc
+++ b/src/dev/alpha/backdoor.cc
@@ -32,7 +32,7 @@
*/
/** @file
- * Alpha Console Definition
+ * Alpha Console Backdoor Definition
*/
#include <cstddef>
@@ -44,21 +44,21 @@
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "dev/alpha/console.hh"
+#include "dev/alpha/backdoor.hh"
#include "dev/platform.hh"
-#include "dev/simconsole.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/AlphaConsole.hh"
+#include "params/AlphaBackdoor.hh"
#include "sim/sim_object.hh"
using namespace std;
using namespace AlphaISA;
-AlphaConsole::AlphaConsole(const Params *p)
- : BasicPioDevice(p), disk(p->disk), console(p->sim_console),
+AlphaBackdoor::AlphaBackdoor(const Params *p)
+ : BasicPioDevice(p), disk(p->disk), terminal(p->terminal),
system(p->system), cpu(p->cpu)
{
@@ -81,10 +81,10 @@ AlphaConsole::AlphaConsole(const Params *p)
}
void
-AlphaConsole::startup()
+AlphaBackdoor::startup()
{
system->setAlphaAccess(pioAddr);
- alphaAccess->numCPUs = system->getNumCPUs();
+ alphaAccess->numCPUs = system->numContexts();
alphaAccess->kernStart = system->getKernelStart();
alphaAccess->kernEnd = system->getKernelEnd();
alphaAccess->entryPoint = system->getKernelEntry();
@@ -94,7 +94,7 @@ AlphaConsole::startup()
}
Tick
-AlphaConsole::read(PacketPtr pkt)
+AlphaBackdoor::read(PacketPtr pkt)
{
/** XXX Do we want to push the addr munging to a bus brige or something? So
@@ -132,14 +132,14 @@ AlphaConsole::read(PacketPtr pkt)
*/
pkt->setBadAddress();
}
- DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ 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(console->console_in());
+ pkt->set(terminal->console_in());
break;
case offsetof(AlphaAccess, cpuClock):
pkt->set(alphaAccess->cpuClock);
@@ -183,7 +183,7 @@ AlphaConsole::read(PacketPtr pkt)
else
panic("Unknown 64bit access, %#x\n", daddr);
}
- DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr,
pkt->get<uint64_t>());
break;
default:
@@ -193,7 +193,7 @@ AlphaConsole::read(PacketPtr pkt)
}
Tick
-AlphaConsole::write(PacketPtr pkt)
+AlphaBackdoor::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
@@ -228,7 +228,7 @@ AlphaConsole::write(PacketPtr pkt)
break;
case offsetof(AlphaAccess, outputChar):
- console->out((char)(val & 0xff));
+ terminal->out((char)(val & 0xff));
break;
default:
@@ -248,7 +248,7 @@ AlphaConsole::write(PacketPtr pkt)
}
void
-AlphaConsole::Access::serialize(ostream &os)
+AlphaBackdoor::Access::serialize(ostream &os)
{
SERIALIZE_SCALAR(last_offset);
SERIALIZE_SCALAR(version);
@@ -270,7 +270,7 @@ AlphaConsole::Access::serialize(ostream &os)
}
void
-AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
+AlphaBackdoor::Access::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(last_offset);
UNSERIALIZE_SCALAR(version);
@@ -292,19 +292,19 @@ AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
}
void
-AlphaConsole::serialize(ostream &os)
+AlphaBackdoor::serialize(ostream &os)
{
alphaAccess->serialize(os);
}
void
-AlphaConsole::unserialize(Checkpoint *cp, const std::string &section)
+AlphaBackdoor::unserialize(Checkpoint *cp, const std::string &section)
{
alphaAccess->unserialize(cp, section);
}
-AlphaConsole *
-AlphaConsoleParams::create()
+AlphaBackdoor *
+AlphaBackdoorParams::create()
{
- return new AlphaConsole(this);
+ return new AlphaBackdoor(this);
}
diff --git a/src/dev/alpha/console.hh b/src/dev/alpha/backdoor.hh
index e77a7fad6..ad3c79823 100644
--- a/src/dev/alpha/console.hh
+++ b/src/dev/alpha/backdoor.hh
@@ -29,28 +29,28 @@
*/
/** @file
- * System Console Interface
+ * System Console Backdoor Interface
*/
-#ifndef __ALPHA_CONSOLE_HH__
-#define __ALPHA_CONSOLE_HH__
+#ifndef __DEV_ALPHA_BACKDOOR_HH__
+#define __DEV_ALPHA_BACKDOOR_HH__
#include "base/range.hh"
#include "dev/alpha/access.h"
#include "dev/io_device.hh"
-#include "params/AlphaConsole.hh"
+#include "params/AlphaBackdoor.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
class BaseCPU;
-class SimConsole;
+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.
+ * 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
@@ -72,7 +72,7 @@ class SimpleDisk;
* primarily used doing boot before the kernel has loaded its device
* drivers.
*/
-class AlphaConsole : public BasicPioDevice
+class AlphaBackdoor : public BasicPioDevice
{
protected:
struct Access : public AlphaAccess
@@ -90,7 +90,7 @@ class AlphaConsole : public BasicPioDevice
SimpleDisk *disk;
/** the system console (the terminal) is accessable from the console */
- SimConsole *console;
+ Terminal *terminal;
/** a pointer to the system we are running in */
AlphaSystem *system;
@@ -99,8 +99,8 @@ class AlphaConsole : public BasicPioDevice
BaseCPU *cpu;
public:
- typedef AlphaConsoleParams Params;
- AlphaConsole(const Params *p);
+ typedef AlphaBackdoorParams Params;
+ AlphaBackdoor(const Params *p);
const Params *
params() const
@@ -123,4 +123,4 @@ class AlphaConsole : public BasicPioDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
-#endif // __ALPHA_CONSOLE_HH__
+#endif // __DEV_ALPHA_BACKDOOR_HH__
diff --git a/src/dev/alpha/tsunami.cc b/src/dev/alpha/tsunami.cc
index 5bc0de5da..b6478fe22 100644
--- a/src/dev/alpha/tsunami.cc
+++ b/src/dev/alpha/tsunami.cc
@@ -37,11 +37,11 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_pchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/alpha/tsunami.hh"
+#include "dev/terminal.hh"
#include "sim/system.hh"
using namespace std;
@@ -96,11 +96,23 @@ Tsunami::pciToDma(Addr pciAddr) const
Addr
-Tsunami::calcConfigAddr(int bus, int dev, int func)
+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)
{
diff --git a/src/dev/alpha/tsunami.hh b/src/dev/alpha/tsunami.hh
index 44c5d41a4..64aafe533 100644
--- a/src/dev/alpha/tsunami.hh
+++ b/src/dev/alpha/tsunami.hh
@@ -116,7 +116,17 @@ class Tsunami : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int 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.
diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc
index 891fe17da..52a2aea14 100644
--- a/src/dev/alpha/tsunami_cchip.cc
+++ b/src/dev/alpha/tsunami_cchip.cc
@@ -109,8 +109,14 @@ TsunamiCChip::read(PacketPtr pkt)
panic("TSDEV_CC_MTR not implemeted\n");
break;
case TSDEV_CC_MISC:
- pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
- (pkt->req->getCpuNum() & 0x3));
+ 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:
diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc
index 710aca48d..9c88904e3 100644
--- a/src/dev/alpha/tsunami_io.cc
+++ b/src/dev/alpha/tsunami_io.cc
@@ -42,7 +42,6 @@
#include "base/time.hh"
#include "base/trace.hh"
-#include "dev/pitreg.h"
#include "dev/rtcreg.h"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami.hh"
@@ -57,386 +56,15 @@ using namespace std;
//Should this be AlphaISA?
using namespace TheISA;
-TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami,
- const TsunamiIO::Params *p)
- : _name(n), event(tsunami, p->frequency), addr(0)
+TsunamiIO::RTC::RTC(const string &n, const TsunamiIOParams *p)
+ : MC146818(p->tsunami, n, p->time, p->year_is_bcd, p->frequency),
+ tsunami(p->tsunami)
{
- memset(clock_data, 0, sizeof(clock_data));
- stat_regA = RTCA_32768HZ | RTCA_1024HZ;
- stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
-
- year = p->time.tm_year;
-
- if (p->year_is_bcd) {
- // 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 = year % 100;
- int tens = year / 10;
- int ones = year % 10;
- year = (tens << 4) + ones;
- }
-
- // Unix is 0-11 for month, data seet says start at 1
- mon = p->time.tm_mon + 1;
- mday = p->time.tm_mday;
- hour = p->time.tm_hour;
- min = p->time.tm_min;
- sec = p->time.tm_sec;
-
- // Datasheet says 1 is sunday
- wday = p->time.tm_wday + 1;
-
- DPRINTFN("Real-time clock set to %s", asctime(&p->time));
-}
-
-void
-TsunamiIO::RTC::writeAddr(const uint8_t data)
-{
- if (data <= RTC_STAT_REGD)
- addr = data;
- else
- panic("RTC addresses over 0xD are not implemented.\n");
-}
-
-void
-TsunamiIO::RTC::writeData(const uint8_t data)
-{
- if (addr < RTC_STAT_REGA)
- clock_data[addr] = data;
- else {
- switch (addr) {
- case RTC_STAT_REGA:
- if (data != (RTCA_32768HZ | RTCA_1024HZ))
- panic("Unimplemented RTC register A value write!\n");
- stat_regA = data;
- break;
- case RTC_STAT_REGB:
- if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | 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())
- event.deschedule();
- }
- 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
-TsunamiIO::RTC::readData()
-{
- 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
-TsunamiIO::RTC::serialize(const string &base, ostream &os)
-{
- paramOut(os, base + ".addr", addr);
- arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
- paramOut(os, base + ".stat_regA", stat_regA);
- paramOut(os, base + ".stat_regB", stat_regB);
-}
-
-void
-TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
- const string &section)
-{
- paramIn(cp, section, base + ".addr", addr);
- 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);
-
- // We're not unserializing the event here, but we need to
- // rescehedule the event since curTick was moved forward by the
- // checkpoint
- event.reschedule(curTick + event.interval);
-}
-
-TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
- : Event(&mainEventQueue), tsunami(t), interval(i)
-{
- DPRINTF(MC146818, "RTC Event Initilizing\n");
- schedule(curTick + interval);
-}
-
-void
-TsunamiIO::RTC::RTCEvent::scheduleIntr()
-{
- schedule(curTick + interval);
-}
-
-void
-TsunamiIO::RTC::RTCEvent::process()
-{
- DPRINTF(MC146818, "RTC Timer Interrupt\n");
- schedule(curTick + interval);
- //Actually interrupt the processor here
- tsunami->cchip->postRTC();
-}
-
-const char *
-TsunamiIO::RTC::RTCEvent::description() const
-{
- return "tsunami RTC interrupt";
-}
-
-TsunamiIO::PITimer::PITimer(const string &name)
- : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
- counter2(name + ".counter2")
-{
- counter[0] = &counter0;
- counter[1] = &counter0;
- counter[2] = &counter0;
-}
-
-void
-TsunamiIO::PITimer::writeControl(const uint8_t data)
-{
- int rw;
- int sel;
-
- sel = GET_CTRL_SEL(data);
-
- if (sel == PIT_READ_BACK)
- panic("PITimer Read-Back Command is not implemented.\n");
-
- rw = GET_CTRL_RW(data);
-
- if (rw == PIT_RW_LATCH_COMMAND)
- counter[sel]->latchCount();
- else {
- counter[sel]->setRW(rw);
- counter[sel]->setMode(GET_CTRL_MODE(data));
- counter[sel]->setBCD(GET_CTRL_BCD(data));
- }
-}
-
-void
-TsunamiIO::PITimer::serialize(const string &base, ostream &os)
-{
- // serialize the counters
- counter0.serialize(base + ".counter0", os);
- counter1.serialize(base + ".counter1", os);
- counter2.serialize(base + ".counter2", os);
-}
-
-void
-TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
- const string &section)
-{
- // unserialze the counters
- counter0.unserialize(base + ".counter0", cp, section);
- counter1.unserialize(base + ".counter1", cp, section);
- counter2.unserialize(base + ".counter2", cp, section);
-}
-
-TsunamiIO::PITimer::Counter::Counter(const string &name)
- : _name(name), event(this), count(0), latched_count(0), period(0),
- mode(0), output_high(false), latch_on(false), read_byte(LSB),
- write_byte(LSB)
-{
-
-}
-
-void
-TsunamiIO::PITimer::Counter::latchCount()
-{
- // behave like a real latch
- if(!latch_on) {
- latch_on = true;
- read_byte = LSB;
- latched_count = count;
- }
-}
-
-uint8_t
-TsunamiIO::PITimer::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 {
- 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
-TsunamiIO::PITimer::Counter::write(const uint8_t data)
-{
- switch (write_byte) {
- case LSB:
- count = (count & 0xFF00) | data;
-
- if (event.scheduled())
- event.deschedule();
- output_high = false;
- write_byte = MSB;
- break;
-
- case MSB:
- count = (count & 0x00FF) | (data << 8);
- period = count;
-
- if (period > 0) {
- DPRINTF(Tsunami, "Timer set to curTick + %d\n",
- count * event.interval);
- event.schedule(curTick + count * event.interval);
- }
- write_byte = LSB;
- break;
- }
-}
-
-void
-TsunamiIO::PITimer::Counter::setRW(int rw_val)
-{
- if (rw_val != PIT_RW_16BIT)
- panic("Only LSB/MSB read/write is implemented.\n");
-}
-
-void
-TsunamiIO::PITimer::Counter::setMode(int mode_val)
-{
- if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
- mode_val != PIT_MODE_SQWAVE)
- panic("PIT mode %#x is not implemented: \n", mode_val);
-
- mode = mode_val;
-}
-
-void
-TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
-{
- if (bcd_val != PIT_BCD_FALSE)
- panic("PITimer does not implement BCD counts.\n");
-}
-
-bool
-TsunamiIO::PITimer::Counter::outputHigh()
-{
- return output_high;
-}
-
-void
-TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
-{
- paramOut(os, base + ".count", 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
-TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
- const string &section)
-{
- paramIn(cp, section, base + ".count", 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;
- paramIn(cp, section, base + ".event_tick", event_tick);
- if (event_tick)
- event.schedule(event_tick);
-}
-
-TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
- : Event(&mainEventQueue)
-{
- interval = (Tick)(Clock::Float::s / 1193180.0);
- counter = c_ptr;
-}
-
-void
-TsunamiIO::PITimer::Counter::CounterEvent::process()
-{
- DPRINTF(Tsunami, "Timer Interrupt\n");
- switch (counter->mode) {
- case PIT_MODE_INTTC:
- counter->output_high = true;
- case PIT_MODE_RATEGEN:
- case PIT_MODE_SQWAVE:
- break;
- default:
- panic("Unimplemented PITimer mode.\n");
- }
-}
-
-const char *
-TsunamiIO::PITimer::Counter::CounterEvent::description() const
-{
- return "tsunami 8254 Interval timer";
}
TsunamiIO::TsunamiIO(const Params *p)
- : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
- rtc(p->name + ".rtc", p->tsunami, p)
+ : BasicPioDevice(p), tsunami(p->tsunami),
+ pitimer(this, p->name + "pitimer"), rtc(p->name + ".rtc", p)
{
pioSize = 0x100;
@@ -486,19 +114,19 @@ TsunamiIO::read(PacketPtr pkt)
pkt->set(0x00);
break;
case TSDEV_TMR0_DATA:
- pkt->set(pitimer.counter0.read());
+ pkt->set(pitimer.readCounter(0));
break;
case TSDEV_TMR1_DATA:
- pkt->set(pitimer.counter1.read());
+ pkt->set(pitimer.readCounter(1));
break;
case TSDEV_TMR2_DATA:
- pkt->set(pitimer.counter2.read());
+ pkt->set(pitimer.readCounter(2));
break;
case TSDEV_RTC_DATA:
- pkt->set(rtc.readData());
+ pkt->set(rtc.readData(rtcAddr));
break;
case TSDEV_CTRL_PORTB:
- if (pitimer.counter2.outputHigh())
+ if (pitimer.outputHigh(2))
pkt->set(PORTB_SPKR_HIGH);
else
pkt->set(0x00);
@@ -561,22 +189,22 @@ TsunamiIO::write(PacketPtr pkt)
mode2 = pkt->get<uint8_t>();
break;
case TSDEV_TMR0_DATA:
- pitimer.counter0.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(0, pkt->get<uint8_t>());
break;
case TSDEV_TMR1_DATA:
- pitimer.counter1.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(1, pkt->get<uint8_t>());
break;
case TSDEV_TMR2_DATA:
- pitimer.counter2.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(2, pkt->get<uint8_t>());
break;
case TSDEV_TMR_CTRL:
pitimer.writeControl(pkt->get<uint8_t>());
break;
case TSDEV_RTC_ADDR:
- rtc.writeAddr(pkt->get<uint8_t>());
+ rtcAddr = pkt->get<uint8_t>();
break;
case TSDEV_RTC_DATA:
- rtc.writeData(pkt->get<uint8_t>());
+ rtc.writeData(rtcAddr, pkt->get<uint8_t>());
break;
case TSDEV_KBD:
case TSDEV_DMA1_CMND:
@@ -623,6 +251,7 @@ TsunamiIO::clearPIC(uint8_t bitvector)
void
TsunamiIO::serialize(ostream &os)
{
+ SERIALIZE_SCALAR(rtcAddr);
SERIALIZE_SCALAR(timerData);
SERIALIZE_SCALAR(mask1);
SERIALIZE_SCALAR(mask2);
@@ -639,6 +268,7 @@ TsunamiIO::serialize(ostream &os)
void
TsunamiIO::unserialize(Checkpoint *cp, const string &section)
{
+ UNSERIALIZE_SCALAR(rtcAddr);
UNSERIALIZE_SCALAR(timerData);
UNSERIALIZE_SCALAR(mask1);
UNSERIALIZE_SCALAR(mask2);
diff --git a/src/dev/alpha/tsunami_io.hh b/src/dev/alpha/tsunami_io.hh
index 05c4ee910..b6d63322b 100644
--- a/src/dev/alpha/tsunami_io.hh
+++ b/src/dev/alpha/tsunami_io.hh
@@ -39,6 +39,8 @@
#include "base/range.hh"
#include "dev/alpha/tsunami.hh"
+#include "dev/intel_8254_timer.hh"
+#include "dev/mc146818.hh"
#include "dev/io_device.hh"
#include "params/TsunamiIO.hh"
#include "sim/eventq.hh"
@@ -53,223 +55,19 @@ class TsunamiIO : public BasicPioDevice
struct tm tm;
protected:
- /** Real-Time Clock (MC146818) */
- class RTC
- {
- private:
- /** Event for RTC periodic interrupt */
- struct RTCEvent : public Event
- {
- /** A pointer back to tsunami to create interrupt the processor. */
- Tsunami* tsunami;
- Tick interval;
-
- RTCEvent(Tsunami* t, 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;
- };
-
- private:
- std::string _name;
- const std::string &name() const { return _name; }
- /** RTC periodic interrupt event */
- RTCEvent event;
-
- /** Current RTC register address/index */
- int addr;
-
- /** 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;
- };
- };
-
- /** RTC status register A */
- uint8_t stat_regA;
-
- /** RTC status register B */
- uint8_t stat_regB;
-
- public:
- RTC(const std::string &name, Tsunami* tsunami,
- const TsunamiIOParams *params);
-
- /** RTC address port: write address of RTC RAM data to access */
- void writeAddr(const uint8_t data);
-
- /** RTC write data */
- void writeData(const uint8_t data);
-
- /** RTC read data */
- uint8_t readData();
-
- /**
- * 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);
- };
-
- /** Programmable Interval Timer (Intel 8254) */
- class PITimer
+ class RTC : public MC146818
{
- /** 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 */
- virtual void process();
-
- /** Event description */
- virtual const char *description() const;
-
- friend class Counter;
- };
-
- private:
- std::string _name;
- const std::string &name() const { return _name; }
-
- CounterEvent event;
-
- /** Current count value */
- uint16_t 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;
-
- public:
- Counter(const std::string &name);
-
- /** Latch the current count (if one is not already latched) */
- void latchCount();
-
- /** 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);
- };
-
- private:
- std::string _name;
- const std::string &name() const { return _name; }
-
- /** PIT has three seperate counters */
- Counter *counter[3];
-
public:
- /** Public way to access individual counters (avoid array accesses) */
- Counter counter0;
- Counter counter1;
- Counter counter2;
-
- PITimer(const std::string &name);
-
- /** Write control word */
- void writeControl(const uint8_t data);
+ Tsunami *tsunami;
+ RTC(const std::string &n, const TsunamiIOParams *p);
- /**
- * 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:
+ void handleEvent()
+ {
+ //Actually interrupt the processor here
+ tsunami->cchip->postRTC();
+ }
};
/** Mask of the PIC1 */
@@ -294,10 +92,12 @@ class TsunamiIO : public BasicPioDevice
Tsunami *tsunami;
/** Intel 8253 Periodic Interval Timer */
- PITimer pitimer;
+ 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.
diff --git a/src/dev/alpha/tsunami_pchip.cc b/src/dev/alpha/tsunami_pchip.cc
index 83bcf8e65..4df7d1150 100644
--- a/src/dev/alpha/tsunami_pchip.cc
+++ b/src/dev/alpha/tsunami_pchip.cc
@@ -300,6 +300,7 @@ TsunamiPChip::translatePciToDma(Addr busAddr)
// if no match was found, then return the original address
return busAddr;
}
+
Addr
TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
{
@@ -310,7 +311,17 @@ TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
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)
diff --git a/src/dev/alpha/tsunami_pchip.hh b/src/dev/alpha/tsunami_pchip.hh
index 53050565f..d31a28dbe 100644
--- a/src/dev/alpha/tsunami_pchip.hh
+++ b/src/dev/alpha/tsunami_pchip.hh
@@ -84,6 +84,8 @@ class TsunamiPChip : public BasicPioDevice
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);
diff --git a/src/dev/copy_engine.cc b/src/dev/copy_engine.cc
new file mode 100644
index 000000000..3c759ac1d
--- /dev/null
+++ b/src/dev/copy_engine.cc
@@ -0,0 +1,764 @@
+/*
+ * 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 "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;
+using namespace std;
+
+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)
+ : 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;
+ delete cePort;
+}
+
+void
+CopyEngine::init()
+{
+ PciDev::init();
+ for (int x = 0; x < chan.size(); x++)
+ chan[x]->init();
+}
+
+void
+CopyEngine::CopyEngineChannel::init()
+{
+ Port *peer;
+
+ cePort = new DmaPort(ce, ce->sys);
+ peer = ce->dmaPort->getPeer()->getOwner()->getPort("");
+ peer->setPeer(cePort);
+ cePort->setPeer(peer);
+}
+
+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);
+}
diff --git a/src/dev/copy_engine.hh b/src/dev/copy_engine.hh
new file mode 100644
index 000000000..dfe469588
--- /dev/null
+++ b/src/dev/copy_engine.hh
@@ -0,0 +1,199 @@
+/*
+ * 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();
+ void init();
+
+ std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
+ virtual void addressRanges(AddrRangeList &range_list) { range_list.clear(); }
+ 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();
+ void init();
+
+ 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__
+
diff --git a/src/dev/copy_engine_defs.hh b/src/dev/copy_engine_defs.hh
new file mode 100644
index 000000000..16bf57d58
--- /dev/null
+++ b/src/dev/copy_engine_defs.hh
@@ -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
+
+
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
index 2316bfed9..063a594e7 100644
--- a/src/dev/etherbus.cc
+++ b/src/dev/etherbus.cc
@@ -49,7 +49,7 @@ using namespace std;
EtherBus::EtherBus(const Params *p)
: EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback),
- event(&mainEventQueue, this), sender(0), dump(p->dump)
+ event(this), sender(0), dump(p->dump)
{
}
@@ -99,7 +99,7 @@ EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0);
DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
delay, ticksPerByte);
- event.schedule(curTick + delay);
+ schedule(event, curTick + delay);
return true;
}
diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh
index 624ceb81a..6408f7f1f 100644
--- a/src/dev/etherbus.hh
+++ b/src/dev/etherbus.hh
@@ -59,8 +59,7 @@ class EtherBus : public EtherObject
EtherBus *bus;
public:
- DoneEvent(EventQueue *q, EtherBus *b)
- : Event(q), bus(b) {}
+ DoneEvent(EtherBus *b) : bus(b) {}
virtual void process() { bus->txDone(); }
virtual const char *description() const
{ return "ethernet bus completion"; }
diff --git a/src/dev/etherdevice.cc b/src/dev/etherdevice.cc
new file mode 100644
index 000000000..5341c02c4
--- /dev/null
+++ b/src/dev/etherdevice.cc
@@ -0,0 +1,367 @@
+/*
+ * 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;
+}
diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh
index a0df0d741..5d86275b4 100644
--- a/src/dev/etherdevice.hh
+++ b/src/dev/etherdevice.hh
@@ -36,6 +36,7 @@
#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"
@@ -64,6 +65,59 @@ class EtherDevice : public PciDev
/** 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__
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
index 471093521..c41ce4e1f 100644
--- a/src/dev/etherdump.cc
+++ b/src/dev/etherdump.cc
@@ -45,75 +45,62 @@
using std::string;
EtherDump::EtherDump(const Params *p)
- : SimObject(p), stream(simout.resolve(p->file).c_str()),
+ : 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
+#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_*)
+ 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)
+ uint32_t caplen; // length of portion present
+ uint32_t len; // length this packet (off wire)
};
void
EtherDump::init()
{
- curtime = time(NULL);
struct pcap_file_header hdr;
hdr.magic = TCPDUMP_MAGIC;
hdr.version_major = PCAP_VERSION_MAJOR;
hdr.version_minor = PCAP_VERSION_MINOR;
- hdr.thiszone = -5 * 3600;
+ hdr.thiszone = 0;
hdr.snaplen = 1500;
hdr.sigfigs = 0;
hdr.linktype = DLT_EN10MB;
- stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
+ stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
- /*
- * output an empty packet with the current time so that we know
- * when the simulation began. This allows us to correlate packets
- * to sim_cycles.
- */
- pcap_pkthdr pkthdr;
- pkthdr.seconds = curtime;
- pkthdr.microseconds = 0;
- pkthdr.caplen = 0;
- pkthdr.len = 0;
- stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
-
- stream.flush();
+ stream->flush();
}
void
EtherDump::dumpPacket(EthPacketPtr &packet)
{
pcap_pkthdr pkthdr;
- pkthdr.seconds = curtime + (curTick / Clock::Int::s);
+ pkthdr.seconds = curTick / Clock::Int::s;
pkthdr.microseconds = (curTick / Clock::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();
+ stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+ stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
+ stream->flush();
}
EtherDump *
diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh
index 1027ce4d0..18a5d2c44 100644
--- a/src/dev/etherdump.hh
+++ b/src/dev/etherdump.hh
@@ -46,13 +46,11 @@
class EtherDump : public SimObject
{
private:
- std::ofstream stream;
+ std::ostream *stream;
const int maxlen;
void dumpPacket(EthPacketPtr &packet);
void init();
- Tick curtime;
-
public:
typedef EtherDumpParams Params;
EtherDump(const Params *p);
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
index b1266000b..f3f38fc20 100644
--- a/src/dev/etherlink.cc
+++ b/src/dev/etherlink.cc
@@ -135,7 +135,7 @@ class LinkDelayEvent : public Event
public:
// non-scheduling version for createForUnserialize()
LinkDelayEvent();
- LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when);
+ LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt);
void process();
@@ -153,7 +153,8 @@ EtherLink::Link::txDone()
if (linkDelay > 0) {
DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
- new LinkDelayEvent(this, packet, curTick + linkDelay);
+ Event *event = new LinkDelayEvent(this, packet);
+ parent->schedule(event, curTick + linkDelay);
} else {
txComplete(packet);
}
@@ -182,7 +183,7 @@ EtherLink::Link::transmit(EthPacketPtr pkt)
DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
delay, ticksPerByte);
- doneEvent.schedule(curTick + delay);
+ parent->schedule(doneEvent, curTick + delay);
return true;
}
@@ -220,23 +221,22 @@ EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
if (event_scheduled) {
Tick event_time;
paramIn(cp, section, base + ".event_time", event_time);
- doneEvent.schedule(event_time);
+ parent->schedule(doneEvent, event_time);
}
}
LinkDelayEvent::LinkDelayEvent()
- : Event(&mainEventQueue), link(NULL)
+ : link(NULL)
{
setFlags(AutoSerialize);
setFlags(AutoDelete);
}
-LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when)
- : Event(&mainEventQueue), link(l), packet(p)
+LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p)
+ : link(l), packet(p)
{
setFlags(AutoSerialize);
setFlags(AutoDelete);
- schedule(when);
}
void
diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc
index 5c552b4bd..2c8343eb0 100644
--- a/src/dev/etherpkt.cc
+++ b/src/dev/etherpkt.cc
@@ -40,7 +40,6 @@ void
EthPacketData::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".length", length);
- paramOut(os, base + ".slack", slack);
arrayParamOut(os, base + ".data", data, length);
}
@@ -49,7 +48,6 @@ EthPacketData::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
paramIn(cp, section, base + ".length", length);
- paramIn(cp, section, base + ".slack", slack);
if (length)
arrayParamIn(cp, section, base + ".data", data, length);
}
diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh
index db2e0d6b5..623895ba8 100644
--- a/src/dev/etherpkt.hh
+++ b/src/dev/etherpkt.hh
@@ -60,24 +60,17 @@ class EthPacketData : public RefCounted
*/
int length;
- /*
- * Extra space taken up by the packet in whatever data structure
- * it is in.
- *
- * NOTE: This can only be use by *one* data structure at a time!
- */
- int slack;
-
public:
- EthPacketData() : data(NULL), length(0), slack(0)
+ EthPacketData()
+ : data(NULL), length(0)
{ }
explicit EthPacketData(size_t size)
- : data(new uint8_t[size]), length(0), slack(0)
+ : data(new uint8_t[size]), length(0)
{ }
- EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0)
- : data(d.release()), length(l), slack(s)
+ EthPacketData(std::auto_ptr<uint8_t> d, int l)
+ : data(d.release()), length(l)
{ }
~EthPacketData() { if (data) delete [] data; }
diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc
index 81b84d179..85d6370be 100644
--- a/src/dev/ethertap.cc
+++ b/src/dev/ethertap.cc
@@ -130,6 +130,9 @@ 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();
@@ -179,8 +182,12 @@ EtherTap::recvPacket(EthPacketPtr packet)
DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
uint32_t len = htonl(packet->length);
- write(socket, &len, sizeof(len));
- write(socket, packet->data, 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();
@@ -239,7 +246,7 @@ EtherTap::process(int revent)
DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
packetBuffer.push(packet);
if (!txEvent.scheduled())
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
} else if (dump) {
dump->dump(packet);
}
@@ -262,7 +269,7 @@ EtherTap::retransmit()
}
if (!packetBuffer.empty() && !txEvent.scheduled())
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
}
EtherInt*
diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh
index be3d73a24..ac287cecb 100644
--- a/src/dev/ethertap.hh
+++ b/src/dev/ethertap.hh
@@ -90,8 +90,7 @@ class EtherTap : public EtherObject
EtherTap *tap;
public:
- TxEvent(EtherTap *_tap)
- : Event(&mainEventQueue), tap(_tap) {}
+ TxEvent(EtherTap *_tap) : tap(_tap) {}
void process() { tap->retransmit(); }
virtual const char *description() const
{ return "EtherTap retransmit"; }
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
index 3f56ec53a..274f60e39 100644
--- a/src/dev/i8254xGBe.cc
+++ b/src/dev/i8254xGBe.cc
@@ -57,10 +57,15 @@ using namespace Net;
IGbE::IGbE(const Params *p)
: EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control),
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
- txTick(false), txFifoTick(false), rxDmaPacket(false), rdtrEvent(this), radvEvent(this),
+ txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
+ fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
+ fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
+ rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
+ rdtrEvent(this), radvEvent(this),
tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
- txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock)
+ txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
+ clock(p->clock), lastInterrupt(0)
{
etherInt = new IGbEInt(name() + ".int", this);
@@ -80,6 +85,9 @@ IGbE::IGbE(const Params *p)
regs.rxdctl.gran(1);
regs.rxdctl.wthresh(1);
regs.fcrth(1);
+ regs.tdwba = 0;
+ regs.rlpml = 0;
+ regs.sw_fw_sync = 0;
regs.pba.rxa(0x30);
regs.pba.txa(0x10);
@@ -105,10 +113,20 @@ IGbE::IGbE(const Params *p)
// Magic happy checksum value
flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
+ // Store the MAC address as queue ID
+ macAddr = p->hardware_address;
+
rxFifo.clear();
txFifo.clear();
}
+void
+IGbE::init()
+{
+ cpa = CPA::cpa();
+ PciDev::init();
+}
+
EtherInt*
IGbE::getEthPort(const std::string &if_name, int idx)
{
@@ -192,6 +210,11 @@ IGbE::read(PacketPtr pkt)
regs.imr &= ~regs.iam;
chkInterrupt();
break;
+ case REG_EICR:
+ // This is only useful for MSI, but the driver reads it every time
+ // Just don't do anything
+ pkt->set<uint32_t>(0);
+ break;
case REG_ITR:
pkt->set<uint32_t>(regs.itr());
break;
@@ -226,6 +249,9 @@ IGbE::read(PacketPtr pkt)
case REG_RDLEN:
pkt->set<uint32_t>(regs.rdlen());
break;
+ case REG_SRRCTL:
+ pkt->set<uint32_t>(regs.srrctl());
+ break;
case REG_RDH:
pkt->set<uint32_t>(regs.rdh());
break;
@@ -241,6 +267,9 @@ IGbE::read(PacketPtr pkt)
regs.rdtr.fpd(0);
}
break;
+ case REG_RXDCTL:
+ pkt->set<uint32_t>(regs.rxdctl());
+ break;
case REG_RADV:
pkt->set<uint32_t>(regs.radv());
break;
@@ -256,6 +285,9 @@ IGbE::read(PacketPtr pkt)
case REG_TDH:
pkt->set<uint32_t>(regs.tdh());
break;
+ case REG_TXDCA_CTL:
+ pkt->set<uint32_t>(regs.txdca_ctl());
+ break;
case REG_TDT:
pkt->set<uint32_t>(regs.tdt());
break;
@@ -268,12 +300,34 @@ IGbE::read(PacketPtr pkt)
case REG_TADV:
pkt->set<uint32_t>(regs.tadv());
break;
+ case REG_TDWBAL:
+ pkt->set<uint32_t>(regs.tdwba & mask(32));
+ break;
+ case REG_TDWBAH:
+ pkt->set<uint32_t>(regs.tdwba >> 32);
+ break;
case REG_RXCSUM:
pkt->set<uint32_t>(regs.rxcsum());
break;
+ case REG_RLPML:
+ pkt->set<uint32_t>(regs.rlpml);
+ break;
+ case REG_RFCTL:
+ pkt->set<uint32_t>(regs.rfctl());
+ break;
case REG_MANC:
pkt->set<uint32_t>(regs.manc());
break;
+ case REG_SWSM:
+ pkt->set<uint32_t>(regs.swsm());
+ regs.swsm.smbi(1);
+ break;
+ case REG_FWSM:
+ pkt->set<uint32_t>(regs.fwsm());
+ break;
+ case REG_SWFWSYNC:
+ pkt->set<uint32_t>(regs.sw_fw_sync);
+ break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@@ -380,6 +434,14 @@ IGbE::write(PacketPtr pkt)
break;
case REG_EERD:
regs.eerd = val;
+ if (regs.eerd.start()) {
+ regs.eerd.done(1);
+ assert(regs.eerd.addr() < EEPROM_SIZE);
+ regs.eerd.data(flash[regs.eerd.addr()]);
+ regs.eerd.start(0);
+ DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
+ regs.eerd.addr(), regs.eerd.data());
+ }
break;
case REG_MDIC:
regs.mdic = val;
@@ -394,10 +456,10 @@ IGbE::write(PacketPtr pkt)
regs.mdic.data(0x796D); // link up
break;
case PHY_PID:
- regs.mdic.data(0x02A8);
+ regs.mdic.data(params()->phy_pid);
break;
case PHY_EPID:
- regs.mdic.data(0x0380);
+ regs.mdic.data(params()->phy_epid);
break;
case PHY_GSTATUS:
regs.mdic.data(0x7C00);
@@ -480,6 +542,9 @@ IGbE::write(PacketPtr pkt)
case REG_TIPG:
; // We don't care, so don't store anything
break;
+ case REG_IVAR0:
+ warn("Writing to IVAR0, ignoring...\n");
+ break;
case REG_FCRTL:
regs.fcrtl = val;
break;
@@ -498,6 +563,9 @@ IGbE::write(PacketPtr pkt)
regs.rdlen = val & ~mask(7);
rxDescCache.areaChanged();
break;
+ case REG_SRRCTL:
+ regs.srrctl = val;
+ break;
case REG_RDH:
regs.rdh = val;
rxDescCache.areaChanged();
@@ -518,6 +586,9 @@ IGbE::write(PacketPtr pkt)
case REG_RADV:
regs.radv = val;
break;
+ case REG_RXDCTL:
+ regs.rxdctl = val;
+ break;
case REG_TDBAL:
regs.tdba.tdbal( val & ~mask(4));
txDescCache.areaChanged();
@@ -534,6 +605,11 @@ IGbE::write(PacketPtr pkt)
regs.tdh = val;
txDescCache.areaChanged();
break;
+ case REG_TXDCA_CTL:
+ regs.txdca_ctl = val;
+ if (regs.txdca_ctl.enabled())
+ panic("No support for DCA\n");
+ break;
case REG_TDT:
regs.tdt = val;
DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
@@ -553,12 +629,38 @@ IGbE::write(PacketPtr pkt)
case REG_TADV:
regs.tadv = val;
break;
+ case REG_TDWBAL:
+ regs.tdwba &= ~mask(32);
+ regs.tdwba |= val;
+ txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
+ break;
+ case REG_TDWBAH:
+ regs.tdwba &= mask(32);
+ regs.tdwba |= (uint64_t)val << 32;
+ txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
+ break;
case REG_RXCSUM:
regs.rxcsum = val;
break;
+ case REG_RLPML:
+ regs.rlpml = val;
+ break;
+ case REG_RFCTL:
+ regs.rfctl = val;
+ if (regs.rfctl.exsten())
+ panic("Extended RX descriptors not implemented\n");
+ break;
case REG_MANC:
regs.manc = val;
break;
+ case REG_SWSM:
+ regs.swsm = val;
+ if (regs.fwsm.eep_fw_semaphore())
+ regs.swsm.swesmbi(0);
+ break;
+ case REG_SWFWSYNC:
+ regs.sw_fw_sync = val;
+ break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@@ -580,16 +682,23 @@ IGbE::postInterrupt(IntTypes t, bool now)
return;
regs.icr = regs.icr() | t;
- if (regs.itr.interval() == 0 || now) {
+
+ Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval();
+ DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n",
+ curTick, regs.itr.interval(), itr_interval);
+
+ if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) {
if (interEvent.scheduled()) {
- interEvent.deschedule();
+ deschedule(interEvent);
}
cpuPostInt();
} else {
- DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
- Clock::Int::ns * 256 * regs.itr.interval());
+ Tick int_time = lastInterrupt + itr_interval;
+ assert(int_time > 0);
+ DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
+ int_time);
if (!interEvent.scheduled()) {
- interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ schedule(interEvent, int_time);
}
}
}
@@ -605,6 +714,8 @@ void
IGbE::cpuPostInt()
{
+ postedInterrupts++;
+
if (!(regs.icr() & regs.imr)) {
DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
return;
@@ -614,24 +725,24 @@ IGbE::cpuPostInt()
if (interEvent.scheduled()) {
- interEvent.deschedule();
+ deschedule(interEvent);
}
if (rdtrEvent.scheduled()) {
regs.icr.rxt0(1);
- rdtrEvent.deschedule();
+ deschedule(rdtrEvent);
}
if (radvEvent.scheduled()) {
regs.icr.rxt0(1);
- radvEvent.deschedule();
+ deschedule(radvEvent);
}
if (tadvEvent.scheduled()) {
regs.icr.txdw(1);
- tadvEvent.deschedule();
+ deschedule(tadvEvent);
}
if (tidvEvent.scheduled()) {
regs.icr.txdw(1);
- tidvEvent.deschedule();
+ deschedule(tidvEvent);
}
regs.icr.int_assert(1);
@@ -640,6 +751,7 @@ IGbE::cpuPostInt()
intrPost();
+ lastInterrupt = curTick;
}
void
@@ -662,7 +774,7 @@ IGbE::chkInterrupt()
if (!(regs.icr() & regs.imr)) {
DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
if (interEvent.scheduled())
- interEvent.deschedule();
+ deschedule(interEvent);
if (regs.icr.int_assert())
cpuClearInt();
}
@@ -676,7 +788,8 @@ IGbE::chkInterrupt()
if (!interEvent.scheduled()) {
DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
* 256 * regs.itr.interval());
- interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ schedule(interEvent,
+ curTick + Clock::Int::ns * 256 * regs.itr.interval());
}
}
}
@@ -686,27 +799,125 @@ IGbE::chkInterrupt()
IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
- : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
+ : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
+ pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
{
+ annSmFetch = "RX Desc Fetch";
+ annSmWb = "RX Desc Writeback";
+ annUnusedDescQ = "RX Unused Descriptors";
+ annUnusedCacheQ = "RX Unused Descriptor Cache";
+ annUsedCacheQ = "RX Used Descriptor Cache";
+ annUsedDescQ = "RX Used Descriptors";
+ annDescQ = "RX Descriptors";
}
void
-IGbE::RxDescCache::writePacket(EthPacketPtr packet)
+IGbE::RxDescCache::pktSplitDone()
{
- // We shouldn't have to deal with any of these yet
- DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
- packet->length, igbe->regs.rctl.descSize());
- assert(packet->length < igbe->regs.rctl.descSize());
+ splitCount++;
+ DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount);
+ assert(splitCount <= 2);
+ if (splitCount != 2)
+ return;
+ splitCount = 0;
+ DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n");
+ pktComplete();
+}
- assert(unusedCache.size());
+int
+IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
+{
+ assert(unusedCache.size());
//if (!unusedCache.size())
// return false;
pktPtr = packet;
pktDone = false;
- igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
- packet->length, &pktEvent, packet->data);
+ int buf_len, hdr_len;
+
+ RxDesc *desc = unusedCache.front();
+ switch (igbe->regs.srrctl.desctype()) {
+ case RXDT_LEGACY:
+ assert(pkt_offset == 0);
+ bytesCopied = packet->length;
+ DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
+ packet->length, igbe->regs.rctl.descSize());
+ assert(packet->length < igbe->regs.rctl.descSize());
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ break;
+ case RXDT_ADV_ONEBUF:
+ assert(pkt_offset == 0);
+ bytesCopied = packet->length;
+ buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+ igbe->regs.rctl.descSize();
+ DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
+ packet->length, igbe->regs.srrctl(), buf_len);
+ assert(packet->length < buf_len);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(0);
+ desc->adv_wb.sph = htole(0);
+ desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
+ break;
+ case RXDT_ADV_SPLIT_A:
+ int split_point;
+
+ buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+ igbe->regs.rctl.descSize();
+ hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
+ DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
+ igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len);
+
+ split_point = hsplit(pktPtr);
+
+ if (packet->length <= hdr_len) {
+ bytesCopied = packet->length;
+ assert(pkt_offset == 0);
+ DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n");
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole((uint16_t)packet->length);
+ desc->adv_wb.sph = htole(0);
+ desc->adv_wb.pkt_len = htole(0);
+ } else if (split_point) {
+ if (pkt_offset) {
+ // we are only copying some data, header/data has already been
+ // copied
+ int max_to_copy = std::min(packet->length - pkt_offset, buf_len);
+ bytesCopied += max_to_copy;
+ DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n");
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent,
+ packet->data + pkt_offset, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(0);
+ desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
+ desc->adv_wb.sph = htole(0);
+ } else {
+ int max_to_copy = std::min(packet->length - split_point, buf_len);
+ bytesCopied += max_to_copy + split_point;
+
+ DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n",
+ split_point);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent,
+ packet->data, igbe->rxWriteDelay);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),
+ max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(split_point);
+ desc->adv_wb.sph = 1;
+ desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
+ }
+ } else {
+ panic("Header split not fitting within header buffer or undecodable"
+ " packet not fitting in header unsupported\n");
+ }
+ break;
+ default:
+ panic("Unimplemnted RX receive buffer type: %d\n",
+ igbe->regs.srrctl.desctype());
+ }
+ return bytesCopied;
+
}
void
@@ -716,10 +927,11 @@ IGbE::RxDescCache::pktComplete()
RxDesc *desc;
desc = unusedCache.front();
+ igbe->anBegin("RXS", "Update Desc");
+
uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
- desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
- DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
- pktPtr->length, crcfixup,
+ DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n",
+ pktPtr->length, bytesCopied, crcfixup,
htole((uint16_t)(pktPtr->length + crcfixup)),
(uint16_t)(pktPtr->length + crcfixup));
@@ -728,20 +940,32 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
- uint8_t status = RXDS_DD | RXDS_EOP;
+ uint16_t status = RXDS_DD;
uint8_t err = 0;
+ uint16_t ext_err = 0;
+ uint16_t csum = 0;
+ uint16_t ptype = 0;
+ uint16_t ip_id = 0;
+
+ assert(bytesCopied <= pktPtr->length);
+ if (bytesCopied == pktPtr->length)
+ status |= RXDS_EOP;
IpPtr ip(pktPtr);
if (ip) {
DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
+ ptype |= RXDP_IPV4;
+ ip_id = ip->id();
if (igbe->regs.rxcsum.ipofld()) {
DPRINTF(EthernetDesc, "Checking IP checksum\n");
status |= RXDS_IPCS;
- desc->csum = htole(cksum(ip));
+ csum = htole(cksum(ip));
+ igbe->rxIpChecksums++;
if (cksum(ip) != 0) {
err |= RXDE_IPE;
+ ext_err |= RXDEE_IPE;
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
}
}
@@ -749,10 +973,13 @@ IGbE::RxDescCache::pktComplete()
if (tcp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking TCP checksum\n");
status |= RXDS_TCPCS;
- desc->csum = htole(cksum(tcp));
+ ptype |= RXDP_TCP;
+ csum = htole(cksum(tcp));
+ igbe->rxTcpChecksums++;
if (cksum(tcp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
err |= RXDE_TCPE;
+ ext_err |= RXDEE_TCPE;
}
}
@@ -760,9 +987,12 @@ IGbE::RxDescCache::pktComplete()
if (udp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking UDP checksum\n");
status |= RXDS_UDPCS;
- desc->csum = htole(cksum(udp));
+ ptype |= RXDP_UDP;
+ csum = htole(cksum(udp));
+ igbe->rxUdpChecksums++;
if (cksum(udp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+ ext_err |= RXDEE_TCPE;
err |= RXDE_TCPE;
}
}
@@ -770,53 +1000,83 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
}
+ switch (igbe->regs.srrctl.desctype()) {
+ case RXDT_LEGACY:
+ desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
+ desc->legacy.status = htole(status);
+ desc->legacy.errors = htole(err);
+ // No vlan support at this point... just set it to 0
+ desc->legacy.vlan = 0;
+ break;
+ case RXDT_ADV_SPLIT_A:
+ case RXDT_ADV_ONEBUF:
+ desc->adv_wb.rss_type = htole(0);
+ desc->adv_wb.pkt_type = htole(ptype);
+ if (igbe->regs.rxcsum.pcsd()) {
+ // no rss support right now
+ desc->adv_wb.rss_hash = htole(0);
+ } else {
+ desc->adv_wb.id = htole(ip_id);
+ desc->adv_wb.csum = htole(csum);
+ }
+ desc->adv_wb.status = htole(status);
+ desc->adv_wb.errors = htole(ext_err);
+ // no vlan support
+ desc->adv_wb.vlan_tag = htole(0);
+ break;
+ default:
+ panic("Unimplemnted RX receive buffer type %d\n",
+ igbe->regs.srrctl.desctype());
+ }
- desc->status = htole(status);
- desc->errors = htole(err);
-
- // No vlan support at this point... just set it to 0
- desc->vlan = 0;
+ DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
+ desc->adv_read.pkt, desc->adv_read.hdr);
- // Deal with the rx timer interrupts
- if (igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
- igbe->regs.rdtr.delay() * igbe->intClock());
- igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() *
- igbe->intClock(),true);
- }
+ if (bytesCopied == pktPtr->length) {
+ DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n");
+ // Deal with the rx timer interrupts
+ if (igbe->regs.rdtr.delay()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
+ igbe->regs.rdtr.delay() * igbe->intClock());
+ igbe->reschedule(igbe->rdtrEvent,
+ curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true);
+ }
- if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
- igbe->regs.radv.idv() * igbe->intClock());
- if (!igbe->radvEvent.scheduled()) {
- igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() *
- igbe->intClock());
+ if (igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
+ igbe->regs.radv.idv() * igbe->intClock());
+ if (!igbe->radvEvent.scheduled()) {
+ igbe->schedule(igbe->radvEvent,
+ curTick + igbe->regs.radv.idv() * igbe->intClock());
+ }
}
- }
- // if neither radv or rdtr, maybe itr is set...
- if (!igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
- igbe->postInterrupt(IT_RXT);
- }
+ // if neither radv or rdtr, maybe itr is set...
+ if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
+ igbe->postInterrupt(IT_RXT);
+ }
- // If the packet is small enough, interrupt appropriately
- // I wonder if this is delayed or not?!
- if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
- DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
- igbe->postInterrupt(IT_SRPD);
+ // If the packet is small enough, interrupt appropriately
+ // I wonder if this is delayed or not?!
+ if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
+ DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
+ igbe->postInterrupt(IT_SRPD);
+ }
+ bytesCopied = 0;
}
- DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
- unusedCache.pop_front();
- usedCache.push_back(desc);
-
-
pktPtr = NULL;
+ igbe->checkDrain();
enableSm();
pktDone = true;
- igbe->checkDrain();
+ igbe->anBegin("RXS", "Done Updating Desc");
+ DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
+ igbe->anDq("RXS", annUnusedCacheQ);
+ unusedCache.pop_front();
+ igbe->anQ("RXS", annUsedCacheQ);
+ usedCache.push_back(desc);
}
void
@@ -842,7 +1102,9 @@ bool
IGbE::RxDescCache::hasOutstandingEvents()
{
return pktEvent.scheduled() || wbEvent.scheduled() ||
- fetchEvent.scheduled();
+ fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
+ pktDataEvent.scheduled();
+
}
void
@@ -850,6 +1112,8 @@ IGbE::RxDescCache::serialize(std::ostream &os)
{
DescCache<RxDesc>::serialize(os);
SERIALIZE_SCALAR(pktDone);
+ SERIALIZE_SCALAR(splitCount);
+ SERIALIZE_SCALAR(bytesCopied);
}
void
@@ -857,6 +1121,8 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
{
DescCache<RxDesc>::unserialize(cp, section);
UNSERIALIZE_SCALAR(pktDone);
+ UNSERIALIZE_SCALAR(splitCount);
+ UNSERIALIZE_SCALAR(bytesCopied);
}
@@ -864,45 +1130,154 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
- pktEvent(this)
+ completionAddress(0), completionEnabled(false),
+ useTso(false), pktEvent(this), headerEvent(this), nullEvent(this)
{
+ annSmFetch = "TX Desc Fetch";
+ annSmWb = "TX Desc Writeback";
+ annUnusedDescQ = "TX Unused Descriptors";
+ annUnusedCacheQ = "TX Unused Descriptor Cache";
+ annUsedCacheQ = "TX Used Descriptor Cache";
+ annUsedDescQ = "TX Used Descriptors";
+ annDescQ = "TX Descriptors";
}
-int
-IGbE::TxDescCache::getPacketSize()
+void
+IGbE::TxDescCache::processContextDesc()
{
assert(unusedCache.size());
-
TxDesc *desc;
+
+ DPRINTF(EthernetDesc, "Checking and processing context descriptors\n");
- DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
-
- while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
- DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n");
+ while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
+ DPRINTF(EthernetDesc, "Got context descriptor type...\n");
- // I think we can just ignore these for now?
desc = unusedCache.front();
- DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1,
- desc->d2);
+ DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
+ desc->d1, desc->d2);
+
+
// is this going to be a tcp or udp packet?
isTcp = TxdOp::tcp(desc) ? true : false;
- // make sure it's ipv4
- //assert(TxdOp::ip(desc));
+ // setup all the TSO variables, they'll be ignored if we don't use
+ // tso for this connection
+ tsoHeaderLen = TxdOp::hdrlen(desc);
+ tsoMss = TxdOp::mss(desc);
+
+ if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
+ DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n",
+ TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc));
+ useTso = true;
+ tsoTotalLen = TxdOp::getLen(desc);
+ tsoLoadedHeader = false;
+ tsoDescBytesUsed = 0;
+ tsoUsedLen = 0;
+ tsoPrevSeq = 0;
+ tsoPktHasHeader = false;
+ tsoPkts = 0;
+
+ }
TxdOp::setDd(desc);
unusedCache.pop_front();
+ igbe->anDq("TXS", annUnusedCacheQ);
usedCache.push_back(desc);
+ igbe->anQ("TXS", annUsedCacheQ);
}
if (!unusedCache.size())
+ return;
+
+ desc = unusedCache.front();
+ if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) {
+ DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n",
+ tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
+ useTso = true;
+ tsoTotalLen = TxdOp::getTsoLen(desc);
+ tsoLoadedHeader = false;
+ tsoDescBytesUsed = 0;
+ tsoUsedLen = 0;
+ tsoPrevSeq = 0;
+ tsoPktHasHeader = false;
+ tsoPkts = 0;
+ }
+
+ if (useTso && !tsoLoadedHeader) {
+ // we need to fetch a header
+ DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
+ assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
+ pktWaiting = true;
+ assert(tsoHeaderLen <= 256);
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
+ tsoHeaderLen, &headerEvent, tsoHeader, 0);
+ }
+}
+
+void
+IGbE::TxDescCache::headerComplete()
+{
+ DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
+ pktWaiting = false;
+
+ assert(unusedCache.size());
+ TxDesc *desc = unusedCache.front();
+ DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
+ TxdOp::getLen(desc), tsoHeaderLen);
+
+ if (TxdOp::getLen(desc) == tsoHeaderLen) {
+ tsoDescBytesUsed = 0;
+ tsoLoadedHeader = true;
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+ } else {
+ // I don't think this case happens, I think the headrer is always
+ // it's own packet, if it wasn't it might be as simple as just
+ // incrementing descBytesUsed by the header length, but I'm not
+ // completely sure
+ panic("TSO header part of bigger packet, not implemented\n");
+ }
+ enableSm();
+ igbe->checkDrain();
+}
+
+int
+IGbE::TxDescCache::getPacketSize(EthPacketPtr p)
+{
+ TxDesc *desc;
+
+
+ if (!unusedCache.size())
return -1;
+
+ DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
- DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
- TxdOp::getLen(unusedCache.front()));
+ assert(!useTso || tsoLoadedHeader);
+ desc = unusedCache.front();
+
+
+ if (useTso) {
+ DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
+ useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
+ DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n",
+ tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
+ DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
+
+ if (tsoPktHasHeader)
+ tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed);
+ else
+ tsoCopyBytes = std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed);
+ Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
+ DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
+ return pkt_size;
+ }
- return TxdOp::getLen(unusedCache.front());
+ DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
+ TxdOp::getLen(unusedCache.front()));
+ return TxdOp::getLen(desc);
}
void
@@ -913,17 +1288,37 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
TxDesc *desc;
desc = unusedCache.front();
+ DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
pktPtr = p;
pktWaiting = true;
- DPRINTF(EthernetDesc, "Starting DMA of packet\n");
- igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
- TxdOp::getLen(desc), &pktEvent, p->data + p->length);
-
-
+ DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
+
+ if (useTso) {
+ assert(tsoLoadedHeader);
+ if (!tsoPktHasHeader) {
+ DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n",
+ tsoHeaderLen);
+ memcpy(p->data, &tsoHeader,tsoHeaderLen);
+ p->length +=tsoHeaderLen;
+ tsoPktHasHeader = true;
+ }
+ }
+
+ if (useTso) {
+ tsoDescBytesUsed += tsoCopyBytes;
+ assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
+ DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n",
+ p->length, tsoCopyBytes);
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed,
+ tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay);
+ } else {
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
+ TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay);
+ }
}
void
@@ -934,6 +1329,8 @@ IGbE::TxDescCache::pktComplete()
assert(unusedCache.size());
assert(pktPtr);
+ igbe->anBegin("TXS", "Update Desc");
+
DPRINTF(EthernetDesc, "DMA of packet complete\n");
@@ -941,40 +1338,83 @@ IGbE::TxDescCache::pktComplete()
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
+ useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
- if (!TxdOp::eop(desc)) {
- // This only supports two descriptors per tx packet
- assert(pktPtr->length == 0);
- pktPtr->length = TxdOp::getLen(desc);
+ // Set the length of the data in the EtherPacket
+ if (useTso) {
+ pktPtr->length += tsoCopyBytes;
+ tsoUsedLen += tsoCopyBytes;
+ } else
+ pktPtr->length += TxdOp::getLen(desc);
+
+ DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
+ tsoDescBytesUsed, tsoCopyBytes);
+
+
+ if ((!TxdOp::eop(desc) && !useTso) ||
+ (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
+ tsoTotalLen != tsoUsedLen && useTso)) {
+ assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
+ igbe->anDq("TXS", annUnusedCacheQ);
unusedCache.pop_front();
+ igbe->anQ("TXS", annUsedCacheQ);
usedCache.push_back(desc);
+
+ tsoDescBytesUsed = 0;
pktDone = true;
pktWaiting = false;
+ pktMultiDesc = true;
+
+ DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
+ pktPtr->length);
pktPtr = NULL;
- DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n");
enableSm();
igbe->checkDrain();
return;
}
- // Set the length of the data in the EtherPacket
- pktPtr->length += TxdOp::getLen(desc);
+ pktMultiDesc = false;
// no support for vlans
assert(!TxdOp::vle(desc));
- // we alway report status
- assert(TxdOp::rs(desc));
-
// we only support single packet descriptors at this point
- assert(TxdOp::eop(desc));
+ if (!useTso)
+ assert(TxdOp::eop(desc));
// set that this packet is done
- TxdOp::setDd(desc);
+ if (TxdOp::rs(desc))
+ TxdOp::setDd(desc);
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ if (useTso) {
+ IpPtr ip(pktPtr);
+ if (ip) {
+ DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
+ tsoPkts);
+ ip->id(ip->id() + tsoPkts++);
+ ip->len(pktPtr->length - EthPtr(pktPtr)->size());
+
+ TcpPtr tcp(ip);
+ if (tcp) {
+ DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n",
+ tcp->seq(), tsoPrevSeq);
+ tcp->seq(tcp->seq() + tsoPrevSeq);
+ if (tsoUsedLen != tsoTotalLen)
+ tcp->flags(tcp->flags() & ~9); // clear fin & psh
+ }
+ UdpPtr udp(ip);
+ if (udp) {
+ DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
+ udp->len(pktPtr->length - EthPtr(pktPtr)->size());
+ }
+ }
+ tsoPrevSeq = tsoUsedLen;
+ }
+
if (DTRACE(EthernetDesc)) {
IpPtr ip(pktPtr);
if (ip)
@@ -988,10 +1428,11 @@ IGbE::TxDescCache::pktComplete()
if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
IpPtr ip(pktPtr);
-
+ assert(ip);
if (TxdOp::ixsm(desc)) {
ip->sum(0);
ip->sum(cksum(ip));
+ igbe->txIpChecksums++;
DPRINTF(EthernetDesc, "Calculated IP checksum\n");
}
if (TxdOp::txsm(desc)) {
@@ -1000,11 +1441,13 @@ IGbE::TxDescCache::pktComplete()
if (tcp) {
tcp->sum(0);
tcp->sum(cksum(tcp));
+ igbe->txTcpChecksums++;
DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
} else if (udp) {
assert(udp);
udp->sum(0);
udp->sum(cksum(udp));
+ igbe->txUdpChecksums++;
DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
} else {
panic("Told to checksum, but don't know how\n");
@@ -1017,47 +1460,100 @@ IGbE::TxDescCache::pktComplete()
DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
if (igbe->regs.tidv.idv()) {
DPRINTF(EthernetDesc, "setting tidv\n");
- igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() *
- igbe->intClock(), true);
+ igbe->reschedule(igbe->tidvEvent,
+ curTick + igbe->regs.tidv.idv() * igbe->intClock(), true);
}
if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
DPRINTF(EthernetDesc, "setting tadv\n");
if (!igbe->tadvEvent.scheduled()) {
- igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() *
- igbe->intClock());
+ igbe->schedule(igbe->tadvEvent,
+ curTick + igbe->regs.tadv.idv() * igbe->intClock());
}
}
}
+ if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) {
+ DPRINTF(EthernetDesc, "Descriptor Done\n");
+ igbe->anDq("TXS", annUnusedCacheQ);
+ unusedCache.pop_front();
+ igbe->anQ("TXS", annUsedCacheQ);
+ usedCache.push_back(desc);
+ tsoDescBytesUsed = 0;
+ }
+
+ if (useTso && tsoUsedLen == tsoTotalLen)
+ useTso = false;
+
- unusedCache.pop_front();
- usedCache.push_back(desc);
+ DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n",
+ pktPtr->length);
pktDone = true;
pktWaiting = false;
pktPtr = NULL;
-
- DPRINTF(EthernetDesc, "Descriptor Done\n");
+ tsoPktHasHeader = false;
if (igbe->regs.txdctl.wthresh() == 0) {
+ igbe->anBegin("TXS", "Desc Writeback");
DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
writeback(0);
+ } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >=
+ descInBlock(usedCache.size())) {
+ DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+ igbe->anBegin("TXS", "Desc Writeback");
+ writeback((igbe->cacheBlockSize()-1)>>4);
} else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+ igbe->anBegin("TXS", "Desc Writeback");
writeback((igbe->cacheBlockSize()-1)>>4);
}
+
enableSm();
igbe->checkDrain();
}
void
+IGbE::TxDescCache::actionAfterWb()
+{
+ DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
+ completionEnabled);
+ igbe->postInterrupt(iGbReg::IT_TXDW);
+ if (completionEnabled) {
+ descEnd = igbe->regs.tdh();
+ DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd,
+ completionAddress);
+ igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)),
+ sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
+ }
+}
+
+void
IGbE::TxDescCache::serialize(std::ostream &os)
{
DescCache<TxDesc>::serialize(os);
SERIALIZE_SCALAR(pktDone);
SERIALIZE_SCALAR(isTcp);
SERIALIZE_SCALAR(pktWaiting);
+ SERIALIZE_SCALAR(pktMultiDesc);
+
+ SERIALIZE_SCALAR(useTso);
+ SERIALIZE_SCALAR(tsoHeaderLen);
+ SERIALIZE_SCALAR(tsoMss);
+ SERIALIZE_SCALAR(tsoTotalLen);
+ SERIALIZE_SCALAR(tsoUsedLen);
+ SERIALIZE_SCALAR(tsoPrevSeq);;
+ SERIALIZE_SCALAR(tsoPktPayloadBytes);
+ SERIALIZE_SCALAR(tsoLoadedHeader);
+ SERIALIZE_SCALAR(tsoPktHasHeader);
+ SERIALIZE_ARRAY(tsoHeader, 256);
+ SERIALIZE_SCALAR(tsoDescBytesUsed);
+ SERIALIZE_SCALAR(tsoCopyBytes);
+ SERIALIZE_SCALAR(tsoPkts);
+
+ SERIALIZE_SCALAR(completionAddress);
+ SERIALIZE_SCALAR(completionEnabled);
+ SERIALIZE_SCALAR(descEnd);
}
void
@@ -1067,6 +1563,25 @@ IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(pktDone);
UNSERIALIZE_SCALAR(isTcp);
UNSERIALIZE_SCALAR(pktWaiting);
+ UNSERIALIZE_SCALAR(pktMultiDesc);
+
+ UNSERIALIZE_SCALAR(useTso);
+ UNSERIALIZE_SCALAR(tsoHeaderLen);
+ UNSERIALIZE_SCALAR(tsoMss);
+ UNSERIALIZE_SCALAR(tsoTotalLen);
+ UNSERIALIZE_SCALAR(tsoUsedLen);
+ UNSERIALIZE_SCALAR(tsoPrevSeq);;
+ UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
+ UNSERIALIZE_SCALAR(tsoLoadedHeader);
+ UNSERIALIZE_SCALAR(tsoPktHasHeader);
+ UNSERIALIZE_ARRAY(tsoHeader, 256);
+ UNSERIALIZE_SCALAR(tsoDescBytesUsed);
+ UNSERIALIZE_SCALAR(tsoCopyBytes);
+ UNSERIALIZE_SCALAR(tsoPkts);
+
+ UNSERIALIZE_SCALAR(completionAddress);
+ UNSERIALIZE_SCALAR(completionEnabled);
+ UNSERIALIZE_SCALAR(descEnd);
}
bool
@@ -1101,9 +1616,9 @@ IGbE::TxDescCache::hasOutstandingEvents()
void
IGbE::restartClock()
{
- if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() ==
- SimObject::Running)
- tickEvent.schedule((curTick/ticks(1)) * ticks(1) + ticks(1));
+ if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
+ getState() == SimObject::Running)
+ schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1));
}
unsigned int
@@ -1122,13 +1637,14 @@ IGbE::drain(Event *de)
rxTick = false;
if (tickEvent.scheduled())
- tickEvent.deschedule();
+ deschedule(tickEvent);
if (count)
changeState(Draining);
else
changeState(Drained);
+ DPRINTF(EthernetSM, "got drain() returning %d", count);
return count;
}
@@ -1142,6 +1658,7 @@ IGbE::resume()
rxTick = true;
restartClock();
+ DPRINTF(EthernetSM, "resuming from drain");
}
void
@@ -1150,6 +1667,7 @@ IGbE::checkDrain()
if (!drainEvent)
return;
+ DPRINTF(EthernetSM, "checkDrain() in drain\n");
txFifoTick = false;
txTick = false;
rxTick = false;
@@ -1172,20 +1690,22 @@ IGbE::txStateMachine()
// If we have a packet available and it's length is not 0 (meaning it's not
// a multidescriptor packet) put it in the fifo, otherwise an the next
// iteration we'll get the rest of the data
- if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
+ if (txPacket && txDescCache.packetAvailable()
+ && !txDescCache.packetMultiDesc() && txPacket->length) {
bool success;
+ anQ("TXS", "TX FIFO Q");
DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
success = txFifo.push(txPacket);
txFifoTick = true && !drainEvent;
assert(success);
txPacket = NULL;
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback((cacheBlockSize()-1)>>4);
return;
}
// Only support descriptor granularity
- assert(regs.txdctl.gran());
if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
postInterrupt(IT_TXDLOW);
@@ -1198,7 +1718,10 @@ IGbE::txStateMachine()
if (!txDescCache.packetWaiting()) {
if (txDescCache.descLeft() == 0) {
postInterrupt(IT_TXQE);
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback(0);
+ anBegin("TXS", "Desc Fetch");
+ anWe("TXS", txDescCache.annUnusedCacheQ);
txDescCache.fetchDescriptors();
DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
"writeback stopping ticking and posting TXQE\n");
@@ -1208,16 +1731,28 @@ IGbE::txStateMachine()
if (!(txDescCache.descUnused())) {
+ anBegin("TXS", "Desc Fetch");
txDescCache.fetchDescriptors();
+ anWe("TXS", txDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
txTick = false;
return;
}
+ anPq("TXS", txDescCache.annUnusedCacheQ);
+
+ txDescCache.processContextDesc();
+ if (txDescCache.packetWaiting()) {
+ DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n");
+ txTick = false;
+ return;
+ }
int size;
- size = txDescCache.getPacketSize();
+ size = txDescCache.getPacketSize(txPacket);
if (size > 0 && txFifo.avail() > size) {
+ anRq("TXS", "TX FIFO Q");
+ anBegin("TXS", "DMA Packet");
DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
"DMA of next packet\n", size);
txFifo.reserve(size);
@@ -1225,8 +1760,10 @@ IGbE::txStateMachine()
} else if (size <= 0) {
DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback(0);
} else {
+ anWf("TXS", "TX FIFO Q");
DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
"available in FIFO\n");
txTick = false;
@@ -1242,10 +1779,16 @@ IGbE::txStateMachine()
bool
IGbE::ethRxPkt(EthPacketPtr pkt)
{
+ rxBytes += pkt->length;
+ rxPackets++;
+
DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
+ anBegin("RXQ", "Wire Recv");
+
if (!regs.rctl.en()) {
DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
+ anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
return true;
}
@@ -1259,9 +1802,23 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
if (!rxFifo.push(pkt)) {
DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
postInterrupt(IT_RXO, true);
+ anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
return false;
}
+ if (CPA::available() && cpa->enabled()) {
+ assert(sys->numSystemsRunning <= 2);
+ System *other_sys;
+ if (sys->systemList[0] == sys)
+ other_sys = sys->systemList[1];
+ else
+ other_sys = sys->systemList[0];
+
+ cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+ anQ("RXQ", "RX FIFO Q");
+ cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+ }
+
return true;
}
@@ -1280,6 +1837,8 @@ IGbE::rxStateMachine()
rxDmaPacket = false;
DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
int descLeft = rxDescCache.descLeft();
+ DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
+ descLeft, regs.rctl.rdmts(), regs.rdlen());
switch (regs.rctl.rdmts()) {
case 2: if (descLeft > .125 * regs.rdlen()) break;
case 1: if (descLeft > .250 * regs.rdlen()) break;
@@ -1289,7 +1848,11 @@ IGbE::rxStateMachine()
break;
}
+ if (rxFifo.empty())
+ rxDescCache.writeback(0);
+
if (descLeft == 0) {
+ anBegin("RXS", "Writeback Descriptors");
rxDescCache.writeback(0);
DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
" writeback and stopping ticking\n");
@@ -1301,6 +1864,7 @@ IGbE::rxStateMachine()
if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
+ anBegin("RXS", "Writeback Descriptors");
if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
rxDescCache.writeback(regs.rxdctl.wthresh()-1);
else
@@ -1310,11 +1874,14 @@ IGbE::rxStateMachine()
if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
}
if (rxDescCache.descUnused() == 0) {
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
+ anWe("RXS", rxDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
"fetching descriptors and stopping ticking\n");
rxTick = false;
@@ -1329,42 +1896,58 @@ IGbE::rxStateMachine()
}
if (!rxDescCache.descUnused()) {
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
+ anWe("RXS", rxDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
rxTick = false;
DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
return;
}
+ anPq("RXS", rxDescCache.annUnusedCacheQ);
if (rxFifo.empty()) {
+ anWe("RXS", "RX FIFO Q");
DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
rxTick = false;
return;
}
+ anPq("RXS", "RX FIFO Q");
+ anBegin("RXS", "Get Desc");
EthPacketPtr pkt;
pkt = rxFifo.front();
- rxDescCache.writePacket(pkt);
+ pktOffset = rxDescCache.writePacket(pkt, pktOffset);
DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
- DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
- rxFifo.pop();
+ if (pktOffset == pkt->length) {
+ anBegin( "RXS", "FIFO Dequeue");
+ DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
+ pktOffset = 0;
+ anDq("RXS", "RX FIFO Q");
+ rxFifo.pop();
+ }
+
DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
rxTick = false;
rxDmaPacket = true;
+ anBegin("RXS", "DMA Packet");
}
void
IGbE::txWire()
{
if (txFifo.empty()) {
+ anWe("TXQ", "TX FIFO Q");
txFifoTick = false;
return;
}
+ anPq("TXQ", "TX FIFO Q");
if (etherInt->sendPacket(txFifo.front())) {
+ cpa->hwQ(CPA::FL_NONE, sys, macAddr, "TXQ", "WireQ", 0);
if (DTRACE(EthernetSM)) {
IpPtr ip(txFifo.front());
if (ip)
@@ -1373,8 +1956,15 @@ IGbE::txWire()
else
DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
}
+ anDq("TXQ", "TX FIFO Q");
+ anBegin("TXQ", "Wire Send");
DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
txFifo.avail());
+
+ txBytes += txFifo.front()->length;
+ txPackets++;
+ txFifoTick = false;
+
txFifo.pop();
} else {
// We'll get woken up when the packet ethTxDone() gets called
@@ -1398,12 +1988,13 @@ IGbE::tick()
if (rxTick || txTick || txFifoTick)
- tickEvent.schedule(curTick + ticks(1));
+ schedule(tickEvent, curTick + ticks(1));
}
void
IGbE::ethTxDone()
{
+ anBegin("TXQ", "Send Done");
// restart the tx state machines if they are stopped
// fifo to send another packet
// tx sm to put more data into the fifo
@@ -1412,6 +2003,7 @@ IGbE::ethTxDone()
txTick = true;
restartClock();
+ txWire();
DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
}
@@ -1426,6 +2018,7 @@ IGbE::serialize(std::ostream &os)
SERIALIZE_SCALAR(eeDataBits);
SERIALIZE_SCALAR(eeOpcode);
SERIALIZE_SCALAR(eeAddr);
+ SERIALIZE_SCALAR(lastInterrupt);
SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
rxFifo.serialize("rxfifo", os);
@@ -1459,6 +2052,8 @@ IGbE::serialize(std::ostream &os)
inter_time = interEvent.when();
SERIALIZE_SCALAR(inter_time);
+ SERIALIZE_SCALAR(pktOffset);
+
nameOut(os, csprintf("%s.TxDescCache", name()));
txDescCache.serialize(os);
@@ -1477,6 +2072,7 @@ IGbE::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(eeDataBits);
UNSERIALIZE_SCALAR(eeOpcode);
UNSERIALIZE_SCALAR(eeAddr);
+ UNSERIALIZE_SCALAR(lastInterrupt);
UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
rxFifo.unserialize("rxfifo", cp, section);
@@ -1501,19 +2097,21 @@ IGbE::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(inter_time);
if (rdtr_time)
- rdtrEvent.schedule(rdtr_time);
+ schedule(rdtrEvent, rdtr_time);
if (radv_time)
- radvEvent.schedule(radv_time);
+ schedule(radvEvent, radv_time);
if (tidv_time)
- tidvEvent.schedule(tidv_time);
+ schedule(tidvEvent, tidv_time);
if (tadv_time)
- tadvEvent.schedule(tadv_time);
+ schedule(tadvEvent, tadv_time);
if (inter_time)
- interEvent.schedule(inter_time);
+ schedule(interEvent, inter_time);
+
+ UNSERIALIZE_SCALAR(pktOffset);
txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh
index 9403c87b6..308cfabde 100644
--- a/src/dev/i8254xGBe.hh
+++ b/src/dev/i8254xGBe.hh
@@ -38,8 +38,8 @@
#include <deque>
#include <string>
+#include "base/cp_annotate.hh"
#include "base/inet.hh"
-#include "base/statistics.hh"
#include "dev/etherdevice.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
@@ -55,6 +55,7 @@ class IGbE : public EtherDevice
{
private:
IGbEInt *etherInt;
+ CPA *cpa;
// device registers
iGbReg::Regs regs;
@@ -84,11 +85,19 @@ class IGbE : public EtherDevice
bool rxDmaPacket;
+ // Number of bytes copied from current RX packet
+ int 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, true);
+ postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
@@ -98,7 +107,7 @@ class IGbE : public EtherDevice
void radvProcess() {
rxDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
- postInterrupt(iGbReg::IT_RXT, true);
+ postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::radvProcess>;
@@ -108,7 +117,7 @@ class IGbE : public EtherDevice
void tadvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
- postInterrupt(iGbReg::IT_TXDW, true);
+ postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
@@ -118,7 +127,7 @@ class IGbE : public EtherDevice
void tidvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
- postInterrupt(iGbReg::IT_TXDW, true);
+ postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
@@ -129,6 +138,8 @@ class IGbE : public EtherDevice
EventWrapper<IGbE, &IGbE::tick> tickEvent;
+ uint64_t macAddr;
+
void rxStateMachine();
void txStateMachine();
void txWire();
@@ -167,6 +178,35 @@ class IGbE : public EtherDevice
*/
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
{
@@ -177,7 +217,7 @@ class IGbE : public EtherDevice
virtual long descLen() const = 0;
virtual void updateHead(long h) = 0;
virtual void enableSm() = 0;
- virtual void intAfterWb() const {}
+ virtual void actionAfterWb() {}
virtual void fetchAfterWb() = 0;
std::deque<T*> usedCache;
@@ -216,9 +256,14 @@ class IGbE : public EtherDevice
EthPacketPtr pktPtr;
public:
+ /** Annotate sm*/
+ std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
+ annUsedDescQ, annUnusedCacheQ, annDescQ;
+
DescCache(IGbE *i, const std::string n, int s)
: igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),
- pktPtr(NULL), fetchEvent(this), wbEvent(this)
+ pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this),
+ fetchEvent(this), wbEvent(this)
{
fetchBuf = new T[size];
wbBuf = new T[size];
@@ -248,62 +293,92 @@ class IGbE : public EtherDevice
int curHead = descHead();
int max_to_wb = usedCache.size();
- DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
- "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
- curHead, descTail(), descLen(), cachePnt, max_to_wb,
- descLeft());
-
// Check if this writeback is less restrictive that the previous
// and if so setup another one immediately following it
- if (wbOut && (aMask < wbAlignment)) {
- moreToWb = true;
- wbAlignment = aMask;
+ if (wbOut) {
+ if (aMask < wbAlignment) {
+ moreToWb = true;
+ wbAlignment = aMask;
+ }
DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
return;
}
-
moreToWb = false;
wbAlignment = aMask;
+
+
+ DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
+ "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+ curHead, descTail(), descLen(), cachePnt, max_to_wb,
+ descLeft());
if (max_to_wb + curHead >= descLen()) {
max_to_wb = descLen() - curHead;
moreToWb = true;
// this is by definition aligned correctly
- } else if (aMask != 0) {
+ } else if (wbAlignment != 0) {
// align the wb point to the mask
- max_to_wb = max_to_wb & ~aMask;
+ max_to_wb = max_to_wb & ~wbAlignment;
}
DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
- if (max_to_wb <= 0 || wbOut)
+ if (max_to_wb <= 0) {
+ if (usedCache.size())
+ igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
+ else
+ igbe->anWe(annSmWb, annUsedCacheQ);
return;
+ }
wbOut = max_to_wb;
+ assert(!wbDelayEvent.scheduled());
+ igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+ igbe->anBegin(annSmWb, "Prepare Writeback Desc");
+ }
+
+ void writeback1()
+ {
+ // If we're draining delay issuing this DMA
+ if (igbe->getState() != SimObject::Running) {
+ igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+ return;
+ }
+
+ DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
+
for (int x = 0; x < wbOut; x++) {
assert(usedCache.size());
- memcpy(&wbBuf[x], usedCache[0], sizeof(T));
- delete usedCache[0];
- usedCache.pop_front();
+ memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+ igbe->anPq(annSmWb, annUsedCacheQ);
+ igbe->anPq(annSmWb, annDescQ);
+ igbe->anQ(annSmWb, annUsedDescQ);
}
+
+ igbe->anBegin(annSmWb, "Writeback Desc DMA");
assert(wbOut);
- igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
- wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);
+ igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)),
+ wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
+ igbe->wbCompDelay);
}
+ 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()
{
size_t max_to_fetch;
- if (curFetching)
+ if (curFetching) {
+ DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
return;
+ }
if (descTail() >= cachePnt)
max_to_fetch = descTail() - cachePnt;
@@ -312,7 +387,20 @@ class IGbE : public EtherDevice
size_t free_cache = size - usedCache.size() - unusedCache.size();
+ if (!max_to_fetch)
+ igbe->anWe(annSmFetch, annUnusedDescQ);
+ else
+ igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
+
+ if (max_to_fetch) {
+ if (!free_cache)
+ igbe->anWf(annSmFetch, annDescQ);
+ else
+ igbe->anRq(annSmFetch, annDescQ, free_cache);
+ }
+
max_to_fetch = std::min(max_to_fetch, free_cache);
+
DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
"%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
@@ -322,31 +410,53 @@ class IGbE : public EtherDevice
// Nothing to do
if (max_to_fetch == 0)
return;
-
+
// So we don't have two descriptor fetches going on at once
curFetching = max_to_fetch;
+ assert(!fetchDelayEvent.scheduled());
+ igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+ igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
+ }
+
+ void fetchDescriptors1()
+ {
+ // If we're draining delay issuing this DMA
+ if (igbe->getState() != SimObject::Running) {
+ igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+ return;
+ }
+
+ igbe->anBegin(annSmFetch, "Fetch Desc");
+
DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
descBase() + cachePnt * sizeof(T),
igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
curFetching * sizeof(T));
assert(curFetching);
igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
- curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
+ curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
+ igbe->fetchCompDelay);
}
+ EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
/** Called by event when dma to read descriptors is completed
*/
void fetchComplete()
{
T *newDesc;
+ igbe->anBegin(annSmFetch, "Fetch Complete");
for (int x = 0; x < curFetching; x++) {
newDesc = new T;
memcpy(newDesc, &fetchBuf[x], sizeof(T));
unusedCache.push_back(newDesc);
+ igbe->anDq(annSmFetch, annUnusedDescQ);
+ igbe->anQ(annSmFetch, annUnusedCacheQ);
+ igbe->anQ(annSmFetch, annDescQ);
}
+
#ifndef NDEBUG
int oldCp = cachePnt;
#endif
@@ -361,6 +471,16 @@ class IGbE : public EtherDevice
DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
oldCp, cachePnt);
+ if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
+ cachePnt)) == 0)
+ {
+ igbe->anWe(annSmFetch, annUnusedDescQ);
+ } else if (!(size - usedCache.size() - unusedCache.size())) {
+ igbe->anWf(annSmFetch, annDescQ);
+ } else {
+ igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
+ }
+
enableSm();
igbe->checkDrain();
}
@@ -372,10 +492,21 @@ class IGbE : public EtherDevice
void wbComplete()
{
+ igbe->anBegin(annSmWb, "Finish Writeback");
+
long curHead = descHead();
#ifndef NDEBUG
long oldHead = curHead;
#endif
+
+ for (int x = 0; x < wbOut; x++) {
+ assert(usedCache.size());
+ delete usedCache[0];
+ usedCache.pop_front();
+
+ igbe->anDq(annSmWb, annUsedCacheQ);
+ igbe->anDq(annSmWb, annDescQ);
+ }
curHead += wbOut;
wbOut = 0;
@@ -390,14 +521,19 @@ class IGbE : public EtherDevice
oldHead, curHead);
// If we still have more to wb, call wb now
- intAfterWb();
+ actionAfterWb();
if (moreToWb) {
+ moreToWb = false;
DPRINTF(EthernetDesc, "Writeback has more todo\n");
writeback(wbAlignment);
}
if (!wbOut) {
igbe->checkDrain();
+ if (usedCache.size())
+ igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
+ else
+ igbe->anWe(annSmWb, annUsedCacheQ);
}
fetchAfterWb();
}
@@ -411,8 +547,8 @@ class IGbE : public EtherDevice
int descLeft() const
{
int left = unusedCache.size();
- if (cachePnt - descTail() >= 0)
- left += (cachePnt - descTail());
+ if (cachePnt >= descTail())
+ left += (descLen() - cachePnt + descTail());
else
left += (descTail() - cachePnt);
@@ -464,6 +600,16 @@ class IGbE : public EtherDevice
arrayParamOut(os, csprintf("unusedCache_%d", x),
(uint8_t*)unusedCache[x],sizeof(T));
}
+
+ Tick fetch_delay = 0, wb_delay = 0;
+ if (fetchDelayEvent.scheduled())
+ fetch_delay = fetchDelayEvent.when();
+ SERIALIZE_SCALAR(fetch_delay);
+ if (wbDelayEvent.scheduled())
+ wb_delay = wbDelayEvent.when();
+ SERIALIZE_SCALAR(wb_delay);
+
+
}
virtual void unserialize(Checkpoint *cp, const std::string &section)
@@ -492,6 +638,15 @@ class IGbE : public EtherDevice
(uint8_t*)temp,sizeof(T));
unusedCache.push_back(temp);
}
+ Tick fetch_delay = 0, wb_delay = 0;
+ UNSERIALIZE_SCALAR(fetch_delay);
+ UNSERIALIZE_SCALAR(wb_delay);
+ if (fetch_delay)
+ igbe->schedule(fetchDelayEvent, fetch_delay);
+ if (wb_delay)
+ igbe->schedule(wbDelayEvent, wb_delay);
+
+
}
virtual bool hasOutstandingEvents() {
return wbEvent.scheduled() || fetchEvent.scheduled();
@@ -516,6 +671,12 @@ class IGbE : public EtherDevice
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 */
+ int bytesCopied;
+
public:
RxDescCache(IGbE *i, std::string n, int s);
@@ -523,20 +684,28 @@ class IGbE : public EtherDevice
* descriptor and update the book keeping. Should only be called when
* there are no dma's pending.
* @param packet ethernet packet to write
- * @return if the packet could be written (there was a free descriptor)
+ * @param pkt_offset bytes already copied from the packet to memory
+ * @return pkt_offset + number of bytes copied during this call
*/
- void writePacket(EthPacketPtr packet);
+ 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.
+ /** 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);
@@ -555,15 +724,37 @@ class IGbE : public EtherDevice
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
virtual void updateHead(long h) { igbe->regs.tdh(h); }
virtual void enableSm();
- virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW); }
+ 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);
@@ -572,9 +763,15 @@ class IGbE : public EtherDevice
* return the size the of the packet to reserve space in tx fifo.
* @return size of the packet
*/
- int getPacketSize();
+ int getPacketSize(EthPacketPtr p);
void getPacketData(EthPacketPtr p);
+ void processContextDesc();
+ /** Return the number of dsecriptors in a cache block for threshold
+ * operations.
+ */
+ int descInBlock(int 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
@@ -586,13 +783,35 @@ class IGbE : public EtherDevice
*/
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);
@@ -610,10 +829,12 @@ class IGbE : public EtherDevice
}
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);
diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh
index 91b3eacc9..4634dd9a3 100644
--- a/src/dev/i8254xGBe_defs.hh
+++ b/src/dev/i8254xGBe_defs.hh
@@ -59,11 +59,14 @@ 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;
@@ -74,12 +77,17 @@ 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;
@@ -87,6 +95,9 @@ 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;
@@ -94,9 +105,9 @@ 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 = 16;
+const uint8_t RCV_ADDRESS_TABLE_SIZE = 24;
const uint8_t MULTICAST_TABLE_SIZE = 128;
-const uint32_t STATS_REGS_SIZE = 0x124;
+const uint32_t STATS_REGS_SIZE = 0x228;
// Registers in that are accessed in the PHY
@@ -108,14 +119,17 @@ const uint8_t PHY_EPSTATUS = 15;
const uint8_t PHY_AGC = 18;
// Receive Descriptor Status Flags
-const uint8_t RXDS_PIF = 0x80;
-const uint8_t RXDS_IPCS = 0x40;
-const uint8_t RXDS_TCPCS = 0x20;
-const uint8_t RXDS_UDPCS = 0x10;
-const uint8_t RXDS_VP = 0x08;
-const uint8_t RXDS_IXSM = 0x04;
-const uint8_t RXDS_EOP = 0x02;
-const uint8_t RXDS_DD = 0x01;
+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;
@@ -125,6 +139,32 @@ 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
{
@@ -147,12 +187,38 @@ enum IntTypes
// Receive Descriptor struct
struct RxDesc {
- Addr buf;
- uint16_t len;
- uint16_t csum;
- uint8_t status;
- uint8_t errors;
- uint16_t vlan;
+ 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 {
@@ -163,24 +229,33 @@ struct TxDesc {
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 isContext(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_CNXT; }
-bool isData(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_DATA; }
+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));
-}
+void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
-bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
+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) { return (isData(d) || isContext(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); }
@@ -199,7 +274,15 @@ 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)); return bits(d->d2,47,40); }
+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
@@ -303,8 +386,8 @@ struct Regs {
struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(start,0,1); // start read
- ADD_FIELD32(done,4,1); // done read
- ADD_FIELD32(addr,8,8); // address
+ ADD_FIELD32(done,1,1); // done read
+ ADD_FIELD32(addr,2,14); // address
ADD_FIELD32(data,16,16); // data
};
EERD eerd;
@@ -470,6 +553,17 @@ struct Regs {
};
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
+ int bufLen() { return pktlen() << 10; }
+ int 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
@@ -531,6 +625,14 @@ struct Regs {
};
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
@@ -563,15 +665,42 @@ struct Regs {
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 #####
@@ -604,6 +733,32 @@ struct Regs {
};
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);
@@ -624,6 +779,7 @@ struct Regs {
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);
@@ -633,12 +789,20 @@ struct Regs {
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)
@@ -661,6 +825,7 @@ struct Regs {
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);
@@ -670,12 +835,20 @@ struct Regs {
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);
}
};
} // iGbReg namespace
diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc
index 6d7f1baf1..3d4e71888 100644
--- a/src/dev/ide_ctrl.cc
+++ b/src/dev/ide_ctrl.cc
@@ -30,203 +30,114 @@
* Miguel Serrano
*/
-#include <cstddef>
-#include <cstdlib>
#include <string>
-#include <vector>
#include "base/trace.hh"
#include "cpu/intr_control.hh"
#include "dev/ide_ctrl.hh"
#include "dev/ide_disk.hh"
-#include "dev/pciconfigall.hh"
-#include "dev/pcireg.h"
-#include "dev/platform.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/IdeController.hh"
-#include "sim/sim_object.hh"
#include "sim/byteswap.hh"
using namespace std;
-////
-// Initialization and destruction
-////
-
-IdeController::IdeController(Params *p)
- : PciDev(p)
+// 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)
{
- // initialize the PIO interface addresses
- pri_cmd_addr = 0;
- pri_cmd_size = BARSize[0];
-
- pri_ctrl_addr = 0;
- pri_ctrl_size = BARSize[1];
-
- sec_cmd_addr = 0;
- sec_cmd_size = BARSize[2];
-
- sec_ctrl_addr = 0;
- sec_ctrl_size = BARSize[3];
-
- // initialize the bus master interface (BMI) address to be configured
- // via PCI
- bmi_addr = 0;
- bmi_size = BARSize[4];
-
- // zero out all of the registers
- memset(bmi_regs.data, 0, sizeof(bmi_regs));
- memset(config_regs.data, 0, sizeof(config_regs.data));
-
- // setup initial values
- // enable both channels
- config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
- config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
- bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
- bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
-
- // reset all internal variables
- io_enabled = false;
- bm_enabled = false;
- memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
-
- // setup the disks attached to controller
- memset(disks, 0, sizeof(disks));
- dev[0] = 0;
- dev[1] = 0;
-
- if (params()->disks.size() > 3)
- panic("IDE controllers support a maximum of 4 devices attached!\n");
-
- for (int i = 0; i < params()->disks.size(); i++) {
- disks[i] = params()->disks[i];
- disks[i]->setController(this);
- }
+ memset(&bmiRegs, 0, sizeof(bmiRegs));
+ bmiRegs.status.dmaCap0 = 1;
+ bmiRegs.status.dmaCap1 = 1;
}
-IdeController::~IdeController()
+IdeController::Channel::~Channel()
{
- for (int i = 0; i < 4; i++)
- if (disks[i])
- delete disks[i];
+ delete master;
+ delete slave;
}
-////
-// Utility functions
-///
-
-void
-IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
- IdeRegType &reg_type)
-{
- offset = addr;
-
- if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
- offset -= pri_cmd_addr;
- reg_type = COMMAND_BLOCK;
- channel = PRIMARY;
- } else if (addr >= pri_ctrl_addr &&
- addr < (pri_ctrl_addr + pri_ctrl_size)) {
- offset -= pri_ctrl_addr;
- reg_type = CONTROL_BLOCK;
- channel = PRIMARY;
- } else if (addr >= sec_cmd_addr &&
- addr < (sec_cmd_addr + sec_cmd_size)) {
- offset -= sec_cmd_addr;
- reg_type = COMMAND_BLOCK;
- channel = SECONDARY;
- } else if (addr >= sec_ctrl_addr &&
- addr < (sec_ctrl_addr + sec_ctrl_size)) {
- offset -= sec_ctrl_addr;
- reg_type = CONTROL_BLOCK;
- channel = SECONDARY;
- } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
- offset -= bmi_addr;
- reg_type = BMI_BLOCK;
- channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
- } else {
- panic("IDE controller access to invalid address: %#x\n", addr);
- }
-}
-
-int
-IdeController::getDisk(IdeChannel 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)
{
- int disk = 0;
- uint8_t *devBit = &dev[0];
-
- if (channel == SECONDARY) {
- disk += 2;
- devBit = &dev[1];
- }
-
- disk += *devBit;
+ if (params()->disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
- assert(*devBit == 0 || *devBit == 1);
+ // 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];
- return disk;
-}
-
-int
-IdeController::getDisk(IdeDisk *diskPtr)
-{
- for (int i = 0; i < 4; i++) {
- if ((long)diskPtr == (long)disks[i])
- return i;
+ for (int i = 0; i < params()->disks.size(); i++) {
+ params()->disks[i]->setController(this);
}
- return -1;
+ primary.select(false);
+ secondary.select(false);
}
bool
IdeController::isDiskSelected(IdeDisk *diskPtr)
{
- for (int i = 0; i < 4; i++) {
- if ((long)diskPtr == (long)disks[i]) {
- // is disk is on primary or secondary channel
- int channel = i/2;
- // is disk the master or slave
- int devID = i%2;
-
- return (dev[channel] == devID);
- }
- }
- panic("Unable to find disk by pointer!!\n");
+ return (primary.selected == diskPtr || secondary.selected == diskPtr);
}
-////
-// Command completion
-////
+void
+IdeController::intrPost()
+{
+ primary.bmiRegs.status.intStatus = 1;
+ PciDev::intrPost();
+}
void
IdeController::setDmaComplete(IdeDisk *disk)
{
- int diskNum = getDisk(disk);
-
- if (diskNum < 0)
- panic("Unable to find disk based on pointer %#x\n", disk);
-
- if (diskNum < 2) {
- // clear the start/stop bit in the command register
- bmi_regs.bmic0 &= ~SSBM;
- // clear the bus master active bit in the status register
- bmi_regs.bmis0 &= ~BMIDEA;
- // set the interrupt bit
- bmi_regs.bmis0 |= IDEINTS;
+ Channel *channel;
+ if (disk == primary.master || disk == primary.slave) {
+ channel = &primary;
+ } else if (disk == secondary.master || disk == secondary.slave) {
+ channel = &secondary;
} else {
- // clear the start/stop bit in the command register
- bmi_regs.bmic1 &= ~SSBM;
- // clear the bus master active bit in the status register
- bmi_regs.bmis1 &= ~BMIDEA;
- // set the interrupt bit
- bmi_regs.bmis1 |= IDEINTS;
+ panic("Unable to find disk based on pointer %#x\n", disk);
}
-}
-
-////
-// Read and write handling
-////
+ channel->bmiRegs.command.startStop = 0;
+ channel->bmiRegs.status.active = 0;
+ channel->bmiRegs.status.intStatus = 1;
+}
Tick
IdeController::readConfig(PacketPtr pkt)
@@ -236,30 +147,28 @@ IdeController::readConfig(PacketPtr pkt)
return PciDev::readConfig(pkt);
}
- assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
-
pkt->allocate();
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
- case IDE_CTRL_CONF_DEV_TIMING:
- pkt->set<uint8_t>(config_regs.sidetim);
+ case DeviceTiming:
+ pkt->set<uint8_t>(deviceTiming);
break;
- case IDE_CTRL_CONF_UDMA_CNTRL:
- pkt->set<uint8_t>(config_regs.udmactl);
+ case UDMAControl:
+ pkt->set<uint8_t>(udmaControl);
break;
- case IDE_CTRL_CONF_PRIM_TIMING+1:
- pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
+ case PrimaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
break;
- case IDE_CTRL_CONF_SEC_TIMING+1:
- pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
+ case SecondaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
+ case IDEConfig:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
break;
- case IDE_CTRL_CONF_IDE_CONFIG+1:
- pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
+ 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",
@@ -270,17 +179,17 @@ IdeController::readConfig(PacketPtr pkt)
break;
case sizeof(uint16_t):
switch (offset) {
- case IDE_CTRL_CONF_PRIM_TIMING:
- pkt->set<uint16_t>(config_regs.idetim0);
+ case PrimaryTiming:
+ pkt->set<uint16_t>(primaryTiming);
break;
- case IDE_CTRL_CONF_SEC_TIMING:
- pkt->set<uint16_t>(config_regs.idetim1);
+ case SecondaryTiming:
+ pkt->set<uint16_t>(secondaryTiming);
break;
- case IDE_CTRL_CONF_UDMA_TIMING:
- pkt->set<uint16_t>(config_regs.udmatim);
+ case UDMATiming:
+ pkt->set<uint16_t>(udmaTiming);
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- pkt->set<uint16_t>(config_regs.ideconfig);
+ case IDEConfig:
+ pkt->set<uint16_t>(ideConfig);
break;
default:
panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
@@ -309,48 +218,45 @@ IdeController::writeConfig(PacketPtr pkt)
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(pkt);
} else {
- assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
-
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
- case IDE_CTRL_CONF_DEV_TIMING:
- config_regs.sidetim = pkt->get<uint8_t>();
+ case DeviceTiming:
+ deviceTiming = pkt->get<uint8_t>();
break;
- case IDE_CTRL_CONF_UDMA_CNTRL:
- config_regs.udmactl = pkt->get<uint8_t>();
+ case UDMAControl:
+ udmaControl = pkt->get<uint8_t>();
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
- (pkt->get<uint8_t>());
+ case IDEConfig:
+ replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
break;
- case IDE_CTRL_CONF_IDE_CONFIG+1:
- config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
- pkt->get<uint8_t>() << 8;
+ 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);
+ 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 IDE_CTRL_CONF_PRIM_TIMING:
- config_regs.idetim0 = pkt->get<uint16_t>();
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_SEC_TIMING:
- config_regs.idetim1 = pkt->get<uint16_t>();
+ case SecondaryTiming:
+ secondaryTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_UDMA_TIMING:
- config_regs.udmatim = pkt->get<uint16_t>();
+ case UDMATiming:
+ udmaTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- config_regs.ideconfig = pkt->get<uint16_t>();
+ case IDEConfig:
+ ideConfig = pkt->get<uint16_t>();
break;
default:
- panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
+ panic("Invalid PCI configuration write "
+ "for size 2 offset: %#x!\n",
offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
@@ -370,317 +276,223 @@ IdeController::writeConfig(PacketPtr pkt)
switch(offset) {
case PCI0_BASE_ADDR0:
if (BARAddrs[0] != 0)
- pri_cmd_addr = BARAddrs[0];
+ primary.cmdAddr = BARAddrs[0];
break;
case PCI0_BASE_ADDR1:
if (BARAddrs[1] != 0)
- pri_ctrl_addr = BARAddrs[1];
+ primary.ctrlAddr = BARAddrs[1];
break;
case PCI0_BASE_ADDR2:
if (BARAddrs[2] != 0)
- sec_cmd_addr = BARAddrs[2];
+ secondary.cmdAddr = BARAddrs[2];
break;
case PCI0_BASE_ADDR3:
if (BARAddrs[3] != 0)
- sec_ctrl_addr = BARAddrs[3];
+ secondary.ctrlAddr = BARAddrs[3];
break;
case PCI0_BASE_ADDR4:
if (BARAddrs[4] != 0)
- bmi_addr = BARAddrs[4];
+ bmiAddr = BARAddrs[4];
break;
case PCI_COMMAND:
- if (letoh(config.command) & PCI_CMD_IOSE)
- io_enabled = true;
- else
- io_enabled = false;
-
- if (letoh(config.command) & PCI_CMD_BME)
- bm_enabled = true;
- else
- bm_enabled = false;
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
break;
}
return configDelay;
}
-
-Tick
-IdeController::read(PacketPtr pkt)
+void
+IdeController::Channel::accessCommand(Addr offset,
+ int size, uint8_t *data, bool read)
{
- Addr offset;
- IdeChannel channel;
- IdeRegType reg_type;
- int disk;
-
- pkt->allocate();
- if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
- panic("Bad IDE read size: %d\n", pkt->getSize());
-
- parseAddr(pkt->getAddr(), offset, channel, reg_type);
-
- if (!io_enabled) {
- pkt->makeAtomicResponse();
- return pioDelay;
- }
-
- switch (reg_type) {
- case BMI_BLOCK:
- switch (pkt->getSize()) {
- case sizeof(uint8_t):
- pkt->set(bmi_regs.data[offset]);
- break;
- case sizeof(uint16_t):
- pkt->set(*(uint16_t*)&bmi_regs.data[offset]);
- break;
- case sizeof(uint32_t):
- pkt->set(*(uint32_t*)&bmi_regs.data[offset]);
- break;
- default:
- panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize());
- }
- break;
-
- case COMMAND_BLOCK:
- case CONTROL_BLOCK:
- disk = getDisk(channel);
+ const Addr SelectOffset = 6;
+ const uint8_t SelectDevBit = 0x10;
- if (disks[disk] == NULL) {
- pkt->set<uint8_t>(0);
- break;
- }
+ if (!read && offset == SelectOffset)
+ select(*data & SelectDevBit);
- switch (offset) {
- case DATA_OFFSET:
- switch (pkt->getSize()) {
- case sizeof(uint16_t):
- disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
- break;
-
- case sizeof(uint32_t):
- disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
- disks[disk]->read(offset, reg_type,
- pkt->getPtr<uint8_t>() + sizeof(uint16_t));
- break;
-
- default:
- panic("IDE read of data reg invalid size: %#x\n", pkt->getSize());
- }
- break;
- default:
- if (pkt->getSize() == sizeof(uint8_t)) {
- disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
- } else
- panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize());
- }
- break;
- default:
- panic("IDE controller read of unknown register block type!\n");
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readCommand(offset, size, data);
+ } else {
+ selected->writeCommand(offset, size, data);
}
- if (pkt->getSize() == 1)
- DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
- else if (pkt->getSize() == 2)
- DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), pkt->get<uint16_t>());
- else
- DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), pkt->get<uint32_t>());
-
- pkt->makeAtomicResponse();
- return pioDelay;
}
-Tick
-IdeController::write(PacketPtr pkt)
+void
+IdeController::Channel::accessControl(Addr offset,
+ int size, uint8_t *data, bool read)
{
- Addr offset;
- IdeChannel channel;
- IdeRegType reg_type;
- int disk;
- uint8_t oldVal, newVal;
-
- parseAddr(pkt->getAddr(), offset, channel, reg_type);
-
- if (!io_enabled) {
- pkt->makeAtomicResponse();
- DPRINTF(IdeCtrl, "io not enabled\n");
- return pioDelay;
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readControl(offset, size, data);
+ } else {
+ selected->writeControl(offset, size, data);
}
+}
- switch (reg_type) {
- case BMI_BLOCK:
- if (!bm_enabled) {
- pkt->makeAtomicResponse();
- return pioDelay;
- }
-
+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) {
- // Bus master IDE command register
- case BMIC1:
- case BMIC0:
- if (pkt->getSize() != sizeof(uint8_t))
- panic("Invalid BMIC write size: %x\n", pkt->getSize());
-
- // select the current disk based on DEV bit
- disk = getDisk(channel);
-
- oldVal = bmi_regs.chan[channel].bmic;
- newVal = pkt->get<uint8_t>();
-
- // if a DMA transfer is in progress, R/W control cannot change
- if (oldVal & SSBM) {
- if ((oldVal & RWCON) ^ (newVal & RWCON)) {
- (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
- }
- }
-
- // see if the start/stop bit is being changed
- if ((oldVal & SSBM) ^ (newVal & SSBM)) {
- if (oldVal & SSBM) {
- // stopping DMA transfer
- DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+ case BMICommand:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", size);
- // clear the BMIDEA bit
- bmi_regs.chan[channel].bmis =
- bmi_regs.chan[channel].bmis & ~BMIDEA;
+ BMICommandReg oldVal = bmiRegs.command;
+ BMICommandReg newVal = *data;
- if (disks[disk] == NULL)
- panic("DMA stop for disk %d which does not exist\n",
- disk);
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal.startStop && oldVal.rw != newVal.rw)
+ oldVal.rw = newVal.rw;
- // inform the disk of the DMA transfer abort
- disks[disk]->abortDma();
- } else {
- // starting DMA transfer
- DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ if (oldVal.startStop != newVal.startStop) {
+ if (selected == NULL)
+ panic("DMA start for disk which does not exist\n");
- // set the BMIDEA bit
- bmi_regs.chan[channel].bmis =
- bmi_regs.chan[channel].bmis | BMIDEA;
+ if (oldVal.startStop) {
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+ bmiRegs.status.active = 0;
- if (disks[disk] == NULL)
- panic("DMA start for disk %d which does not exist\n",
- disk);
+ selected->abortDma();
+ } else {
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ bmiRegs.status.active = 1;
- // inform the disk of the DMA transfer start
- disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
+ selected->startDma(letoh(bmiRegs.bmidtp));
+ }
}
- }
-
- // update the register value
- bmi_regs.chan[channel].bmic = newVal;
- break;
-
- // Bus master IDE status register
- case BMIS0:
- case BMIS1:
- if (pkt->getSize() != sizeof(uint8_t))
- panic("Invalid BMIS write size: %x\n", pkt->getSize());
-
- oldVal = bmi_regs.chan[channel].bmis;
- newVal = pkt->get<uint8_t>();
-
- // the BMIDEA bit is RO
- newVal |= (oldVal & BMIDEA);
- // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
- if ((oldVal & IDEINTS) && (newVal & IDEINTS))
- newVal &= ~IDEINTS; // clear the interrupt?
- else
- (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
-
- if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
- newVal &= ~IDEDMAE;
- else
- (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
-
- bmi_regs.chan[channel].bmis = newVal;
+ bmiRegs.command = newVal;
+ }
break;
-
- // Bus master IDE descriptor table pointer register
- case BMIDTP0:
- case BMIDTP1:
+ case BMIStatus:
{
- if (pkt->getSize() != sizeof(uint32_t))
- panic("Invalid BMIDTP write size: %x\n", pkt->getSize());
-
- bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);
+ 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 (pkt->getSize() != sizeof(uint8_t) &&
- pkt->getSize() != sizeof(uint16_t) &&
- pkt->getSize() != sizeof(uint32_t))
- panic("IDE controller write of invalid write size: %x\n",
- pkt->getSize());
-
- // do a default copy of data into the registers
- memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize());
+ 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);
}
- break;
- case COMMAND_BLOCK:
- if (offset == IDE_SELECT_OFFSET) {
- uint8_t *devBit = &dev[channel];
- *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;
- }
- // fall-through ok!
- case CONTROL_BLOCK:
- disk = getDisk(channel);
+ }
+}
- if (disks[disk] == NULL)
- break;
+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());
- switch (offset) {
- case DATA_OFFSET:
- switch (pkt->getSize()) {
- case sizeof(uint16_t):
- disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
- break;
+ if (!ioEnabled) {
+ pkt->makeAtomicResponse();
+ DPRINTF(IdeCtrl, "io not enabled\n");
+ return;
+ }
- case sizeof(uint32_t):
- disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
- disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +
- sizeof(uint16_t));
- break;
- default:
- panic("IDE write of data reg invalid size: %#x\n", pkt->getSize());
- }
- break;
- default:
- if (pkt->getSize() == sizeof(uint8_t)) {
- disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
- } else
- panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize());
+ 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;
+ primary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= primary.ctrlAddr &&
+ addr < (primary.ctrlAddr + primary.ctrlSize)) {
+ addr -= primary.ctrlAddr;
+ 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);
}
- break;
- default:
- panic("IDE controller write of unknown register block type!\n");
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
}
+ uint32_t data;
if (pkt->getSize() == 1)
- DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
+ data = pkt->get<uint8_t>();
else if (pkt->getSize() == 2)
- DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), pkt->get<uint16_t>());
+ data = pkt->get<uint16_t>();
else
- DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), pkt->get<uint32_t>());
-
+ data = pkt->get<uint32_t>();
+ DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
+ read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
pkt->makeAtomicResponse();
+}
+
+Tick
+IdeController::read(PacketPtr pkt)
+{
+ dispatchAccess(pkt, true);
return pioDelay;
}
-////
-// Serialization
-////
+Tick
+IdeController::write(PacketPtr pkt)
+{
+ dispatchAccess(pkt, false);
+ return pioDelay;
+}
void
IdeController::serialize(std::ostream &os)
@@ -688,30 +500,40 @@ IdeController::serialize(std::ostream &os)
// Serialize the PciDev base class
PciDev::serialize(os);
- // Serialize register addresses and sizes
- SERIALIZE_SCALAR(pri_cmd_addr);
- SERIALIZE_SCALAR(pri_cmd_size);
- SERIALIZE_SCALAR(pri_ctrl_addr);
- SERIALIZE_SCALAR(pri_ctrl_size);
- SERIALIZE_SCALAR(sec_cmd_addr);
- SERIALIZE_SCALAR(sec_cmd_size);
- SERIALIZE_SCALAR(sec_ctrl_addr);
- SERIALIZE_SCALAR(sec_ctrl_size);
- SERIALIZE_SCALAR(bmi_addr);
- SERIALIZE_SCALAR(bmi_size);
-
- // Serialize registers
- SERIALIZE_ARRAY(bmi_regs.data,
- sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
- SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
- SERIALIZE_ARRAY(config_regs.data,
- sizeof(config_regs.data) / sizeof(config_regs.data[0]));
+ // 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(io_enabled);
- SERIALIZE_SCALAR(bm_enabled);
- SERIALIZE_ARRAY(cmd_in_progress,
- sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
+ 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
@@ -720,30 +542,44 @@ IdeController::unserialize(Checkpoint *cp, const std::string &section)
// Unserialize the PciDev base class
PciDev::unserialize(cp, section);
- // Unserialize register addresses and sizes
- UNSERIALIZE_SCALAR(pri_cmd_addr);
- UNSERIALIZE_SCALAR(pri_cmd_size);
- UNSERIALIZE_SCALAR(pri_ctrl_addr);
- UNSERIALIZE_SCALAR(pri_ctrl_size);
- UNSERIALIZE_SCALAR(sec_cmd_addr);
- UNSERIALIZE_SCALAR(sec_cmd_size);
- UNSERIALIZE_SCALAR(sec_ctrl_addr);
- UNSERIALIZE_SCALAR(sec_ctrl_size);
- UNSERIALIZE_SCALAR(bmi_addr);
- UNSERIALIZE_SCALAR(bmi_size);
-
- // Unserialize registers
- UNSERIALIZE_ARRAY(bmi_regs.data,
- sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
- UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
- UNSERIALIZE_ARRAY(config_regs.data,
- sizeof(config_regs.data) / sizeof(config_regs.data[0]));
+ // 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(io_enabled);
- UNSERIALIZE_SCALAR(bm_enabled);
- UNSERIALIZE_ARRAY(cmd_in_progress,
- sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
+ 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 *
diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh
index f22d83e9c..89dc1ee9d 100644
--- a/src/dev/ide_ctrl.hh
+++ b/src/dev/ide_ctrl.hh
@@ -37,61 +37,13 @@
#ifndef __IDE_CTRL_HH__
#define __IDE_CTRL_HH__
+#include "base/bitunion.hh"
#include "dev/pcidev.hh"
#include "dev/pcireg.h"
#include "dev/io_device.hh"
#include "params/IdeController.hh"
-#define BMIC0 0x0 // Bus master IDE command register
-#define BMIS0 0x2 // Bus master IDE status register
-#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register
-#define BMIC1 0x8 // Bus master IDE command register
-#define BMIS1 0xa // Bus master IDE status register
-#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register
-
-// Bus master IDE command register bit fields
-#define RWCON 0x08 // Bus master read/write control
-#define SSBM 0x01 // Start/stop bus master
-
-// Bus master IDE status register bit fields
-#define DMA1CAP 0x40 // Drive 1 DMA capable
-#define DMA0CAP 0x20 // Drive 0 DMA capable
-#define IDEINTS 0x04 // IDE Interrupt Status
-#define IDEDMAE 0x02 // IDE DMA error
-#define BMIDEA 0x01 // Bus master IDE active
-
-// IDE Command byte fields
-#define IDE_SELECT_OFFSET (6)
-#define IDE_SELECT_DEV_BIT 0x10
-
-#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
-#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
-
-// IDE Timing Register bit fields
-#define IDETIM_DECODE_EN 0x8000
-
-// PCI device specific register byte offsets
-#define IDE_CTRL_CONF_START 0x40
-#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs))
-
-#define IDE_CTRL_CONF_PRIM_TIMING 0x40
-#define IDE_CTRL_CONF_SEC_TIMING 0x42
-#define IDE_CTRL_CONF_DEV_TIMING 0x44
-#define IDE_CTRL_CONF_UDMA_CNTRL 0x48
-#define IDE_CTRL_CONF_UDMA_TIMING 0x4A
-#define IDE_CTRL_CONF_IDE_CONFIG 0x54
-
-
-enum IdeRegType {
- COMMAND_BLOCK,
- CONTROL_BLOCK,
- BMI_BLOCK
-};
-
class IdeDisk;
-class IntrControl;
-class PciConfigAll;
-class Platform;
/**
* Device model for an Intel PIIX4 IDE controller
@@ -99,137 +51,109 @@ class Platform;
class IdeController : public PciDev
{
- friend class IdeDisk;
+ 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;
- enum IdeChannel {
- PRIMARY = 0,
- SECONDARY = 1
- };
+ /** IDE disks connected to this controller */
+ IdeDisk *master, *slave;
- private:
- /** Primary command block registers */
- Addr pri_cmd_addr;
- Addr pri_cmd_size;
- /** Primary control block registers */
- Addr pri_ctrl_addr;
- Addr pri_ctrl_size;
- /** Secondary command block registers */
- Addr sec_cmd_addr;
- Addr sec_cmd_size;
- /** Secondary control block registers */
- Addr sec_ctrl_addr;
- Addr sec_ctrl_size;
- /** Bus master interface (BMI) registers */
- Addr bmi_addr;
- Addr bmi_size;
+ /** Currently selected disk */
+ IdeDisk *selected;
- private:
- /** Registers used for bus master interface */
- union {
- uint8_t data[16];
-
- struct {
- uint8_t bmic0;
- uint8_t reserved_0;
- uint8_t bmis0;
- uint8_t reserved_1;
- uint32_t bmidtp0;
- uint8_t bmic1;
- uint8_t reserved_2;
- uint8_t bmis1;
- uint8_t reserved_3;
- uint32_t bmidtp1;
- };
-
- struct {
- uint8_t bmic;
- uint8_t reserved_4;
- uint8_t bmis;
- uint8_t reserved_5;
- uint32_t bmidtp;
- } chan[2];
+ bool selectBit;
- } bmi_regs;
- /** Shadows of the device select bit */
- uint8_t dev[2];
- /** Registers used in device specific PCI configuration */
- union {
- uint8_t data[22];
-
- struct {
- uint16_t idetim0;
- uint16_t idetim1;
- uint8_t sidetim;
- uint8_t reserved_0[3];
- uint8_t udmactl;
- uint8_t reserved_1;
- uint16_t udmatim;
- uint8_t reserved_2[8];
- uint16_t ideconfig;
- };
- } config_regs;
+ void
+ select(bool selSlave)
+ {
+ selectBit = selSlave;
+ selected = selectBit ? slave : master;
+ }
- // Internal management variables
- bool io_enabled;
- bool bm_enabled;
- bool cmd_in_progress[4];
+ 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);
- private:
- /** IDE disks connected to controller */
- IdeDisk *disks[4];
+ Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize);
+ ~Channel();
- private:
- /** Parse the access address to pass on to device */
- void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
- IdeRegType &reg_type);
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
- /** Select the disk based on the channel and device bit */
- int getDisk(IdeChannel channel);
+ Channel primary;
+ Channel secondary;
- /** Select the disk based on a pointer */
- int getDisk(IdeDisk *diskPtr);
+ /** Bus master interface (BMI) registers */
+ Addr bmiAddr, bmiSize;
- public:
- /** See if a disk is selected based on its pointer */
- bool isDiskSelected(IdeDisk *diskPtr);
+ /** 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;
+
+ void dispatchAccess(PacketPtr pkt, bool read);
public:
typedef IdeControllerParams Params;
const Params *params() const { return (const Params *)_params; }
IdeController(Params *p);
- ~IdeController();
- virtual Tick writeConfig(PacketPtr pkt);
- virtual Tick readConfig(PacketPtr pkt);
+ /** 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);
- /**
- * Read a done field for a given target.
- * @param pkt Packet describing what is to be read
- * @return The amount of time to complete this request
- */
- virtual Tick read(PacketPtr pkt);
-
- /**
- * Write a done field for a given target.
- * @param pkt Packet describing what is to be written
- * @return The amount of time to complete this request
- */
- 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);
+ 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_
diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc
index 8f9999beb..83faf508e 100644
--- a/src/dev/ide_disk.cc
+++ b/src/dev/ide_disk.cc
@@ -177,7 +177,7 @@ Addr
IdeDisk::pciToDma(Addr pciAddr)
{
if (ctrl)
- return ctrl->plat->pciToDma(pciAddr);
+ return ctrl->pciToDma(pciAddr);
else
panic("Access to unset controller!\n");
}
@@ -187,120 +187,127 @@ IdeDisk::pciToDma(Addr pciAddr)
////
void
-IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
+IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
{
- DevAction_t action = ACT_NONE;
-
- switch (reg_type) {
- case COMMAND_BLOCK:
- switch (offset) {
- // Data transfers occur two bytes at a time
- case DATA_OFFSET:
- *(uint16_t*)data = cmdReg.data;
- action = ACT_DATA_READ_SHORT;
- break;
- case ERROR_OFFSET:
- *data = cmdReg.error;
- break;
- case NSECTOR_OFFSET:
- *data = cmdReg.sec_count;
- break;
- case SECTOR_OFFSET:
- *data = cmdReg.sec_num;
- break;
- case LCYL_OFFSET:
- *data = cmdReg.cyl_low;
- break;
- case HCYL_OFFSET:
- *data = cmdReg.cyl_high;
- break;
- case DRIVE_OFFSET:
- *data = cmdReg.drive;
- break;
- case STATUS_OFFSET:
- *data = status;
- action = ACT_STAT_READ;
- break;
- default:
- panic("Invalid IDE command register offset: %#x\n", offset);
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ } else if (size == sizeof(uint32_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ updateState(ACT_DATA_READ_SHORT);
+ *((uint16_t *)data + 1) = cmdReg.data;
+ } else {
+ panic("Data read of unsupported size %d.\n", size);
}
+ updateState(ACT_DATA_READ_SHORT);
+ return;
+ }
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case ERROR_OFFSET:
+ *data = cmdReg.error;
break;
- case CONTROL_BLOCK:
- if (offset == ALTSTAT_OFFSET)
- *data = status;
- else
- panic("Invalid IDE control register offset: %#x\n", offset);
+ case NSECTOR_OFFSET:
+ *data = cmdReg.sec_count;
+ break;
+ case SECTOR_OFFSET:
+ *data = cmdReg.sec_num;
+ break;
+ case LCYL_OFFSET:
+ *data = cmdReg.cyl_low;
+ break;
+ case HCYL_OFFSET:
+ *data = cmdReg.cyl_high;
+ break;
+ case DRIVE_OFFSET:
+ *data = cmdReg.drive;
+ break;
+ case STATUS_OFFSET:
+ *data = status;
+ updateState(ACT_STAT_READ);
break;
default:
- panic("Unknown register block!\n");
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
- DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,
- (uint32_t)*data);
-
- if (action != ACT_NONE)
- updateState(action);
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
}
void
-IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
+IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
{
- DevAction_t action = ACT_NONE;
+ assert(size == sizeof(uint8_t));
+ *data = status;
+ if (offset != ALTSTAT_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
+}
- switch (reg_type) {
- case COMMAND_BLOCK:
- switch (offset) {
- case DATA_OFFSET:
- cmdReg.data = *(uint16_t*)data;
- action = ACT_DATA_WRITE_SHORT;
- break;
- case FEATURES_OFFSET:
- break;
- case NSECTOR_OFFSET:
- cmdReg.sec_count = *data;
- break;
- case SECTOR_OFFSET:
- cmdReg.sec_num = *data;
- break;
- case LCYL_OFFSET:
- cmdReg.cyl_low = *data;
- break;
- case HCYL_OFFSET:
- cmdReg.cyl_high = *data;
- break;
- case DRIVE_OFFSET:
- cmdReg.drive = *data;
- action = ACT_SELECT_WRITE;
- break;
- case COMMAND_OFFSET:
- cmdReg.command = *data;
- action = ACT_CMD_WRITE;
- break;
- default:
- panic("Invalid IDE command register offset: %#x\n", offset);
+void
+IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ } else if (size == sizeof(uint32_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ updateState(ACT_DATA_WRITE_SHORT);
+ cmdReg.data = *((const uint16_t *)data + 1);
+ } else {
+ panic("Data write of unsupported size %d.\n", size);
}
+ updateState(ACT_DATA_WRITE_SHORT);
+ return;
+ }
+
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case FEATURES_OFFSET:
break;
- case CONTROL_BLOCK:
- if (offset == CONTROL_OFFSET) {
- if (*data & CONTROL_RST_BIT) {
- // force the device into the reset state
- devState = Device_Srst;
- action = ACT_SRST_SET;
- } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
- action = ACT_SRST_CLEAR;
-
- nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
- }
- else
- panic("Invalid IDE control register offset: %#x\n", offset);
+ case NSECTOR_OFFSET:
+ cmdReg.sec_count = *data;
+ break;
+ case SECTOR_OFFSET:
+ cmdReg.sec_num = *data;
+ break;
+ case LCYL_OFFSET:
+ cmdReg.cyl_low = *data;
+ break;
+ case HCYL_OFFSET:
+ cmdReg.cyl_high = *data;
+ break;
+ case DRIVE_OFFSET:
+ cmdReg.drive = *data;
+ updateState(ACT_SELECT_WRITE);
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ updateState(ACT_CMD_WRITE);
break;
default:
- panic("Unknown register block!\n");
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
+ DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+}
+
+void
+IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset != CONTROL_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ updateState(ACT_SRST_SET);
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
+ updateState(ACT_SRST_CLEAR);
+ }
+
+ nIENBit = *data & CONTROL_IEN_BIT;
DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
(uint32_t)*data);
- if (action != ACT_NONE)
- updateState(action);
}
////
@@ -315,7 +322,7 @@ IdeDisk::doDmaTransfer()
dmaState, devState);
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaTransferEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else
ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
@@ -349,7 +356,7 @@ IdeDisk::doDmaDataRead()
DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
diskDelay, totalDiskDelay);
- dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
+ schedule(dmaReadWaitEvent, curTick + totalDiskDelay);
}
void
@@ -395,7 +402,7 @@ IdeDisk::doDmaRead()
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaReadWaitEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaReadCG->done()) {
assert(dmaReadCG->complete() < MAX_DMA_SIZE);
@@ -457,7 +464,7 @@ IdeDisk::doDmaDataWrite()
cmdBytesLeft -= SectorSize;
}
- dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
+ schedule(dmaWriteWaitEvent, curTick + totalDiskDelay);
}
void
@@ -470,7 +477,7 @@ IdeDisk::doDmaWrite()
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaWriteWaitEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaWriteCG->done()) {
assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
@@ -545,7 +552,7 @@ IdeDisk::startDma(const uint32_t &prdTableBase)
dmaState = Dma_Transfer;
// schedule dma transfer (doDmaTransfer)
- dmaTransferEvent.schedule(curTick + 1);
+ schedule(dmaTransferEvent, curTick + 1);
}
void
@@ -683,7 +690,6 @@ IdeDisk::intrPost()
// talk to controller to set interrupt
if (ctrl) {
- ctrl->bmi_regs.bmis0 |= IDEINTS;
ctrl->intrPost();
}
}
@@ -1073,12 +1079,12 @@ IdeDisk::unserialize(Checkpoint *cp, const string &section)
switch (event) {
case None : break;
- case Transfer : dmaTransferEvent.schedule(reschedule); break;
- case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
- case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
- case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
- case DmaRead : dmaReadEvent.schedule(reschedule); break;
- case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
+ case Transfer : schedule(dmaTransferEvent, reschedule); break;
+ case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
+ case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
+ case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
+ case DmaRead : schedule(dmaReadEvent, reschedule); break;
+ case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
}
// Unserialize device registers
diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh
index 62c89add4..1b455e8ad 100644
--- a/src/dev/ide_disk.hh
+++ b/src/dev/ide_disk.hh
@@ -238,12 +238,12 @@ class IdeDisk : public SimObject
/** Interrupt pending */
bool intrPending;
- Stats::Scalar<> dmaReadFullPages;
- Stats::Scalar<> dmaReadBytes;
- Stats::Scalar<> dmaReadTxs;
- Stats::Scalar<> dmaWriteFullPages;
- Stats::Scalar<> dmaWriteBytes;
- Stats::Scalar<> dmaWriteTxs;
+ Stats::Scalar dmaReadFullPages;
+ Stats::Scalar dmaReadBytes;
+ Stats::Scalar dmaReadTxs;
+ Stats::Scalar dmaWriteFullPages;
+ Stats::Scalar dmaWriteBytes;
+ Stats::Scalar dmaWriteTxs;
Stats::Formula rdBandwidth;
Stats::Formula wrBandwidth;
Stats::Formula totBandwidth;
@@ -278,8 +278,10 @@ class IdeDisk : public SimObject
}
// Device register read/write
- void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
- void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
+ 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);
diff --git a/src/dev/intel_8254_timer.cc b/src/dev/intel_8254_timer.cc
new file mode 100644
index 000000000..d5dd043e1
--- /dev/null
+++ b/src/dev/intel_8254_timer.cc
@@ -0,0 +1,278 @@
+/*
+ * 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 "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), 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 = count;
+ }
+}
+
+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 {
+ 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:
+ count = (count & 0xFF00) | data;
+
+ if (event.scheduled())
+ parent->deschedule(event);
+ output_high = false;
+ write_byte = MSB;
+ break;
+
+ case MSB:
+ count = (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 = count - 1;
+ else
+ period = 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 + ".count", 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 + ".count", 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;
+ 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)(Clock::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);
+}
+
+const char *
+Intel8254Timer::Counter::CounterEvent::description() const
+{
+ return "Intel 8254 Interval timer";
+}
diff --git a/src/dev/intel_8254_timer.hh b/src/dev/intel_8254_timer.hh
new file mode 100644
index 000000000..bb650d33b
--- /dev/null
+++ b/src/dev/intel_8254_timer.hh
@@ -0,0 +1,244 @@
+/*
+ * 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 <string>
+#include <iostream>
+
+#include "base/bitunion.hh"
+#include "sim/eventq.hh"
+#include "sim/host.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);
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ unsigned int num;
+
+ CounterEvent event;
+
+ /** Current count value */
+ uint16_t 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();
+
+ /** 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__
diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc
index 527397ed8..cdba171a6 100644
--- a/src/dev/io_device.cc
+++ b/src/dev/io_device.cc
@@ -117,7 +117,7 @@ DmaPort::recvTiming(PacketPtr pkt)
else if (backoffTime < device->maxBackoffDelay)
backoffTime <<= 1;
- backoffEvent.reschedule(curTick + backoffTime, true);
+ reschedule(backoffEvent, curTick + backoffTime, true);
DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
@@ -138,7 +138,10 @@ DmaPort::recvTiming(PacketPtr pkt)
state->numBytes += pkt->req->getSize();
assert(state->totBytes >= state->numBytes);
if (state->totBytes == state->numBytes) {
- state->completionEvent->process();
+ if (state->delay)
+ schedule(state->completionEvent, curTick + state->delay);
+ else
+ state->completionEvent->process();
delete state;
}
delete pkt->req;
@@ -187,9 +190,9 @@ void
DmaPort::recvRetry()
{
assert(transmitList.size());
- PacketPtr pkt = transmitList.front();
bool result = true;
do {
+ PacketPtr pkt = transmitList.front();
DPRINTF(DMA, "Retry on %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
result = sendTiming(pkt);
@@ -206,7 +209,7 @@ DmaPort::recvRetry()
if (transmitList.size() && backoffTime && !inRetry) {
DPRINTF(DMA, "Scheduling backoff for %d\n", curTick+backoffTime);
if (!backoffEvent.scheduled())
- backoffEvent.schedule(backoffTime+curTick);
+ schedule(backoffEvent, backoffTime + curTick);
}
DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
transmitList.size(), backoffTime, inRetry,
@@ -216,13 +219,13 @@ DmaPort::recvRetry()
void
DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
- uint8_t *data)
+ uint8_t *data, Tick delay)
{
assert(event);
assert(device->getState() == SimObject::Running);
- DmaReqState *reqState = new DmaReqState(event, this, size);
+ DmaReqState *reqState = new DmaReqState(event, this, size, delay);
DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
@@ -294,7 +297,7 @@ DmaPort::sendDma()
!backoffEvent.scheduled()) {
DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
backoffTime+curTick);
- backoffEvent.schedule(backoffTime+curTick);
+ schedule(backoffEvent, backoffTime + curTick);
}
} else if (state == Enums::atomic) {
transmitList.pop_front();
@@ -314,7 +317,7 @@ DmaPort::sendDma()
if (state->totBytes == state->numBytes) {
assert(!state->completionEvent->scheduled());
- state->completionEvent->schedule(curTick + lat);
+ schedule(state->completionEvent, curTick + lat + state->delay);
delete state;
delete pkt->req;
}
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
index 876166adb..70af6093d 100644
--- a/src/dev/io_device.hh
+++ b/src/dev/io_device.hh
@@ -32,6 +32,7 @@
#ifndef __DEV_IO_DEVICE_HH__
#define __DEV_IO_DEVICE_HH__
+#include "base/fast_alloc.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/tport.hh"
@@ -73,7 +74,7 @@ class PioPort : public SimpleTimingPort
class DmaPort : public Port
{
protected:
- struct DmaReqState : public Packet::SenderState
+ struct DmaReqState : public Packet::SenderState, public FastAlloc
{
/** Event to call on the device when this transaction (all packets)
* complete. */
@@ -88,8 +89,12 @@ class DmaPort : public Port
/** Number of bytes that have been acked for this transaction. */
Addr numBytes;
- DmaReqState(Event *ce, Port *p, Addr tb)
- : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0)
+ /** Amount to delay completion of dma by */
+ Tick delay;
+
+ DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay)
+ : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0),
+ delay(_delay)
{}
};
@@ -143,7 +148,7 @@ class DmaPort : public Port
DmaPort(DmaDevice *dev, System *s);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
- uint8_t *data = NULL);
+ uint8_t *data, Tick delay);
bool dmaPending() { return pendingCount > 0; }
@@ -207,7 +212,8 @@ class PioDevice : public MemObject
{
if (if_name == "pio") {
if (pioPort != NULL)
- panic("pio port already connected to.");
+ fatal("%s: pio port already connected to %s",
+ name(), pioPort->getPeer()->name());
pioPort = new PioPort(this, sys);
return pioPort;
} else
@@ -264,14 +270,14 @@ class DmaDevice : public PioDevice
return dynamic_cast<const Params *>(_params);
}
- void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
+ void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
{
- dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data);
+ dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
}
- void dmaRead(Addr addr, int size, Event *event, uint8_t *data)
+ void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
{
- dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data);
+ dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
}
bool dmaPending() { return dmaPort->dmaPending(); }
@@ -284,12 +290,14 @@ class DmaDevice : public PioDevice
{
if (if_name == "pio") {
if (pioPort != NULL)
- panic("pio port already connected to.");
+ fatal("%s: pio port already connected to %s",
+ name(), pioPort->getPeer()->name());
pioPort = new PioPort(this, sys);
return pioPort;
} else if (if_name == "dma") {
if (dmaPort != NULL)
- panic("dma port already connected to.");
+ fatal("%s: dma port already connected to %s",
+ name(), dmaPort->getPeer()->name());
dmaPort = new DmaPort(this, sys);
return dmaPort;
} else
diff --git a/src/dev/mc146818.cc b/src/dev/mc146818.cc
new file mode 100644
index 000000000..c01d945b3
--- /dev/null
+++ b/src/dev/mc146818.cc
@@ -0,0 +1,192 @@
+/*
+ * 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 <time.h>
+
+#include <string>
+
+#include "base/bitfield.hh"
+#include "base/time.hh"
+#include "base/trace.hh"
+#include "dev/mc146818.hh"
+#include "dev/rtcreg.h"
+
+using namespace std;
+
+MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
+ bool bcd, Tick frequency)
+ : EventManager(em), _name(n), event(this, frequency)
+{
+ 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;
+
+ year = time.tm_year;
+
+ if (bcd) {
+ // 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 = year % 100;
+ int tens = year / 10;
+ int ones = year % 10;
+ year = (tens << 4) + ones;
+ }
+
+ // 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;
+
+ DPRINTFN("Real-time clock set to %s", asctime(&time));
+}
+
+MC146818::~MC146818()
+{
+}
+
+void
+MC146818::writeData(const uint8_t addr, const uint8_t data)
+{
+ if (addr < RTC_STAT_REGA)
+ clock_data[addr] = data;
+ 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_BIN | 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::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);
+}
+
+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);
+
+ // We're not unserializing the event here, but we need to
+ // rescehedule the event since curTick was moved forward by the
+ // checkpoint
+ reschedule(event, curTick + event.interval);
+}
+
+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";
+}
diff --git a/src/dev/mc146818.hh b/src/dev/mc146818.hh
new file mode 100644
index 000000000..e145ad3fd
--- /dev/null
+++ b/src/dev/mc146818.hh
@@ -0,0 +1,126 @@
+/*
+ * 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;
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ /** RTC periodic interrupt event */
+ RTCEvent event;
+
+ /** 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;
+ };
+ };
+
+ /** 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);
+
+ /**
+ * 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__
diff --git a/src/dev/mips/Malta.py b/src/dev/mips/Malta.py
index d321a6361..d215bf329 100755
--- a/src/dev/mips/Malta.py
+++ b/src/dev/mips/Malta.py
@@ -28,12 +28,13 @@
from m5.params import *
from m5.proxy import *
+
+from BadDevice import BadDevice
from Device import BasicPioDevice
+from MipsBackdoor import MipsBackdoor
+from Pci import PciConfigAll
from Platform import Platform
-from MipsConsole import MipsConsole
from Uart import Uart8250
-from Pci import PciConfigAll
-from BadDevice import BadDevice
class MaltaCChip(BasicPioDevice):
type = 'MaltaCChip'
@@ -56,7 +57,7 @@ class Malta(Platform):
cchip = MaltaCChip(pio_addr=0x801a0000000)
io = MaltaIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0xBFD003F8)
- console = MipsConsole(pio_addr=0xBFD00F00, disk=Parent.simple_disk)
+ backdoor = MipsBackdoor(pio_addr=0xBFD00F00, 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
@@ -65,4 +66,4 @@ class Malta(Platform):
self.cchip.pio = bus.port
self.io.pio = bus.port
self.uart.pio = bus.port
- self.console.pio = bus.port
+ self.backdoor.pio = bus.port
diff --git a/src/dev/mips/MipsConsole.py b/src/dev/mips/MipsBackdoor.py
index 36575677a..f65250238 100644
--- a/src/dev/mips/MipsConsole.py
+++ b/src/dev/mips/MipsBackdoor.py
@@ -30,9 +30,9 @@ from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
-class MipsConsole(BasicPioDevice):
- type = 'MipsConsole'
+class MipsBackdoor(BasicPioDevice):
+ type = 'MipsBackdoor'
cpu = Param.BaseCPU(Parent.cpu[0], "Processor")
disk = Param.SimpleDisk("Simple Disk")
- sim_console = Param.SimConsole(Parent.any, "The Simulator Console")
+ terminal = Param.Terminal(Parent.any, "The console terminal")
system = Param.MipsSystem(Parent.any, "system object")
diff --git a/src/dev/mips/SConscript b/src/dev/mips/SConscript
index 22e91ff09..e83e47ebd 100755
--- a/src/dev/mips/SConscript
+++ b/src/dev/mips/SConscript
@@ -32,13 +32,13 @@
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'mips':
- SimObject('MipsConsole.py')
+ SimObject('MipsBackdoor.py')
SimObject('Malta.py')
TraceFlag('Malta')
TraceFlag('MC146818')
- Source('console.cc')
+ Source('backdoor.cc')
Source('malta.cc')
Source('malta_cchip.cc')
Source('malta_io.cc')
diff --git a/src/dev/mips/access.h b/src/dev/mips/access.h
index dbf3661b3..416b80590 100755
--- a/src/dev/mips/access.h
+++ b/src/dev/mips/access.h
@@ -48,37 +48,37 @@ typedef unsigned long uint64_t;
// 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
+ 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:
+ uint32_t kernStart; // 14:
+ uint32_t kernEnd; // 18:
+ uint32_t entryPoint; // 1c:
// console simple output stuff
- uint32_t outputChar; // 20: Placeholder for output
+ 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:
+ 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:
+ 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:
+ uint64_t cpuClock; // 38: MHz
+ uint64_t mem_size; // 40:
};
#endif // __MIPS_ACCESS_H__
diff --git a/src/dev/mips/console.cc b/src/dev/mips/backdoor.cc
index 185e1acbc..313f12567 100755
--- a/src/dev/mips/console.cc
+++ b/src/dev/mips/backdoor.cc
@@ -32,7 +32,7 @@
*/
/** @file
- * Mips Console Definition
+ * Mips Console Backdoor Definition
*/
#include <cstddef>
#include <string>
@@ -43,22 +43,22 @@
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "dev/mips/console.hh"
+#include "dev/mips/backdoor.hh"
#include "dev/platform.hh"
-#include "dev/simconsole.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/MipsConsole.hh"
+#include "params/MipsBackdoor.hh"
#include "sim/sim_object.hh"
using namespace std;
using namespace MipsISA;
-MipsConsole::MipsConsole(const Params *p)
- : BasicPioDevice(p), disk(p->disk), console(p->sim_console),
+MipsBackdoor::MipsBackdoor(const Params *p)
+ : BasicPioDevice(p), disk(p->disk), terminal(p->terminal),
system(p->system), cpu(p->cpu)
{
@@ -81,7 +81,7 @@ MipsConsole::MipsConsole(const Params *p)
}
void
-MipsConsole::startup()
+MipsBackdoor::startup()
{
system->setMipsAccess(pioAddr);
mipsAccess->numCPUs = system->getNumCPUs();
@@ -94,7 +94,7 @@ MipsConsole::startup()
}
Tick
-MipsConsole::read(PacketPtr pkt)
+MipsBackdoor::read(PacketPtr pkt)
{
/** XXX Do we want to push the addr munging to a bus brige or something? So
@@ -125,7 +125,7 @@ MipsConsole::read(PacketPtr pkt)
pkt->set(mipsAccess->intrClockFrequency);
break;
case offsetof(MipsAccess, inputChar):
- pkt->set(console->console_in());
+ pkt->set(terminal->console_in());
break;
case offsetof(MipsAccess, cpuClock):
pkt->set(mipsAccess->cpuClock);
@@ -169,7 +169,7 @@ MipsConsole::read(PacketPtr pkt)
else
panic("Unknown 32bit access, %#x\n", daddr);
}
- //DPRINTF(MipsConsole, "read: offset=%#x val=%#x\n", daddr,
+ //DPRINTF(MipsBackdoor, "read: offset=%#x val=%#x\n", daddr,
// pkt->get<uint64_t>());
break;
default:
@@ -181,7 +181,7 @@ MipsConsole::read(PacketPtr pkt)
}
Tick
-MipsConsole::write(PacketPtr pkt)
+MipsBackdoor::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
@@ -215,7 +215,7 @@ MipsConsole::write(PacketPtr pkt)
break;
case offsetof(MipsAccess, outputChar):
- console->out((char)(val & 0xff));
+ terminal->out((char)(val & 0xff));
break;
default:
@@ -235,7 +235,7 @@ MipsConsole::write(PacketPtr pkt)
}
void
-MipsConsole::Access::serialize(ostream &os)
+MipsBackdoor::Access::serialize(ostream &os)
{
SERIALIZE_SCALAR(last_offset);
SERIALIZE_SCALAR(version);
@@ -257,7 +257,7 @@ MipsConsole::Access::serialize(ostream &os)
}
void
-MipsConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
+MipsBackdoor::Access::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(last_offset);
UNSERIALIZE_SCALAR(version);
@@ -279,19 +279,19 @@ MipsConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
}
void
-MipsConsole::serialize(ostream &os)
+MipsBackdoor::serialize(ostream &os)
{
mipsAccess->serialize(os);
}
void
-MipsConsole::unserialize(Checkpoint *cp, const std::string &section)
+MipsBackdoor::unserialize(Checkpoint *cp, const std::string &section)
{
mipsAccess->unserialize(cp, section);
}
-MipsConsole *
-MipsConsoleParams::create()
+MipsBackdoor *
+MipsBackdoorParams::create()
{
- return new MipsConsole(this);
+ return new MipsBackdoor(this);
}
diff --git a/src/dev/mips/console.hh b/src/dev/mips/backdoor.hh
index 34792090d..b8cc0ae46 100755
--- a/src/dev/mips/console.hh
+++ b/src/dev/mips/backdoor.hh
@@ -29,28 +29,28 @@
*/
/** @file
- * System Console Interface
+ * System Console Backdoor Interface
*/
-#ifndef __MIPS_CONSOLE_HH__
-#define __MIPS_CONSOLE_HH__
+#ifndef __DEV_MIPS_BACKDOOR_HH__
+#define __DEV_MIPS_BACKDOOR_HH__
#include "base/range.hh"
#include "dev/mips/access.h"
#include "dev/io_device.hh"
-#include "params/MipsConsole.hh"
+#include "params/MipsBackdoor.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
class BaseCPU;
-class SimConsole;
+class Terminal;
class MipsSystem;
class SimpleDisk;
/**
* Memory mapped interface to the system console. This device
* represents a shared data region between the OS Kernel and the
- * System Console.
+ * 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
@@ -72,7 +72,7 @@ class SimpleDisk;
* primarily used doing boot before the kernel has loaded its device
* drivers.
*/
-class MipsConsole : public BasicPioDevice
+class MipsBackdoor : public BasicPioDevice
{
protected:
struct Access : public MipsAccess
@@ -89,8 +89,8 @@ class MipsConsole : public BasicPioDevice
/** the disk must be accessed from the console */
SimpleDisk *disk;
- /** the system console (the terminal) is accessable from the console */
- SimConsole *console;
+ /** the system terminal is accessable from the console */
+ Terminal *terminal;
/** a pointer to the system we are running in */
MipsSystem *system;
@@ -99,8 +99,8 @@ class MipsConsole : public BasicPioDevice
BaseCPU *cpu;
public:
- typedef MipsConsoleParams Params;
- MipsConsole(const Params *p);
+ typedef MipsBackdoorParams Params;
+ MipsBackdoor(const Params *p);
const Params *
params() const
@@ -123,4 +123,4 @@ class MipsConsole : public BasicPioDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
-#endif // __MIPS_CONSOLE_HH__
+#endif // __DEV_MIPS_BACKDOOR_HH__
diff --git a/src/dev/mips/malta.cc b/src/dev/mips/malta.cc
index 0b1fa15ba..21e79d999 100755
--- a/src/dev/mips/malta.cc
+++ b/src/dev/mips/malta.cc
@@ -38,11 +38,11 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/mips/malta_cchip.hh"
#include "dev/mips/malta_pchip.hh"
#include "dev/mips/malta_io.hh"
#include "dev/mips/malta.hh"
+#include "dev/terminal.hh"
#include "params/Malta.hh"
#include "sim/system.hh"
diff --git a/src/dev/mips/malta_cchip.cc b/src/dev/mips/malta_cchip.cc
index 5a4ea4585..265977665 100755
--- a/src/dev/mips/malta_cchip.cc
+++ b/src/dev/mips/malta_cchip.cc
@@ -103,7 +103,7 @@ MaltaCChip::read(PacketPtr pkt)
break;
case TSDEV_CC_MISC:
pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
- (pkt->req->getCpuNum() & 0x3));
+ (pkt->req->contextId() & 0x3));
break;
case TSDEV_CC_AAR0:
case TSDEV_CC_AAR1:
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
index bd48bdca5..fb3446299 100644
--- a/src/dev/ns_gige.cc
+++ b/src/dev/ns_gige.cc
@@ -36,6 +36,7 @@
#include <deque>
#include <string>
+#include "base/debug.hh"
#include "base/inet.hh"
#include "cpu/thread_context.hh"
#include "dev/etherlink.hh"
@@ -44,9 +45,7 @@
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/NSGigE.hh"
-#include "sim/debug.hh"
#include "sim/host.hh"
-#include "sim/stats.hh"
#include "sim/system.hh"
const char *NsRxStateStrings[] =
@@ -131,341 +130,6 @@ NSGigE::NSGigE(Params *p)
NSGigE::~NSGigE()
{}
-void
-NSGigE::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;
-}
-
-
/**
* This is to write to the PCI general configuration registers
*/
@@ -1186,6 +850,7 @@ NSGigE::devIntrPost(uint32_t interrupts)
Tick when = curTick;
if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
when += intrDelay;
+ postedInterrupts++;
cpuIntrPost(when);
}
}
@@ -1226,9 +891,6 @@ NSGigE::devIntrClear(uint32_t interrupts)
postedRxOrn++;
}
- if (regs.isr & regs.imr & ISR_IMPL)
- postedInterrupts++;
-
interrupts &= ~ISR_NOIMPL;
regs.isr &= ~interrupts;
@@ -1283,7 +945,8 @@ NSGigE::cpuIntrPost(Tick when)
if (intrEvent)
intrEvent->squash();
- intrEvent = new IntrEvent(this, intrTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrTick);
}
void
@@ -1780,7 +1443,7 @@ NSGigE::rxKick()
NsRxStateStrings[rxState]);
if (clock && !rxKickEvent.scheduled())
- rxKickEvent.schedule(rxKickTick);
+ schedule(rxKickEvent, rxKickTick);
}
void
@@ -1830,7 +1493,7 @@ NSGigE::transmit()
if (!txFifo.empty() && !txEvent.scheduled()) {
DPRINTF(Ethernet, "reschedule transmit\n");
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
}
}
@@ -2036,19 +1699,34 @@ NSGigE::txKick()
IpPtr ip(txPacket);
if (extsts & EXTSTS_UDPPKT) {
UdpPtr udp(ip);
- udp->sum(0);
- udp->sum(cksum(udp));
- txUdpChecksums++;
+ if (udp) {
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ txUdpChecksums++;
+ } else {
+ debug_break();
+ warn_once("UDPPKT set, but not UDP!\n");
+ }
} else if (extsts & EXTSTS_TCPPKT) {
TcpPtr tcp(ip);
- tcp->sum(0);
- tcp->sum(cksum(tcp));
- txTcpChecksums++;
+ if (tcp) {
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ txTcpChecksums++;
+ } else {
+ debug_break();
+ warn_once("TCPPKT set, but not UDP!\n");
+ }
}
if (extsts & EXTSTS_IPPKT) {
- ip->sum(0);
- ip->sum(cksum(ip));
- txIpChecksums++;
+ if (ip) {
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ txIpChecksums++;
+ } else {
+ debug_break();
+ warn_once("IPPKT set, but not UDP!\n");
+ }
}
}
@@ -2208,7 +1886,7 @@ NSGigE::txKick()
NsTxStateStrings[txState]);
if (clock && !txKickEvent.scheduled())
- txKickEvent.schedule(txKickTick);
+ schedule(txKickEvent, txKickTick);
}
/**
@@ -2322,7 +2000,7 @@ NSGigE::transferDone()
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
- txEvent.reschedule(curTick + ticks(1), true);
+ reschedule(txEvent, curTick + ticks(1), true);
}
bool
@@ -2723,7 +2401,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
this->txDmaState = (DmaState) txDmaState;
UNSERIALIZE_SCALAR(txKickTick);
if (txKickTick)
- txKickEvent.schedule(txKickTick);
+ schedule(txKickEvent, txKickTick);
/*
* unserialize rx state machine
@@ -2741,7 +2419,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
this->rxDmaState = (DmaState) rxDmaState;
UNSERIALIZE_SCALAR(rxKickTick);
if (rxKickTick)
- rxKickEvent.schedule(rxKickTick);
+ schedule(rxKickEvent, rxKickTick);
/*
* Unserialize EEPROM state machine
@@ -2761,7 +2439,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
Tick transmitTick;
UNSERIALIZE_SCALAR(transmitTick);
if (transmitTick)
- txEvent.schedule(curTick + transmitTick);
+ schedule(txEvent, curTick + transmitTick);
/*
* unserialize receive address filter settings
@@ -2782,7 +2460,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
Tick intrEventTick;
UNSERIALIZE_SCALAR(intrEventTick);
if (intrEventTick) {
- intrEvent = new IntrEvent(this, intrEventTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrEventTick);
}
}
diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh
index dfdd81b66..87cf56962 100644
--- a/src/dev/ns_gige.hh
+++ b/src/dev/ns_gige.hh
@@ -38,7 +38,6 @@
#define __DEV_NS_GIGE_HH__
#include "base/inet.hh"
-#include "base/statistics.hh"
#include "dev/etherdevice.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
@@ -63,10 +62,10 @@ const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0
* Ethernet device registers
*/
struct dp_regs {
- uint32_t command;
- uint32_t config;
- uint32_t mear;
- uint32_t ptscr;
+ uint32_t command;
+ uint32_t config;
+ uint32_t mear;
+ uint32_t ptscr;
uint32_t isr;
uint32_t imr;
uint32_t ier;
@@ -372,60 +371,6 @@ class NSGigE : public EtherDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
-
- public:
- void regStats();
-
- private:
- 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;
};
/*
diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc
index faf033705..74396be5d 100644
--- a/src/dev/pciconfigall.cc
+++ b/src/dev/pciconfigall.cc
@@ -47,7 +47,7 @@ using namespace std;
PciConfigAll::PciConfigAll(const Params *p)
: PioDevice(p)
{
- pioAddr = p->platform->calcConfigAddr(params()->bus,0,0);
+ pioAddr = p->platform->calcPciConfigAddr(params()->bus,0,0);
}
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index aa532414c..b311ed8cf 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -41,7 +41,7 @@
#include "base/inifile.hh"
#include "base/intmath.hh" // for isPowerOf2(
#include "base/misc.hh"
-#include "base/str.hh" // for to_number
+#include "base/str.hh" // for to_number
#include "base/trace.hh"
#include "dev/pciconfigall.hh"
#include "dev/pcidev.hh"
@@ -56,10 +56,10 @@ using namespace std;
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
int funcid, Platform *p)
- : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p),
- busId(busid), deviceId(devid), functionId(funcid)
+ : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev),
+ platform(p), busId(busid), deviceId(devid), functionId(funcid)
{
- configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
+ configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId);
}
@@ -121,15 +121,26 @@ PciDev::PciDev(const Params *p)
BARSize[4] = p->BAR4Size;
BARSize[5] = p->BAR5Size;
+ legacyIO[0] = p->BAR0LegacyIO;
+ legacyIO[1] = p->BAR1LegacyIO;
+ legacyIO[2] = p->BAR2LegacyIO;
+ legacyIO[3] = p->BAR3LegacyIO;
+ legacyIO[4] = p->BAR4LegacyIO;
+ legacyIO[5] = p->BAR5LegacyIO;
+
for (int i = 0; i < 6; ++i) {
- uint32_t barsize = BARSize[i];
- if (barsize != 0 && !isPowerOf2(barsize)) {
- fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
+ if (legacyIO[i]) {
+ BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i]));
+ config.baseAddr[i] = 0;
+ } else {
+ BARAddrs[i] = 0;
+ uint32_t barsize = BARSize[i];
+ if (barsize != 0 && !isPowerOf2(barsize)) {
+ fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
+ }
}
}
- memset(BARAddrs, 0, sizeof(BARAddrs));
-
plat->registerPciDevice(0, p->pci_dev, p->pci_func,
letoh(config.interruptLine));
}
@@ -216,8 +227,10 @@ PciDev::writeConfig(PacketPtr pkt)
switch (offset) {
case PCI0_INTERRUPT_LINE:
config.interruptLine = pkt->get<uint8_t>();
+ break;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
+ break;
case PCI_LATENCY_TIMER:
config.latencyTimer = pkt->get<uint8_t>();
break;
@@ -240,8 +253,10 @@ PciDev::writeConfig(PacketPtr pkt)
switch (offset) {
case PCI_COMMAND:
config.command = pkt->get<uint8_t>();
+ break;
case PCI_STATUS:
config.status = pkt->get<uint8_t>();
+ break;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
break;
@@ -264,30 +279,32 @@ PciDev::writeConfig(PacketPtr pkt)
{
int barnum = BAR_NUMBER(offset);
- // convert BAR values to host endianness
- uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
- uint32_t he_new_bar = letoh(pkt->get<uint32_t>());
-
- uint32_t bar_mask =
- BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
-
- // Writing 0xffffffff to a BAR tells the card to set the
- // value of the bar to a bitmask indicating the size of
- // memory it needs
- if (he_new_bar == 0xffffffff) {
- he_new_bar = ~(BARSize[barnum] - 1);
- } else {
- // does it mean something special to write 0 to a BAR?
- he_new_bar &= ~bar_mask;
- if (he_new_bar) {
- Addr space_base = BAR_IO_SPACE(he_old_bar) ?
- TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY;
- BARAddrs[barnum] = he_new_bar + space_base;
- pioPort->sendStatusChange(Port::RangeChange);
+ if (!legacyIO[barnum]) {
+ // convert BAR values to host endianness
+ uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
+ uint32_t he_new_bar = letoh(pkt->get<uint32_t>());
+
+ uint32_t bar_mask =
+ BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
+
+ // Writing 0xffffffff to a BAR tells the card to set the
+ // value of the bar to a bitmask indicating the size of
+ // memory it needs
+ if (he_new_bar == 0xffffffff) {
+ he_new_bar = ~(BARSize[barnum] - 1);
+ } else {
+ // does it mean something special to write 0 to a BAR?
+ he_new_bar &= ~bar_mask;
+ if (he_new_bar) {
+ BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
+ platform->calcPciIOAddr(he_new_bar) :
+ platform->calcPciMemAddr(he_new_bar);
+ pioPort->sendStatusChange(Port::RangeChange);
+ }
}
+ config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
+ (he_old_bar & bar_mask));
}
- config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
- (he_old_bar & bar_mask));
}
break;
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
index a584a957d..5da8b2dfc 100644
--- a/src/dev/pcidev.hh
+++ b/src/dev/pcidev.hh
@@ -99,6 +99,9 @@ class PciDev : public DmaDevice
/** The current address mapping of the BARs */
Addr BARAddrs[6];
+ /** Whether the BARs are really hardwired legacy IO locations. */
+ bool legacyIO[6];
+
/**
* Does the given address lie within the space mapped by the given
* base address register?
diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h
index df57acdb0..5639d8e29 100644
--- a/src/dev/pcireg.h
+++ b/src/dev/pcireg.h
@@ -69,18 +69,18 @@ union PCIConfig {
};
// Common PCI offsets
-#define PCI_VENDOR_ID 0x00 // Vendor ID ro
-#define PCI_DEVICE_ID 0x02 // Device ID ro
-#define PCI_COMMAND 0x04 // Command rw
-#define PCI_STATUS 0x06 // Status rw
-#define PCI_REVISION_ID 0x08 // Revision ID ro
-#define PCI_CLASS_CODE 0x09 // Class Code ro
-#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
-#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
-#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
-#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
-#define PCI_HEADER_TYPE 0x0E // Header Type ro
-#define PCI_BIST 0x0F // Built in self test rw
+#define PCI_VENDOR_ID 0x00 // Vendor ID ro
+#define PCI_DEVICE_ID 0x02 // Device ID ro
+#define PCI_COMMAND 0x04 // Command rw
+#define PCI_STATUS 0x06 // Status rw
+#define PCI_REVISION_ID 0x08 // Revision ID ro
+#define PCI_CLASS_CODE 0x09 // Class Code ro
+#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
+#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
+#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
+#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
+#define PCI_HEADER_TYPE 0x0E // Header Type ro
+#define PCI_BIST 0x0F // Built in self test rw
// some pci command reg bitfields
#define PCI_CMD_BME 0x04 // Bus master function enable
@@ -88,62 +88,62 @@ union PCIConfig {
#define PCI_CMD_IOSE 0x01 // I/O space enable
// Type 0 PCI offsets
-#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
-#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
-#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
-#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
-#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
-#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
-#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
-#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
-#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
-#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
-#define PCI0_RESERVED0 0x34
-#define PCI0_RESERVED1 0x38
-#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
-#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
-#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
-#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
+#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
+#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
+#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
+#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
+#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
+#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
+#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
+#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
+#define PCI0_RESERVED0 0x34
+#define PCI0_RESERVED1 0x38
+#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
+#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
+#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
+#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
// Type 1 PCI offsets
-#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
-#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
-#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
-#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
-#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
-#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
-#define PCI1_IO_BASE 0x1C // I/O Base rw
-#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
-#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
-#define PCI1_MEM_BASE 0x20 // Memory Base rw
-#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
-#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
-#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
-#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
-#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
-#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
-#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
-#define PCI1_RESERVED 0x34 // Reserved ro
-#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
-#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
-#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
-#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
+#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
+#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
+#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
+#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
+#define PCI1_IO_BASE 0x1C // I/O Base rw
+#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
+#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
+#define PCI1_MEM_BASE 0x20 // Memory Base rw
+#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
+#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
+#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
+#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
+#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
+#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
+#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
+#define PCI1_RESERVED 0x34 // Reserved ro
+#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
+#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
+#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
+#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
// Device specific offsets
-#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
+#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
#define PCI_CONFIG_SIZE 0xFF
// Some Vendor IDs
-#define PCI_VENDOR_DEC 0x1011
-#define PCI_VENDOR_NCR 0x101A
-#define PCI_VENDOR_QLOGIC 0x1077
-#define PCI_VENDOR_SIMOS 0x1291
+#define PCI_VENDOR_DEC 0x1011
+#define PCI_VENDOR_NCR 0x101A
+#define PCI_VENDOR_QLOGIC 0x1077
+#define PCI_VENDOR_SIMOS 0x1291
// Some Product IDs
-#define PCI_PRODUCT_DEC_PZA 0x0008
-#define PCI_PRODUCT_NCR_810 0x0001
-#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
-#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
-#define PCI_PRODUCT_SIMOS_ETHER 0x1292
+#define PCI_PRODUCT_DEC_PZA 0x0008
+#define PCI_PRODUCT_NCR_810 0x0001
+#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
+#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
+#define PCI_PRODUCT_SIMOS_ETHER 0x1292
#endif // __PCIREG_H__
diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc
index 37f7ff680..97d6c04af 100644
--- a/src/dev/pktfifo.cc
+++ b/src/dev/pktfifo.cc
@@ -40,23 +40,24 @@ PacketFifo::copyout(void *dest, int offset, int len)
if (offset + len >= size())
return false;
- list<EthPacketPtr>::iterator p = fifo.begin();
- list<EthPacketPtr>::iterator end = fifo.end();
+ iterator i = fifo.begin();
+ iterator end = fifo.end();
while (len > 0) {
- while (offset >= (*p)->length) {
- offset -= (*p)->length;
- ++p;
+ EthPacketPtr &pkt = i->packet;
+ while (offset >= pkt->length) {
+ offset -= pkt->length;
+ ++i;
}
- if (p == end)
+ if (i == end)
panic("invalid fifo");
- int size = min((*p)->length - offset, len);
- memcpy(data, (*p)->data, size);
+ int size = min(pkt->length - offset, len);
+ memcpy(data, pkt->data, size);
offset = 0;
len -= size;
data += size;
- ++p;
+ ++i;
}
return true;
@@ -64,6 +65,26 @@ PacketFifo::copyout(void *dest, int offset, int len)
void
+PacketFifoEntry::serialize(const string &base, ostream &os)
+{
+ packet->serialize(base + ".packet", os);
+ paramOut(os, base + ".slack", slack);
+ paramOut(os, base + ".number", number);
+ paramOut(os, base + ".priv", priv);
+}
+
+void
+PacketFifoEntry::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ packet = new EthPacketData(16384);
+ packet->unserialize(base + ".packet", cp, section);
+ paramIn(cp, section, base + ".slack", slack);
+ paramIn(cp, section, base + ".number", number);
+ paramIn(cp, section, base + ".priv", priv);
+}
+
+void
PacketFifo::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".size", _size);
@@ -72,11 +93,11 @@ PacketFifo::serialize(const string &base, ostream &os)
paramOut(os, base + ".packets", fifo.size());
int i = 0;
- list<EthPacketPtr>::iterator p = fifo.begin();
- list<EthPacketPtr>::iterator end = fifo.end();
- while (p != end) {
- (*p)->serialize(csprintf("%s.packet%d", base, i), os);
- ++p;
+ iterator entry = fifo.begin();
+ iterator end = fifo.end();
+ while (entry != end) {
+ entry->serialize(csprintf("%s.entry%d", base, i), os);
+ ++entry;
++i;
}
}
@@ -94,8 +115,8 @@ PacketFifo::unserialize(const string &base, Checkpoint *cp,
fifo.clear();
for (int i = 0; i < fifosize; ++i) {
- EthPacketPtr p = new EthPacketData(16384);
- p->unserialize(csprintf("%s.packet%d", base, i), cp, section);
- fifo.push_back(p);
+ PacketFifoEntry entry;
+ entry.unserialize(csprintf("%s.entry%d", base, i), cp, section);
+ fifo.push_back(entry);
}
}
diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh
index 45157ba41..6ded248be 100644
--- a/src/dev/pktfifo.hh
+++ b/src/dev/pktfifo.hh
@@ -39,20 +39,59 @@
#include "sim/serialize.hh"
class Checkpoint;
+
+struct PacketFifoEntry
+{
+ EthPacketPtr packet;
+ uint64_t number;
+ int slack;
+ int priv;
+
+ PacketFifoEntry()
+ {
+ clear();
+ }
+
+ PacketFifoEntry(const PacketFifoEntry &s)
+ : packet(s.packet), number(s.number), slack(s.slack), priv(s.priv)
+ {
+ }
+
+ PacketFifoEntry(EthPacketPtr p, uint64_t n)
+ : packet(p), number(n), slack(0), priv(-1)
+ {
+ }
+
+ void clear()
+ {
+ packet = NULL;
+ number = 0;
+ slack = 0;
+ priv = -1;
+ }
+
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+};
+
class PacketFifo
{
public:
- typedef std::list<EthPacketPtr> fifo_list;
+
+ typedef std::list<PacketFifoEntry> fifo_list;
typedef fifo_list::iterator iterator;
protected:
- std::list<EthPacketPtr> fifo;
+ std::list<PacketFifoEntry> fifo;
+ uint64_t _counter;
int _maxsize;
int _size;
int _reserved;
public:
- explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {}
+ explicit PacketFifo(int max)
+ : _counter(0), _maxsize(max), _size(0), _reserved(0) {}
virtual ~PacketFifo() {}
int packets() const { return fifo.size(); }
@@ -73,18 +112,21 @@ class PacketFifo
iterator begin() { return fifo.begin(); }
iterator end() { return fifo.end(); }
- EthPacketPtr front() { return fifo.front(); }
+ EthPacketPtr front() { return fifo.begin()->packet; }
bool push(EthPacketPtr ptr)
{
assert(ptr->length);
assert(_reserved <= ptr->length);
- assert(ptr->slack == 0);
if (avail() < ptr->length - _reserved)
return false;
_size += ptr->length;
- fifo.push_back(ptr);
+
+ PacketFifoEntry entry;
+ entry.packet = ptr;
+ entry.number = _counter++;
+ fifo.push_back(entry);
_reserved = 0;
return true;
}
@@ -94,18 +136,17 @@ class PacketFifo
if (empty())
return;
- EthPacketPtr &packet = fifo.front();
- _size -= packet->length;
- _size -= packet->slack;
- packet->slack = 0;
- packet = NULL;
+ iterator entry = fifo.begin();
+ _size -= entry->packet->length;
+ _size -= entry->slack;
+ entry->packet = NULL;
fifo.pop_front();
}
void clear()
{
for (iterator i = begin(); i != end(); ++i)
- (*i)->slack = 0;
+ i->clear();
fifo.clear();
_size = 0;
_reserved = 0;
@@ -113,51 +154,48 @@ class PacketFifo
void remove(iterator i)
{
- EthPacketPtr &packet = *i;
if (i != fifo.begin()) {
iterator prev = i;
--prev;
assert(prev != fifo.end());
- (*prev)->slack += packet->length;
+ prev->slack += i->packet->length;
+ prev->slack += i->slack;
} else {
- _size -= packet->length;
- _size -= packet->slack;
+ _size -= i->packet->length;
+ _size -= i->slack;
}
- packet->slack = 0;
- packet = NULL;
+ i->clear();
fifo.erase(i);
}
bool copyout(void *dest, int offset, int len);
- int countPacketsBefore(iterator end)
+ int countPacketsBefore(iterator i)
{
- iterator i = fifo.begin();
- int count = 0;
-
- while (i != end) {
- ++count;
- ++i;
- }
-
- return count;
+ if (i == fifo.end())
+ return 0;
+ return i->number - fifo.begin()->number;
}
int countPacketsAfter(iterator i)
{
iterator end = fifo.end();
- int count = 0;
+ if (i == end)
+ return 0;
+ return (--end)->number - i->number;
+ }
- while (i != end) {
- ++count;
- ++i;
- }
+ void check()
+ {
+ int total = 0;
+ for (iterator i = begin(); i != end(); ++i)
+ total += i->packet->length + i->slack;
- return count;
+ if (total != _size)
+ panic("total (%d) is not == to size (%d)\n", total, _size);
}
-
/**
* Serialization stuff
*/
diff --git a/src/dev/platform.hh b/src/dev/platform.hh
index 699b168ce..5f6f1df81 100644
--- a/src/dev/platform.hh
+++ b/src/dev/platform.hh
@@ -46,7 +46,7 @@
class PciConfigAll;
class IntrControl;
-class SimConsole;
+class Terminal;
class Uart;
class System;
@@ -69,7 +69,9 @@ class Platform : public SimObject
virtual void postPciInt(int line);
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
- virtual Addr calcConfigAddr(int bus, int dev, int func) = 0;
+ virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0;
+ virtual Addr calcPciIOAddr(Addr addr) = 0;
+ virtual Addr calcPciMemAddr(Addr addr) = 0;
virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
uint8_t intr);
diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h
index 37255777b..b1406c464 100644
--- a/src/dev/rtcreg.h
+++ b/src/dev/rtcreg.h
@@ -30,32 +30,32 @@
* Nathan Binkert
*/
-#define RTC_SEC 0x00
-#define RTC_SEC_ALRM 0x01
-#define RTC_MIN 0x02
-#define RTC_MIN_ALRM 0x03
-#define RTC_HR 0x04
-#define RTC_HR_ALRM 0x05
-#define RTC_DOW 0x06
-#define RTC_DOM 0x07
-#define RTC_MON 0x08
-#define RTC_YEAR 0x09
+static const int RTC_SEC = 0x00;
+static const int RTC_SEC_ALRM = 0x01;
+static const int RTC_MIN = 0x02;
+static const int RTC_MIN_ALRM = 0x03;
+static const int RTC_HR = 0x04;
+static const int RTC_HR_ALRM = 0x05;
+static const int RTC_DOW = 0x06;
+static const int RTC_DOM = 0x07;
+static const int RTC_MON = 0x08;
+static const int RTC_YEAR = 0x09;
-#define RTC_STAT_REGA 0x0A
-#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
-#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
-#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
+static const int RTC_STAT_REGA = 0x0A;
+static const int RTCA_1024HZ = 0x06; /* 1024Hz periodic interrupt frequency */
+static const int RTCA_32768HZ = 0x20; /* 22-stage divider, 32.768KHz timebase */
+static const int RTCA_UIP = 0x80; /* 1 = date and time update in progress */
-#define RTC_STAT_REGB 0x0B
-#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
-#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
-#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
-#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */
-#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */
-#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */
-#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
-#define RTCB_NO_UPDT 0x80 /* stop clock updates */
+static const int RTC_STAT_REGB = 0x0B;
+static const int RTCB_DST = 0x01; /* USA Daylight Savings Time enable */
+static const int RTCB_24HR = 0x02; /* 0 = 12 hours, 1 = 24 hours */
+static const int RTCB_BIN = 0x04; /* 0 = BCD, 1 = Binary coded time */
+static const int RTCB_SQWE = 0x08; /* 1 = output sqare wave at SQW pin */
+static const int RTCB_UPDT_IE = 0x10; /* 1 = enable update-ended interrupt */
+static const int RTCB_ALRM_IE = 0x20; /* 1 = enable alarm interrupt */
+static const int RTCB_PRDC_IE = 0x40; /* 1 = enable periodic clock interrupt */
+static const int RTCB_NO_UPDT = 0x80; /* stop clock updates */
-#define RTC_STAT_REGC 0x0C
-#define RTC_STAT_REGD 0x0D
+static const int RTC_STAT_REGC = 0x0C;
+static const int RTC_STAT_REGD = 0x0D;
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
index c63966528..37c6a8259 100644
--- a/src/dev/sinic.cc
+++ b/src/dev/sinic.cc
@@ -33,6 +33,7 @@
#include <string>
#include "arch/vtophys.hh"
+#include "base/debug.hh"
#include "base/inet.hh"
#include "cpu/thread_context.hh"
#include "cpu/intr_control.hh"
@@ -40,11 +41,11 @@
#include "dev/sinic.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
-#include "sim/debug.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"
#include "sim/stats.hh"
+using namespace std;
using namespace Net;
using namespace TheISA;
@@ -265,6 +266,35 @@ Device::regStats()
totPackets = txPackets + rxPackets;
txPacketRate = txPackets / simSeconds;
rxPacketRate = rxPackets / simSeconds;
+
+ _maxVnicDistance = 0;
+
+ maxVnicDistance
+ .name(name() + ".maxVnicDistance")
+ .desc("maximum vnic distance")
+ ;
+
+ totalVnicDistance
+ .name(name() + ".totalVnicDistance")
+ .desc("total vnic distance")
+ ;
+ numVnicDistance
+ .name(name() + ".numVnicDistance")
+ .desc("number of vnic distance measurements")
+ ;
+
+ avgVnicDistance
+ .name(name() + ".avgVnicDistance")
+ .desc("average vnic distance")
+ ;
+
+ avgVnicDistance = totalVnicDistance / numVnicDistance;
+}
+
+void
+Device::resetStats()
+{
+ _maxVnicDistance = 0;
}
EtherInt*
@@ -289,6 +319,10 @@ Device::prepareIO(int cpu, int index)
index, size);
}
+//add stats for head of line blocking
+//add stats for average fifo length
+//add stats for average number of vnics busy
+
void
Device::prepareRead(int cpu, int index)
{
@@ -301,7 +335,7 @@ Device::prepareRead(int cpu, int index)
uint64_t rxdone = vnic.RxDone;
rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
- rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
+ rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
rxdone = set_RxDone_NotHigh(rxdone, rxLow);
regs.RxData = vnic.RxData;
regs.RxDone = rxdone;
@@ -311,10 +345,23 @@ Device::prepareRead(int cpu, int index)
uint64_t txdone = vnic.TxDone;
txdone = set_TxDone_Packets(txdone, txFifo.packets());
txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
- txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
+ txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
regs.TxData = vnic.TxData;
regs.TxDone = txdone;
regs.TxWait = txdone;
+
+ int head = 0xffff;
+
+ if (!rxFifo.empty()) {
+ int vnic = rxFifo.begin()->priv;
+ if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
+ head = vnic;
+ }
+
+ regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
+ regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
+ regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
+ regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
}
void
@@ -332,7 +379,7 @@ Device::read(PacketPtr pkt)
assert(config.command & PCI_CMD_MSE);
assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
- int cpu = pkt->req->getCpuNum();
+ int cpu = pkt->req->contextId();
Addr daddr = pkt->getAddr() - BARAddrs[0];
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
@@ -419,7 +466,7 @@ Device::write(PacketPtr pkt)
assert(config.command & PCI_CMD_MSE);
assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
- int cpu = pkt->req->getCpuNum();
+ int cpu = pkt->req->contextId();
Addr daddr = pkt->getAddr() - BARAddrs[0];
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
@@ -473,22 +520,25 @@ Device::write(PacketPtr pkt)
vnic.rxUnique = rxUnique++;
vnic.RxDone = Regs::RxDone_Busy;
vnic.RxData = pkt->get<uint64_t>();
+ rxBusyCount++;
if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
panic("vtophys not implemented in newmem");
-/* Addr vaddr = Regs::get_RxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+ Addr vaddr = Regs::get_RxData_Addr(reg64);
Addr paddr = vtophys(req->xc, vaddr);
DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
"vaddr=%#x, paddr=%#x\n",
index, vnic.rxUnique, vaddr, paddr);
- vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
+ vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
+#endif
} else {
DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
index, vnic.rxUnique);
}
- if (vnic.rxPacket == rxFifo.end()) {
+ if (vnic.rxIndex == rxFifo.end()) {
DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
rxList.push_back(index);
} else {
@@ -512,15 +562,17 @@ Device::write(PacketPtr pkt)
if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
panic("vtophys won't work here in newmem.\n");
- /*Addr vaddr = Regs::get_TxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+ Addr vaddr = Regs::get_TxData_Addr(reg64);
Addr paddr = vtophys(req->xc, vaddr);
- DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+ DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
"vaddr=%#x, paddr=%#x\n",
index, vnic.txUnique, vaddr, paddr);
- vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+ vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
+#endif
} else {
- DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+ DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
index, vnic.txUnique);
}
@@ -643,7 +695,8 @@ Base::cpuIntrPost(Tick when)
if (intrEvent)
intrEvent->squash();
- intrEvent = new IntrEvent(this, intrTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrTick);
}
void
@@ -761,18 +814,31 @@ Device::reset()
regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
regs.RxMaxCopy = params()->rx_max_copy;
regs.TxMaxCopy = params()->tx_max_copy;
- regs.RxMaxIntr = params()->rx_max_intr;
+ regs.ZeroCopySize = params()->zero_copy_size;
+ regs.ZeroCopyMark = params()->zero_copy_threshold;
regs.VirtualCount = params()->virtual_count;
+ regs.RxMaxIntr = params()->rx_max_intr;
regs.RxFifoSize = params()->rx_fifo_size;
regs.TxFifoSize = params()->tx_fifo_size;
- regs.RxFifoMark = params()->rx_fifo_threshold;
- regs.TxFifoMark = params()->tx_fifo_threshold;
+ regs.RxFifoLow = params()->rx_fifo_low_mark;
+ regs.TxFifoLow = params()->tx_fifo_threshold;
+ regs.RxFifoHigh = params()->rx_fifo_threshold;
+ regs.TxFifoHigh = params()->tx_fifo_high_mark;
regs.HwAddr = params()->hardware_address;
+ if (regs.RxMaxCopy < regs.ZeroCopyMark)
+ panic("Must be able to copy at least as many bytes as the threshold");
+
+ if (regs.ZeroCopySize >= regs.ZeroCopyMark)
+ panic("The number of bytes to copy must be less than the threshold");
+
rxList.clear();
rxBusy.clear();
rxActive = -1;
txList.clear();
+ rxBusyCount = 0;
+ rxDirtyCount = 0;
+ rxMappedCount = 0;
rxState = rxIdle;
txState = txIdle;
@@ -788,7 +854,7 @@ Device::reset()
virtualRegs.clear();
virtualRegs.resize(size);
for (int i = 0; i < size; ++i)
- virtualRegs[i].rxPacket = rxFifo.end();
+ virtualRegs[i].rxIndex = rxFifo.end();
}
void
@@ -822,6 +888,7 @@ Device::rxKick()
}
next:
+ rxFifo.check();
if (rxState == rxIdle)
goto exit;
@@ -845,12 +912,28 @@ Device::rxKick()
int size = virtualRegs.size();
for (int i = 0; i < size; ++i) {
VirtualReg *vn = &virtualRegs[i];
- if (vn->rxPacket != end &&
- !Regs::get_RxDone_Busy(vn->RxDone)) {
+ bool busy = Regs::get_RxDone_Busy(vn->RxDone);
+ if (vn->rxIndex != end) {
+ bool dirty = vn->rxPacketOffset > 0;
+ const char *status;
+
+ if (busy && dirty)
+ status = "busy,dirty";
+ else if (busy)
+ status = "busy";
+ else if (dirty)
+ status = "dirty";
+ else
+ status = "mapped";
+
DPRINTF(EthernetSM,
- "vnic %d (rxunique %d), has outstanding packet %d\n",
- i, vn->rxUnique,
- rxFifo.countPacketsBefore(vn->rxPacket));
+ "vnic %d %s (rxunique %d), packet %d, slack %d\n",
+ i, status, vn->rxUnique,
+ rxFifo.countPacketsBefore(vn->rxIndex),
+ vn->rxIndex->slack);
+ } else if (busy) {
+ DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
+ i, vn->rxUnique);
}
}
}
@@ -860,7 +943,7 @@ Device::rxKick()
rxBusy.pop_front();
vnic = &virtualRegs[rxActive];
- if (vnic->rxPacket == rxFifo.end())
+ if (vnic->rxIndex == rxFifo.end())
panic("continuing vnic without packet\n");
DPRINTF(EthernetSM,
@@ -869,6 +952,14 @@ Device::rxKick()
rxState = rxBeginCopy;
+ int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
+ totalVnicDistance += vnic_distance;
+ numVnicDistance += 1;
+ if (vnic_distance > _maxVnicDistance) {
+ maxVnicDistance = vnic_distance;
+ _maxVnicDistance = vnic_distance;
+ }
+
break;
}
@@ -891,14 +982,16 @@ Device::rxKick()
rxActive, vnic->rxUnique);
// Grab a new packet from the fifo.
- vnic->rxPacket = rxFifoPtr++;
+ vnic->rxIndex = rxFifoPtr++;
+ vnic->rxIndex->priv = rxActive;
vnic->rxPacketOffset = 0;
- vnic->rxPacketBytes = (*vnic->rxPacket)->length;
+ vnic->rxPacketBytes = vnic->rxIndex->packet->length;
assert(vnic->rxPacketBytes);
+ rxMappedCount++;
vnic->rxDoneData = 0;
/* scope for variables */ {
- IpPtr ip(*vnic->rxPacket);
+ IpPtr ip(vnic->rxIndex->packet);
if (ip) {
DPRINTF(Ethernet, "ID is %d\n", ip->id());
vnic->rxDoneData |= Regs::RxDone_IpPacket;
@@ -939,16 +1032,26 @@ Device::rxKick()
rxDmaAddr = params()->platform->pciToDma(
Regs::get_RxData_Addr(vnic->RxData));
- rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
+ rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
vnic->rxPacketBytes);
- rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
+
+ /*
+ * if we're doing zero/delay copy and we're below the fifo
+ * threshold, see if we should try to do the zero/defer copy
+ */
+ if ((Regs::get_Config_ZeroCopy(regs.Config) ||
+ Regs::get_Config_DelayCopy(regs.Config)) &&
+ !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
+ if (rxDmaLen > regs.ZeroCopyMark)
+ rxDmaLen = regs.ZeroCopySize;
+ }
+ rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
rxState = rxCopy;
if (rxDmaAddr == 1LL) {
rxState = rxCopyDone;
break;
}
-
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
break;
@@ -959,17 +1062,25 @@ Device::rxKick()
case rxCopyDone:
vnic->RxDone = vnic->rxDoneData;
vnic->RxDone |= Regs::RxDone_Complete;
+ rxBusyCount--;
if (vnic->rxPacketBytes == rxDmaLen) {
+ if (vnic->rxPacketOffset)
+ rxDirtyCount--;
+
// Packet is complete. Indicate how many bytes were copied
vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
DPRINTF(EthernetSM,
"rxKick: packet complete on vnic %d (rxunique %d)\n",
rxActive, vnic->rxUnique);
- rxFifo.remove(vnic->rxPacket);
- vnic->rxPacket = rxFifo.end();
+ rxFifo.remove(vnic->rxIndex);
+ vnic->rxIndex = rxFifo.end();
+ rxMappedCount--;
} else {
+ if (!vnic->rxPacketOffset)
+ rxDirtyCount++;
+
vnic->rxPacketBytes -= rxDmaLen;
vnic->rxPacketOffset += rxDmaLen;
vnic->RxDone |= Regs::RxDone_More;
@@ -989,10 +1100,10 @@ Device::rxKick()
rxEmpty = true;
}
- if (rxFifo.size() < params()->rx_fifo_low_mark)
+ if (rxFifo.size() < regs.RxFifoLow)
rxLow = true;
- if (rxFifo.size() > params()->rx_fifo_threshold)
+ if (rxFifo.size() > regs.RxFifoHigh)
rxLow = false;
devIntrPost(Regs::Intr_RxDMA);
@@ -1044,7 +1155,7 @@ Device::transmit()
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
txFifo.avail());
- goto reschedule;
+ return;
}
txFifo.pop();
@@ -1072,15 +1183,9 @@ Device::transmit()
txFifo.avail());
interrupts = Regs::Intr_TxPacket;
- if (txFifo.size() < regs.TxFifoMark)
+ if (txFifo.size() < regs.TxFifoLow)
interrupts |= Regs::Intr_TxLow;
devIntrPost(interrupts);
-
- reschedule:
- if (!txFifo.empty() && !txEvent.scheduled()) {
- DPRINTF(Ethernet, "reschedule transmit\n");
- txEvent.schedule(curTick + retryTime);
- }
}
void
@@ -1211,7 +1316,7 @@ Device::transferDone()
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
- txEvent.reschedule(curTick + ticks(1), true);
+ reschedule(txEvent, curTick + ticks(1), true);
}
bool
@@ -1278,7 +1383,7 @@ Device::recvPacket(EthPacketPtr packet)
return true;
}
- if (rxFifo.size() >= regs.RxFifoMark)
+ if (rxFifo.size() >= regs.RxFifoHigh)
devIntrPost(Regs::Intr_RxHigh);
if (!rxFifo.push(packet)) {
@@ -1351,7 +1456,8 @@ Base::unserialize(Checkpoint *cp, const std::string &section)
Tick intrEventTick;
UNSERIALIZE_SCALAR(intrEventTick);
if (intrEventTick) {
- intrEvent = new IntrEvent(this, intrEventTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrEventTick);
}
}
@@ -1372,19 +1478,13 @@ Device::serialize(std::ostream &os)
TxStateStrings[txState]);
/*
- * Serialize the device registers
+ * Serialize the device registers that could be modified by the OS.
*/
SERIALIZE_SCALAR(regs.Config);
SERIALIZE_SCALAR(regs.IntrStatus);
SERIALIZE_SCALAR(regs.IntrMask);
- SERIALIZE_SCALAR(regs.RxMaxCopy);
- SERIALIZE_SCALAR(regs.TxMaxCopy);
- SERIALIZE_SCALAR(regs.RxMaxIntr);
- SERIALIZE_SCALAR(regs.VirtualCount);
SERIALIZE_SCALAR(regs.RxData);
- SERIALIZE_SCALAR(regs.RxDone);
SERIALIZE_SCALAR(regs.TxData);
- SERIALIZE_SCALAR(regs.TxDone);
/*
* Serialize the virtual nic state
@@ -1400,12 +1500,12 @@ Device::serialize(std::ostream &os)
paramOut(os, reg + ".TxData", vnic->TxData);
paramOut(os, reg + ".TxDone", vnic->TxDone);
- bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+ bool rxPacketExists = vnic->rxIndex != rxFifo.end();
paramOut(os, reg + ".rxPacketExists", rxPacketExists);
if (rxPacketExists) {
int rxPacket = 0;
PacketFifo::iterator i = rxFifo.begin();
- while (i != vnic->rxPacket) {
+ while (i != vnic->rxIndex) {
assert(i != rxFifo.end());
++i;
++rxPacket;
@@ -1418,10 +1518,15 @@ Device::serialize(std::ostream &os)
paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
}
- int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+ int rxFifoPtr = -1;
+ if (this->rxFifoPtr != rxFifo.end())
+ rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
SERIALIZE_SCALAR(rxFifoPtr);
SERIALIZE_SCALAR(rxActive);
+ SERIALIZE_SCALAR(rxBusyCount);
+ SERIALIZE_SCALAR(rxDirtyCount);
+ SERIALIZE_SCALAR(rxMappedCount);
VirtualList::iterator i, end;
for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
@@ -1478,21 +1583,18 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
Base::unserialize(cp, section);
/*
- * Unserialize the device registers
+ * Unserialize the device registers that may have been written by the OS.
*/
UNSERIALIZE_SCALAR(regs.Config);
UNSERIALIZE_SCALAR(regs.IntrStatus);
UNSERIALIZE_SCALAR(regs.IntrMask);
- UNSERIALIZE_SCALAR(regs.RxMaxCopy);
- UNSERIALIZE_SCALAR(regs.TxMaxCopy);
- UNSERIALIZE_SCALAR(regs.RxMaxIntr);
- UNSERIALIZE_SCALAR(regs.VirtualCount);
UNSERIALIZE_SCALAR(regs.RxData);
- UNSERIALIZE_SCALAR(regs.RxDone);
UNSERIALIZE_SCALAR(regs.TxData);
- UNSERIALIZE_SCALAR(regs.TxDone);
UNSERIALIZE_SCALAR(rxActive);
+ UNSERIALIZE_SCALAR(rxBusyCount);
+ UNSERIALIZE_SCALAR(rxDirtyCount);
+ UNSERIALIZE_SCALAR(rxMappedCount);
int rxListSize;
UNSERIALIZE_SCALAR(rxListSize);
@@ -1533,9 +1635,13 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
int rxFifoPtr;
UNSERIALIZE_SCALAR(rxFifoPtr);
- this->rxFifoPtr = rxFifo.begin();
- for (int i = 0; i < rxFifoPtr; ++i)
- ++this->rxFifoPtr;
+ if (rxFifoPtr >= 0) {
+ this->rxFifoPtr = rxFifo.begin();
+ for (int i = 0; i < rxFifoPtr; ++i)
+ ++this->rxFifoPtr;
+ } else {
+ this->rxFifoPtr = rxFifo.end();
+ }
/*
* Unserialize tx state machine
@@ -1582,15 +1688,15 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
if (rxPacketExists) {
int rxPacket;
paramIn(cp, section, reg + ".rxPacket", rxPacket);
- vnic->rxPacket = rxFifo.begin();
+ vnic->rxIndex = rxFifo.begin();
while (rxPacket--)
- ++vnic->rxPacket;
+ ++vnic->rxIndex;
paramIn(cp, section, reg + ".rxPacketOffset",
vnic->rxPacketOffset);
paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
} else {
- vnic->rxPacket = rxFifo.end();
+ vnic->rxIndex = rxFifo.end();
}
paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
}
@@ -1601,7 +1707,7 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
Tick transmitTick;
UNSERIALIZE_SCALAR(transmitTick);
if (transmitTick)
- txEvent.schedule(curTick + transmitTick);
+ schedule(txEvent, curTick + transmitTick);
pioPort->sendStatusChange(Port::RangeChange);
diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh
index e85d93fe4..cd8412ef4 100644
--- a/src/dev/sinic.hh
+++ b/src/dev/sinic.hh
@@ -115,19 +115,24 @@ class Device : public Base
uint32_t IntrMask; // 0x0c
uint32_t RxMaxCopy; // 0x10
uint32_t TxMaxCopy; // 0x14
- uint32_t RxMaxIntr; // 0x18
- uint32_t VirtualCount; // 0x1c
- uint32_t RxFifoSize; // 0x20
- uint32_t TxFifoSize; // 0x24
- uint32_t RxFifoMark; // 0x28
- uint32_t TxFifoMark; // 0x2c
- uint64_t RxData; // 0x30
- uint64_t RxDone; // 0x38
- uint64_t RxWait; // 0x40
- uint64_t TxData; // 0x48
- uint64_t TxDone; // 0x50
- uint64_t TxWait; // 0x58
- uint64_t HwAddr; // 0x60
+ uint32_t ZeroCopySize; // 0x18
+ uint32_t ZeroCopyMark; // 0x1c
+ uint32_t VirtualCount; // 0x20
+ uint32_t RxMaxIntr; // 0x24
+ uint32_t RxFifoSize; // 0x28
+ uint32_t TxFifoSize; // 0x2c
+ uint32_t RxFifoLow; // 0x30
+ uint32_t TxFifoLow; // 0x34
+ uint32_t RxFifoHigh; // 0x38
+ uint32_t TxFifoHigh; // 0x3c
+ uint64_t RxData; // 0x40
+ uint64_t RxDone; // 0x48
+ uint64_t RxWait; // 0x50
+ uint64_t TxData; // 0x58
+ uint64_t TxDone; // 0x60
+ uint64_t TxWait; // 0x68
+ uint64_t HwAddr; // 0x70
+ uint64_t RxStatus; // 0x78
} regs;
struct VirtualReg {
@@ -136,7 +141,7 @@ class Device : public Base
uint64_t TxData;
uint64_t TxDone;
- PacketFifo::iterator rxPacket;
+ PacketFifo::iterator rxIndex;
int rxPacketOffset;
int rxPacketBytes;
uint64_t rxDoneData;
@@ -159,6 +164,10 @@ class Device : public Base
int rxActive;
VirtualList txList;
+ int rxBusyCount;
+ int rxMappedCount;
+ int rxDirtyCount;
+
uint8_t &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
@@ -274,34 +283,42 @@ class Device : public Base
* Statistics
*/
private:
- Stats::Scalar<> rxBytes;
+ Stats::Scalar rxBytes;
Stats::Formula rxBandwidth;
- Stats::Scalar<> rxPackets;
+ Stats::Scalar rxPackets;
Stats::Formula rxPacketRate;
- Stats::Scalar<> rxIpPackets;
- Stats::Scalar<> rxTcpPackets;
- Stats::Scalar<> rxUdpPackets;
- Stats::Scalar<> rxIpChecksums;
- Stats::Scalar<> rxTcpChecksums;
- Stats::Scalar<> rxUdpChecksums;
-
- Stats::Scalar<> txBytes;
+ Stats::Scalar rxIpPackets;
+ Stats::Scalar rxTcpPackets;
+ Stats::Scalar rxUdpPackets;
+ Stats::Scalar rxIpChecksums;
+ Stats::Scalar rxTcpChecksums;
+ Stats::Scalar rxUdpChecksums;
+
+ Stats::Scalar txBytes;
Stats::Formula txBandwidth;
Stats::Formula totBandwidth;
Stats::Formula totPackets;
Stats::Formula totBytes;
Stats::Formula totPacketRate;
- Stats::Scalar<> txPackets;
+ Stats::Scalar txPackets;
Stats::Formula txPacketRate;
- Stats::Scalar<> txIpPackets;
- Stats::Scalar<> txTcpPackets;
- Stats::Scalar<> txUdpPackets;
- Stats::Scalar<> txIpChecksums;
- Stats::Scalar<> txTcpChecksums;
- Stats::Scalar<> txUdpChecksums;
+ Stats::Scalar txIpPackets;
+ Stats::Scalar txTcpPackets;
+ Stats::Scalar txUdpPackets;
+ Stats::Scalar txIpChecksums;
+ Stats::Scalar txTcpChecksums;
+ Stats::Scalar txUdpChecksums;
+
+ Stats::Scalar totalVnicDistance;
+ Stats::Scalar numVnicDistance;
+ Stats::Scalar maxVnicDistance;
+ Stats::Formula avgVnicDistance;
+
+ int _maxVnicDistance;
public:
virtual void regStats();
+ virtual void resetStats();
/**
* Serialization stuff
diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh
index de4188145..7ac7abad0 100644
--- a/src/dev/sinicreg.hh
+++ b/src/dev/sinicreg.hh
@@ -48,7 +48,7 @@
static const uint64_t NAME##_width = WIDTH; \
static const uint64_t NAME##_offset = OFFSET; \
static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \
- static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
+ static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
static inline uint64_t get_##NAME(uint64_t reg) \
{ return (reg & NAME) >> OFFSET; } \
static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \
@@ -67,20 +67,25 @@ __SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status
__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask
__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy
__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy
-__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt
-__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs
-__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes
-__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes
-__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark
-__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark
-__SINIC_REG32(RxData, 0x30); // 64: receive data
-__SINIC_REG32(RxDone, 0x38); // 64: receive done
-__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait)
-__SINIC_REG32(TxData, 0x48); // 64: transmit data
-__SINIC_REG32(TxDone, 0x50); // 64: transmit done
-__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait)
-__SINIC_REG32(HwAddr, 0x60); // 64: mac address
-__SINIC_REG32(Size, 0x68); // register addres space size
+__SINIC_REG32(ZeroCopySize, 0x18); // 32: bytes to copy if below threshold
+__SINIC_REG32(ZeroCopyMark, 0x1c); // 32: only zero-copy above this threshold
+__SINIC_REG32(VirtualCount, 0x20); // 32: number of virutal NICs
+__SINIC_REG32(RxMaxIntr, 0x24); // 32: max receives per interrupt
+__SINIC_REG32(RxFifoSize, 0x28); // 32: rx fifo capacity in bytes
+__SINIC_REG32(TxFifoSize, 0x2c); // 32: tx fifo capacity in bytes
+__SINIC_REG32(RxFifoLow, 0x30); // 32: rx fifo low watermark
+__SINIC_REG32(TxFifoLow, 0x34); // 32: tx fifo low watermark
+__SINIC_REG32(RxFifoHigh, 0x38); // 32: rx fifo high watermark
+__SINIC_REG32(TxFifoHigh, 0x3c); // 32: tx fifo high watermark
+__SINIC_REG32(RxData, 0x40); // 64: receive data
+__SINIC_REG32(RxDone, 0x48); // 64: receive done
+__SINIC_REG32(RxWait, 0x50); // 64: receive done (busy wait)
+__SINIC_REG32(TxData, 0x58); // 64: transmit data
+__SINIC_REG32(TxDone, 0x60); // 64: transmit done
+__SINIC_REG32(TxWait, 0x68); // 64: transmit done (busy wait)
+__SINIC_REG32(HwAddr, 0x70); // 64: mac address
+__SINIC_REG32(RxStatus, 0x78);
+__SINIC_REG32(Size, 0x80); // register addres space size
// Config register bits
__SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy
@@ -116,9 +121,10 @@ __SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced
__SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits
// RX Data Description
-__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual
-__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k
-__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
+__SINIC_VAL64(RxData_NoDelay, 61, 1); // Don't Delay this copy
+__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual
+__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k
+__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
// TX Data Description
__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more)
@@ -159,6 +165,11 @@ __SINIC_VAL64(TxDone_Res6, 21, 1); // reserved
__SINIC_VAL64(TxDone_Res7, 20, 1); // reserved
__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k
+__SINIC_VAL64(RxStatus_Dirty, 48, 16);
+__SINIC_VAL64(RxStatus_Mapped, 32, 16);
+__SINIC_VAL64(RxStatus_Busy, 16, 16);
+__SINIC_VAL64(RxStatus_Head, 0, 16);
+
struct Info
{
uint8_t size;
@@ -174,31 +185,37 @@ regInfo(Addr daddr)
{
static Regs::Info invalid = { 0, false, false, "invalid" };
static Regs::Info info [] = {
- { 4, true, true, "Config" },
- { 4, false, true, "Command" },
- { 4, true, true, "IntrStatus" },
- { 4, true, true, "IntrMask" },
- { 4, true, false, "RxMaxCopy" },
- { 4, true, false, "TxMaxCopy" },
- { 4, true, false, "RxMaxIntr" },
- { 4, true, false, "VirtualCount" },
- { 4, true, false, "RxFifoSize" },
- { 4, true, false, "TxFifoSize" },
- { 4, true, false, "RxFifoMark" },
- { 4, true, false, "TxFifoMark" },
- { 8, true, true, "RxData" },
+ { 4, true, true, "Config" },
+ { 4, false, true, "Command" },
+ { 4, true, true, "IntrStatus" },
+ { 4, true, true, "IntrMask" },
+ { 4, true, false, "RxMaxCopy" },
+ { 4, true, false, "TxMaxCopy" },
+ { 4, true, false, "ZeroCopySize" },
+ { 4, true, false, "ZeroCopyMark" },
+ { 4, true, false, "VirtualCount" },
+ { 4, true, false, "RxMaxIntr" },
+ { 4, true, false, "RxFifoSize" },
+ { 4, true, false, "TxFifoSize" },
+ { 4, true, false, "RxFifoLow" },
+ { 4, true, false, "TxFifoLow" },
+ { 4, true, false, "RxFifoHigh" },
+ { 4, true, false, "TxFifoHigh" },
+ { 8, true, true, "RxData" },
+ invalid,
+ { 8, true, false, "RxDone" },
invalid,
- { 8, true, false, "RxDone" },
+ { 8, true, false, "RxWait" },
invalid,
- { 8, true, false, "RxWait" },
+ { 8, true, true, "TxData" },
invalid,
- { 8, true, true, "TxData" },
+ { 8, true, false, "TxDone" },
invalid,
- { 8, true, false, "TxDone" },
+ { 8, true, false, "TxWait" },
invalid,
- { 8, true, false, "TxWait" },
+ { 8, true, false, "HwAddr" },
invalid,
- { 8, true, false, "HwAddr" },
+ { 8, true, false, "RxStatus" },
invalid,
};
diff --git a/src/dev/sparc/T1000.py b/src/dev/sparc/T1000.py
index a033e27e2..cbf390737 100644
--- a/src/dev/sparc/T1000.py
+++ b/src/dev/sparc/T1000.py
@@ -29,9 +29,9 @@
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr
-from Uart import Uart8250
from Platform import Platform
-from SimConsole import SimConsole
+from Terminal import Terminal
+from Uart import Uart8250
class MmDisk(BasicPioDevice):
@@ -98,11 +98,11 @@ class T1000(Platform):
fake_ssi = IsaFake(pio_addr=0xff00000000, pio_size=0x10000000)
#warn_access="Accessing SSI -- Unimplemented!")
- hconsole = SimConsole()
+ hterm = Terminal()
hvuart = Uart8250(pio_addr=0xfff0c2c000)
htod = DumbTOD()
- pconsole = SimConsole()
+ pterm = Terminal()
puart0 = Uart8250(pio_addr=0x1f10000000)
iob = Iob()
@@ -116,8 +116,8 @@ class T1000(Platform):
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
- self.hvuart.sim_console = self.hconsole
- self.puart0.sim_console = self.pconsole
+ self.hvuart.terminal = self.hterm
+ self.puart0.terminal = self.pterm
self.fake_clk.pio = bus.port
self.fake_membnks.pio = bus.port
self.fake_l2_1.pio = bus.port
diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc
index 6608fc64a..4543dd07b 100644
--- a/src/dev/sparc/iob.cc
+++ b/src/dev/sparc/iob.cc
@@ -120,7 +120,7 @@ void
Iob::readJBus(PacketPtr pkt)
{
Addr accessAddr = pkt->getAddr() - iobJBusAddr;
- int cpuid = pkt->req->getCpuNum();
+ int cpuid = pkt->req->contextId();
int index;
uint64_t data;
@@ -235,7 +235,7 @@ void
Iob::writeJBus(PacketPtr pkt)
{
Addr accessAddr = pkt->getAddr() - iobJBusAddr;
- int cpuid = pkt->req->getCpuNum();
+ int cpuid = pkt->req->contextId();
int index;
uint64_t data;
@@ -276,7 +276,7 @@ void
Iob::generateIpi(Type type, int cpu_id, int vector)
{
SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
- if (cpu_id >= sys->getNumCPUs())
+ if (cpu_id >= sys->numContexts())
return;
switch (type) {
diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc
index 49e44af55..88fb358ef 100644
--- a/src/dev/sparc/t1000.cc
+++ b/src/dev/sparc/t1000.cc
@@ -37,8 +37,8 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/sparc/t1000.hh"
+#include "dev/terminal.hh"
#include "sim/system.hh"
using namespace std;
@@ -94,7 +94,21 @@ T1000::pciToDma(Addr pciAddr) const
Addr
-T1000::calcConfigAddr(int bus, int dev, int func)
+T1000::calcPciConfigAddr(int bus, int dev, int func)
+{
+ panic("Need implementation\n");
+ M5_DUMMY_RETURN
+}
+
+Addr
+T1000::calcPciIOAddr(Addr addr)
+{
+ panic("Need implementation\n");
+ M5_DUMMY_RETURN
+}
+
+Addr
+T1000::calcPciMemAddr(Addr addr)
{
panic("Need implementation\n");
M5_DUMMY_RETURN
diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh
index 76de0a550..01ff3d319 100644
--- a/src/dev/sparc/t1000.hh
+++ b/src/dev/sparc/t1000.hh
@@ -91,7 +91,17 @@ class T1000 : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int 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_T1000_HH__
diff --git a/src/dev/simconsole.cc b/src/dev/terminal.cc
index e8dc1b210..fba0c6130 100644
--- a/src/dev/simconsole.cc
+++ b/src/dev/terminal.cc
@@ -30,27 +30,28 @@
*/
/* @file
- * Implements the user interface to a serial console
+ * Implements the user interface to a serial terminal
*/
#include <sys/ioctl.h>
#include <sys/termios.h>
-#include <sys/types.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
+#include <cctype>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
+#include "base/atomicio.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/socket.hh"
#include "base/trace.hh"
#include "dev/platform.hh"
-#include "dev/simconsole.hh"
+#include "dev/terminal.hh"
#include "dev/uart.hh"
using namespace std;
@@ -59,50 +60,46 @@ using namespace std;
/*
* Poll event for the listen socket
*/
-SimConsole::ListenEvent::ListenEvent(SimConsole *c, int fd, int e)
- : PollEvent(fd, e), cons(c)
+Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e)
+ : PollEvent(fd, e), term(t)
{
}
void
-SimConsole::ListenEvent::process(int revent)
+Terminal::ListenEvent::process(int revent)
{
- cons->accept();
+ term->accept();
}
/*
* Poll event for the data socket
*/
-SimConsole::DataEvent::DataEvent(SimConsole *c, int fd, int e)
- : PollEvent(fd, e), cons(c)
+Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e)
+ : PollEvent(fd, e), term(t)
{
}
void
-SimConsole::DataEvent::process(int revent)
+Terminal::DataEvent::process(int revent)
{
if (revent & POLLIN)
- cons->data();
+ term->data();
else if (revent & POLLNVAL)
- cons->detach();
+ term->detach();
}
/*
- * SimConsole code
+ * Terminal code
*/
-SimConsole::SimConsole(const Params *p)
+Terminal::Terminal(const Params *p)
: SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number),
data_fd(-1), txbuf(16384), rxbuf(16384), outfile(NULL)
#if TRACING_ON == 1
, linebuf(16384)
#endif
{
- if (!p->output.empty()) {
- if (p->append_name)
- outfile = simout.find(p->output + "." + p->name);
- else
- outfile = simout.find(p->output);
-
+ if (p->output) {
+ outfile = simout.find(p->name);
outfile->setf(ios::unitbuf);
}
@@ -110,7 +107,7 @@ SimConsole::SimConsole(const Params *p)
listen(p->port);
}
-SimConsole::~SimConsole()
+Terminal::~Terminal()
{
if (data_fd != -1)
::close(data_fd);
@@ -123,15 +120,20 @@ SimConsole::~SimConsole()
}
///////////////////////////////////////////////////////////////////////
-// socket creation and console attach
+// socket creation and terminal attach
//
void
-SimConsole::listen(int port)
+Terminal::listen(int port)
{
+ if (ListenSocket::allDisabled()) {
+ warn_once("Sockets disabled, not accepting terminal connections");
+ return;
+ }
+
while (!listener.listen(port, true)) {
- DPRINTF(Console,
- ": can't bind address console port %d inuse PID %d\n",
+ DPRINTF(Terminal,
+ ": can't bind address terminal port %d inuse PID %d\n",
port, getpid());
port++;
}
@@ -147,15 +149,15 @@ SimConsole::listen(int port)
}
void
-SimConsole::accept()
+Terminal::accept()
{
if (!listener.islistening())
panic("%s: cannot accept a connection if not listening!", name());
int fd = listener.accept(true);
if (data_fd != -1) {
- char message[] = "console already attached!\n";
- ::write(fd, message, sizeof(message));
+ char message[] = "terminal already attached!\n";
+ atomic_write(fd, message, sizeof(message));
::close(fd);
return;
}
@@ -165,7 +167,7 @@ SimConsole::accept()
pollQueue.schedule(dataEvent);
stringstream stream;
- ccprintf(stream, "==== m5 slave console: Console %d ====", number);
+ ccprintf(stream, "==== m5 slave terminal: Terminal %d ====", number);
// we need an actual carriage return followed by a newline for the
// terminal
@@ -173,13 +175,13 @@ SimConsole::accept()
write((const uint8_t *)stream.str().c_str(), stream.str().size());
- DPRINTFN("attach console %d\n", number);
+ DPRINTFN("attach terminal %d\n", number);
txbuf.readall(data_fd);
}
void
-SimConsole::detach()
+Terminal::detach()
{
if (data_fd != -1) {
::close(data_fd);
@@ -190,11 +192,11 @@ SimConsole::detach()
delete dataEvent;
dataEvent = NULL;
- DPRINTFN("detach console %d\n", number);
+ DPRINTFN("detach terminal %d\n", number);
}
void
-SimConsole::data()
+Terminal::data()
{
uint8_t buf[1024];
int len;
@@ -208,10 +210,10 @@ SimConsole::data()
}
size_t
-SimConsole::read(uint8_t *buf, size_t len)
+Terminal::read(uint8_t *buf, size_t len)
{
if (data_fd < 0)
- panic("Console not properly attached.\n");
+ panic("Terminal not properly attached.\n");
size_t ret;
do {
@@ -230,23 +232,16 @@ SimConsole::read(uint8_t *buf, size_t len)
return ret;
}
-// Console output.
+// Terminal output.
size_t
-SimConsole::write(const uint8_t *buf, size_t len)
+Terminal::write(const uint8_t *buf, size_t len)
{
if (data_fd < 0)
- panic("Console not properly attached.\n");
+ panic("Terminal not properly attached.\n");
- size_t ret;
- for (;;) {
- ret = ::write(data_fd, buf, len);
-
- if (ret >= 0)
- break;
-
- if (errno != EINTR)
- detach();
- }
+ ssize_t ret = atomic_write(data_fd, buf, len);
+ if (ret < len)
+ detach();
return ret;
}
@@ -257,7 +252,7 @@ SimConsole::write(const uint8_t *buf, size_t len)
#define RECEIVE_ERROR (ULL(3) << 62)
uint8_t
-SimConsole::in()
+Terminal::in()
{
bool empty;
uint8_t c;
@@ -268,14 +263,14 @@ SimConsole::in()
empty = rxbuf.empty();
- DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n",
+ DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n",
isprint(c) ? c : ' ', c, !empty);
return c;
}
uint64_t
-SimConsole::console_in()
+Terminal::console_in()
{
uint64_t value;
@@ -287,26 +282,25 @@ SimConsole::console_in()
value = RECEIVE_NONE;
}
- DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value);
+ DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value);
return value;
}
void
-SimConsole::out(char c)
+Terminal::out(char c)
{
#if TRACING_ON == 1
- if (DTRACE(Console)) {
+ if (DTRACE(Terminal)) {
static char last = '\0';
- if (c != '\n' && c != '\r' ||
- last != '\n' && last != '\r') {
+ if ((c != '\n' && c != '\r') || (last != '\n' && last != '\r')) {
if (c == '\n' || c == '\r') {
int size = linebuf.size();
char *buffer = new char[size + 1];
linebuf.read(buffer, size);
buffer[size] = '\0';
- DPRINTF(Console, "%s\n", buffer);
+ DPRINTF(Terminal, "%s\n", buffer);
delete [] buffer;
} else {
linebuf.write(c);
@@ -325,13 +319,13 @@ SimConsole::out(char c)
if (outfile)
outfile->write(&c, 1);
- DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n",
+ DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
isprint(c) ? c : ' ', (int)c);
}
-SimConsole *
-SimConsoleParams::create()
+Terminal *
+TerminalParams::create()
{
- return new SimConsole(this);
+ return new Terminal(this);
}
diff --git a/src/dev/simconsole.hh b/src/dev/terminal.hh
index c8d453960..d2499b6b2 100644
--- a/src/dev/simconsole.hh
+++ b/src/dev/terminal.hh
@@ -30,11 +30,11 @@
*/
/* @file
- * User Console Interface
+ * User Terminal Interface
*/
-#ifndef __CONSOLE_HH__
-#define __CONSOLE_HH__
+#ifndef __DEV_TERMINAL_HH__
+#define __DEV_TERMINAL_HH__
#include <iostream>
@@ -43,12 +43,12 @@
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "sim/sim_object.hh"
-#include "params/SimConsole.hh"
+#include "params/Terminal.hh"
-class ConsoleListener;
+class TerminalListener;
class Uart;
-class SimConsole : public SimObject
+class Terminal : public SimObject
{
public:
Uart *uart;
@@ -57,10 +57,10 @@ class SimConsole : public SimObject
class ListenEvent : public PollEvent
{
protected:
- SimConsole *cons;
+ Terminal *term;
public:
- ListenEvent(SimConsole *c, int fd, int e);
+ ListenEvent(Terminal *t, int fd, int e);
void process(int revent);
};
@@ -70,10 +70,10 @@ class SimConsole : public SimObject
class DataEvent : public PollEvent
{
protected:
- SimConsole *cons;
+ Terminal *term;
public:
- DataEvent(SimConsole *c, int fd, int e);
+ DataEvent(Terminal *t, int fd, int e);
void process(int revent);
};
@@ -85,9 +85,9 @@ class SimConsole : public SimObject
int data_fd;
public:
- typedef SimConsoleParams Params;
- SimConsole(const Params *p);
- ~SimConsole();
+ typedef TerminalParams Params;
+ Terminal(const Params *p);
+ ~Terminal();
protected:
ListenSocket listener;
@@ -119,10 +119,10 @@ class SimConsole : public SimObject
/////////////////
// OS interface
- // Get a character from the console.
+ // Get a character from the terminal.
uint8_t in();
- // get a character from the console in the console specific format
+ // get a character from the terminal in the console specific format
// corresponds to GETC:
// retval<63:61>
// 000: success: character received
@@ -136,11 +136,11 @@ class SimConsole : public SimObject
// Interrupts are cleared when the buffer is empty.
uint64_t console_in();
- // Send a character to the console
+ // Send a character to the terminal
void out(char c);
- //Ask the console if data is available
+ // Ask the terminal if data is available
bool dataAvailable() { return !rxbuf.empty(); }
};
-#endif // __CONSOLE_HH__
+#endif // __DEV_TERMINAL_HH__
diff --git a/src/dev/uart.cc b/src/dev/uart.cc
index c9a2ae964..ab0ebde2c 100644
--- a/src/dev/uart.cc
+++ b/src/dev/uart.cc
@@ -32,17 +32,17 @@
* Implements a base class for UARTs
*/
-#include "dev/simconsole.hh"
-#include "dev/uart.hh"
#include "dev/platform.hh"
+#include "dev/terminal.hh"
+#include "dev/uart.hh"
using namespace std;
Uart::Uart(const Params *p)
- : BasicPioDevice(p), platform(p->platform), cons(p->sim_console)
+ : BasicPioDevice(p), platform(p->platform), term(p->terminal)
{
status = 0;
// set back pointers
- cons->uart = this;
+ term->uart = this;
}
diff --git a/src/dev/uart.hh b/src/dev/uart.hh
index f5d5e2855..ba10c204c 100644
--- a/src/dev/uart.hh
+++ b/src/dev/uart.hh
@@ -39,7 +39,7 @@
#include "dev/io_device.hh"
#include "params/Uart.hh"
-class SimConsole;
+class Terminal;
class Platform;
const int RX_INT = 0x1;
@@ -51,7 +51,7 @@ class Uart : public BasicPioDevice
protected:
int status;
Platform *platform;
- SimConsole *cons;
+ Terminal *term;
public:
typedef UartParams Params;
diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc
index b4dc93645..93f71f49b 100644
--- a/src/dev/uart8250.cc
+++ b/src/dev/uart8250.cc
@@ -38,9 +38,9 @@
#include "base/inifile.hh"
#include "base/str.hh" // for to_number
#include "base/trace.hh"
-#include "dev/simconsole.hh"
-#include "dev/uart8250.hh"
#include "dev/platform.hh"
+#include "dev/terminal.hh"
+#include "dev/uart8250.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
@@ -48,7 +48,7 @@ using namespace std;
using namespace TheISA;
Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit)
- : Event(&mainEventQueue), uart(u)
+ : uart(u)
{
DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
intrBit = bit;
@@ -93,9 +93,9 @@ Uart8250::IntrEvent::scheduleIntr()
DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
curTick + interval);
if (!scheduled())
- schedule(curTick + interval);
+ uart->schedule(this, curTick + interval);
else
- reschedule(curTick + interval);
+ uart->reschedule(this, curTick + interval);
}
@@ -120,8 +120,8 @@ Uart8250::read(PacketPtr pkt)
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // read byte
- if (cons->dataAvailable())
- pkt->set(cons->in());
+ if (term->dataAvailable())
+ pkt->set(term->in());
else {
pkt->set((uint8_t)0);
// A limited amount of these are ok.
@@ -130,7 +130,7 @@ Uart8250::read(PacketPtr pkt)
status &= ~RX_INT;
platform->clearConsoleInt();
- if (cons->dataAvailable() && (IER & UART_IER_RDI))
+ if (term->dataAvailable() && (IER & UART_IER_RDI))
rxIntrEvent.scheduleIntr();
} else { // dll divisor latch
;
@@ -165,7 +165,7 @@ Uart8250::read(PacketPtr pkt)
uint8_t lsr;
lsr = 0;
// check if there are any bytes to be read
- if (cons->dataAvailable())
+ if (term->dataAvailable())
lsr = UART_LSR_DR;
lsr |= UART_LSR_TEMT | UART_LSR_THRE;
pkt->set(lsr);
@@ -201,7 +201,7 @@ Uart8250::write(PacketPtr pkt)
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // write byte
- cons->out(pkt->get<uint8_t>());
+ term->out(pkt->get<uint8_t>());
platform->clearConsoleInt();
status &= ~TX_INT;
if (UART_IER_THRI & IER)
@@ -231,19 +231,19 @@ Uart8250::write(PacketPtr pkt)
{
DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
if (txIntrEvent.scheduled())
- txIntrEvent.deschedule();
+ deschedule(txIntrEvent);
if (status & TX_INT)
platform->clearConsoleInt();
status &= ~TX_INT;
}
- if ((UART_IER_RDI & IER) && cons->dataAvailable()) {
+ if ((UART_IER_RDI & IER) && term->dataAvailable()) {
DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
rxIntrEvent.scheduleIntr();
} else {
DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
if (rxIntrEvent.scheduled())
- rxIntrEvent.deschedule();
+ deschedule(rxIntrEvent);
if (status & RX_INT)
platform->clearConsoleInt();
status &= ~RX_INT;
@@ -329,9 +329,9 @@ Uart8250::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(rxintrwhen);
UNSERIALIZE_SCALAR(txintrwhen);
if (rxintrwhen != 0)
- rxIntrEvent.schedule(rxintrwhen);
+ schedule(rxIntrEvent, rxintrwhen);
if (txintrwhen != 0)
- txIntrEvent.schedule(txintrwhen);
+ schedule(txIntrEvent, txintrwhen);
}
Uart8250 *
diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh
index 2c69667e1..79c31d5cf 100644
--- a/src/dev/uart8250.hh
+++ b/src/dev/uart8250.hh
@@ -65,7 +65,7 @@ const uint8_t UART_LSR_DR = 0x01;
const uint8_t UART_MCR_LOOP = 0x10;
-class SimConsole;
+class Terminal;
class Platform;
class Uart8250 : public Uart
diff --git a/src/dev/x86/Cmos.py b/src/dev/x86/Cmos.py
new file mode 100644
index 000000000..0a92145e2
--- /dev/null
+++ b/src/dev/x86/Cmos.py
@@ -0,0 +1,41 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class Cmos(BasicPioDevice):
+ type = 'Cmos'
+ cxx_class='X86ISA::Cmos'
+ time = Param.Time('01/01/2009',
+ "System time to use ('Now' for actual time)")
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal RTC alarm interrupts to')
diff --git a/src/dev/x86/I8042.py b/src/dev/x86/I8042.py
new file mode 100644
index 000000000..31192adcd
--- /dev/null
+++ b/src/dev/x86/I8042.py
@@ -0,0 +1,45 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class I8042(BasicPioDevice):
+ type = 'I8042'
+ cxx_class = 'X86ISA::I8042'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ # This isn't actually used for anything here.
+ pio_addr = 0x0
+ data_port = Param.Addr('Data port address')
+ command_port = Param.Addr('Command/status port address')
+ mouse_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal the mouse has data')
+ keyboard_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal the keyboard has data')
diff --git a/src/dev/x86/I82094AA.py b/src/dev/x86/I82094AA.py
new file mode 100644
index 000000000..9d57beed1
--- /dev/null
+++ b/src/dev/x86/I82094AA.py
@@ -0,0 +1,43 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSinkPin
+
+class I82094AA(BasicPioDevice):
+ type = 'I82094AA'
+ cxx_class = 'X86ISA::I82094AA'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ pio_addr = Param.Addr("Device address")
+ int_port = Port("Port for sending and receiving interrupt messages")
+ external_int_pic = Param.I8259(NULL, "External PIC, if any")
+
+ def pin(self, line):
+ return X86IntSinkPin(device=self, number=line)
diff --git a/src/dev/x86/I8237.py b/src/dev/x86/I8237.py
new file mode 100644
index 000000000..20788a164
--- /dev/null
+++ b/src/dev/x86/I8237.py
@@ -0,0 +1,36 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+
+class I8237(BasicPioDevice):
+ type = 'I8237'
+ cxx_class = 'X86ISA::I8237'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
diff --git a/src/dev/x86/I8254.py b/src/dev/x86/I8254.py
new file mode 100644
index 000000000..f468717cc
--- /dev/null
+++ b/src/dev/x86/I8254.py
@@ -0,0 +1,39 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class I8254(BasicPioDevice):
+ type = 'I8254'
+ cxx_class = 'X86ISA::I8254'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal timer interrupts to')
diff --git a/src/dev/x86/I8259.py b/src/dev/x86/I8259.py
new file mode 100644
index 000000000..0a516d30a
--- /dev/null
+++ b/src/dev/x86/I8259.py
@@ -0,0 +1,50 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin, X86IntSinkPin
+
+class X86I8259CascadeMode(Enum):
+ map = {'I8259Master' : 0,
+ 'I8259Slave' : 1,
+ 'I8259Single' : 2
+ }
+
+class I8259(BasicPioDevice):
+ type = 'I8259'
+ cxx_class='X86ISA::I8259'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ output = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'The pin this I8259 drives')
+ mode = Param.X86I8259CascadeMode('How this I8259 is cascaded')
+ slave = Param.I8259(NULL, 'Slave I8259, if any')
+
+ def pin(self, line):
+ return X86IntSinkPin(device=self, number=line)
diff --git a/src/dev/x86/Opteron.py b/src/dev/x86/Opteron.py
deleted file mode 100644
index cb015e2e7..000000000
--- a/src/dev/x86/Opteron.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from m5.params import *
-from m5.proxy import *
-from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr
-from Uart import Uart8250
-from Platform import Platform
-from Pci import PciConfigAll
-from SimConsole import SimConsole
-
-class Opteron(Platform):
- type = 'Opteron'
- system = Param.System(Parent.any, "system")
-
- pciconfig = PciConfigAll()
-
- def attachIO(self, bus):
- self.pciconfig.pio = bus.default
- bus.responder_set = True
- bus.responder = self.pciconfig
diff --git a/src/dev/x86/Pc.py b/src/dev/x86/Pc.py
new file mode 100644
index 000000000..6f315cbcb
--- /dev/null
+++ b/src/dev/x86/Pc.py
@@ -0,0 +1,83 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+
+from Device import IsaFake
+from Pci import PciConfigAll
+from Platform import Platform
+from SouthBridge import SouthBridge
+from Terminal import Terminal
+from Uart import Uart8250
+
+def x86IOAddress(port):
+ IO_address_space_base = 0x8000000000000000
+ return IO_address_space_base + port;
+
+class Pc(Platform):
+ type = 'Pc'
+ system = Param.System(Parent.any, "system")
+
+ pciconfig = PciConfigAll()
+
+ south_bridge = SouthBridge()
+
+ # "Non-existant" port used for timing purposes by the linux kernel
+ i_dont_exist = IsaFake(pio_addr=x86IOAddress(0x80), pio_size=1)
+
+ # Ports behind the pci config and data regsiters. These don't do anything,
+ # but the linux kernel fiddles with them anway.
+ behind_pci = IsaFake(pio_addr=x86IOAddress(0xcf8), pio_size=8)
+
+ # Serial port and terminal
+ terminal = Terminal()
+ com_1 = Uart8250()
+ com_1.pio_addr = x86IOAddress(0x3f8)
+ com_1.terminal = terminal
+
+ # Devices to catch access to non-existant serial ports.
+ fake_com_2 = IsaFake(pio_addr=x86IOAddress(0x2f8), pio_size=8)
+ fake_com_3 = IsaFake(pio_addr=x86IOAddress(0x3e8), pio_size=8)
+ fake_com_4 = IsaFake(pio_addr=x86IOAddress(0x2e8), pio_size=8)
+
+ # A device to catch accesses to the non-existant floppy controller.
+ fake_floppy = IsaFake(pio_addr=x86IOAddress(0x3f2), pio_size=2)
+
+ def attachIO(self, bus):
+ self.south_bridge.attachIO(bus)
+ self.i_dont_exist.pio = bus.port
+ self.behind_pci.pio = bus.port
+ self.com_1.pio = bus.port
+ self.fake_com_2.pio = bus.port
+ self.fake_com_3.pio = bus.port
+ self.fake_com_4.pio = bus.port
+ self.fake_floppy.pio = bus.port
+ self.pciconfig.pio = bus.default
+ bus.responder_set = True
+ bus.responder = self.pciconfig
diff --git a/src/dev/x86/PcSpeaker.py b/src/dev/x86/PcSpeaker.py
new file mode 100644
index 000000000..7ca62ec1e
--- /dev/null
+++ b/src/dev/x86/PcSpeaker.py
@@ -0,0 +1,37 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+
+class PcSpeaker(BasicPioDevice):
+ type = 'PcSpeaker'
+ cxx_class = 'X86ISA::Speaker'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ i8254 = Param.I8254('Timer that drives the speaker')
diff --git a/src/dev/x86/SConscript b/src/dev/x86/SConscript
index c500531b1..e7543dfdf 100644
--- a/src/dev/x86/SConscript
+++ b/src/dev/x86/SConscript
@@ -26,12 +26,44 @@
# (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
+# Authors: Gabe Black
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'x86':
- SimObject('Opteron.py')
+ SimObject('Pc.py')
+ Source('pc.cc')
- Source('opteron.cc')
+ SimObject('SouthBridge.py')
+ Source('south_bridge.cc')
+
+ SimObject('Cmos.py')
+ Source('cmos.cc')
+ TraceFlag('CMOS', 'Accesses to CMOS devices')
+
+ SimObject('I8259.py')
+ Source('i8259.cc')
+ TraceFlag('I8259', 'Accesses to the I8259 PIC devices')
+
+ SimObject('I8254.py')
+ Source('i8254.cc')
+ TraceFlag('I8254', 'Interrupts from the I8254 timer');
+
+ SimObject('I8237.py')
+ Source('i8237.cc')
+ TraceFlag('I8237', 'The I8237 dma controller');
+
+ SimObject('I8042.py')
+ Source('i8042.cc')
+ TraceFlag('I8042', 'The I8042 keyboard controller');
+
+ SimObject('PcSpeaker.py')
+ Source('speaker.cc')
+ TraceFlag('PcSpeaker')
+
+ SimObject('I82094AA.py')
+ Source('i82094aa.cc')
+ TraceFlag('I82094AA')
+
+ SimObject('X86IntPin.py')
+ Source('intdev.cc')
diff --git a/src/dev/x86/SouthBridge.py b/src/dev/x86/SouthBridge.py
new file mode 100644
index 000000000..d89ed9dc6
--- /dev/null
+++ b/src/dev/x86/SouthBridge.py
@@ -0,0 +1,122 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+from Cmos import Cmos
+from I8042 import I8042
+from I82094AA import I82094AA
+from I8237 import I8237
+from I8254 import I8254
+from I8259 import I8259
+from Ide import IdeController
+from PcSpeaker import PcSpeaker
+from X86IntPin import X86IntLine
+from m5.SimObject import SimObject
+
+def x86IOAddress(port):
+ IO_address_space_base = 0x8000000000000000
+ return IO_address_space_base + port;
+
+class SouthBridge(SimObject):
+ type = 'SouthBridge'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ platform = Param.Platform(Parent.any, "Platform this device is part of")
+
+ _pic1 = I8259(pio_addr=x86IOAddress(0x20), mode='I8259Master')
+ _pic2 = I8259(pio_addr=x86IOAddress(0xA0), mode='I8259Slave')
+ _cmos = Cmos(pio_addr=x86IOAddress(0x70))
+ _dma1 = I8237(pio_addr=x86IOAddress(0x0))
+ _keyboard = I8042(data_port=x86IOAddress(0x60), \
+ command_port=x86IOAddress(0x64))
+ _pit = I8254(pio_addr=x86IOAddress(0x40))
+ _speaker = PcSpeaker(pio_addr=x86IOAddress(0x61))
+ _io_apic = I82094AA(pio_addr=0xFEC00000)
+ # This is to make sure the interrupt lines are instantiated. Don't use
+ # it for anything directly.
+ int_lines = VectorParam.X86IntLine([], "Interrupt lines")
+
+ pic1 = Param.I8259(_pic1, "Master PIC")
+ pic2 = Param.I8259(_pic2, "Slave PIC")
+ cmos = Param.Cmos(_cmos, "CMOS memory and real time clock device")
+ dma1 = Param.I8237(_dma1, "The first dma controller")
+ keyboard = Param.I8042(_keyboard, "The keyboard controller")
+ pit = Param.I8254(_pit, "Programmable interval timer")
+ speaker = Param.PcSpeaker(_speaker, "PC speaker")
+ io_apic = Param.I82094AA(_io_apic, "I/O APIC")
+
+ def connectPins(self, source, sink):
+ self.int_lines.append(X86IntLine(source=source, sink=sink))
+
+ # IDE controller
+ ide = IdeController(disks=[], pci_func=0, pci_dev=4, pci_bus=0)
+ ide.BAR0 = 0x1f0
+ ide.BAR0LegacyIO = True
+ ide.BAR1 = 0x3f4
+ ide.BAR1Size = '3B'
+ ide.BAR1LegacyIO = True
+ ide.BAR2 = 0x170
+ ide.BAR2LegacyIO = True
+ ide.BAR3 = 0x374
+ ide.BAR3Size = '3B'
+ ide.BAR3LegacyIO = True
+ ide.BAR4 = 1
+ ide.Command = 1
+ ide.InterruptLine = 14
+ ide.InterruptPin = 1
+
+ def attachIO(self, bus):
+ # Route interupt signals
+ self.connectPins(self.pic1.output, self.io_apic.pin(0))
+ self.connectPins(self.pic2.output, self.pic1.pin(2))
+ self.connectPins(self.cmos.int_pin, self.pic2.pin(0))
+ self.connectPins(self.pit.int_pin, self.pic1.pin(0))
+ self.connectPins(self.pit.int_pin, self.io_apic.pin(2))
+# self.connectPins(self.keyboard.keyboard_int_pin,
+# self.pic1.pin(1))
+ self.connectPins(self.keyboard.keyboard_int_pin,
+ self.io_apic.pin(1))
+# self.connectPins(self.keyboard.mouse_int_pin,
+# self.pic2.pin(4))
+ self.connectPins(self.keyboard.mouse_int_pin,
+ self.io_apic.pin(12))
+ # Tell the devices about each other
+ self.pic1.slave = self.pic2
+ self.speaker.i8254 = self.pit
+ self.io_apic.external_int_pic = self.pic1
+ # Connect to the bus
+ self.cmos.pio = bus.port
+ self.dma1.pio = bus.port
+ self.ide.pio = bus.port
+ self.keyboard.pio = bus.port
+ self.pic1.pio = bus.port
+ self.pic2.pio = bus.port
+ self.pit.pio = bus.port
+ self.speaker.pio = bus.port
+ self.io_apic.pio = bus.port
+ self.io_apic.int_port = bus.port
diff --git a/src/dev/x86/X86IntPin.py b/src/dev/x86/X86IntPin.py
new file mode 100644
index 000000000..35e274624
--- /dev/null
+++ b/src/dev/x86/X86IntPin.py
@@ -0,0 +1,51 @@
+# 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: Gabe Black
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+# A generic pin to drive an interrupt signal generated by a device.
+class X86IntSourcePin(SimObject):
+ type = 'X86IntSourcePin'
+ cxx_class = 'X86ISA::IntSourcePin'
+
+# A generic pin to receive an interrupt signal generated by another device.
+class X86IntSinkPin(SimObject):
+ type = 'X86IntSinkPin'
+ cxx_class = 'X86ISA::IntSinkPin'
+
+ device = Param.SimObject("Device this pin belongs to")
+ number = Param.Int("The pin number on the device")
+
+# An interrupt line which is driven by a source pin and drives a sink pin.
+class X86IntLine(SimObject):
+ type = 'X86IntLine'
+ cxx_class = 'X86ISA::IntLine'
+
+ source = Param.X86IntSourcePin("Pin driving this line")
+ sink = Param.X86IntSinkPin("Pin driven by this line")
diff --git a/src/dev/x86/cmos.cc b/src/dev/x86/cmos.cc
new file mode 100644
index 000000000..e08c56e8c
--- /dev/null
+++ b/src/dev/x86/cmos.cc
@@ -0,0 +1,118 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "dev/x86/cmos.hh"
+#include "dev/x86/intdev.hh"
+#include "mem/packet_access.hh"
+
+void
+X86ISA::Cmos::X86RTC::handleEvent()
+{
+ assert(intPin);
+ intPin->raise();
+ //XXX This is a hack.
+ intPin->lower();
+}
+
+Tick
+X86ISA::Cmos::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ pkt->set(address);
+ break;
+ case 0x1:
+ pkt->set(readRegister(address));
+ break;
+ default:
+ panic("Read from undefined CMOS port.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::Cmos::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ address = pkt->get<uint8_t>();
+ break;
+ case 0x1:
+ writeRegister(address, pkt->get<uint8_t>());
+ break;
+ default:
+ panic("Write to undefined CMOS port.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+uint8_t
+X86ISA::Cmos::readRegister(uint8_t reg)
+{
+ assert(reg < numRegs);
+ uint8_t val;
+ if (reg <= 0xD) {
+ val = rtc.readData(reg);
+ DPRINTF(CMOS,
+ "Reading CMOS RTC reg %x as %x.\n", reg, val);
+ } else {
+ val = regs[reg];
+ DPRINTF(CMOS,
+ "Reading non-volitile CMOS address %x as %x.\n", reg, val);
+ }
+ return val;
+}
+
+void
+X86ISA::Cmos::writeRegister(uint8_t reg, uint8_t val)
+{
+ assert(reg < numRegs);
+ if (reg <= 0xD) {
+ DPRINTF(CMOS, "Writing CMOS RTC reg %x with %x.\n",
+ reg, val);
+ rtc.writeData(reg, val);
+ } else {
+ DPRINTF(CMOS, "Writing non-volitile CMOS address %x with %x.\n",
+ reg, val);
+ regs[reg] = val;
+ }
+}
+
+X86ISA::Cmos *
+CmosParams::create()
+{
+ return new X86ISA::Cmos(this);
+}
diff --git a/src/dev/x86/cmos.hh b/src/dev/x86/cmos.hh
new file mode 100644
index 000000000..76276dbc1
--- /dev/null
+++ b/src/dev/x86/cmos.hh
@@ -0,0 +1,89 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_CMOS_HH__
+#define __DEV_X86_CMOS_HH__
+
+#include "dev/io_device.hh"
+#include "dev/mc146818.hh"
+#include "params/Cmos.hh"
+
+namespace X86ISA
+{
+
+class IntSourcePin;
+
+class Cmos : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+
+ uint8_t address;
+
+ static const int numRegs = 128;
+
+ uint8_t regs[numRegs];
+
+ uint8_t readRegister(uint8_t reg);
+ void writeRegister(uint8_t reg, uint8_t val);
+
+ class X86RTC : public MC146818
+ {
+ protected:
+ IntSourcePin * intPin;
+ public:
+ X86RTC(EventManager *em, const std::string &n, const struct tm time,
+ bool bcd, Tick frequency, IntSourcePin * _intPin) :
+ MC146818(em, n, time, bcd, frequency), intPin(_intPin)
+ {
+ }
+ protected:
+ void handleEvent();
+ } rtc;
+
+ public:
+ typedef CmosParams Params;
+
+ Cmos(const Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ rtc(this, "rtc", p->time, true, ULL(5000000000), p->int_pin)
+ {
+ pioSize = 2;
+ memset(regs, 0, numRegs * sizeof(uint8_t));
+ address = 0;
+ }
+
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_CMOS_HH__
diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc
new file mode 100644
index 000000000..afcbfdfb4
--- /dev/null
+++ b/src/dev/x86/i8042.cc
@@ -0,0 +1,446 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "base/bitunion.hh"
+#include "dev/x86/i8042.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+// The 8042 has a whopping 32 bytes of internal RAM.
+const uint8_t RamSize = 32;
+const uint8_t NumOutputBits = 14;
+const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83};
+const uint8_t X86ISA::PS2Mouse::ID[] = {0x00};
+const uint8_t CommandAck = 0xfa;
+const uint8_t CommandNack = 0xfe;
+const uint8_t BatSuccessful = 0xaa;
+
+void
+X86ISA::I8042::addressRanges(AddrRangeList &range_list)
+{
+ range_list.clear();
+ range_list.push_back(RangeSize(dataPort, 1));
+ range_list.push_back(RangeSize(commandPort, 1));
+}
+
+void
+X86ISA::I8042::writeData(uint8_t newData, bool mouse)
+{
+ DPRINTF(I8042, "Set data %#02x.\n", newData);
+ dataReg = newData;
+ statusReg.outputFull = 1;
+ statusReg.mouseOutputFull = (mouse ? 1 : 0);
+ if (!mouse && commandByte.keyboardFullInt) {
+ DPRINTF(I8042, "Sending keyboard interrupt.\n");
+ keyboardIntPin->raise();
+ //This is a hack
+ keyboardIntPin->lower();
+ } else if (mouse && commandByte.mouseFullInt) {
+ DPRINTF(I8042, "Sending mouse interrupt.\n");
+ mouseIntPin->raise();
+ //This is a hack
+ mouseIntPin->lower();
+ }
+}
+
+void
+X86ISA::PS2Device::ack()
+{
+ bufferData(&CommandAck, sizeof(CommandAck));
+}
+
+void
+X86ISA::PS2Device::nack()
+{
+ bufferData(&CommandNack, sizeof(CommandNack));
+}
+
+void
+X86ISA::PS2Device::bufferData(const uint8_t *data, int size)
+{
+ assert(data || size == 0);
+ while (size) {
+ outBuffer.push(*(data++));
+ size--;
+ }
+}
+
+uint8_t
+X86ISA::I8042::readDataOut()
+{
+ uint8_t data = dataReg;
+ statusReg.outputFull = 0;
+ statusReg.mouseOutputFull = 0;
+ if (keyboard.hasData()) {
+ writeData(keyboard.getData(), false);
+ } else if (mouse.hasData()) {
+ writeData(mouse.getData(), true);
+ }
+ return data;
+}
+
+bool
+X86ISA::PS2Keyboard::processData(uint8_t data)
+{
+ if (lastCommand != NoCommand) {
+ switch (lastCommand) {
+ case LEDWrite:
+ DPRINTF(I8042, "Setting LEDs: "
+ "caps lock %s, num lock %s, scroll lock %s\n",
+ bits(data, 2) ? "on" : "off",
+ bits(data, 1) ? "on" : "off",
+ bits(data, 0) ? "on" : "off");
+ ack();
+ lastCommand = NoCommand;
+ break;
+ case TypematicInfo:
+ DPRINTF(I8042, "Setting typematic info to %#02x.\n", data);
+ ack();
+ lastCommand = NoCommand;
+ break;
+ }
+ return hasData();
+ }
+ switch (data) {
+ case LEDWrite:
+ DPRINTF(I8042, "Got LED write command.\n");
+ ack();
+ lastCommand = LEDWrite;
+ break;
+ case DiagnosticEcho:
+ panic("Keyboard diagnostic echo unimplemented.\n");
+ case AlternateScanCodes:
+ panic("Accessing alternate scan codes unimplemented.\n");
+ case ReadID:
+ DPRINTF(I8042, "Got keyboard read ID command.\n");
+ ack();
+ bufferData((uint8_t *)&ID, sizeof(ID));
+ break;
+ case TypematicInfo:
+ DPRINTF(I8042, "Setting typematic info.\n");
+ ack();
+ lastCommand = TypematicInfo;
+ break;
+ case Enable:
+ DPRINTF(I8042, "Enabling the keyboard.\n");
+ ack();
+ break;
+ case Disable:
+ DPRINTF(I8042, "Disabling the keyboard.\n");
+ ack();
+ break;
+ case DefaultsAndDisable:
+ DPRINTF(I8042, "Disabling and resetting the keyboard.\n");
+ ack();
+ break;
+ case AllKeysToTypematic:
+ panic("Setting all keys to typemantic unimplemented.\n");
+ case AllKeysToMakeRelease:
+ panic("Setting all keys to make/release unimplemented.\n");
+ case AllKeysToMake:
+ panic("Setting all keys to make unimplemented.\n");
+ case AllKeysToTypematicMakeRelease:
+ panic("Setting all keys to "
+ "typematic/make/release unimplemented.\n");
+ case KeyToTypematic:
+ panic("Setting a key to typematic unimplemented.\n");
+ case KeyToMakeRelease:
+ panic("Setting a key to make/release unimplemented.\n");
+ case KeyToMakeOnly:
+ panic("Setting key to make only unimplemented.\n");
+ case Resend:
+ panic("Keyboard resend unimplemented.\n");
+ case Reset:
+ panic("Keyboard reset unimplemented.\n");
+ default:
+ panic("Unknown keyboard command %#02x.\n", data);
+ }
+ return hasData();
+}
+
+bool
+X86ISA::PS2Mouse::processData(uint8_t data)
+{
+ if (lastCommand != NoCommand) {
+ switch(lastCommand) {
+ case SetResolution:
+ DPRINTF(I8042, "Mouse resolution set to %d.\n", data);
+ resolution = data;
+ ack();
+ lastCommand = NoCommand;
+ break;
+ case SampleRate:
+ DPRINTF(I8042, "Mouse sample rate %d samples "
+ "per second.\n", data);
+ sampleRate = data;
+ ack();
+ lastCommand = NoCommand;
+ break;
+ default:
+ panic("Not expecting data for a mouse command.\n");
+ }
+ return hasData();
+ }
+ switch (data) {
+ case Scale1to1:
+ DPRINTF(I8042, "Setting mouse scale to 1:1.\n");
+ status.twoToOne = 0;
+ ack();
+ break;
+ case Scale2to1:
+ DPRINTF(I8042, "Setting mouse scale to 2:1.\n");
+ status.twoToOne = 1;
+ ack();
+ break;
+ case SetResolution:
+ DPRINTF(I8042, "Setting mouse resolution.\n");
+ lastCommand = SetResolution;
+ ack();
+ break;
+ case GetStatus:
+ DPRINTF(I8042, "Getting mouse status.\n");
+ ack();
+ bufferData((uint8_t *)&(status), 1);
+ bufferData(&resolution, sizeof(resolution));
+ bufferData(&sampleRate, sizeof(sampleRate));
+ break;
+ case ReadData:
+ panic("Reading mouse data unimplemented.\n");
+ case ResetWrapMode:
+ panic("Resetting mouse wrap mode unimplemented.\n");
+ case WrapMode:
+ panic("Setting mouse wrap mode unimplemented.\n");
+ case RemoteMode:
+ panic("Setting mouse remote mode unimplemented.\n");
+ case ReadID:
+ DPRINTF(I8042, "Mouse ID requested.\n");
+ ack();
+ bufferData(ID, sizeof(ID));
+ break;
+ case SampleRate:
+ DPRINTF(I8042, "Setting mouse sample rate.\n");
+ lastCommand = SampleRate;
+ ack();
+ break;
+ case DisableReporting:
+ DPRINTF(I8042, "Disabling data reporting.\n");
+ status.enabled = 0;
+ ack();
+ break;
+ case EnableReporting:
+ DPRINTF(I8042, "Enabling data reporting.\n");
+ status.enabled = 1;
+ ack();
+ break;
+ case DefaultsAndDisable:
+ DPRINTF(I8042, "Disabling and resetting mouse.\n");
+ sampleRate = 100;
+ resolution = 4;
+ status.twoToOne = 0;
+ status.enabled = 0;
+ ack();
+ break;
+ case Resend:
+ panic("Mouse resend unimplemented.\n");
+ case Reset:
+ DPRINTF(I8042, "Resetting the mouse.\n");
+ sampleRate = 100;
+ resolution = 4;
+ status.twoToOne = 0;
+ status.enabled = 0;
+ ack();
+ bufferData(&BatSuccessful, sizeof(BatSuccessful));
+ bufferData(ID, sizeof(ID));
+ break;
+ default:
+ warn("Unknown mouse command %#02x.\n", data);
+ nack();
+ break;
+ }
+ return hasData();
+}
+
+
+Tick
+X86ISA::I8042::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr addr = pkt->getAddr();
+ if (addr == dataPort) {
+ uint8_t data = readDataOut();
+ //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
+ pkt->set<uint8_t>(data);
+ } else if (addr == commandPort) {
+ //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
+ pkt->set<uint8_t>((uint8_t)statusReg);
+ } else {
+ panic("Read from unrecognized port %#x.\n", addr);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8042::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr addr = pkt->getAddr();
+ uint8_t data = pkt->get<uint8_t>();
+ if (addr == dataPort) {
+ statusReg.commandLast = 0;
+ switch (lastCommand) {
+ case NoCommand:
+ if (keyboard.processData(data)) {
+ writeData(keyboard.getData(), false);
+ }
+ break;
+ case WriteToMouse:
+ if (mouse.processData(data)) {
+ writeData(mouse.getData(), true);
+ }
+ break;
+ case WriteCommandByte:
+ commandByte = data;
+ DPRINTF(I8042, "Got data %#02x for \"Write "
+ "command byte\" command.\n", data);
+ statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
+ break;
+ case WriteMouseOutputBuff:
+ DPRINTF(I8042, "Got data %#02x for \"Write "
+ "mouse output buffer\" command.\n", data);
+ writeData(data, true);
+ break;
+ default:
+ panic("Data written for unrecognized "
+ "command %#02x\n", lastCommand);
+ }
+ lastCommand = NoCommand;
+ } else if (addr == commandPort) {
+ DPRINTF(I8042, "Got command %#02x.\n", data);
+ statusReg.commandLast = 1;
+ // These purposefully leave off the first byte of the controller RAM
+ // so it can be handled specially.
+ if (data > ReadControllerRamBase &&
+ data < ReadControllerRamBase + RamSize) {
+ panic("Attempted to use i8042 read controller RAM command to "
+ "get byte %d.\n", data - ReadControllerRamBase);
+ } else if (data > WriteControllerRamBase &&
+ data < WriteControllerRamBase + RamSize) {
+ panic("Attempted to use i8042 read controller RAM command to "
+ "get byte %d.\n", data - ReadControllerRamBase);
+ } else if (data >= PulseOutputBitBase &&
+ data < PulseOutputBitBase + NumOutputBits) {
+ panic("Attempted to use i8042 pulse output bit command to "
+ "to pulse bit %d.\n", data - PulseOutputBitBase);
+ }
+ switch (data) {
+ case GetCommandByte:
+ DPRINTF(I8042, "Getting command byte.\n");
+ writeData(commandByte);
+ break;
+ case WriteCommandByte:
+ DPRINTF(I8042, "Setting command byte.\n");
+ lastCommand = WriteCommandByte;
+ break;
+ case CheckForPassword:
+ panic("i8042 \"Check for password\" command not implemented.\n");
+ case LoadPassword:
+ panic("i8042 \"Load password\" command not implemented.\n");
+ case CheckPassword:
+ panic("i8042 \"Check password\" command not implemented.\n");
+ case DisableMouse:
+ DPRINTF(I8042, "Disabling mouse at controller.\n");
+ commandByte.disableMouse = 1;
+ break;
+ case EnableMouse:
+ DPRINTF(I8042, "Enabling mouse at controller.\n");
+ commandByte.disableMouse = 0;
+ break;
+ case TestMouse:
+ panic("i8042 \"Test mouse\" command not implemented.\n");
+ case SelfTest:
+ panic("i8042 \"Self test\" command not implemented.\n");
+ case InterfaceTest:
+ panic("i8042 \"Interface test\" command not implemented.\n");
+ case DiagnosticDump:
+ panic("i8042 \"Diagnostic dump\" command not implemented.\n");
+ case DisableKeyboard:
+ DPRINTF(I8042, "Disabling keyboard at controller.\n");
+ commandByte.disableKeyboard = 1;
+ break;
+ case EnableKeyboard:
+ DPRINTF(I8042, "Enabling keyboard at controller.\n");
+ commandByte.disableKeyboard = 0;
+ break;
+ case ReadInputPort:
+ panic("i8042 \"Read input port\" command not implemented.\n");
+ case ContinuousPollLow:
+ panic("i8042 \"Continuous poll low\" command not implemented.\n");
+ case ContinuousPollHigh:
+ panic("i8042 \"Continuous poll high\" command not implemented.\n");
+ case ReadOutputPort:
+ panic("i8042 \"Read output port\" command not implemented.\n");
+ case WriteOutputPort:
+ panic("i8042 \"Write output port\" command not implemented.\n");
+ case WriteKeyboardOutputBuff:
+ panic("i8042 \"Write keyboard output buffer\" "
+ "command not implemented.\n");
+ case WriteMouseOutputBuff:
+ DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
+ lastCommand = WriteMouseOutputBuff;
+ break;
+ case WriteToMouse:
+ DPRINTF(I8042, "Expecting mouse command.\n");
+ lastCommand = WriteToMouse;
+ break;
+ case DisableA20:
+ panic("i8042 \"Disable A20\" command not implemented.\n");
+ case EnableA20:
+ panic("i8042 \"Enable A20\" command not implemented.\n");
+ case ReadTestInputs:
+ panic("i8042 \"Read test inputs\" command not implemented.\n");
+ case SystemReset:
+ panic("i8042 \"System reset\" command not implemented.\n");
+ default:
+ panic("Write to unknown i8042 "
+ "(keyboard controller) command port.\n");
+ }
+ } else {
+ panic("Write to unrecognized port %#x.\n", addr);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::I8042 *
+I8042Params::create()
+{
+ return new X86ISA::I8042(this);
+}
diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh
new file mode 100644
index 000000000..8a941f9a5
--- /dev/null
+++ b/src/dev/x86/i8042.hh
@@ -0,0 +1,259 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_I8042_HH__
+#define __DEV_X86_I8042_HH__
+
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I8042.hh"
+
+#include <queue>
+
+namespace X86ISA
+{
+
+class IntPin;
+
+class PS2Device
+{
+ protected:
+ std::queue<uint8_t> outBuffer;
+
+ static const uint16_t NoCommand = (uint16_t)(-1);
+
+ uint16_t lastCommand;
+ void bufferData(const uint8_t *data, int size);
+ void ack();
+ void nack();
+
+ public:
+ virtual ~PS2Device()
+ {};
+
+ PS2Device() : lastCommand(NoCommand)
+ {}
+
+ bool hasData()
+ {
+ return !outBuffer.empty();
+ }
+
+ uint8_t getData()
+ {
+ uint8_t data = outBuffer.front();
+ outBuffer.pop();
+ return data;
+ }
+
+ virtual bool processData(uint8_t data) = 0;
+};
+
+class PS2Mouse : public PS2Device
+{
+ protected:
+ static const uint8_t ID[];
+
+ enum Command
+ {
+ Scale1to1 = 0xE6,
+ Scale2to1 = 0xE7,
+ SetResolution = 0xE8,
+ GetStatus = 0xE9,
+ ReadData = 0xEB,
+ ResetWrapMode = 0xEC,
+ WrapMode = 0xEE,
+ RemoteMode = 0xF0,
+ ReadID = 0xF2,
+ SampleRate = 0xF3,
+ EnableReporting = 0xF4,
+ DisableReporting = 0xF5,
+ DefaultsAndDisable = 0xF6,
+ Resend = 0xFE,
+ Reset = 0xFF
+ };
+
+ BitUnion8(Status)
+ Bitfield<6> remote;
+ Bitfield<5> enabled;
+ Bitfield<4> twoToOne;
+ Bitfield<2> leftButton;
+ Bitfield<0> rightButton;
+ EndBitUnion(Status)
+
+ Status status;
+ uint8_t resolution;
+ uint8_t sampleRate;
+ public:
+ PS2Mouse() : PS2Device(), status(0), resolution(4), sampleRate(100)
+ {}
+
+ bool processData(uint8_t data);
+};
+
+class PS2Keyboard : public PS2Device
+{
+ protected:
+ static const uint8_t ID[];
+
+ enum Command
+ {
+ LEDWrite = 0xED,
+ DiagnosticEcho = 0xEE,
+ AlternateScanCodes = 0xF0,
+ ReadID = 0xF2,
+ TypematicInfo = 0xF3,
+ Enable = 0xF4,
+ Disable = 0xF5,
+ DefaultsAndDisable = 0xF6,
+ AllKeysToTypematic = 0xF7,
+ AllKeysToMakeRelease = 0xF8,
+ AllKeysToMake = 0xF9,
+ AllKeysToTypematicMakeRelease = 0xFA,
+ KeyToTypematic = 0xFB,
+ KeyToMakeRelease = 0xFC,
+ KeyToMakeOnly = 0xFD,
+ Resend = 0xFE,
+ Reset = 0xFF
+ };
+
+ public:
+ bool processData(uint8_t data);
+};
+
+class I8042 : public BasicPioDevice
+{
+ protected:
+ enum Command
+ {
+ GetCommandByte = 0x20,
+ ReadControllerRamBase = 0x20,
+ WriteCommandByte = 0x60,
+ WriteControllerRamBase = 0x60,
+ CheckForPassword = 0xA4,
+ LoadPassword = 0xA5,
+ CheckPassword = 0xA6,
+ DisableMouse = 0xA7,
+ EnableMouse = 0xA8,
+ TestMouse = 0xA9,
+ SelfTest = 0xAA,
+ InterfaceTest = 0xAB,
+ DiagnosticDump = 0xAC,
+ DisableKeyboard = 0xAD,
+ EnableKeyboard = 0xAE,
+ ReadInputPort = 0xC0,
+ ContinuousPollLow = 0xC1,
+ ContinuousPollHigh = 0xC2,
+ ReadOutputPort = 0xD0,
+ WriteOutputPort = 0xD1,
+ WriteKeyboardOutputBuff = 0xD2,
+ WriteMouseOutputBuff = 0xD3,
+ WriteToMouse = 0xD4,
+ DisableA20 = 0xDD,
+ EnableA20 = 0xDF,
+ ReadTestInputs = 0xE0,
+ PulseOutputBitBase = 0xF0,
+ SystemReset = 0xFE
+ };
+
+ BitUnion8(StatusReg)
+ Bitfield<7> parityError;
+ Bitfield<6> timeout;
+ Bitfield<5> mouseOutputFull;
+ Bitfield<4> keyboardUnlocked;
+ Bitfield<3> commandLast;
+ Bitfield<2> passedSelfTest;
+ Bitfield<1> inputFull;
+ Bitfield<0> outputFull;
+ EndBitUnion(StatusReg)
+
+ BitUnion8(CommandByte)
+ Bitfield<6> convertScanCodes;
+ Bitfield<5> disableMouse;
+ Bitfield<4> disableKeyboard;
+ Bitfield<2> passedSelfTest;
+ Bitfield<1> mouseFullInt;
+ Bitfield<0> keyboardFullInt;
+ EndBitUnion(CommandByte)
+
+ Tick latency;
+ Addr dataPort;
+ Addr commandPort;
+
+ StatusReg statusReg;
+ CommandByte commandByte;
+
+ uint8_t dataReg;
+
+ static const uint16_t NoCommand = (uint16_t)(-1);
+ uint16_t lastCommand;
+
+ IntSourcePin *mouseIntPin;
+ IntSourcePin *keyboardIntPin;
+
+ PS2Mouse mouse;
+ PS2Keyboard keyboard;
+
+ void writeData(uint8_t newData, bool mouse = false);
+ uint8_t readDataOut();
+
+ public:
+ typedef I8042Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8042(Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ dataPort(p->data_port), commandPort(p->command_port),
+ statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand),
+ mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin)
+ {
+ statusReg.passedSelfTest = 1;
+ statusReg.commandLast = 1;
+ statusReg.keyboardUnlocked = 1;
+
+ commandByte.convertScanCodes = 1;
+ commandByte.passedSelfTest = 1;
+ commandByte.keyboardFullInt = 1;
+ }
+
+ void addressRanges(AddrRangeList &range_list);
+
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8042_HH__
diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc
new file mode 100644
index 000000000..d160fcb24
--- /dev/null
+++ b/src/dev/x86/i82094aa.cc
@@ -0,0 +1,236 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "arch/x86/intmessage.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8259.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "sim/system.hh"
+
+X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this),
+ latency(p->pio_latency), pioAddr(p->pio_addr),
+ extIntPic(p->external_int_pic)
+{
+ // This assumes there's only one I/O APIC in the system
+ id = sys->numContexts();
+ assert(id <= 0xf);
+ arbId = id;
+ regSel = 0;
+ RedirTableEntry entry = 0;
+ entry.mask = 1;
+ for (int i = 0; i < TableSize; i++) {
+ redirTable[i] = entry;
+ pinStates[i] = false;
+ }
+}
+
+Tick
+X86ISA::I82094AA::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 4);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch(offset) {
+ case 0:
+ pkt->set<uint32_t>(regSel);
+ break;
+ case 16:
+ pkt->set<uint32_t>(readReg(regSel));
+ break;
+ default:
+ panic("Illegal read from I/O APIC.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I82094AA::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 4);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch(offset) {
+ case 0:
+ regSel = pkt->get<uint32_t>();
+ break;
+ case 16:
+ writeReg(regSel, pkt->get<uint32_t>());
+ break;
+ default:
+ panic("Illegal write to I/O APIC.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+void
+X86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
+{
+ if (offset == 0x0) {
+ id = bits(value, 27, 24);
+ } else if (offset == 0x1) {
+ // The IOAPICVER register is read only.
+ } else if (offset == 0x2) {
+ arbId = bits(value, 27, 24);
+ } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
+ int index = (offset - 0x10) / 2;
+ if (offset % 2) {
+ redirTable[index].topDW = value;
+ redirTable[index].topReserved = 0;
+ } else {
+ redirTable[index].bottomDW = value;
+ redirTable[index].bottomReserved = 0;
+ }
+ } else {
+ warn("Access to undefined I/O APIC register %#x.\n", offset);
+ }
+ DPRINTF(I82094AA,
+ "Wrote %#x to I/O APIC register %#x .\n", value, offset);
+}
+
+uint32_t
+X86ISA::I82094AA::readReg(uint8_t offset)
+{
+ uint32_t result = 0;
+ if (offset == 0x0) {
+ result = id << 24;
+ } else if (offset == 0x1) {
+ result = ((TableSize - 1) << 16) | APICVersion;
+ } else if (offset == 0x2) {
+ result = arbId << 24;
+ } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
+ int index = (offset - 0x10) / 2;
+ if (offset % 2) {
+ result = redirTable[index].topDW;
+ } else {
+ result = redirTable[index].bottomDW;
+ }
+ } else {
+ warn("Access to undefined I/O APIC register %#x.\n", offset);
+ }
+ DPRINTF(I82094AA,
+ "Read %#x from I/O APIC register %#x.\n", result, offset);
+ return result;
+}
+
+void
+X86ISA::I82094AA::signalInterrupt(int line)
+{
+ DPRINTF(I82094AA, "Received interrupt %d.\n", line);
+ assert(line < TableSize);
+ RedirTableEntry entry = redirTable[line];
+ if (entry.mask) {
+ DPRINTF(I82094AA, "Entry was masked.\n");
+ return;
+ } else {
+ TriggerIntMessage message;
+ message.destination = entry.dest;
+ if (entry.deliveryMode == DeliveryMode::ExtInt) {
+ assert(extIntPic);
+ message.vector = extIntPic->getVector();
+ } else {
+ message.vector = entry.vector;
+ }
+ message.deliveryMode = entry.deliveryMode;
+ message.destMode = entry.destMode;
+ message.level = entry.polarity;
+ message.trigger = entry.trigger;
+
+ if (DeliveryMode::isReserved(entry.deliveryMode)) {
+ fatal("Tried to use reserved delivery mode "
+ "for IO APIC entry %d.\n", line);
+ } else if (DTRACE(I82094AA)) {
+ DPRINTF(I82094AA, "Delivery mode is: %s.\n",
+ DeliveryMode::names[entry.deliveryMode]);
+ DPRINTF(I82094AA, "Vector is %#x.\n", message.vector);
+ }
+
+ if (entry.destMode == 0) {
+ DPRINTF(I82094AA,
+ "Sending interrupt to APIC ID %d.\n", entry.dest);
+ PacketPtr pkt = buildIntRequest(entry.dest, message);
+ if (sys->getMemoryMode() == Enums::timing)
+ intPort->sendMessageTiming(pkt, latency);
+ else if (sys->getMemoryMode() == Enums::atomic)
+ intPort->sendMessageAtomic(pkt);
+ else
+ panic("Unrecognized memory mode.\n");
+ } else {
+ DPRINTF(I82094AA, "Sending interrupts to APIC IDs:"
+ "%s%s%s%s%s%s%s%s\n",
+ bits((int)entry.dest, 0) ? " 0": "",
+ bits((int)entry.dest, 1) ? " 1": "",
+ bits((int)entry.dest, 2) ? " 2": "",
+ bits((int)entry.dest, 3) ? " 3": "",
+ bits((int)entry.dest, 4) ? " 4": "",
+ bits((int)entry.dest, 5) ? " 5": "",
+ bits((int)entry.dest, 6) ? " 6": "",
+ bits((int)entry.dest, 7) ? " 7": ""
+ );
+ uint8_t dests = entry.dest;
+ uint8_t id = 0;
+ while(dests) {
+ if (dests & 0x1) {
+ PacketPtr pkt = buildIntRequest(id, message);
+ if (sys->getMemoryMode() == Enums::timing)
+ intPort->sendMessageTiming(pkt, latency);
+ else if (sys->getMemoryMode() == Enums::atomic)
+ intPort->sendMessageAtomic(pkt);
+ else
+ panic("Unrecognized memory mode.\n");
+ }
+ dests >>= 1;
+ id++;
+ }
+ }
+ }
+}
+
+void
+X86ISA::I82094AA::raiseInterruptPin(int number)
+{
+ assert(number < TableSize);
+ if (!pinStates[number])
+ signalInterrupt(number);
+ pinStates[number] = true;
+}
+
+void
+X86ISA::I82094AA::lowerInterruptPin(int number)
+{
+ assert(number < TableSize);
+ pinStates[number] = false;
+}
+
+X86ISA::I82094AA *
+I82094AAParams::create()
+{
+ return new X86ISA::I82094AA(this);
+}
diff --git a/src/dev/x86/i82094aa.hh b/src/dev/x86/i82094aa.hh
new file mode 100644
index 000000000..b11e2bcb1
--- /dev/null
+++ b/src/dev/x86/i82094aa.hh
@@ -0,0 +1,127 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_I82094AA_HH__
+#define __DEV_X86_I82094AA_HH__
+
+#include "base/bitunion.hh"
+#include "base/range_map.hh"
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I82094AA.hh"
+
+namespace X86ISA
+{
+
+class I8259;
+
+class I82094AA : public PioDevice, public IntDev
+{
+ public:
+ BitUnion64(RedirTableEntry)
+ Bitfield<63, 32> topDW;
+ Bitfield<55, 32> topReserved;
+ Bitfield<31, 0> bottomDW;
+ Bitfield<31, 17> bottomReserved;
+ Bitfield<63, 56> dest;
+ Bitfield<16> mask;
+ Bitfield<15> trigger;
+ Bitfield<14> remoteIRR;
+ Bitfield<13> polarity;
+ Bitfield<12> deliveryStatus;
+ Bitfield<11> destMode;
+ Bitfield<10, 8> deliveryMode;
+ Bitfield<7, 0> vector;
+ EndBitUnion(RedirTableEntry)
+
+ protected:
+ Tick latency;
+ Addr pioAddr;
+
+ I8259 * extIntPic;
+
+ uint8_t regSel;
+ uint8_t id;
+ uint8_t arbId;
+
+ static const uint8_t TableSize = 24;
+ // This implementation is based on version 0x11, but 0x14 avoids having
+ // to deal with the arbitration and APIC bus guck.
+ static const uint8_t APICVersion = 0x14;
+
+ RedirTableEntry redirTable[TableSize];
+ bool pinStates[TableSize];
+
+ public:
+ typedef I82094AAParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I82094AA(Params *p);
+
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+
+ void addressRanges(AddrRangeList &range_list)
+ {
+ range_list.clear();
+ range_list.push_back(RangeEx(pioAddr, pioAddr + 4));
+ range_list.push_back(RangeEx(pioAddr + 16, pioAddr + 20));
+ }
+
+ void getIntAddrRange(AddrRangeList &range_list)
+ {
+ range_list.clear();
+ range_list.push_back(RangeEx(x86InterruptAddress(1, 0),
+ x86InterruptAddress(1, 0) + PhysAddrAPICRangeSize));
+ }
+
+ void writeReg(uint8_t offset, uint32_t value);
+ uint32_t readReg(uint8_t offset);
+
+ Port *getPort(const std::string &if_name, int idx = -1)
+ {
+ if (if_name == "int_port")
+ return intPort;
+ return PioDevice::getPort(if_name, idx);
+ }
+
+ void signalInterrupt(int line);
+ void raiseInterruptPin(int number);
+ void lowerInterruptPin(int number);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__
diff --git a/src/dev/x86/i8237.cc b/src/dev/x86/i8237.cc
new file mode 100644
index 000000000..f6ea9d75f
--- /dev/null
+++ b/src/dev/x86/i8237.cc
@@ -0,0 +1,132 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "dev/x86/i8237.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+Tick
+X86ISA::I8237::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch (offset) {
+ case 0x0:
+ panic("Read from i8237 channel 0 current address unimplemented.\n");
+ case 0x1:
+ panic("Read from i8237 channel 0 remaining "
+ "word count unimplemented.\n");
+ case 0x2:
+ panic("Read from i8237 channel 1 current address unimplemented.\n");
+ case 0x3:
+ panic("Read from i8237 channel 1 remaining "
+ "word count unimplemented.\n");
+ case 0x4:
+ panic("Read from i8237 channel 2 current address unimplemented.\n");
+ case 0x5:
+ panic("Read from i8237 channel 2 remaining "
+ "word count unimplemented.\n");
+ case 0x6:
+ panic("Read from i8237 channel 3 current address unimplemented.\n");
+ case 0x7:
+ panic("Read from i8237 channel 3 remaining "
+ "word count unimplemented.\n");
+ case 0x8:
+ panic("Read from i8237 status register unimplemented.\n");
+ default:
+ panic("Read from undefined i8237 register %d.\n", offset);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8237::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch (offset) {
+ case 0x0:
+ panic("Write to i8237 channel 0 starting address unimplemented.\n");
+ case 0x1:
+ panic("Write to i8237 channel 0 starting "
+ "word count unimplemented.\n");
+ case 0x2:
+ panic("Write to i8237 channel 1 starting address unimplemented.\n");
+ case 0x3:
+ panic("Write to i8237 channel 1 starting "
+ "word count unimplemented.\n");
+ case 0x4:
+ panic("Write to i8237 channel 2 starting address unimplemented.\n");
+ case 0x5:
+ panic("Write to i8237 channel 2 starting "
+ "word count unimplemented.\n");
+ case 0x6:
+ panic("Write to i8237 channel 3 starting address unimplemented.\n");
+ case 0x7:
+ panic("Write to i8237 channel 3 starting "
+ "word count unimplemented.\n");
+ case 0x8:
+ panic("Write to i8237 command register unimplemented.\n");
+ case 0x9:
+ panic("Write to i8237 request register unimplemented.\n");
+ case 0xa:
+ {
+ uint8_t command = pkt->get<uint8_t>();
+ uint8_t select = bits(command, 1, 0);
+ uint8_t bitVal = bits(command, 2);
+ if (!bitVal)
+ panic("Turning on i8237 channels unimplemented.\n");
+ replaceBits(maskReg, select, bitVal);
+ }
+ break;
+ case 0xb:
+ panic("Write to i8237 mode register unimplemented.\n");
+ case 0xc:
+ panic("Write to i8237 clear LSB/MSB flip-flop "
+ "register unimplemented.\n");
+ case 0xd:
+ panic("Write to i8237 master clear/reset register unimplemented.\n");
+ case 0xe:
+ panic("Write to i8237 clear mask register unimplemented.\n");
+ case 0xf:
+ panic("Write to i8237 write all mask register bits unimplemented.\n");
+ default:
+ panic("Write to undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::I8237 *
+I8237Params::create()
+{
+ return new X86ISA::I8237(this);
+}
diff --git a/src/dev/x86/i8237.hh b/src/dev/x86/i8237.hh
new file mode 100644
index 000000000..2d73b8ab5
--- /dev/null
+++ b/src/dev/x86/i8237.hh
@@ -0,0 +1,66 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_I8237_HH__
+#define __DEV_X86_I8237_HH__
+
+#include "dev/io_device.hh"
+#include "params/I8237.hh"
+
+namespace X86ISA
+{
+
+class I8237 : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+ uint8_t maskReg;
+
+ public:
+ typedef I8237Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8237(Params *p) : BasicPioDevice(p), latency(p->pio_latency), maskReg(0)
+ {
+ pioSize = 16;
+ }
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8237_HH__
diff --git a/src/dev/x86/opteron.cc b/src/dev/x86/i8254.cc
index ba46f2dfa..5eb28844a 100644
--- a/src/dev/x86/opteron.cc
+++ b/src/dev/x86/i8254.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,82 +28,56 @@
* Authors: Gabe Black
*/
-/** @file
- * Implementation of Opteron platform.
- */
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "arch/x86/x86_traits.hh"
-#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
-#include "dev/x86/opteron.hh"
-#include "sim/system.hh"
-
-using namespace std;
-using namespace TheISA;
-
-Opteron::Opteron(const Params *p)
- : Platform(p), system(p->system)
-{
- // set the back pointer from the system to myself
- system->platform = this;
-}
-
-Tick
-Opteron::intrFrequency()
-{
- panic("Need implementation\n");
- M5_DUMMY_RETURN
-}
-
-void
-Opteron::postConsoleInt()
-{
- warn_once("Don't know what interrupt to post for console.\n");
- //panic("Need implementation\n");
-}
+#include "dev/x86/i8254.hh"
+#include "dev/x86/intdev.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
void
-Opteron::clearConsoleInt()
+X86ISA::I8254::counterInterrupt(unsigned int num)
{
- warn_once("Don't know what interrupt to clear for console.\n");
- //panic("Need implementation\n");
+ DPRINTF(I8254, "Interrupt from counter %d.\n", num);
+ if (num == 0) {
+ intPin->raise();
+ //XXX This is a hack.
+ intPin->lower();
+ }
}
-void
-Opteron::postPciInt(int line)
-{
- panic("Need implementation\n");
-}
-
-void
-Opteron::clearPciInt(int line)
-{
- panic("Need implementation\n");
-}
-
-Addr
-Opteron::pciToDma(Addr pciAddr) const
+Tick
+X86ISA::I8254::read(PacketPtr pkt)
{
- panic("Need implementation\n");
- M5_DUMMY_RETURN
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ if (offset < 3) {
+ pkt->set(pit.readCounter(offset));
+ } else if (offset == 3) {
+ pkt->set(uint8_t(-1));
+ } else {
+ panic("Read from undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
}
-
-Addr
-Opteron::calcConfigAddr(int bus, int dev, int func)
+Tick
+X86ISA::I8254::write(PacketPtr pkt)
{
- assert(func < 8);
- assert(dev < 32);
- assert(bus == 0);
- return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11));
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ if (offset < 3) {
+ pit.writeCounter(offset, pkt->get<uint8_t>());
+ } else if (offset == 3) {
+ pit.writeControl(pkt->get<uint8_t>());
+ } else {
+ panic("Write to undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
}
-Opteron *
-OpteronParams::create()
+X86ISA::I8254 *
+I8254Params::create()
{
- return new Opteron(this);
+ return new X86ISA::I8254(this);
}
diff --git a/src/dev/x86/i8254.hh b/src/dev/x86/i8254.hh
new file mode 100644
index 000000000..7de20dfd4
--- /dev/null
+++ b/src/dev/x86/i8254.hh
@@ -0,0 +1,116 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_I8254_HH__
+#define __DEV_X86_I8254_HH__
+
+#include "dev/intel_8254_timer.hh"
+#include "dev/io_device.hh"
+#include "params/I8254.hh"
+
+namespace X86ISA
+{
+
+class IntSourcePin;
+
+class I8254 : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+ class X86Intel8254Timer : public Intel8254Timer
+ {
+ protected:
+ I8254 * parent;
+
+ void
+ counterInterrupt(unsigned int num)
+ {
+ parent->counterInterrupt(num);
+ }
+
+ public:
+ X86Intel8254Timer(const std::string &name, I8254 * _parent) :
+ Intel8254Timer(_parent, name), parent(_parent)
+ {}
+ };
+
+
+ X86Intel8254Timer pit;
+
+ IntSourcePin *intPin;
+
+ void counterInterrupt(unsigned int num);
+
+ public:
+ typedef I8254Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8254(Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ pit(p->name, this), intPin(p->int_pin)
+ {
+ pioSize = 4;
+ }
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+
+ bool
+ outputHigh(unsigned int num)
+ {
+ return pit.outputHigh(num);
+ }
+
+ uint8_t
+ readCounter(unsigned int num)
+ {
+ return pit.readCounter(num);
+ }
+
+ void
+ writeCounter(unsigned int num, const uint8_t data)
+ {
+ pit.writeCounter(num, data);
+ }
+
+ void
+ writeControl(uint8_t val)
+ {
+ pit.writeControl(val);
+ }
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__
diff --git a/src/dev/x86/i8259.cc b/src/dev/x86/i8259.cc
new file mode 100644
index 000000000..b868295eb
--- /dev/null
+++ b/src/dev/x86/i8259.cc
@@ -0,0 +1,310 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "base/bitfield.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8259.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+X86ISA::I8259::I8259(Params * p) : BasicPioDevice(p), IntDev(this),
+ latency(p->pio_latency), output(p->output),
+ mode(p->mode), slave(p->slave),
+ IRR(0), ISR(0), IMR(0),
+ readIRR(true), initControlWord(0), autoEOI(false)
+{
+ for (int i = 0; i < NumLines; i++)
+ pinStates[i] = false;
+ pioSize = 2;
+}
+
+Tick
+X86ISA::I8259::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ if (readIRR) {
+ DPRINTF(I8259, "Reading IRR as %#x.\n", IRR);
+ pkt->set(IRR);
+ } else {
+ DPRINTF(I8259, "Reading ISR as %#x.\n", ISR);
+ pkt->set(ISR);
+ }
+ break;
+ case 0x1:
+ DPRINTF(I8259, "Reading IMR as %#x.\n", IMR);
+ pkt->set(IMR);
+ break;
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8259::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ uint8_t val = pkt->get<uint8_t>();
+ switch (pkt->getAddr() - pioAddr) {
+ case 0x0:
+ if (bits(val, 4)) {
+ DPRINTF(I8259, "Received initialization command word 1.\n");
+ IMR = 0;
+ edgeTriggered = bits(val, 3);
+ DPRINTF(I8259, "%s triggered mode.\n",
+ edgeTriggered ? "Edge" : "Level");
+ cascadeMode = !bits(val, 1);
+ DPRINTF(I8259, "%s mode.\n",
+ cascadeMode ? "Cascade" : "Single");
+ expectICW4 = bits(val, 0);
+ if (!expectICW4) {
+ autoEOI = false;
+ }
+ initControlWord = 1;
+ DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2);
+ } else if (bits(val, 4, 3) == 0) {
+ DPRINTF(I8259, "Received operation command word 2.\n");
+ switch (bits(val, 7, 5)) {
+ case 0x0:
+ DPRINTF(I8259,
+ "Subcommand: Rotate in auto-EOI mode (clear).\n");
+ break;
+ case 0x1:
+ {
+ int line = findMsbSet(ISR);
+ DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n",
+ line);
+ handleEOI(line);
+ }
+ break;
+ case 0x2:
+ DPRINTF(I8259, "Subcommand: No operation.\n");
+ break;
+ case 0x3:
+ {
+ int line = bits(val, 2, 0);
+ DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n",
+ line);
+ handleEOI(line);
+ }
+ break;
+ case 0x4:
+ DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n");
+ break;
+ case 0x5:
+ DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n");
+ break;
+ case 0x6:
+ DPRINTF(I8259, "Subcommand: Set priority command.\n");
+ DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
+ bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
+ break;
+ case 0x7:
+ DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n");
+ DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
+ bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
+ break;
+ }
+ } else if (bits(val, 4, 3) == 1) {
+ DPRINTF(I8259, "Received operation command word 3.\n");
+ if (bits(val, 7)) {
+ DPRINTF(I8259, "%s special mask mode.\n",
+ bits(val, 6) ? "Set" : "Clear");
+ }
+ if (bits(val, 1)) {
+ readIRR = bits(val, 0);
+ DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR");
+ }
+ }
+ break;
+ case 0x1:
+ switch (initControlWord) {
+ case 0x0:
+ DPRINTF(I8259, "Received operation command word 1.\n");
+ DPRINTF(I8259, "Wrote IMR value %#x.\n", val);
+ IMR = val;
+ break;
+ case 0x1:
+ DPRINTF(I8259, "Received initialization command word 2.\n");
+ vectorOffset = val & ~mask(3);
+ DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n",
+ vectorOffset, vectorOffset | mask(3));
+ if (cascadeMode) {
+ initControlWord++;
+ } else {
+ cascadeBits = 0;
+ initControlWord = 0;
+ }
+ break;
+ case 0x2:
+ DPRINTF(I8259, "Received initialization command word 3.\n");
+ if (mode == Enums::I8259Master) {
+ DPRINTF(I8259, "Slaves attached to IRQs:%s%s%s%s%s%s%s%s\n",
+ bits(val, 0) ? " 0" : "",
+ bits(val, 1) ? " 1" : "",
+ bits(val, 2) ? " 2" : "",
+ bits(val, 3) ? " 3" : "",
+ bits(val, 4) ? " 4" : "",
+ bits(val, 5) ? " 5" : "",
+ bits(val, 6) ? " 6" : "",
+ bits(val, 7) ? " 7" : "");
+ cascadeBits = val;
+ } else {
+ DPRINTF(I8259, "Slave ID is %d.\n", val & mask(3));
+ cascadeBits = val & mask(3);
+ }
+ if (expectICW4)
+ initControlWord++;
+ else
+ initControlWord = 0;
+ break;
+ case 0x3:
+ DPRINTF(I8259, "Received initialization command word 4.\n");
+ if (bits(val, 4)) {
+ DPRINTF(I8259, "Special fully nested mode.\n");
+ } else {
+ DPRINTF(I8259, "Not special fully nested mode.\n");
+ }
+ if (bits(val, 3) == 0) {
+ DPRINTF(I8259, "Nonbuffered.\n");
+ } else if (bits(val, 2) == 0) {
+ DPRINTF(I8259, "Buffered.\n");
+ } else {
+ DPRINTF(I8259, "Unrecognized buffer mode.\n");
+ }
+ autoEOI = bits(val, 1);
+ DPRINTF(I8259, "%s End Of Interrupt.\n",
+ autoEOI ? "Automatic" : "Normal");
+
+ DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85");
+ initControlWord = 0;
+ break;
+ }
+ break;
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+void
+X86ISA::I8259::handleEOI(int line)
+{
+ ISR &= ~(1 << line);
+ // There may be an interrupt that was waiting which can
+ // now be sent.
+ if (IRR)
+ requestInterrupt(findMsbSet(IRR));
+}
+
+void
+X86ISA::I8259::requestInterrupt(int line)
+{
+ if (bits(ISR, 7, line) == 0) {
+ if (output) {
+ DPRINTF(I8259, "Propogating interrupt.\n");
+ output->raise();
+ //XXX This is a hack.
+ output->lower();
+ } else {
+ warn("Received interrupt but didn't have "
+ "anyone to tell about it.\n");
+ }
+ }
+}
+
+void
+X86ISA::I8259::signalInterrupt(int line)
+{
+ DPRINTF(I8259, "Interrupt requested for line %d.\n", line);
+ if (line >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ line, NumLines - 1);
+ if (bits(IMR, line)) {
+ DPRINTF(I8259, "Interrupt %d was masked.\n", line);
+ } else {
+ IRR |= 1 << line;
+ requestInterrupt(line);
+ }
+}
+
+void
+X86ISA::I8259::raiseInterruptPin(int number)
+{
+ DPRINTF(I8259, "Interrupt signal raised for pin %d.\n", number);
+ if (number >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ number, NumLines - 1);
+ if (!pinStates[number])
+ signalInterrupt(number);
+ pinStates[number] = true;
+}
+
+void
+X86ISA::I8259::lowerInterruptPin(int number)
+{
+ DPRINTF(I8259, "Interrupt signal lowered for pin %d.\n", number);
+ if (number >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ number, NumLines - 1);
+ pinStates[number] = false;
+}
+
+int
+X86ISA::I8259::getVector()
+{
+ /*
+ * This code only handles one slave. Since that's how the PC platform
+ * always uses the 8259 PIC, there shouldn't be any need for more. If
+ * there -is- a need for more for some reason, "slave" can become a
+ * vector of slaves.
+ */
+ int line = findMsbSet(IRR);
+ IRR &= ~(1 << line);
+ DPRINTF(I8259, "Interrupt %d was accepted.\n", line);
+ if (autoEOI) {
+ handleEOI(line);
+ } else {
+ ISR |= 1 << line;
+ }
+ if (slave && bits(cascadeBits, line)) {
+ DPRINTF(I8259, "Interrupt was from slave who will "
+ "provide the vector.\n");
+ return slave->getVector();
+ }
+ return line | vectorOffset;
+}
+
+X86ISA::I8259 *
+I8259Params::create()
+{
+ return new X86ISA::I8259(this);
+}
diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh
new file mode 100644
index 000000000..dfb56646a
--- /dev/null
+++ b/src/dev/x86/i8259.hh
@@ -0,0 +1,105 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_I8259_HH__
+#define __DEV_X86_I8259_HH__
+
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I8259.hh"
+#include "enums/X86I8259CascadeMode.hh"
+
+namespace X86ISA
+{
+
+class I82094AA;
+
+class I8259 : public BasicPioDevice, public IntDev
+{
+ protected:
+ static const int NumLines = 8;
+ bool pinStates[NumLines];
+
+ Tick latency;
+ IntSourcePin *output;
+ Enums::X86I8259CascadeMode mode;
+ I8259 * slave;
+
+ // Interrupt Request Register
+ uint8_t IRR;
+ // In Service Register
+ uint8_t ISR;
+ // Interrupt Mask Register
+ uint8_t IMR;
+
+ // The higher order bits of the vector to return
+ uint8_t vectorOffset;
+
+ bool cascadeMode;
+ // A bit vector of lines with slaves attached, or the slave id, depending
+ // on if this is a master or slave PIC.
+ uint8_t cascadeBits;
+
+ bool edgeTriggered;
+ bool readIRR;
+
+ // State machine information for reading in initialization control words.
+ bool expectICW4;
+ int initControlWord;
+
+ // Whether or not the PIC is in auto EOI mode.
+ bool autoEOI;
+
+ void requestInterrupt(int line);
+ void handleEOI(int line);
+
+ public:
+ typedef I8259Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8259(Params * p);
+
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+
+ void signalInterrupt(int line);
+ void raiseInterruptPin(int number);
+ void lowerInterruptPin(int number);
+ int getVector();
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8259_HH__
diff --git a/src/dev/x86/intdev.cc b/src/dev/x86/intdev.cc
new file mode 100644
index 000000000..e386687a9
--- /dev/null
+++ b/src/dev/x86/intdev.cc
@@ -0,0 +1,49 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "dev/x86/intdev.hh"
+
+X86ISA::IntSourcePin *
+X86IntSourcePinParams::create()
+{
+ return new X86ISA::IntSourcePin(this);
+}
+
+X86ISA::IntSinkPin *
+X86IntSinkPinParams::create()
+{
+ return new X86ISA::IntSinkPin(this);
+}
+
+X86ISA::IntLine *
+X86IntLineParams::create()
+{
+ return new X86ISA::IntLine(this);
+}
diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh
new file mode 100644
index 000000000..ca8e7eea5
--- /dev/null
+++ b/src/dev/x86/intdev.hh
@@ -0,0 +1,216 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_INTDEV_HH__
+#define __DEV_X86_INTDEV_HH__
+
+#include <assert.h>
+#include <string>
+
+#include "arch/x86/x86_traits.hh"
+#include "mem/mem_object.hh"
+#include "mem/mport.hh"
+#include "sim/sim_object.hh"
+#include "params/X86IntSourcePin.hh"
+#include "params/X86IntSinkPin.hh"
+#include "params/X86IntLine.hh"
+
+namespace X86ISA {
+
+class IntDev
+{
+ protected:
+ class IntPort : public MessagePort
+ {
+ IntDev * device;
+ Tick latency;
+ Addr intAddr;
+ public:
+ IntPort(const std::string &_name, MemObject * _parent,
+ IntDev *dev, Tick _latency) :
+ MessagePort(_name, _parent), device(dev), latency(_latency)
+ {
+ }
+
+ void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+ {
+ snoop = false;
+ device->getIntAddrRange(resp);
+ }
+
+ Tick recvMessage(PacketPtr pkt)
+ {
+ return device->recvMessage(pkt);
+ }
+
+ void recvStatusChange(Status status)
+ {
+ if (status == RangeChange) {
+ sendStatusChange(Port::RangeChange);
+ }
+ }
+
+ };
+
+ IntPort * intPort;
+
+ public:
+ IntDev(MemObject * parent, Tick latency = 0)
+ {
+ if (parent != NULL) {
+ intPort = new IntPort(parent->name() + ".int_port",
+ parent, this, latency);
+ } else {
+ intPort = NULL;
+ }
+ }
+
+ virtual ~IntDev()
+ {}
+
+ virtual void
+ signalInterrupt(int line)
+ {
+ panic("signalInterrupt not implemented.\n");
+ }
+
+ virtual void
+ raiseInterruptPin(int number)
+ {
+ panic("raiseInterruptPin not implemented.\n");
+ }
+
+ virtual void
+ lowerInterruptPin(int number)
+ {
+ panic("lowerInterruptPin not implemented.\n");
+ }
+
+ virtual Tick
+ recvMessage(PacketPtr pkt)
+ {
+ panic("recvMessage not implemented.\n");
+ return 0;
+ }
+
+ virtual void
+ getIntAddrRange(AddrRangeList &range_list)
+ {
+ panic("intAddrRange not implemented.\n");
+ }
+};
+
+class IntSinkPin : public SimObject
+{
+ public:
+ IntDev * device;
+ int number;
+
+ typedef X86IntSinkPinParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ IntSinkPin(Params *p) : SimObject(p),
+ device(dynamic_cast<IntDev *>(p->device)), number(p->number)
+ {
+ assert(device);
+ }
+};
+
+class IntSourcePin : public SimObject
+{
+ protected:
+ std::vector<IntSinkPin *> sinks;
+
+ public:
+ typedef X86IntSourcePinParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ void
+ addSink(IntSinkPin *sink)
+ {
+ sinks.push_back(sink);
+ }
+
+ void
+ raise()
+ {
+ for (int i = 0; i < sinks.size(); i++) {
+ const IntSinkPin &pin = *sinks[i];
+ pin.device->raiseInterruptPin(pin.number);
+ }
+ }
+
+ void
+ lower()
+ {
+ for (int i = 0; i < sinks.size(); i++) {
+ const IntSinkPin &pin = *sinks[i];
+ pin.device->lowerInterruptPin(pin.number);
+ }
+ }
+
+ IntSourcePin(Params *p) : SimObject(p)
+ {}
+};
+
+class IntLine : public SimObject
+{
+ protected:
+ IntSourcePin *source;
+ IntSinkPin *sink;
+
+ public:
+ typedef X86IntLineParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ IntLine(Params *p) : SimObject(p), source(p->source), sink(p->sink)
+ {
+ source->addSink(sink);
+ }
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_INTDEV_HH__
diff --git a/src/dev/x86/pc.cc b/src/dev/x86/pc.cc
new file mode 100644
index 000000000..d1ab4af7f
--- /dev/null
+++ b/src/dev/x86/pc.cc
@@ -0,0 +1,176 @@
+/*
+ * 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: Gabe Black
+ */
+
+/** @file
+ * Implementation of PC platform.
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "arch/x86/intmessage.hh"
+#include "arch/x86/x86_traits.hh"
+#include "cpu/intr_control.hh"
+#include "dev/terminal.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8254.hh"
+#include "dev/x86/i8259.hh"
+#include "dev/x86/pc.hh"
+#include "dev/x86/south_bridge.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+Pc::Pc(const Params *p)
+ : Platform(p), system(p->system)
+{
+ southBridge = NULL;
+ // set the back pointer from the system to myself
+ system->platform = this;
+}
+
+void
+Pc::init()
+{
+ assert(southBridge);
+
+ /*
+ * Initialize the timer.
+ */
+ I8254 & timer = *southBridge->pit;
+ //Timer 0, mode 2, no bcd, 16 bit count
+ timer.writeControl(0x34);
+ //Timer 0, latch command
+ timer.writeControl(0x00);
+ //Write a 16 bit count of 0
+ timer.writeCounter(0, 0);
+ timer.writeCounter(0, 0);
+
+ /*
+ * Initialize the I/O APIC.
+ */
+ I82094AA & ioApic = *southBridge->ioApic;
+ I82094AA::RedirTableEntry entry = 0;
+ entry.deliveryMode = DeliveryMode::ExtInt;
+ entry.vector = 0x20;
+ ioApic.writeReg(0x10, entry.bottomDW);
+ ioApic.writeReg(0x11, entry.topDW);
+ entry.deliveryMode = DeliveryMode::Fixed;
+ entry.vector = 0x24;
+ ioApic.writeReg(0x18, entry.bottomDW);
+ ioApic.writeReg(0x19, entry.topDW);
+ entry.mask = 1;
+ entry.vector = 0x21;
+ ioApic.writeReg(0x12, entry.bottomDW);
+ ioApic.writeReg(0x13, entry.topDW);
+ entry.vector = 0x20;
+ ioApic.writeReg(0x14, entry.bottomDW);
+ ioApic.writeReg(0x15, entry.topDW);
+ entry.vector = 0x28;
+ ioApic.writeReg(0x20, entry.bottomDW);
+ ioApic.writeReg(0x21, entry.topDW);
+ entry.vector = 0x2C;
+ ioApic.writeReg(0x28, entry.bottomDW);
+ ioApic.writeReg(0x29, entry.topDW);
+ entry.vector = 0x2E;
+ ioApic.writeReg(0x2C, entry.bottomDW);
+ ioApic.writeReg(0x2D, entry.topDW);
+ entry.vector = 0x30;
+ ioApic.writeReg(0x30, entry.bottomDW);
+ ioApic.writeReg(0x31, entry.topDW);
+}
+
+Tick
+Pc::intrFrequency()
+{
+ panic("Need implementation for intrFrequency\n");
+ M5_DUMMY_RETURN
+}
+
+void
+Pc::postConsoleInt()
+{
+ southBridge->ioApic->signalInterrupt(4);
+ southBridge->pic1->signalInterrupt(4);
+}
+
+void
+Pc::clearConsoleInt()
+{
+ warn_once("Don't know what interrupt to clear for console.\n");
+ //panic("Need implementation\n");
+}
+
+void
+Pc::postPciInt(int line)
+{
+ southBridge->ioApic->signalInterrupt(line);
+}
+
+void
+Pc::clearPciInt(int line)
+{
+ warn_once("Tried to clear PCI interrupt %d\n", line);
+}
+
+Addr
+Pc::pciToDma(Addr pciAddr) const
+{
+ return pciAddr;
+}
+
+Addr
+Pc::calcPciConfigAddr(int bus, int dev, int func)
+{
+ assert(func < 8);
+ assert(dev < 32);
+ assert(bus == 0);
+ return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11));
+}
+
+Addr
+Pc::calcPciIOAddr(Addr addr)
+{
+ return PhysAddrPrefixIO + addr;
+}
+
+Addr
+Pc::calcPciMemAddr(Addr addr)
+{
+ return addr;
+}
+
+Pc *
+PcParams::create()
+{
+ return new Pc(this);
+}
diff --git a/src/dev/x86/opteron.hh b/src/dev/x86/pc.hh
index 3026bce73..427cc4165 100644
--- a/src/dev/x86/opteron.hh
+++ b/src/dev/x86/pc.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,29 +30,36 @@
/**
* @file
- * Declaration of top level class for the Opteron platform chips. This class
+ * Declaration of top level class for PC platform components. This class
* just retains pointers to all its children so the children can communicate.
*/
-#ifndef __DEV_Opteron_HH__
-#define __DEV_Opteron_HH__
+#ifndef __DEV_PC_HH__
+#define __DEV_PC_HH__
#include "dev/platform.hh"
-#include "params/Opteron.hh"
+#include "params/Pc.hh"
class IdeController;
class System;
+class SouthBridge;
-class Opteron : public Platform
+class Pc : public Platform
{
public:
/** Pointer to the system */
System *system;
+ SouthBridge *southBridge;
public:
- typedef OpteronParams Params;
+ typedef PcParams Params;
- Opteron(const Params *p);
+ /**
+ * Do platform initialization stuff
+ */
+ void init();
+
+ Pc(const Params *p);
/**
* Return the interrupting frequency to AlphaAccess
@@ -86,7 +93,17 @@ class Opteron : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int 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_OPTERON_HH__
+#endif // __DEV_PC_HH__
diff --git a/src/dev/x86/south_bridge.cc b/src/dev/x86/south_bridge.cc
new file mode 100644
index 000000000..c456f478d
--- /dev/null
+++ b/src/dev/x86/south_bridge.cc
@@ -0,0 +1,52 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include <assert.h>
+
+#include "dev/x86/pc.hh"
+#include "dev/x86/south_bridge.hh"
+
+using namespace X86ISA;
+
+SouthBridge::SouthBridge(const Params *p) : SimObject(p),
+ platform(p->platform), pit(p->pit), pic1(p->pic1), pic2(p->pic2),
+ cmos(p->cmos), speaker(p->speaker), ioApic(p->io_apic)
+{
+ // Let the platform know where we are
+ Pc * pc = dynamic_cast<Pc *>(platform);
+ assert(pc);
+ pc->southBridge = this;
+}
+
+SouthBridge *
+SouthBridgeParams::create()
+{
+ return new SouthBridge(this);
+}
diff --git a/src/dev/x86/south_bridge.hh b/src/dev/x86/south_bridge.hh
new file mode 100644
index 000000000..61d6d387a
--- /dev/null
+++ b/src/dev/x86/south_bridge.hh
@@ -0,0 +1,70 @@
+/*
+ * 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: Gabe Black
+ */
+
+#ifndef __DEV_X86_SOUTH_BRIDGE_HH__
+#define __DEV_X86_SOUTH_BRIDGE_HH__
+
+#include "sim/sim_object.hh"
+#include "params/SouthBridge.hh"
+
+namespace X86ISA
+{
+ class I8254;
+ class I8259;
+ class Cmos;
+ class Speaker;
+ class I82094AA;
+}
+
+class SouthBridge : public SimObject
+{
+ protected:
+ Platform * platform;
+
+ public:
+ X86ISA::I8254 * pit;
+ X86ISA::I8259 * pic1;
+ X86ISA::I8259 * pic2;
+ X86ISA::Cmos * cmos;
+ X86ISA::Speaker * speaker;
+ X86ISA::I82094AA * ioApic;
+
+ public:
+ typedef SouthBridgeParams Params;
+ SouthBridge(const Params *p);
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+};
+
+#endif //__DEV_X86_SOUTH_BRIDGE_HH__
diff --git a/src/dev/x86/speaker.cc b/src/dev/x86/speaker.cc
new file mode 100644
index 000000000..c6eb9db9e
--- /dev/null
+++ b/src/dev/x86/speaker.cc
@@ -0,0 +1,79 @@
+/*
+ * 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: Gabe Black
+ */
+
+#include "base/bitunion.hh"
+#include "base/trace.hh"
+#include "dev/x86/i8254.hh"
+#include "dev/x86/speaker.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+Tick
+X86ISA::Speaker::read(PacketPtr pkt)
+{
+ assert(pkt->getAddr() == pioAddr);
+ assert(pkt->getSize() == 1);
+ controlVal.timer = timer->outputHigh(2) ? 1 : 0;
+ DPRINTF(PcSpeaker,
+ "Reading from speaker device: gate %s, speaker %s, output %s.\n",
+ controlVal.gate ? "on" : "off",
+ controlVal.speaker ? "on" : "off",
+ controlVal.timer ? "on" : "off");
+ pkt->set((uint8_t)controlVal);
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::Speaker::write(PacketPtr pkt)
+{
+ assert(pkt->getAddr() == pioAddr);
+ assert(pkt->getSize() == 1);
+ SpeakerControl val = pkt->get<uint8_t>();
+ controlVal.gate = val.gate;
+ //Change the gate value in the timer.
+ if (!val.gate)
+ warn("The gate bit of the pc speaker isn't implemented and "
+ "is always on.\n");
+ //This would control whether the timer output is hooked up to a physical
+ //speaker. Since M5 can't make noise, it's value doesn't actually do
+ //anything.
+ controlVal.speaker = val.speaker;
+ DPRINTF(PcSpeaker, "Writing to speaker device: gate %s, speaker %s.\n",
+ controlVal.gate ? "on" : "off", controlVal.speaker ? "on" : "off");
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::Speaker *
+PcSpeakerParams::create()
+{
+ return new X86ISA::Speaker(this);
+}
diff --git a/src/dev/pitreg.h b/src/dev/x86/speaker.hh
index d42925a41..6778dcb28 100644
--- a/src/dev/pitreg.h
+++ b/src/dev/x86/speaker.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,51 +25,55 @@
* (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: Miguel Serrano
+ * Authors: Gabe Black
*/
-/* @file
- * Device register definitions for a device's PCI config space
- */
+#ifndef __DEV_X86_SPEAKER_HH__
+#define __DEV_X86_SPEAKER_HH__
+
+#include "base/bitunion.hh"
+#include "params/PcSpeaker.hh"
+
+namespace X86ISA
+{
+
+class I8254;
-#ifndef __PITREG_H__
-#define __PITREG_H__
+class Speaker : public BasicPioDevice
+{
+ protected:
+ Tick latency;
-#include <sys/types.h>
+ BitUnion8(SpeakerControl)
+ Bitfield<0> gate;
+ Bitfield<1> speaker;
+ Bitfield<5> timer;
+ EndBitUnion(SpeakerControl)
-// Control Word Format
+ SpeakerControl controlVal;
-#define PIT_SEL_SHFT 0x6
-#define PIT_RW_SHFT 0x4
-#define PIT_MODE_SHFT 0x1
-#define PIT_BCD_SHFT 0x0
+ I8254 * timer;
-#define PIT_SEL_MASK 0x3
-#define PIT_RW_MASK 0x3
-#define PIT_MODE_MASK 0x7
-#define PIT_BCD_MASK 0x1
+ public:
+ typedef PcSpeakerParams Params;
-#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m)
-#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK)
-#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK)
-#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK)
-#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK)
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
-#define PIT_READ_BACK 0x3
+ Speaker(Params *p) : BasicPioDevice(p),
+ latency(p->pio_latency), controlVal(0), timer(p->i8254)
+ {
+ pioSize = 1;
+ }
-#define PIT_RW_LATCH_COMMAND 0x0
-#define PIT_RW_LSB_ONLY 0x1
-#define PIT_RW_MSB_ONLY 0x2
-#define PIT_RW_16BIT 0x3
+ Tick read(PacketPtr pkt);
-#define PIT_MODE_INTTC 0x0
-#define PIT_MODE_ONESHOT 0x1
-#define PIT_MODE_RATEGEN 0x2
-#define PIT_MODE_SQWAVE 0x3
-#define PIT_MODE_SWSTROBE 0x4
-#define PIT_MODE_HWSTROBE 0x5
+ Tick write(PacketPtr pkt);
+};
-#define PIT_BCD_FALSE 0x0
-#define PIT_BCD_TRUE 0x1
+}; // namespace X86ISA
-#endif // __PITREG_H__
+#endif //__DEV_X86_SPEAKER_HH__