summaryrefslogtreecommitdiff
path: root/src/dev
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev')
-rw-r--r--src/dev/SConscript74
-rw-r--r--src/dev/alpha/SConscript43
-rw-r--r--src/dev/alpha/tsunami_cchip.cc12
-rw-r--r--src/dev/alpha/tsunamireg.h21
-rw-r--r--src/dev/etherbus.cc2
-rw-r--r--src/dev/etherdump.cc2
-rw-r--r--src/dev/etherlink.cc2
-rw-r--r--src/dev/i8254xGBe.cc1122
-rw-r--r--src/dev/i8254xGBe.hh420
-rw-r--r--src/dev/i8254xGBe_defs.hh957
-rw-r--r--src/dev/ide_disk.cc2
-rw-r--r--src/dev/io_device.hh14
-rw-r--r--src/dev/ns_gige.cc26
-rw-r--r--src/dev/pcidev.cc2
-rw-r--r--src/dev/platform.hh3
-rw-r--r--src/dev/simconsole.cc224
-rw-r--r--src/dev/simconsole.hh76
-rw-r--r--src/dev/sparc/SConscript23
-rw-r--r--src/dev/sparc/iob.cc402
-rw-r--r--src/dev/sparc/iob.hh153
-rw-r--r--src/dev/sparc/mm_disk.cc2
-rw-r--r--src/dev/uart.cc1
-rw-r--r--src/dev/uart8250.hh13
23 files changed, 2696 insertions, 900 deletions
diff --git a/src/dev/SConscript b/src/dev/SConscript
index 951bc29d1..ea529b536 100644
--- a/src/dev/SConscript
+++ b/src/dev/SConscript
@@ -29,51 +29,29 @@
# Authors: Steve Reinhardt
# Gabe Black
-import os.path, sys
-
-# Import build environment variable from SConstruct.
-Import('env')
-
-# Right now there are no source files immediately in this directory
-sources = []
-
-#
-# Now include other ISA-specific sources from the ISA subdirectories.
-#
-
-isa = env['TARGET_ISA'] # someday this may be a list of ISAs
-
-#
-# These source files can be used by any architecture
-#
-
-sources += Split('''
- baddev.cc
- disk_image.cc
- etherbus.cc
- etherdump.cc
- etherint.cc
- etherlink.cc
- etherpkt.cc
- ethertap.cc
- ide_ctrl.cc
- ide_disk.cc
- io_device.cc
- isa_fake.cc
- ns_gige.cc
- pciconfigall.cc
- pcidev.cc
- pktfifo.cc
- platform.cc
- simconsole.cc
- simple_disk.cc
- ''')
-
-# Let the target architecture define what additional sources it needs
-sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env')
-
-# Convert file names to SCons File objects. This takes care of the
-# path relative to the top of the directory tree.
-sources = [File(s) for s in sources]
-
-Return('sources')
+Import('*')
+
+if env['FULL_SYSTEM']:
+ Source('baddev.cc')
+ Source('disk_image.cc')
+ Source('etherbus.cc')
+ Source('etherdump.cc')
+ Source('etherint.cc')
+ Source('etherlink.cc')
+ Source('etherpkt.cc')
+ Source('ethertap.cc')
+ Source('i8254xGBe.cc')
+ Source('ide_ctrl.cc')
+ Source('ide_disk.cc')
+ Source('io_device.cc')
+ Source('isa_fake.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('uart.cc')
+ Source('uart8250.cc')
diff --git a/src/dev/alpha/SConscript b/src/dev/alpha/SConscript
index fb0e626d3..c985fdd9f 100644
--- a/src/dev/alpha/SConscript
+++ b/src/dev/alpha/SConscript
@@ -29,40 +29,11 @@
# Authors: Steve Reinhardt
# Gabe Black
-import os.path, sys
+Import('*')
-# Import build environment variable from SConstruct.
-Import('env')
-
-sources = Split('''
- console.cc
- tsunami.cc
- tsunami_cchip.cc
- tsunami_io.cc
- tsunami_pchip.cc
- ''')
-# baddev.cc
-# disk_image.cc
-# etherbus.cc
-# etherdump.cc
-# etherint.cc
-# etherlink.cc
-# etherpkt.cc
-# ethertap.cc
-# ide_ctrl.cc
-# ide_disk.cc
-# io_device.cc
-# isa_fake.cc
-# ns_gige.cc
-# pciconfigall.cc
-# pcidev.cc
-# pktfifo.cc
-# platform.cc
-# simconsole.cc
-# simple_disk.cc
-
-# Convert file names to SCons File objects. This takes care of the
-# path relative to the top of the directory tree.
-sources = [File(s) for s in sources]
-
-Return('sources')
+if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'alpha':
+ Source('console.cc')
+ Source('tsunami.cc')
+ Source('tsunami_cchip.cc')
+ Source('tsunami_io.cc')
+ Source('tsunami_pchip.cc')
diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc
index 15c47984b..118160adf 100644
--- a/src/dev/alpha/tsunami_cchip.cc
+++ b/src/dev/alpha/tsunami_cchip.cc
@@ -372,7 +372,7 @@ TsunamiCChip::write(PacketPtr pkt)
void
TsunamiCChip::clearIPI(uint64_t ipintr)
{
- int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
+ int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipintr) {
@@ -398,7 +398,7 @@ TsunamiCChip::clearIPI(uint64_t ipintr)
void
TsunamiCChip::clearITI(uint64_t itintr)
{
- int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
+ int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (itintr) {
@@ -418,7 +418,7 @@ TsunamiCChip::clearITI(uint64_t itintr)
void
TsunamiCChip::reqIPI(uint64_t ipreq)
{
- int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
+ int numcpus = sys->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipreq) {
@@ -445,7 +445,7 @@ TsunamiCChip::reqIPI(uint64_t ipreq)
void
TsunamiCChip::postRTC()
{
- int size = tsunami->intrctrl->cpu->system->threadContexts.size();
+ int size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
for (int i = 0; i < size; i++) {
@@ -463,7 +463,7 @@ void
TsunamiCChip::postDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
- uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size();
+ uint64_t size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
drir |= bitvector;
@@ -481,7 +481,7 @@ void
TsunamiCChip::clearDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
- uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size();
+ uint64_t size = sys->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
if (drir & bitvector)
diff --git a/src/dev/alpha/tsunamireg.h b/src/dev/alpha/tsunamireg.h
index d603972be..a2742e36d 100644
--- a/src/dev/alpha/tsunamireg.h
+++ b/src/dev/alpha/tsunamireg.h
@@ -136,15 +136,6 @@
/* Added for keyboard accesses */
#define TSDEV_KBD 0x64
-/* Added for ATA PCI DMA */
-#define ATA_PCI_DMA 0x00
-#define ATA_PCI_DMA2 0x02
-#define ATA_PCI_DMA3 0x16
-#define ATA_PCI_DMA4 0x17
-#define ATA_PCI_DMA5 0x1a
-#define ATA_PCI_DMA6 0x11
-#define ATA_PCI_DMA7 0x14
-
#define TSDEV_RTC_ADDR 0x70
#define TSDEV_RTC_DATA 0x71
@@ -155,18 +146,6 @@
#define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO
-// UART Defines
-#define UART_IER_RDI 0x01
-#define UART_IER_THRI 0x02
-#define UART_IER_RLSI 0x04
-
-
-#define UART_LSR_TEMT 0x40
-#define UART_LSR_THRE 0x20
-#define UART_LSR_DR 0x01
-
-#define UART_MCR_LOOP 0x10
-
// System Control PortB Status Bits
#define PORTB_SPKR_HIGH 0x20
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
index 348bb818a..cedb3cd4d 100644
--- a/src/dev/etherbus.cc
+++ b/src/dev/etherbus.cc
@@ -43,7 +43,7 @@
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
#include "sim/builder.hh"
-#include "sim/root.hh"
+#include "sim/core.hh"
using namespace std;
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
index 0c986cc21..04463f3ee 100644
--- a/src/dev/etherdump.cc
+++ b/src/dev/etherdump.cc
@@ -41,7 +41,7 @@
#include "base/output.hh"
#include "dev/etherdump.hh"
#include "sim/builder.hh"
-#include "sim/root.hh"
+#include "sim/core.hh"
using std::string;
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
index cd3812270..5d30e1744 100644
--- a/src/dev/etherlink.cc
+++ b/src/dev/etherlink.cc
@@ -47,7 +47,7 @@
#include "sim/builder.hh"
#include "sim/serialize.hh"
#include "sim/system.hh"
-#include "sim/root.hh"
+#include "sim/core.hh"
using namespace std;
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
index 7fc68f4e7..d6449f6c5 100644
--- a/src/dev/i8254xGBe.cc
+++ b/src/dev/i8254xGBe.cc
@@ -35,7 +35,13 @@
* other MACs with slight modifications.
*/
+
+/*
+ * @todo really there are multiple dma engines.. we should implement them.
+ */
+
#include "base/inet.hh"
+#include "base/trace.hh"
#include "dev/i8254xGBe.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
@@ -43,32 +49,37 @@
#include "sim/stats.hh"
#include "sim/system.hh"
+#include <algorithm>
+
using namespace iGbReg;
+using namespace Net;
IGbE::IGbE(Params *p)
- : PciDev(p), etherInt(NULL)
+ : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control),
+ rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
+ txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this),
+ tidvEvent(this), tickEvent(this), interEvent(this),
+ rxDescCache(this, name()+".TxDesc", p->rx_desc_cache_size),
+ txDescCache(this, name()+".RxDesc", p->tx_desc_cache_size), clock(p->clock)
{
// Initialized internal registers per Intel documentation
- regs.tctl.reg = 0;
- regs.rctl.reg = 0;
- regs.ctrl.reg = 0;
- regs.ctrl.fd = 1;
- regs.ctrl.lrst = 1;
- regs.ctrl.speed = 2;
- regs.ctrl.frcspd = 1;
- regs.sts.reg = 0;
- regs.eecd.reg = 0;
- regs.eecd.fwe = 1;
- regs.eecd.ee_type = 1;
- regs.eerd.reg = 0;
- regs.icd.reg = 0;
- regs.imc.reg = 0;
- regs.rctl.reg = 0;
- regs.tctl.reg = 0;
- regs.manc.reg = 0;
-
- regs.pba.rxa = 0x30;
- regs.pba.txa = 0x10;
+ // All registers intialized to 0 by per register constructor
+ regs.ctrl.fd(1);
+ regs.ctrl.lrst(1);
+ regs.ctrl.speed(2);
+ regs.ctrl.frcspd(1);
+ regs.sts.speed(3); // Say we're 1000Mbps
+ regs.sts.fd(1); // full duplex
+ regs.eecd.fwe(1);
+ regs.eecd.ee_type(1);
+ regs.imr = 0;
+ regs.iam = 0;
+ regs.rxdctl.gran(1);
+ regs.rxdctl.wthresh(1);
+ regs.fcrth(1);
+
+ regs.pba.rxa(0x30);
+ regs.pba.txa(0x10);
eeOpBits = 0;
eeAddrBits = 0;
@@ -78,8 +89,20 @@ IGbE::IGbE(Params *p)
// clear all 64 16 bit words of the eeprom
memset(&flash, 0, EEPROM_SIZE*2);
+ //We'll need to instert the MAC address into the flash
+ flash[0] = 0xA4A4;
+ flash[1] = 0xB6B6;
+ flash[2] = 0xC8C8;
+
+ uint16_t csum = 0;
+ for (int x = 0; x < EEPROM_SIZE; x++)
+ csum += flash[x];
+
// Magic happy checksum value
- flash[0] = 0xBABA;
+ flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
+
+ rxFifo.clear();
+ txFifo.clear();
}
@@ -124,47 +147,129 @@ IGbE::read(PacketPtr pkt)
switch (daddr) {
- case CTRL:
- pkt->set<uint32_t>(regs.ctrl.reg);
- break;
- case STATUS:
- pkt->set<uint32_t>(regs.sts.reg);
- break;
- case EECD:
- pkt->set<uint32_t>(regs.eecd.reg);
- break;
- case EERD:
- pkt->set<uint32_t>(regs.eerd.reg);
- break;
- case ICR:
- pkt->set<uint32_t>(regs.icd.reg);
- break;
- case IMC:
- pkt->set<uint32_t>(regs.imc.reg);
- break;
- case RCTL:
- pkt->set<uint32_t>(regs.rctl.reg);
- break;
- case TCTL:
- pkt->set<uint32_t>(regs.tctl.reg);
- break;
- case PBA:
- pkt->set<uint32_t>(regs.pba.reg);
- break;
- case WUC:
- case LEDCTL:
- pkt->set<uint32_t>(0); // We don't care, so just return 0
- break;
- case MANC:
- pkt->set<uint32_t>(regs.manc.reg);
- break;
+ case REG_CTRL:
+ pkt->set<uint32_t>(regs.ctrl());
+ break;
+ case REG_STATUS:
+ pkt->set<uint32_t>(regs.sts());
+ break;
+ case REG_EECD:
+ pkt->set<uint32_t>(regs.eecd());
+ break;
+ case REG_EERD:
+ pkt->set<uint32_t>(regs.eerd());
+ break;
+ case REG_CTRL_EXT:
+ pkt->set<uint32_t>(regs.ctrl_ext());
+ break;
+ case REG_MDIC:
+ pkt->set<uint32_t>(regs.mdic());
+ break;
+ case REG_ICR:
+ pkt->set<uint32_t>(regs.icr());
+ if (regs.icr.int_assert())
+ regs.imr &= regs.iam;
+ if (regs.imr == 0 || (regs.icr.int_assert() && regs.ctrl_ext.iame())) {
+ regs.icr(0);
+ cpuClearInt();
+ }
+ break;
+ case REG_ITR:
+ pkt->set<uint32_t>(regs.itr());
+ break;
+ case REG_RCTL:
+ pkt->set<uint32_t>(regs.rctl());
+ break;
+ case REG_FCTTV:
+ pkt->set<uint32_t>(regs.fcttv());
+ break;
+ case REG_TCTL:
+ pkt->set<uint32_t>(regs.tctl());
+ break;
+ case REG_PBA:
+ pkt->set<uint32_t>(regs.pba());
+ break;
+ case REG_WUC:
+ case REG_LEDCTL:
+ pkt->set<uint32_t>(0); // We don't care, so just return 0
+ break;
+ case REG_FCRTL:
+ pkt->set<uint32_t>(regs.fcrtl());
+ break;
+ case REG_FCRTH:
+ pkt->set<uint32_t>(regs.fcrth());
+ break;
+ case REG_RDBAL:
+ pkt->set<uint32_t>(regs.rdba.rdbal());
+ break;
+ case REG_RDBAH:
+ pkt->set<uint32_t>(regs.rdba.rdbah());
+ break;
+ case REG_RDLEN:
+ pkt->set<uint32_t>(regs.rdlen());
+ break;
+ case REG_RDH:
+ pkt->set<uint32_t>(regs.rdh());
+ break;
+ case REG_RDT:
+ pkt->set<uint32_t>(regs.rdt());
+ break;
+ case REG_RDTR:
+ pkt->set<uint32_t>(regs.rdtr());
+ if (regs.rdtr.fpd()) {
+ rxDescCache.writeback(0);
+ postInterrupt(IT_RXT);
+ regs.rdtr.fpd(0);
+ }
+ if (regs.rdtr.delay()) {
+ Tick t = regs.rdtr.delay() * Clock::Int::ns * 1024;
+ if (rdtrEvent.scheduled())
+ rdtrEvent.reschedule(curTick + t);
+ else
+ rdtrEvent.schedule(curTick + t);
+ }
+ break;
+ case REG_RADV:
+ pkt->set<uint32_t>(regs.radv());
+ break;
+ case REG_TDBAL:
+ pkt->set<uint32_t>(regs.tdba.tdbal());
+ break;
+ case REG_TDBAH:
+ pkt->set<uint32_t>(regs.tdba.tdbah());
+ break;
+ case REG_TDLEN:
+ pkt->set<uint32_t>(regs.tdlen());
+ break;
+ case REG_TDH:
+ pkt->set<uint32_t>(regs.tdh());
+ break;
+ case REG_TDT:
+ pkt->set<uint32_t>(regs.tdt());
+ break;
+ case REG_TIDV:
+ pkt->set<uint32_t>(regs.tidv());
+ break;
+ case REG_TXDCTL:
+ pkt->set<uint32_t>(regs.txdctl());
+ break;
+ case REG_TADV:
+ pkt->set<uint32_t>(regs.tadv());
+ break;
+ case REG_RXCSUM:
+ pkt->set<uint32_t>(regs.rxcsum());
+ break;
+ case REG_MANC:
+ pkt->set<uint32_t>(regs.manc());
+ break;
default:
- if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) &&
- !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) &&
- !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4))
- pkt->set<uint32_t>(0);
- else
- panic("Read request to unknown register number: %#x\n", daddr);
+ if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
+ !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
+ !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) &&
+ !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE)))
+ panic("Read request to unknown register number: %#x\n", daddr);
+ else
+ pkt->set<uint32_t>(0);
};
pkt->result = Packet::Success;
@@ -194,93 +299,253 @@ IGbE::write(PacketPtr pkt)
///
uint32_t val = pkt->get<uint32_t>();
+ Regs::RCTL oldrctl;
+ Regs::TCTL oldtctl;
+
switch (daddr) {
- case CTRL:
- regs.ctrl.reg = val;
- break;
- case STATUS:
- regs.sts.reg = val;
- break;
- case EECD:
- int oldClk;
- oldClk = regs.eecd.sk;
- regs.eecd.reg = val;
- // See if this is a eeprom access and emulate accordingly
- if (!oldClk && regs.eecd.sk) {
- if (eeOpBits < 8) {
- eeOpcode = eeOpcode << 1 | regs.eecd.din;
- eeOpBits++;
- } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
- eeAddr = eeAddr << 1 | regs.eecd.din;
- eeAddrBits++;
- } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
- assert(eeAddr>>1 < EEPROM_SIZE);
- DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
- flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
- regs.eecd.dout = (flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1;
- eeDataBits++;
- } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
- regs.eecd.dout = 0;
- eeDataBits++;
- } else
- panic("What's going on with eeprom interface? opcode:"
- " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
- (uint32_t)eeOpBits, (uint32_t)eeAddr,
- (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
-
- // Reset everything for the next command
- if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
+ case REG_CTRL:
+ regs.ctrl = val;
+ if (regs.ctrl.tfce())
+ warn("TX Flow control enabled, should implement\n");
+ if (regs.ctrl.rfce())
+ warn("RX Flow control enabled, should implement\n");
+ break;
+ case REG_CTRL_EXT:
+ regs.ctrl_ext = val;
+ break;
+ case REG_STATUS:
+ regs.sts = val;
+ break;
+ case REG_EECD:
+ int oldClk;
+ oldClk = regs.eecd.sk();
+ regs.eecd = val;
+ // See if this is a eeprom access and emulate accordingly
+ if (!oldClk && regs.eecd.sk()) {
+ if (eeOpBits < 8) {
+ eeOpcode = eeOpcode << 1 | regs.eecd.din();
+ eeOpBits++;
+ } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
+ eeAddr = eeAddr << 1 | regs.eecd.din();
+ eeAddrBits++;
+ } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
+ assert(eeAddr>>1 < EEPROM_SIZE);
+ DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
+ flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
+ regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
+ eeDataBits++;
+ } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
+ regs.eecd.dout(0);
+ eeDataBits++;
+ } else
+ panic("What's going on with eeprom interface? opcode:"
+ " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
+ (uint32_t)eeOpBits, (uint32_t)eeAddr,
+ (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
+
+ // Reset everything for the next command
+ if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
(eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
- eeOpBits = 0;
- eeAddrBits = 0;
- eeDataBits = 0;
+ eeOpBits = 0;
+ eeAddrBits = 0;
+ eeDataBits = 0;
eeOpcode = 0;
- eeAddr = 0;
- }
+ eeAddr = 0;
+ }
DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
- (uint32_t)eeOpcode, (uint32_t) eeOpBits,
- (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
+ (uint32_t)eeOpcode, (uint32_t) eeOpBits,
+ (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
- eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
- panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
- (uint32_t)eeOpBits);
-
-
- }
- // If driver requests eeprom access, immediately give it to it
- regs.eecd.ee_gnt = regs.eecd.ee_req;
- break;
- case EERD:
- regs.eerd.reg = val;
- break;
- case ICR:
- regs.icd.reg = val;
- break;
- case IMC:
- regs.imc.reg = val;
- break;
- case RCTL:
- regs.rctl.reg = val;
- break;
- case TCTL:
- regs.tctl.reg = val;
- break;
- case PBA:
- regs.pba.rxa = val;
- regs.pba.txa = 64 - regs.pba.rxa;
- break;
- case WUC:
- case LEDCTL:
- ; // We don't care, so don't store anything
- break;
- case MANC:
- regs.manc.reg = val;
- break;
+ eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
+ panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
+ (uint32_t)eeOpBits);
+
+
+ }
+ // If driver requests eeprom access, immediately give it to it
+ regs.eecd.ee_gnt(regs.eecd.ee_req());
+ break;
+ case REG_EERD:
+ regs.eerd = val;
+ break;
+ case REG_MDIC:
+ regs.mdic = val;
+ if (regs.mdic.i())
+ panic("No support for interrupt on mdic complete\n");
+ if (regs.mdic.phyadd() != 1)
+ panic("No support for reading anything but phy\n");
+ DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing"
+ : "Reading", regs.mdic.regadd());
+ switch (regs.mdic.regadd()) {
+ case PHY_PSTATUS:
+ regs.mdic.data(0x796D); // link up
+ break;
+ case PHY_PID:
+ regs.mdic.data(0x02A8);
+ break;
+ case PHY_EPID:
+ regs.mdic.data(0x0380);
+ break;
+ case PHY_GSTATUS:
+ regs.mdic.data(0x7C00);
+ break;
+ case PHY_EPSTATUS:
+ regs.mdic.data(0x3000);
+ break;
+ case PHY_AGC:
+ regs.mdic.data(0x180); // some random length
+ break;
+ default:
+ regs.mdic.data(0);
+ warn("Accessing unknown phy register %d\n", regs.mdic.regadd());
+ }
+ regs.mdic.r(1);
+ break;
+ case REG_ICR:
+ if (regs.icr.int_assert())
+ regs.imr &= regs.iam;
+
+ regs.icr = ~bits(val,30,0) & regs.icr();
+ // if no more bits are set clear the int_asserted bit
+ if (!bits(regs.icr(),31,31))
+ cpuClearInt();
+
+ break;
+ case REG_ITR:
+ regs.itr = val;
+ break;
+ case REG_ICS:
+ postInterrupt((IntTypes)val);
+ break;
+ case REG_IMS:
+ regs.imr |= val;
+ chkInterrupt();
+ break;
+ case REG_IMC:
+ regs.imr &= ~val;
+ chkInterrupt();
+ break;
+ case REG_IAM:
+ regs.iam = val;
+ break;
+ case REG_RCTL:
+ oldrctl = regs.rctl;
+ regs.rctl = val;
+ if (regs.rctl.rst()) {
+ rxDescCache.reset();
+ rxFifo.clear();
+ regs.rctl.rst(0);
+ }
+ if (regs.rctl.en())
+ rxTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + cycles(1));
+ break;
+ case REG_FCTTV:
+ regs.fcttv = val;
+ break;
+ case REG_TCTL:
+ regs.tctl = val;
+ oldtctl = regs.tctl;
+ regs.tctl = val;
+ if (regs.tctl.en())
+ txTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + cycles(1));
+ if (regs.tctl.en() && !oldtctl.en()) {
+ txDescCache.reset();
+ }
+ break;
+ case REG_PBA:
+ regs.pba.rxa(val);
+ regs.pba.txa(64 - regs.pba.rxa());
+ break;
+ case REG_WUC:
+ case REG_LEDCTL:
+ case REG_FCAL:
+ case REG_FCAH:
+ case REG_FCT:
+ case REG_VET:
+ case REG_AIFS:
+ case REG_TIPG:
+ ; // We don't care, so don't store anything
+ break;
+ case REG_FCRTL:
+ regs.fcrtl = val;
+ break;
+ case REG_FCRTH:
+ regs.fcrth = val;
+ break;
+ case REG_RDBAL:
+ regs.rdba.rdbal( val & ~mask(4));
+ rxDescCache.areaChanged();
+ break;
+ case REG_RDBAH:
+ regs.rdba.rdbah(val);
+ rxDescCache.areaChanged();
+ break;
+ case REG_RDLEN:
+ regs.rdlen = val & ~mask(7);
+ rxDescCache.areaChanged();
+ break;
+ case REG_RDH:
+ regs.rdh = val;
+ rxDescCache.areaChanged();
+ break;
+ case REG_RDT:
+ regs.rdt = val;
+ rxTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + cycles(1));
+ break;
+ case REG_RDTR:
+ regs.rdtr = val;
+ break;
+ case REG_RADV:
+ regs.radv = val;
+ break;
+ case REG_TDBAL:
+ regs.tdba.tdbal( val & ~mask(4));
+ txDescCache.areaChanged();
+ break;
+ case REG_TDBAH:
+ regs.tdba.tdbah(val);
+ txDescCache.areaChanged();
+ break;
+ case REG_TDLEN:
+ regs.tdlen = val & ~mask(7);
+ txDescCache.areaChanged();
+ break;
+ case REG_TDH:
+ regs.tdh = val;
+ txDescCache.areaChanged();
+ break;
+ case REG_TDT:
+ regs.tdt = val;
+ txTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + cycles(1));
+ break;
+ case REG_TIDV:
+ regs.tidv = val;
+ break;
+ case REG_TXDCTL:
+ regs.txdctl = val;
+ break;
+ case REG_TADV:
+ regs.tadv = val;
+ break;
+ case REG_RXCSUM:
+ regs.rxcsum = val;
+ break;
+ case REG_MANC:
+ regs.manc = val;
+ break;
default:
- if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) &&
- !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) &&
- !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4))
+ if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
+ !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
+ !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
panic("Write request to unknown register number: %#x\n", daddr);
};
@@ -288,18 +553,585 @@ IGbE::write(PacketPtr pkt)
return pioDelay;
}
+void
+IGbE::postInterrupt(IntTypes t, bool now)
+{
+ // Interrupt is already pending
+ if (t & regs.icr())
+ return;
+
+ if (regs.icr() & regs.imr)
+ {
+ // already in an interrupt state, set new int and done
+ regs.icr = regs.icr() | t;
+ } else {
+ regs.icr = regs.icr() | t;
+ if (regs.itr.interval() == 0 || now) {
+ if (now) {
+ if (interEvent.scheduled())
+ interEvent.deschedule();
+ }
+ cpuPostInt();
+ } else {
+ DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
+ Clock::Int::ns * 256 * regs.itr.interval());
+ assert(!interEvent.scheduled());
+ interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ }
+ }
+}
+
+void
+IGbE::cpuPostInt()
+{
+ if (rdtrEvent.scheduled()) {
+ regs.icr.rxt0(1);
+ rdtrEvent.deschedule();
+ }
+ if (radvEvent.scheduled()) {
+ regs.icr.rxt0(1);
+ radvEvent.deschedule();
+ }
+ if (tadvEvent.scheduled()) {
+ regs.icr.txdw(1);
+ tadvEvent.deschedule();
+ }
+ if (tidvEvent.scheduled()) {
+ regs.icr.txdw(1);
+ tidvEvent.deschedule();
+ }
+
+ regs.icr.int_assert(1);
+ DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
+ regs.icr());
+ intrPost();
+}
+
+void
+IGbE::cpuClearInt()
+{
+ regs.icr.int_assert(0);
+ DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
+ regs.icr());
+ intrClear();
+}
+
+void
+IGbE::chkInterrupt()
+{
+ // Check if we need to clear the cpu interrupt
+ if (!(regs.icr() & regs.imr))
+ cpuClearInt();
+
+ // Check if we need to set the cpu interupt
+ postInterrupt(IT_NONE);
+}
+
+
+IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
+ : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
+
+{
+}
bool
-IGbE::ethRxPkt(EthPacketPtr packet)
+IGbE::RxDescCache::writePacket(EthPacketPtr packet)
{
- panic("Need to implemenet\n");
+ // We shouldn't have to deal with any of these yet
+ assert(packet->length < igbe->regs.rctl.descSize());
+
+ if (!unusedCache.size())
+ return false;
+
+ pktPtr = packet;
+
+ igbe->dmaWrite(unusedCache.front()->buf, packet->length, &pktEvent, packet->data);
+ return true;
+}
+
+void
+IGbE::RxDescCache::pktComplete()
+{
+ assert(unusedCache.size());
+ RxDesc *desc;
+ desc = unusedCache.front();
+
+ desc->len = pktPtr->length;
+ // no support for anything but starting at 0
+ assert(igbe->regs.rxcsum.pcss() == 0);
+
+ DPRINTF(EthernetDesc, "RxDesc: Packet written to memory updating Descriptor\n");
+
+ uint8_t status = RXDS_DD | RXDS_EOP;
+ uint8_t err = 0;
+ IpPtr ip(pktPtr);
+ if (ip) {
+ if (igbe->regs.rxcsum.ipofld()) {
+ DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n");
+ status |= RXDS_IPCS;
+ desc->csum = cksum(ip);
+ if (cksum(ip) != 0) {
+ err |= RXDE_IPE;
+ DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
+ }
+ }
+ TcpPtr tcp(ip);
+ if (tcp && igbe->regs.rxcsum.tuofld()) {
+ DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n");
+ status |= RXDS_TCPCS;
+ desc->csum = cksum(tcp);
+ if (cksum(tcp) != 0) {
+ DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
+ err |= RXDE_TCPE;
+ }
+ }
+
+ UdpPtr udp(ip);
+ if (udp && igbe->regs.rxcsum.tuofld()) {
+ DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n");
+ status |= RXDS_UDPCS;
+ desc->csum = cksum(udp);
+ if (cksum(tcp) != 0) {
+ DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
+ err |= RXDE_TCPE;
+ }
+ }
+ } // if ip
+
+ desc->status = status;
+ desc->errors = err;
+
+ // No vlan support at this point... just set it to 0
+ desc->vlan = 0;
+
+ // 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());
+ if (igbe->rdtrEvent.scheduled())
+ igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() *
+ igbe->intClock());
+ else
+ igbe->rdtrEvent.schedule(curTick + igbe->regs.rdtr.delay() *
+ igbe->intClock());
+ }
+
+ 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 the packet is small enough, interrupt appropriately
+ if (pktPtr->length <= igbe->regs.rsrpd.idv())
+ igbe->postInterrupt(IT_SRPD);
+
+ DPRINTF(EthernetDesc, "RxDesc: Processing of this descriptor complete\n");
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+ pktPtr = NULL;
+ enableSm();
+ pktDone = true;
+}
+
+void
+IGbE::RxDescCache::enableSm()
+{
+ igbe->rxTick = true;
+ if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
+ igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
+ igbe->cycles(1));
+}
+
+bool
+IGbE::RxDescCache::packetDone()
+{
+ if (pktDone) {
+ pktDone = false;
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
+
+IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
+ : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
+ pktEvent(this)
+
+{
+}
+
+int
+IGbE::TxDescCache::getPacketSize()
+{
+ assert(unusedCache.size());
+
+ TxDesc *desc;
+
+ DPRINTF(EthernetDesc, "TxDesc: Starting processing of descriptor\n");
+
+ while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
+ DPRINTF(EthernetDesc, "TxDesc: Got context descriptor type... skipping\n");
+
+ // I think we can just ignore these for now?
+ desc = unusedCache.front();
+ // 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));
+
+ TxdOp::setDd(desc);
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+ }
+
+ if (!unusedCache.size())
+ return -1;
+
+ DPRINTF(EthernetDesc, "TxDesc: Next TX packet is %d bytes\n",
+ TxdOp::getLen(unusedCache.front()));
+
+ return TxdOp::getLen(unusedCache.front());
+}
+
+void
+IGbE::TxDescCache::getPacketData(EthPacketPtr p)
+{
+ assert(unusedCache.size());
+
+ TxDesc *desc;
+ desc = unusedCache.front();
+
+ assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
+
+ pktPtr = p;
+
+ pktWaiting = true;
+
+ DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n");
+ igbe->dmaRead(TxdOp::getBuf(desc), TxdOp::getLen(desc), &pktEvent, p->data);
+
+
+}
+
+void
+IGbE::TxDescCache::pktComplete()
+{
+
+ TxDesc *desc;
+ assert(unusedCache.size());
+ assert(pktPtr);
+
+ DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n");
+
+ desc = unusedCache.front();
+ assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
+
+ // 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));
+
+ // set that this packet is done
+ TxdOp::setDd(desc);
+
+ // Checksums are only ofloaded for new descriptor types
+ if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
+ DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n");
+ IpPtr ip(pktPtr);
+ if (TxdOp::ixsm(desc)) {
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ DPRINTF(EthernetDesc, "TxDesc: Calculated IP checksum\n");
+ }
+ if (TxdOp::txsm(desc)) {
+ if (isTcp) {
+ TcpPtr tcp(ip);
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ DPRINTF(EthernetDesc, "TxDesc: Calculated TCP checksum\n");
+ } else {
+ UdpPtr udp(ip);
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ DPRINTF(EthernetDesc, "TxDesc: Calculated UDP checksum\n");
+ }
+ }
+ }
+
+ if (TxdOp::ide(desc)) {
+ // Deal with the rx timer interrupts
+ DPRINTF(EthernetDesc, "TxDesc: Descriptor had IDE set\n");
+ if (igbe->regs.tidv.idv()) {
+ DPRINTF(EthernetDesc, "TxDesc: setting tidv\n");
+ if (igbe->tidvEvent.scheduled())
+ igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() *
+ igbe->intClock());
+ else
+ igbe->tidvEvent.schedule(curTick + igbe->regs.tidv.idv() *
+ igbe->intClock());
+ }
+
+ if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
+ DPRINTF(EthernetDesc, "TxDesc: setting tadv\n");
+ if (!igbe->tadvEvent.scheduled())
+ igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() *
+ igbe->intClock());
+ }
+ }
+
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+ pktDone = true;
+ pktWaiting = false;
+ pktPtr = NULL;
+
+ DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n");
+}
+
+bool
+IGbE::TxDescCache::packetAvailable()
+{
+ if (pktDone) {
+ pktDone = false;
+ return true;
+ }
+ return false;
+}
+
+void
+IGbE::TxDescCache::enableSm()
+{
+ igbe->txTick = true;
+ if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
+ igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
+ igbe->cycles(1));
+}
+
+
+
+
+///////////////////////////////////// IGbE /////////////////////////////////
+
+void
+IGbE::txStateMachine()
+{
+ if (!regs.tctl.en()) {
+ txTick = false;
+ DPRINTF(EthernetSM, "TXS: RX disabled, stopping ticking\n");
+ return;
+ }
+
+ if (txPacket && txDescCache.packetAvailable()) {
+ bool success;
+ DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
+ success = txFifo.push(txPacket);
+ assert(success);
+ txPacket = NULL;
+ 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);
+ }
+
+ if (!txPacket) {
+ txPacket = new EthPacketData(16384);
+ }
+
+ if (!txDescCache.packetWaiting()) {
+ if (txDescCache.descLeft() == 0) {
+ DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing writeback\n");
+ txDescCache.writeback(0);
+ DPRINTF(EthernetSM, "TXS: No descriptors left, stopping ticking\n");
+ txTick = false;
+ }
+
+ if (!(txDescCache.descUnused())) {
+ DPRINTF(EthernetSM, "TXS: No descriptors available in cache, stopping ticking\n");
+ txTick = false;
+ DPRINTF(EthernetSM, "TXS: No descriptors left, fetching\n");
+ txDescCache.fetchDescriptors();
+ return;
+ }
+
+ int size;
+ size = txDescCache.getPacketSize();
+ if (size > 0 && rxFifo.avail() > size) {
+ DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining DMA of next packet\n");
+ rxFifo.reserve(size);
+ txDescCache.getPacketData(txPacket);
+ } else {
+ DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
+ txDescCache.writeback(0);
+ }
+
+ return;
+ }
+}
+
+bool
+IGbE::ethRxPkt(EthPacketPtr pkt)
+{
+ DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
+ if (!regs.rctl.en()) {
+ DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
+ return true;
+ }
+
+ // restart the state machines if they are stopped
+ rxTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled()) {
+ DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
+ tickEvent.schedule(curTick/cycles(1) + cycles(1));
+ }
+
+ if (!rxFifo.push(pkt)) {
+ DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
+ postInterrupt(IT_RXO, true);
+ return false;
+ }
+ return true;
+}
+
+
+void
+IGbE::rxStateMachine()
+{
+ if (!regs.rctl.en()) {
+ rxTick = false;
+ DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
+ return;
+ }
+
+ // If the packet is done check for interrupts/descriptors/etc
+ if (rxDescCache.packetDone()) {
+ DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
+ int descLeft = rxDescCache.descLeft();
+ switch (regs.rctl.rdmts()) {
+ case 2: if (descLeft > .125 * regs.rdlen()) break;
+ case 1: if (descLeft > .250 * regs.rdlen()) break;
+ case 0: if (descLeft > .500 * regs.rdlen()) break;
+ DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n");
+ postInterrupt(IT_RXDMT);
+ break;
+ }
+
+ if (descLeft == 0) {
+ DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing writeback\n");
+ rxDescCache.writeback(0);
+ DPRINTF(EthernetSM, "RXS: No descriptors left, stopping ticking\n");
+ rxTick = false;
+ }
+
+ // only support descriptor granulaties
+ assert(regs.rxdctl.gran());
+
+ if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
+ DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
+ rxDescCache.writeback(cacheBlockSize()-1);
+ }
+
+ if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
+ ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
+ DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
+ rxDescCache.fetchDescriptors();
+ }
+
+ if (rxDescCache.descUnused() == 0) {
+ DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
+ rxTick = false;
+ DPRINTF(EthernetSM, "RXS: Fetching descriptors because none available\n");
+ rxDescCache.fetchDescriptors();
+ }
+ return;
+ }
+
+ if (!rxDescCache.descUnused()) {
+ DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
+ rxTick = false;
+ DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
+ rxDescCache.fetchDescriptors();
+ return;
+ }
+
+ if (rxFifo.empty()) {
+ DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
+ rxTick = false;
+ return;
+ }
+
+ EthPacketPtr pkt;
+ pkt = rxFifo.front();
+
+ DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
+ if (!rxDescCache.writePacket(pkt)) {
+ return;
+ }
+
+ DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
+ rxFifo.pop();
+ DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
+ rxTick = false;
}
+void
+IGbE::txWire()
+{
+ if (txFifo.empty()) {
+ return;
+ }
+
+ txTick = true;
+
+ if (etherInt->sendPacket(txFifo.front())) {
+ DPRINTF(Ethernet, "TxFIFO: Successful transmit, bytes in fifo: %d\n",
+ txFifo.avail());
+ txFifo.pop();
+ }
+
+ if (txFifo.empty()) {
+ postInterrupt(IT_TXQE);
+ DPRINTF(Ethernet, "TxFIFO: Empty, posting interruppt\n");
+ }
+}
+
+void
+IGbE::tick()
+{
+ DPRINTF(EthernetSM, "IGbE: -------------- Cycle -------------- ");
+
+ if (rxTick)
+ rxStateMachine();
+
+ if (txTick) {
+ txStateMachine();
+ txWire();
+ }
+
+ if (rxTick || txTick)
+ tickEvent.schedule(curTick + cycles(1));
+}
void
IGbE::ethTxDone()
{
- panic("Need to implemenet\n");
+ // restart the state machines if they are stopped
+ txTick = true;
+ if ((rxTick || txTick) && !tickEvent.scheduled())
+ tickEvent.schedule(curTick/cycles(1) + cycles(1));
+ DPRINTF(Ethernet, "TxFIFO: Transmission complete\n");
}
void
diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh
index ce4007263..d7d20ae50 100644
--- a/src/dev/i8254xGBe.hh
+++ b/src/dev/i8254xGBe.hh
@@ -35,6 +35,9 @@
#ifndef __DEV_I8254XGBE_HH__
#define __DEV_I8254XGBE_HH__
+#include <deque>
+#include <string>
+
#include "base/inet.hh"
#include "base/statistics.hh"
#include "dev/etherint.hh"
@@ -50,22 +53,434 @@ class IGbE : public PciDev
{
private:
IGbEInt *etherInt;
+
+ // device registers
iGbReg::Regs regs;
+
+ // eeprom data, status and control bits
int eeOpBits, eeAddrBits, eeDataBits;
uint8_t eeOpcode, eeAddr;
-
uint16_t flash[iGbReg::EEPROM_SIZE];
+ // cached parameters from params struct
+ Tick tickRate;
+ bool useFlowControl;
+
+ // packet fifos
+ PacketFifo rxFifo;
+ PacketFifo txFifo;
+
+ // Packet that we are currently putting into the txFifo
+ EthPacketPtr txPacket;
+
+ // Should to Rx/Tx State machine tick?
+ bool rxTick;
+ bool txTick;
+
+ // Event and function to deal with RDTR timer expiring
+ void rdtrProcess() { postInterrupt(iGbReg::IT_RXDMT, true); }
+ //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
+ EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
+
+ // Event and function to deal with RADV timer expiring
+ void radvProcess() { postInterrupt(iGbReg::IT_RXDMT, true); }
+ //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
+ EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
+
+ // Event and function to deal with TADV timer expiring
+ void tadvProcess() { postInterrupt(iGbReg::IT_TXDW, true); }
+ //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
+ EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
+
+ // Event and function to deal with TIDV timer expiring
+ void tidvProcess() { postInterrupt(iGbReg::IT_TXDW, true); };
+ //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
+ EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
+
+ // Main event to tick the device
+ void tick();
+ //friend class EventWrapper<IGbE, &IGbE::tick>;
+ EventWrapper<IGbE, &IGbE::tick> tickEvent;
+
+
+ void rxStateMachine();
+ void txStateMachine();
+ void txWire();
+
+ /** Write an interrupt into the interrupt pending register and check mask
+ * and interrupt limit timer before sending interrupt to CPU
+ * @param t the type of interrupt we are posting
+ * @param now should we ignore the interrupt limiting timer
+ */
+ void postInterrupt(iGbReg::IntTypes t, bool now = false);
+
+ /** Check and see if changes to the mask register have caused an interrupt
+ * to need to be sent or perhaps removed an interrupt cause.
+ */
+ void chkInterrupt();
+
+ /** Send an interrupt to the cpu
+ */
+ void cpuPostInt();
+ // Event to moderate interrupts
+ EventWrapper<IGbE, &IGbE::cpuPostInt> interEvent;
+
+ /** Clear the interupt line to the cpu
+ */
+ void cpuClearInt();
+
+ Tick intClock() { return Clock::Int::ns * 1024; }
+
+ template<class T>
+ class DescCache
+ {
+ protected:
+ virtual Addr descBase() const = 0;
+ virtual long descHead() const = 0;
+ virtual long descTail() const = 0;
+ virtual long descLen() const = 0;
+ virtual void updateHead(long h) = 0;
+ virtual void enableSm() = 0;
+
+ std::deque<T*> usedCache;
+ std::deque<T*> unusedCache;
+
+ T *fetchBuf;
+ T *wbBuf;
+
+ // Pointer to the device we cache for
+ IGbE *igbe;
+
+ // Name of this descriptor cache
+ std::string _name;
+
+ // How far we've cached
+ int cachePnt;
+
+ // The size of the descriptor cache
+ int size;
+
+ // How many descriptors we are currently fetching
+ int curFetching;
+
+ // How many descriptors we are currently writing back
+ int wbOut;
+
+ // if the we wrote back to the end of the descriptor ring and are going
+ // to have to wrap and write more
+ bool moreToWb;
+
+ // What the alignment is of the next descriptor writeback
+ Addr wbAlignment;
+
+ /** The packet that is currently being dmad to memory if any
+ */
+ EthPacketPtr pktPtr;
+
+ public:
+ 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)
+ {
+ fetchBuf = new T[size];
+ wbBuf = new T[size];
+ }
+
+ virtual ~DescCache()
+ {
+ reset();
+ }
+
+ std::string name() { return _name; }
+
+ /** If the address/len/head change when we've got descriptors that are
+ * dirty that is very bad. This function checks that we don't and if we
+ * do panics.
+ */
+ void areaChanged()
+ {
+ if (usedCache.size() > 0 || unusedCache.size() > 0)
+ panic("Descriptor Address, Length or Head changed. Bad\n");
+ }
+
+ void writeback(Addr aMask)
+ {
+ int curHead = descHead();
+ int max_to_wb = usedCache.size() + curHead;
+
+ 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;
+ DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
+ return;
+ }
+
+
+ moreToWb = false;
+ wbAlignment = aMask;
+
+ if (max_to_wb > descLen()) {
+ max_to_wb = descLen() - curHead;
+ moreToWb = true;
+ // this is by definition aligned correctly
+ } else if (aMask != 0) {
+ // align the wb point to the mask
+ max_to_wb = max_to_wb & ~(aMask>>4);
+ }
+
+ DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
+
+ if (max_to_wb <= 0 || wbOut)
+ return;
+
+ wbOut = max_to_wb - curHead;
+
+ for (int x = 0; x < wbOut; x++)
+ memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+
+ for (int x = 0; x < wbOut; x++) {
+ assert(usedCache.size());
+ delete usedCache[0];
+ usedCache.pop_front();
+ };
+
+ igbe->dmaWrite(descBase() + curHead * sizeof(T), wbOut * sizeof(T),
+ &wbEvent, (uint8_t*)wbBuf);
+ }
+
+ /** 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 = cachePnt - descTail();
+ if (max_to_fetch < 0)
+ max_to_fetch = descLen() - cachePnt;
+
+ max_to_fetch = std::min(max_to_fetch, (size - usedCache.size() -
+ unusedCache.size()));
+
+ DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
+ "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+ descHead(), descTail(), descLen(), cachePnt,
+ max_to_fetch, descLeft());
+
+ // Nothing to do
+ if (max_to_fetch == 0 || curFetching)
+ return;
+
+ // So we don't have two descriptor fetches going on at once
+ curFetching = max_to_fetch;
+
+ igbe->dmaRead(descBase() + cachePnt * sizeof(T),
+ curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
+ }
+
+
+ /** Called by event when dma to read descriptors is completed
+ */
+ void fetchComplete()
+ {
+ T *newDesc;
+ for (int x = 0; x < curFetching; x++) {
+ newDesc = new T;
+ memcpy(newDesc, &fetchBuf[x], sizeof(T));
+ unusedCache.push_back(newDesc);
+ }
+
+#ifndef NDEBUG
+ int oldCp = cachePnt;
+#endif
+
+ cachePnt += curFetching;
+ if (cachePnt > descLen())
+ cachePnt -= descLen();
+
+ DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
+ oldCp, cachePnt);
+
+ enableSm();
+
+ }
+
+ EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
+
+ /** Called by event when dma to writeback descriptors is completed
+ */
+ void wbComplete()
+ {
+ long curHead = descHead();
+#ifndef NDEBUG
+ long oldHead = curHead;
+#endif
+
+ curHead += wbOut;
+ wbOut = 0;
+
+ if (curHead > descLen())
+ curHead = 0;
+
+ // Update the head
+ updateHead(curHead);
+
+ DPRINTF(EthernetDesc, "Writeback complete cachePnt %d -> %d\n",
+ oldHead, curHead);
+
+ // If we still have more to wb, call wb now
+ if (moreToWb) {
+ DPRINTF(EthernetDesc, "Writeback has more todo\n");
+ writeback(wbAlignment);
+ }
+ }
+
+
+ EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
+
+ /* Return the number of descriptors left in the ring, so the device has
+ * a way to figure out if it needs to interrupt.
+ */
+ int descLeft() const
+ {
+ int left = unusedCache.size();
+ if (cachePnt - descTail() >= 0)
+ left += (cachePnt - descTail());
+ else
+ left += (descLen() - cachePnt);
+
+ return left;
+ }
+
+ /* Return the number of descriptors used and not written back.
+ */
+ int descUsed() const { return usedCache.size(); }
+
+ /* Return the number of cache unused descriptors we have. */
+ int descUnused() const {return unusedCache.size(); }
+
+ /* Get into a state where the descriptor address/head/etc colud be
+ * changed */
+ void reset()
+ {
+ DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
+ for (int x = 0; x < usedCache.size(); x++)
+ delete usedCache[x];
+ for (int x = 0; x < unusedCache.size(); x++)
+ delete unusedCache[x];
+
+ usedCache.clear();
+ unusedCache.clear();
+ }
+
+ };
+
+
+ class RxDescCache : public DescCache<iGbReg::RxDesc>
+ {
+ protected:
+ virtual Addr descBase() const { return igbe->regs.rdba(); }
+ virtual long descHead() const { return igbe->regs.rdh(); }
+ virtual long descLen() const { return igbe->regs.rdlen() >> 4; }
+ virtual long descTail() const { return igbe->regs.rdt(); }
+ virtual void updateHead(long h) { igbe->regs.rdh(h); }
+ virtual void enableSm();
+
+ bool pktDone;
+
+ public:
+ RxDescCache(IGbE *i, std::string n, int s);
+
+ /** Write the given packet into the buffer(s) pointed to by the
+ * descriptor and update the book keeping. Should only be called when
+ * there are no dma's pending.
+ * @param packet ethernet packet to write
+ * @return if the packet could be written (there was a free descriptor)
+ */
+ bool writePacket(EthPacketPtr packet);
+ /** Called by event when dma to write packet is completed
+ */
+ void pktComplete();
+
+ /** Check if the dma on the packet has completed.
+ */
+
+ bool packetDone();
+
+ EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
+
+ };
+ friend class RxDescCache;
+
+ RxDescCache rxDescCache;
+
+ class TxDescCache : public DescCache<iGbReg::TxDesc>
+ {
+ protected:
+ virtual Addr descBase() const { return igbe->regs.tdba(); }
+ virtual long descHead() const { return igbe->regs.tdh(); }
+ virtual long descTail() const { return igbe->regs.tdt(); }
+ virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
+ virtual void updateHead(long h) { igbe->regs.tdh(h); }
+ virtual void enableSm();
+
+ bool pktDone;
+ bool isTcp;
+ bool pktWaiting;
+
+ public:
+ TxDescCache(IGbE *i, std::string n, int s);
+
+ /** Tell the cache to DMA a packet from main memory into its buffer and
+ * return the size the of the packet to reserve space in tx fifo.
+ * @return size of the packet
+ */
+ int getPacketSize();
+ void getPacketData(EthPacketPtr p);
+
+ /** Ask if the packet has been transfered so the state machine can give
+ * it to the fifo.
+ * @return packet available in descriptor cache
+ */
+ bool packetAvailable();
+
+ /** Ask if we are still waiting for the packet to be transfered.
+ * @return packet still in transit.
+ */
+ bool packetWaiting() { return pktWaiting; }
+
+ /** Called by event when dma to write packet is completed
+ */
+ void pktComplete();
+ EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
+
+ };
+ friend class TxDescCache;
+
+ TxDescCache txDescCache;
public:
struct Params : public PciDev::Params
{
- ;
+ bool use_flow_control;
+ int rx_fifo_size;
+ int tx_fifo_size;
+ int rx_desc_cache_size;
+ int tx_desc_cache_size;
+ Tick clock;
};
IGbE(Params *params);
~IGbE() {;}
+ Tick clock;
+ inline Tick cycles(int numCycles) const { return numCycles * clock; }
+
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
@@ -76,6 +491,7 @@ class IGbE : public PciDev
void setEthInt(IGbEInt *i) { assert(!etherInt); etherInt = i; }
+
const Params *params() const {return (const Params *)_params; }
virtual void serialize(std::ostream &os);
diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh
index ae0925356..d9648a7c2 100644
--- a/src/dev/i8254xGBe_defs.hh
+++ b/src/dev/i8254xGBe_defs.hh
@@ -31,433 +31,570 @@
/* @file
* Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers.
*/
+#include "base/bitfield.hh"
namespace iGbReg {
-const uint32_t CTRL = 0x00000; //*
-const uint32_t STATUS = 0x00008; //*
-const uint32_t EECD = 0x00010; //*
-const uint32_t EERD = 0x00014; //*
-const uint32_t CTRL_EXT = 0x00018;
-const uint32_t PBA = 0x01000;
-const uint32_t ICR = 0x000C0; //*
-const uint32_t ITR = 0x000C4;
-const uint32_t ICS = 0x000C8;
-const uint32_t IMS = 0x000D0;
-const uint32_t IMC = 0x000D8; //*
-const uint32_t RCTL = 0x00100; //*
-const uint32_t RDBAL = 0x02800;
-const uint32_t RDBAH = 0x02804;
-const uint32_t RDLEN = 0x02808;
-const uint32_t RDH = 0x02810;
-const uint32_t RDT = 0x02818;
-const uint32_t RDTR = 0x02820;
-const uint32_t RADV = 0x0282C;
-const uint32_t RSRPD = 0x02C00;
-const uint32_t TCTL = 0x00400; //*
-const uint32_t TDBAL = 0x03800;
-const uint32_t TDBAH = 0x03804;
-const uint32_t TDLEN = 0x03808;
-const uint32_t TDH = 0x03810;
-const uint32_t THT = 0x03818;
-const uint32_t TIDV = 0x03820;
-const uint32_t TXDMAC = 0x03000;
-const uint32_t TXDCTL = 0x03828;
-const uint32_t TADV = 0x0282C;
-const uint32_t TSPMT = 0x03830;
-const uint32_t RXDCTL = 0x02828;
-const uint32_t RXCSUM = 0x05000;
-const uint32_t MANC = 0x05820;//*
+
+// Registers used by the Intel GbE NIC
+const uint32_t REG_CTRL = 0x00000;
+const uint32_t REG_STATUS = 0x00008;
+const uint32_t REG_EECD = 0x00010;
+const uint32_t REG_EERD = 0x00014;
+const uint32_t REG_CTRL_EXT = 0x00018;
+const uint32_t REG_MDIC = 0x00020;
+const uint32_t REG_FCAL = 0x00028;
+const uint32_t REG_FCAH = 0x0002C;
+const uint32_t REG_FCT = 0x00030;
+const uint32_t REG_VET = 0x00038;
+const uint32_t REG_PBA = 0x01000;
+const uint32_t REG_ICR = 0x000C0;
+const uint32_t REG_ITR = 0x000C4;
+const uint32_t REG_ICS = 0x000C8;
+const uint32_t REG_IMS = 0x000D0;
+const uint32_t REG_IMC = 0x000D8;
+const uint32_t REG_IAM = 0x000E0;
+const uint32_t REG_RCTL = 0x00100;
+const uint32_t REG_FCTTV = 0x00170;
+const uint32_t REG_TIPG = 0x00410;
+const uint32_t REG_AIFS = 0x00458;
+const uint32_t REG_LEDCTL = 0x00e00;
+const uint32_t REG_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_RDH = 0x02810;
+const uint32_t REG_RDT = 0x02818;
+const uint32_t REG_RDTR = 0x02820;
+const uint32_t REG_RXDCTL = 0x02828;
+const uint32_t REG_RADV = 0x0282C;
+const uint32_t REG_TCTL = 0x00400;
+const uint32_t REG_TDBAL = 0x03800;
+const uint32_t REG_TDBAH = 0x03804;
+const uint32_t REG_TDLEN = 0x03808;
+const uint32_t REG_TDH = 0x03810;
+const uint32_t REG_TDT = 0x03818;
+const uint32_t REG_TIDV = 0x03820;
+const uint32_t REG_TXDCTL = 0x03828;
+const uint32_t REG_TADV = 0x0382C;
+const uint32_t REG_CRCERRS = 0x04000;
+const uint32_t REG_RXCSUM = 0x05000;
+const uint32_t REG_MTA = 0x05200;
+const uint32_t REG_RAL = 0x05400;
+const uint32_t REG_RAH = 0x05404;
+const uint32_t REG_VFTA = 0x05600;
+
+const uint32_t REG_WUC = 0x05800;
+const uint32_t REG_MANC = 0x05820;
const uint8_t EEPROM_READ_OPCODE_SPI = 0x03;
const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05;
const uint8_t EEPROM_SIZE = 64;
+const uint16_t EEPROM_CSUM = 0xBABA;
+
+const uint8_t VLAN_FILTER_TABLE_SIZE = 128;
+const uint8_t RCV_ADDRESS_TABLE_SIZE = 16;
+const uint8_t MULTICAST_TABLE_SIZE = 128;
+const uint32_t STATS_REGS_SIZE = 0x124;
+
+
+// Registers in that are accessed in the PHY
+const uint8_t PHY_PSTATUS = 0x1;
+const uint8_t PHY_PID = 0x2;
+const uint8_t PHY_EPID = 0x3;
+const uint8_t PHY_GSTATUS = 10;
+const uint8_t PHY_EPSTATUS = 15;
+const uint8_t PHY_AGC = 18;
+
+// Receive Descriptor Status Flags
+const 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;
+// Receive Descriptor Error Flags
+const uint8_t RXDE_RXE = 0x80;
+const uint8_t RXDE_IPE = 0x40;
+const uint8_t RXDE_TCPE = 0x20;
+const uint8_t RXDE_SEQ = 0x04;
+const uint8_t RXDE_SE = 0x02;
+const uint8_t RXDE_CE = 0x01;
+
+// Interrupt types
+enum IntTypes
+{
+ IT_NONE = 0x00000, //dummy value
+ IT_TXDW = 0x00001,
+ IT_TXQE = 0x00002,
+ IT_LSC = 0x00004,
+ IT_RXSEQ = 0x00008,
+ IT_RXDMT = 0x00010,
+ IT_RXO = 0x00040,
+ IT_RXT = 0x00080,
+ IT_MADC = 0x00200,
+ IT_RXCFG = 0x00400,
+ IT_GPI0 = 0x02000,
+ IT_GPI1 = 0x04000,
+ IT_TXDLOW = 0x08000,
+ IT_SRPD = 0x10000,
+ IT_ACK = 0x20000
+};
+
+// Receive Descriptor struct
struct RxDesc {
Addr buf;
uint16_t len;
uint16_t csum;
- union {
- uint8_t status;
- struct { // these may be in the worng order
- uint8_t dd:1; // descriptor done (hw is done when 1)
- uint8_t eop:1; // end of packet
- uint8_t xism:1; // ignore checksum
- uint8_t vp:1; // packet is vlan packet
- uint8_t rsv:1; // reserved
- uint8_t tcpcs:1; // TCP checksum done
- uint8_t ipcs:1; // IP checksum done
- uint8_t pif:1; // passed in-exact filter
- } st;
- };
- union {
- uint8_t errors;
- struct {
- uint8_t ce:1; // crc error or alignment error
- uint8_t se:1; // symbol error
- uint8_t seq:1; // sequence error
- uint8_t rsv:1; // reserved
- uint8_t cxe:1; // carrier extension error
- uint8_t tcpe:1; // tcp checksum error
- uint8_t ipe:1; // ip checksum error
- uint8_t rxe:1; // PX data error
- } er;
- };
- union {
- uint16_t special;
- struct {
- uint16_t vlan:12; //vlan id
- uint16_t cfi:1; // canocial form id
- uint16_t pri:3; // user priority
- } sp;
- };
+ uint8_t status;
+ uint8_t errors;
+ uint16_t vlan;
};
-union TxDesc {
- uint8_t data[16];
- struct {
- Addr buf;
- uint16_t len;
- uint8_t cso;
- union {
- uint8_t command;
- struct {
- uint8_t eop:1; // end of packet
- uint8_t ifcs:1; // insert crc
- uint8_t ic:1; // insert checksum
- uint8_t rs:1; // report status
- uint8_t rps:1; // report packet sent
- uint8_t dext:1; // extension
- uint8_t vle:1; // vlan enable
- uint8_t ide:1; // interrupt delay enable
- } cmd;
- };
- union {
- uint8_t status:4;
- struct {
- uint8_t dd:1; // descriptor done
- uint8_t ec:1; // excess collisions
- uint8_t lc:1; // late collision
- uint8_t tu:1; // transmit underrun
- } st;
- };
- uint8_t reserved:4;
- uint8_t css;
- union {
- uint16_t special;
- struct {
- uint16_t vlan:12; //vlan id
- uint16_t cfi:1; // canocial form id
- uint16_t pri:3; // user priority
- } sp;
- };
- } legacy;
-
- // Type 0000 descriptor
- struct {
- uint8_t ipcss;
- uint8_t ipcso;
- uint16_t ipcse;
- uint8_t tucss;
- uint8_t tucso;
- uint16_t tucse;
- uint32_t paylen:20;
- uint8_t dtype:4;
- union {
- uint8_t tucommand;
- struct {
- uint8_t tcp:1; // tcp/udp
- uint8_t ip:1; // ip ipv4/ipv6
- uint8_t tse:1; // tcp segment enbale
- uint8_t rs:1; // report status
- uint8_t rsv0:1; // reserved
- uint8_t dext:1; // descriptor extension
- uint8_t rsv1:1; // reserved
- uint8_t ide:1; // interrupt delay enable
- } tucmd;
- };
- union {
- uint8_t status:4;
- struct {
- uint8_t dd:1;
- uint8_t rsvd:3;
- } sta;
- };
- uint8_t reserved:4;
- uint8_t hdrlen;
- uint16_t mss;
- } t0;
-
- // Type 0001 descriptor
- struct {
- Addr buf;
- uint32_t dtalen:20;
- uint8_t dtype:4;
- union {
- uint8_t dcommand;
- struct {
- uint8_t eop:1; // end of packet
- uint8_t ifcs:1; // insert crc
- uint8_t tse:1; // segmentation enable
- uint8_t rs:1; // report status
- uint8_t rps:1; // report packet sent
- uint8_t dext:1; // extension
- uint8_t vle:1; // vlan enable
- uint8_t ide:1; // interrupt delay enable
- } dcmd;
- };
- union {
- uint8_t status:4;
- struct {
- uint8_t dd:1; // descriptor done
- uint8_t ec:1; // excess collisions
- uint8_t lc:1; // late collision
- uint8_t tu:1; // transmit underrun
- } sta;
- };
- union {
- uint8_t pktopts;
- struct {
- uint8_t ixsm:1; // insert ip checksum
- uint8_t txsm:1; // insert tcp checksum
- };
- };
- union {
- uint16_t special;
- struct {
- uint16_t vlan:12; //vlan id
- uint16_t cfi:1; // canocial form id
- uint16_t pri:3; // user priority
- } sp;
- };
- } t1;
-
- // Junk to test descriptor type!
- struct {
- uint64_t junk;
- uint32_t junk1:20;
- uint8_t dtype;
- uint8_t junk2:5;
- uint8_t dext:1;
- uint8_t junk3:2;
- uint8_t junk4:4;
- uint32_t junk5;
- } type;
+struct TxDesc {
+ uint64_t d1;
+ uint64_t d2;
};
+namespace TxdOp {
+const uint8_t TXD_CNXT = 0x0;
+const uint8_t TXD_DATA = 0x0;
+
+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; }
+
+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->d1, 35, 32, 1);
+}
+
+bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
+bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
+bool rs(TxDesc *d) { return bits(d->d2, 28,28); }
+bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 27,27); }
+bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 27,27); }
+bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 26,26); }
+bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
+bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 26,26); }
+bool tcp(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
+
+uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
+uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
+
+bool ixsm(TxDesc *d) { return isData(d) && bits(d->d2, 40,40); }
+bool txsm(TxDesc *d) { return isData(d) && bits(d->d2, 41,41); }
+
+int tucse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,63,48); }
+int tucso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,47,40); }
+int tucss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,39,32); }
+int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
+int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
+int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
+int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
+int hdrlen(TxDesc *d) { assert(isContext(d)); return bits(d->d2,47,40); }
+} // namespace TxdOp
+
+
+#define ADD_FIELD32(NAME, OFFSET, BITS) \
+ inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD64(NAME, OFFSET, BITS) \
+ inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
struct Regs {
- union { // 0x0000 CTRL Register
- uint32_t reg;
- struct {
- uint8_t fd:1; // full duplex
- uint8_t bem:1; // big endian mode
- uint8_t pcipr:1; // PCI priority
- uint8_t lrst:1; // link reset
- uint8_t tme:1; // test mode enable
- uint8_t asde:1; // Auto-speed detection
- uint8_t slu:1; // Set link up
- uint8_t ilos:1; // invert los-of-signal
- uint8_t speed:2; // speed selection bits
- uint8_t be32:1; // big endian mode 32
- uint8_t frcspd:1; // force speed
- uint8_t frcdpx:1; // force duplex
- uint8_t duden:1; // dock/undock enable
- uint8_t dudpol:1; // dock/undock polarity
- uint8_t fphyrst:1; // force phy reset
- uint8_t extlen:1; // external link status enable
- uint8_t rsvd:1; // reserved
- uint8_t sdp0d:1; // software controlled pin data
- uint8_t sdp1d:1; // software controlled pin data
- uint8_t sdp2d:1; // software controlled pin data
- uint8_t sdp3d:1; // software controlled pin data
- uint8_t sdp0i:1; // software controlled pin dir
- uint8_t sdp1i:1; // software controlled pin dir
- uint8_t sdp2i:1; // software controlled pin dir
- uint8_t sdp3i:1; // software controlled pin dir
- uint8_t rst:1; // reset
- uint8_t rfce:1; // receive flow control enable
- uint8_t tfce:1; // transmit flow control enable
- uint8_t rte:1; // routing tag enable
- uint8_t vme:1; // vlan enable
- uint8_t phyrst:1; // phy reset
- } ;
- } ctrl;
-
- union { // 0x0008 STATUS
- uint32_t reg;
- struct {
- uint8_t fd:1; // full duplex
- uint8_t lu:1; // link up
- uint8_t func:2; // function id
- uint8_t txoff:1; // transmission paused
- uint8_t tbimode:1; // tbi mode
- uint8_t speed:2; // link speed
- uint8_t asdv:2; // auto speed detection value
- uint8_t mtxckok:1; // mtx clock running ok
- uint8_t pci66:1; // In 66Mhz pci slot
- uint8_t bus64:1; // in 64 bit slot
- uint8_t pcix:1; // Pci mode
- uint8_t pcixspd:1; // pci x speed
- uint8_t reserved; // reserved
- } ;
- } sts;
-
- union { // 0x0010 EECD
- uint32_t reg;
- struct {
- uint8_t sk:1; // clack input to the eeprom
- uint8_t cs:1; // chip select to eeprom
- uint8_t din:1; // data input to eeprom
- uint8_t dout:1; // data output bit
- uint8_t fwe:2; // flash write enable
- uint8_t ee_req:1; // request eeprom access
- uint8_t ee_gnt:1; // grant eeprom access
- uint8_t ee_pres:1; // eeprom present
- uint8_t ee_size:1; // eeprom size
- uint8_t ee_sz1:1; // eeprom size
- uint8_t rsvd:2; // reserved
- uint8_t ee_type:1; // type of eeprom
- } ;
- } eecd;
-
- union { // 0x0014 EERD
- uint32_t reg;
- struct {
- uint8_t start:1; // start read
- uint8_t done:1; // done read
- uint16_t addr:14; // address
- uint16_t data; // data
- };
- } eerd;
-
- union { // 0x00C0 ICR
- uint32_t reg;
- struct {
- uint8_t txdw:1; // tx descr witten back
- uint8_t txqe:1; // tx queue empty
- uint8_t lsc:1; // link status change
- uint8_t rxseq:1; // rcv sequence error
- uint8_t rxdmt0:1; // rcv descriptor min thresh
- uint8_t rsvd1:1; // reserved
- uint8_t rxo:1; // receive overrunn
- uint8_t rxt0:1; // receiver timer interrupt
- uint8_t rsvd2:1; // reserved
- uint8_t mdac:1; // mdi/o access complete
- uint8_t rxcfg:1; // recv /c/ ordered sets
- uint8_t rsvd3:1; // reserved
- uint8_t phyint:1; // phy interrupt
- uint8_t gpi1:1; // gpi int 1
- uint8_t gpi2:1; // gpi int 2
- uint8_t txdlow:1; // transmit desc low thresh
- uint8_t srpd:1; // small receive packet detected
- uint16_t rsvd4:15; // reserved
- } ;
- } icd;
-
- union { // 0x00C0 IMC
- uint32_t reg;
- struct {
- uint8_t txdw:1; // tx descr witten back
- uint8_t txqe:1; // tx queue empty
- uint8_t lsc:1; // link status change
- uint8_t rxseq:1; // rcv sequence error
- uint8_t rxdmt0:1; // rcv descriptor min thresh
- uint8_t rsvd1:1; // reserved
- uint8_t rxo:1; // receive overrunn
- uint8_t rxt0:1; // receiver timer interrupt
- uint8_t rsvd2:1; // reserved
- uint8_t mdac:1; // mdi/o access complete
- uint8_t rxcfg:1; // recv /c/ ordered sets
- uint8_t rsvd3:1; // reserved
- uint8_t phyint:1; // phy interrupt
- uint8_t gpi1:1; // gpi int 1
- uint8_t gpi2:1; // gpi int 2
- uint8_t txdlow:1; // transmit desc low thresh
- uint8_t srpd:1; // small receive packet detected
- uint16_t rsvd4:15; // reserved
- } ;
- } imc;
-
- union { // 0x0100 RCTL
- uint32_t reg;
- struct {
- uint8_t rst:1; // Reset
- uint8_t en:1; // Enable
- uint8_t sbp:1; // Store bad packets
- uint8_t upe:1; // Unicast Promiscuous enabled
- uint8_t mpe:1; // Multicast promiscuous enabled
- uint8_t lpe:1; // long packet reception enabled
- uint8_t lbm:2; //
- uint8_t rdmts:2; //
- uint8_t rsvd:2; //
- uint8_t mo:2; //
- uint8_t mdr:1; //
- uint8_t bam:1; //
- uint8_t bsize:2; //
- uint8_t vpe:1; //
- uint8_t cfien:1; //
- uint8_t cfi:1; //
- uint8_t rsvd2:1; //
- uint8_t dpf:1; // discard pause frames
- uint8_t pmcf:1; // pass mac control frames
- uint8_t rsvd3:1; // reserved
- uint8_t bsex:1; // buffer size extension
- uint8_t secrc:1; // strip ethernet crc from incoming packet
- uint8_t rsvd1:5; // reserved
- } ;
- } rctl;
-
- union { // 0x0400 TCTL
- uint32_t reg;
- struct {
- uint8_t rst:1; // Reset
- uint8_t en:1; // Enable
- uint8_t bce:1; // busy check enable
- uint8_t psp:1; // pad short packets
- uint8_t ct:8; // collision threshold
- uint16_t cold:10; // collision distance
- uint8_t swxoff:1; // software xoff transmission
- uint8_t pbe:1; // packet burst enable
- uint8_t rtlc:1; // retransmit late collisions
- uint8_t nrtu:1; // on underrun no TX
- uint8_t mulr:1; // multiple request
- uint8_t rsvd:5; // reserved
- } ;
- } tctl;
-
- union { // 0x5820 MANC
- uint32_t reg;
- struct {
- uint8_t smbus:1; // SMBus enabled #####
- uint8_t asf:1; // ASF enabled #####
- uint8_t ronforce:1; // reset of force
- uint8_t rsvd:5; // reserved
- uint8_t rmcp1:1; // rcmp1 filtering
- uint8_t rmcp2:1; // rcmp2 filtering
- uint8_t ipv4:1; // enable ipv4
- uint8_t ipv6:1; // enable ipv6
- uint8_t snap:1; // accept snap
- uint8_t arp:1; // filter arp #####
- uint8_t neighbor:1; // neighbor discovery
- uint8_t arp_resp:1; // arp response
- uint8_t tcorst:1; // tco reset happened
- uint8_t rcvtco:1; // receive tco enabled ######
- uint8_t blkphyrst:1;// block phy resets ########
- uint8_t rcvall:1; // receive all
- uint8_t macaddrfltr:1; // mac address filtering ######
- uint8_t mng2host:1; // mng2 host packets #######
- uint8_t ipaddrfltr:1; // ip address filtering
- uint8_t xsumfilter:1; // checksum filtering
- uint8_t brfilter:1; // broadcast filtering
- uint8_t smbreq:1; // smb request
- uint8_t smbgnt:1; // smb grant
- uint8_t smbclkin:1; // smbclkin
- uint8_t smbdatain:1; // smbdatain
- uint8_t smbdataout:1; // smb data out
- uint8_t smbclkout:1; // smb clock out
- uint8_t rsvd2:2;
- };
- } manc;
+ 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; }
+ };
+
+ struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(fd,0,1); // full duplex
+ ADD_FIELD32(bem,1,1); // big endian mode
+ ADD_FIELD32(pcipr,2,1); // PCI priority
+ ADD_FIELD32(lrst,3,1); // link reset
+ ADD_FIELD32(tme,4,1); // test mode enable
+ ADD_FIELD32(asde,5,1); // Auto-speed detection
+ ADD_FIELD32(slu,6,1); // Set link up
+ ADD_FIELD32(ilos,7,1); // invert los-of-signal
+ ADD_FIELD32(speed,8,2); // speed selection bits
+ ADD_FIELD32(be32,10,1); // big endian mode 32
+ ADD_FIELD32(frcspd,11,1); // force speed
+ ADD_FIELD32(frcdpx,12,1); // force duplex
+ ADD_FIELD32(duden,13,1); // dock/undock enable
+ ADD_FIELD32(dudpol,14,1); // dock/undock polarity
+ ADD_FIELD32(fphyrst,15,1); // force phy reset
+ ADD_FIELD32(extlen,16,1); // external link status enable
+ ADD_FIELD32(rsvd,17,1); // reserved
+ ADD_FIELD32(sdp0d,18,1); // software controlled pin data
+ ADD_FIELD32(sdp1d,19,1); // software controlled pin data
+ ADD_FIELD32(sdp2d,20,1); // software controlled pin data
+ ADD_FIELD32(sdp3d,21,1); // software controlled pin data
+ ADD_FIELD32(sdp0i,22,1); // software controlled pin dir
+ ADD_FIELD32(sdp1i,23,1); // software controlled pin dir
+ ADD_FIELD32(sdp2i,24,1); // software controlled pin dir
+ ADD_FIELD32(sdp3i,25,1); // software controlled pin dir
+ ADD_FIELD32(rst,26,1); // reset
+ ADD_FIELD32(rfce,27,1); // receive flow control enable
+ ADD_FIELD32(tfce,28,1); // transmit flow control enable
+ ADD_FIELD32(rte,29,1); // routing tag enable
+ ADD_FIELD32(vme,30,1); // vlan enable
+ ADD_FIELD32(phyrst,31,1); // phy reset
+ };
+ CTRL ctrl;
+
+ struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(fd,0,1); // full duplex
+ ADD_FIELD32(lu,1,1); // link up
+ ADD_FIELD32(func,2,2); // function id
+ ADD_FIELD32(txoff,4,1); // transmission paused
+ ADD_FIELD32(tbimode,5,1); // tbi mode
+ ADD_FIELD32(speed,6,2); // link speed
+ ADD_FIELD32(asdv,8,2); // auto speed detection value
+ ADD_FIELD32(mtxckok,10,1); // mtx clock running ok
+ ADD_FIELD32(pci66,11,1); // In 66Mhz pci slot
+ ADD_FIELD32(bus64,12,1); // in 64 bit slot
+ ADD_FIELD32(pcix,13,1); // Pci mode
+ ADD_FIELD32(pcixspd,14,2); // pci x speed
+ };
+ STATUS sts;
+
+ struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(sk,0,1); // clack input to the eeprom
+ ADD_FIELD32(cs,1,1); // chip select to eeprom
+ ADD_FIELD32(din,2,1); // data input to eeprom
+ ADD_FIELD32(dout,3,1); // data output bit
+ ADD_FIELD32(fwe,4,2); // flash write enable
+ ADD_FIELD32(ee_req,6,1); // request eeprom access
+ ADD_FIELD32(ee_gnt,7,1); // grant eeprom access
+ ADD_FIELD32(ee_pres,8,1); // eeprom present
+ ADD_FIELD32(ee_size,9,1); // eeprom size
+ ADD_FIELD32(ee_sz1,10,1); // eeprom size
+ ADD_FIELD32(rsvd,11,2); // reserved
+ ADD_FIELD32(ee_type,13,1); // type of eeprom
+ } ;
+ EECD eecd;
+
+ struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(start,0,1); // start read
+ ADD_FIELD32(done,4,1); // done read
+ ADD_FIELD32(addr,8,8); // address
+ ADD_FIELD32(data,16,16); // data
+ };
+ EERD eerd;
+
+ struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(gpi_en,0,4); // enable interrupts from gpio
+ ADD_FIELD32(phyint,5,1); // reads the phy internal int status
+ ADD_FIELD32(sdp2_data,6,1); // data from gpio sdp
+ ADD_FIELD32(spd3_data,7,1); // data frmo gpio sdp
+ ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2
+ ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2
+ ADD_FIELD32(asdchk,12,1); // initiate auto-speed-detection
+ ADD_FIELD32(eerst,13,1); // reset the eeprom
+ ADD_FIELD32(spd_byps,15,1); // bypass speed select
+ ADD_FIELD32(ro_dis,17,1); // disable relaxed memory ordering
+ ADD_FIELD32(vreg,21,1); // power down the voltage regulator
+ ADD_FIELD32(link_mode,22,2); // interface to talk to the link
+ ADD_FIELD32(iame, 27,1); // interrupt acknowledge auto-mask ??
+ ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device
+ ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ??
+ };
+ CTRL_EXT ctrl_ext;
+
+ struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(data,0,16); // data
+ ADD_FIELD32(regadd,16,5); // register address
+ ADD_FIELD32(phyadd,21,5); // phy addresses
+ ADD_FIELD32(op,26,2); // opcode
+ ADD_FIELD32(r,28,1); // ready
+ ADD_FIELD32(i,29,1); // interrupt
+ ADD_FIELD32(e,30,1); // error
+ };
+ MDIC mdic;
+
+ struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(txdw,0,1) // tx descr witten back
+ ADD_FIELD32(txqe,1,1) // tx queue empty
+ ADD_FIELD32(lsc,2,1) // link status change
+ ADD_FIELD32(rxseq,3,1) // rcv sequence error
+ ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh
+ ADD_FIELD32(rsvd1,5,1) // reserved
+ ADD_FIELD32(rxo,6,1) // receive overrunn
+ ADD_FIELD32(rxt0,7,1) // receiver timer interrupt
+ ADD_FIELD32(mdac,9,1) // mdi/o access complete
+ ADD_FIELD32(rxcfg,10,1) // recv /c/ ordered sets
+ ADD_FIELD32(phyint,12,1) // phy interrupt
+ ADD_FIELD32(gpi1,13,1) // gpi int 1
+ ADD_FIELD32(gpi2,14,1) // gpi int 2
+ ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
+ ADD_FIELD32(srpd,16,1) // small receive packet detected
+ ADD_FIELD32(ack,17,1); // receive ack frame
+ ADD_FIELD32(int_assert, 31,0); // interrupt caused a system interrupt
+ };
+ ICR icr;
+
+ uint32_t imr; // register that contains the current interrupt mask
+
+ struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval
+ // specified in 256ns interrupts
+ };
+ ITR itr;
+
+ // When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write
+ // causes the IAM register contents to be written into the IMC
+ // automatically clearing all interrupts that have a bit in the IAM set
+ uint32_t iam;
+
+ struct RCTL : public Reg<uint32_t> { // 0x0100 RCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rst,0,1); // Reset
+ ADD_FIELD32(en,1,1); // Enable
+ ADD_FIELD32(sbp,2,1); // Store bad packets
+ ADD_FIELD32(upe,3,1); // Unicast Promiscuous enabled
+ ADD_FIELD32(mpe,4,1); // Multicast promiscuous enabled
+ ADD_FIELD32(lpe,5,1); // long packet reception enabled
+ ADD_FIELD32(lbm,6,2); //
+ ADD_FIELD32(rdmts,8,2); //
+ ADD_FIELD32(mo,12,2); //
+ ADD_FIELD32(mdr,14,1); //
+ ADD_FIELD32(bam,15,1); //
+ ADD_FIELD32(bsize,16,2); //
+ ADD_FIELD32(vfe,18,1); //
+ ADD_FIELD32(cfien,19,1); //
+ ADD_FIELD32(cfi,20,1); //
+ ADD_FIELD32(dpf,22,1); // discard pause frames
+ ADD_FIELD32(pmcf,23,1); // pass mac control frames
+ ADD_FIELD32(bsex,25,1); // buffer size extension
+ ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet
+ int descSize()
+ {
+ switch(bsize()) {
+ case 0: return bsex() ? 2048 : -1;
+ case 1: return bsex() ? 1024 : 16384;
+ case 2: return bsex() ? 512 : 8192;
+ case 3: return bsex() ? 256 : 4096;
+ default:
+ return -1;
+ }
+ }
+ };
+ RCTL rctl;
+
+ struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(ttv,0,16); // Transmit Timer Value
+ };
+ FCTTV fcttv;
+
+ struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rst,0,1); // Reset
+ ADD_FIELD32(en,1,1); // Enable
+ ADD_FIELD32(bce,2,1); // busy check enable
+ ADD_FIELD32(psp,3,1); // pad short packets
+ ADD_FIELD32(ct,4,8); // collision threshold
+ ADD_FIELD32(cold,12,10); // collision distance
+ ADD_FIELD32(swxoff,22,1); // software xoff transmission
+ ADD_FIELD32(pbe,23,1); // packet burst enable
+ ADD_FIELD32(rtlc,24,1); // retransmit late collisions
+ ADD_FIELD32(nrtu,25,1); // on underrun no TX
+ ADD_FIELD32(mulr,26,1); // multiple request
+ };
+ TCTL tctl;
+
+ struct PBA : public Reg<uint32_t> { // 0x1000 PBA Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rxa,0,16);
+ ADD_FIELD32(txa,16,16);
+ };
+ PBA pba;
+
+ struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have
+ // a larger buffer
+ ADD_FIELD32(xone, 31,1);
+ };
+ FCRTL fcrtl;
+
+ struct FCRTH : public Reg<uint32_t> { // 0x2168 FCRTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have
+ //a larger buffer
+ ADD_FIELD32(xfce, 31,1);
+ };
+ FCRTH fcrth;
+
+ struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
+ using Reg<uint64_t>::operator=;
+ ADD_FIELD64(rdbal,4,28); // base address of rx descriptor ring
+ ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
+ };
+ RDBA rdba;
+
+ struct RDLEN : public Reg<uint32_t> { // 0x2808 RDLEN Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
+ };
+ RDLEN rdlen;
+
+ struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rdh,0,16); // head of the descriptor ring
+ };
+ RDH rdh;
+
+ struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(rdt,0,16); // tail of the descriptor ring
+ };
+ RDT rdt;
+
+ struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(delay,0,16); // receive delay timer
+ ADD_FIELD32(fpd, 31,1); // flush partial descriptor block ??
+ };
+ RDTR rdtr;
+
+ struct RXDCTL : public Reg<uint32_t> { // 0x2828 RXDCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(pthresh,0,6); // prefetch threshold, less that this
+ // consider prefetch
+ ADD_FIELD32(hthresh,8,6); // number of descriptors in host mem to
+ // consider prefetch
+ ADD_FIELD32(wthresh,16,6); // writeback threshold
+ ADD_FIELD32(gran,24,1); // granularity 0 = desc, 1 = cacheline
+ };
+ RXDCTL rxdctl;
+
+ struct RADV : public Reg<uint32_t> { // 0x282C RADV Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(idv,0,16); // absolute interrupt delay
+ };
+ RADV radv;
+
+ struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(idv,0,12); // size to interrutp on small packets
+ };
+ RSRPD rsrpd;
+
+ struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
+ using Reg<uint64_t>::operator=;
+ ADD_FIELD64(tdbal,4,28); // base address of transmit descriptor ring
+ ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
+ };
+ TDBA tdba;
+
+ struct TDLEN : public Reg<uint32_t> { // 0x3808 TDLEN Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
+ };
+ TDLEN tdlen;
+
+ struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(tdh,0,16); // head of the descriptor ring
+ };
+ TDH tdh;
+
+ struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
+ };
+ TDT tdt;
+
+ struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(idv,0,16); // interrupt delay
+ };
+ TIDV tidv;
+
+ struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(pthresh, 0,6); // if number of descriptors control has is
+ // below this number, a prefetch is considered
+ ADD_FIELD32(hthresh,8,8); // number of valid descriptors is host memory
+ // before a prefetch is considered
+ ADD_FIELD32(wthresh,16,6); // number of descriptors to keep until
+ // writeback is considered
+ ADD_FIELD32(gran, 24,1); // granulatiry of above values (0 = cacheline,
+ // 1 == desscriptor)
+ ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt
+ // below this level
+ };
+ TXDCTL txdctl;
+
+ struct TADV : public Reg<uint32_t> { // 0x382C TADV Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(idv,0,16); // absolute interrupt delay
+ };
+ TADV tadv;
+
+ struct 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);
+ };
+ RXCSUM rxcsum;
+
+ struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(smbus,0,1); // SMBus enabled #####
+ ADD_FIELD32(asf,1,1); // ASF enabled #####
+ ADD_FIELD32(ronforce,2,1); // reset of force
+ ADD_FIELD32(rsvd,3,5); // reserved
+ ADD_FIELD32(rmcp1,8,1); // rcmp1 filtering
+ ADD_FIELD32(rmcp2,9,1); // rcmp2 filtering
+ ADD_FIELD32(ipv4,10,1); // enable ipv4
+ ADD_FIELD32(ipv6,11,1); // enable ipv6
+ ADD_FIELD32(snap,12,1); // accept snap
+ ADD_FIELD32(arp,13,1); // filter arp #####
+ ADD_FIELD32(neighbor,14,1); // neighbor discovery
+ ADD_FIELD32(arp_resp,15,1); // arp response
+ ADD_FIELD32(tcorst,16,1); // tco reset happened
+ ADD_FIELD32(rcvtco,17,1); // receive tco enabled ######
+ ADD_FIELD32(blkphyrst,18,1);// block phy resets ########
+ ADD_FIELD32(rcvall,19,1); // receive all
+ ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ######
+ ADD_FIELD32(mng2host,21,1); // mng2 host packets #######
+ ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering
+ ADD_FIELD32(xsumfilter,23,1); // checksum filtering
+ ADD_FIELD32(brfilter,24,1); // broadcast filtering
+ ADD_FIELD32(smbreq,25,1); // smb request
+ ADD_FIELD32(smbgnt,26,1); // smb grant
+ ADD_FIELD32(smbclkin,27,1); // smbclkin
+ ADD_FIELD32(smbdatain,28,1); // smbdatain
+ ADD_FIELD32(smbdataout,29,1); // smb data out
+ ADD_FIELD32(smbclkout,30,1); // smb clock out
+ };
+ MANC manc;
};
}; // iGbReg namespace
diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc
index 5083c9c8d..9fa0cedde 100644
--- a/src/dev/ide_disk.cc
+++ b/src/dev/ide_disk.cc
@@ -48,7 +48,7 @@
#include "dev/alpha/tsunami_pchip.hh"
#include "sim/builder.hh"
#include "sim/sim_object.hh"
-#include "sim/root.hh"
+#include "sim/core.hh"
#include "arch/isa_traits.hh"
using namespace std;
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
index c56eba267..cd7a5296a 100644
--- a/src/dev/io_device.hh
+++ b/src/dev/io_device.hh
@@ -132,6 +132,7 @@ class DmaPort : public Port
bool dmaPending() { return pendingCount > 0; }
+ int cacheBlockSize() { return peerBlockSize(); }
unsigned int drain(Event *de);
};
@@ -256,15 +257,22 @@ class DmaDevice : public PioDevice
virtual ~DmaDevice();
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
- { dmaPort->dmaAction(Packet::WriteInvalidateReq, addr, size, event, data) ; }
+ {
+ dmaPort->dmaAction(MemCmd::WriteInvalidateReq,
+ addr, size, event, data);
+ }
- void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL)
- { dmaPort->dmaAction(Packet::ReadReq, addr, size, event, data); }
+ void dmaRead(Addr addr, int size, Event *event, uint8_t *data)
+ {
+ dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data);
+ }
bool dmaPending() { return dmaPort->dmaPending(); }
virtual unsigned int drain(Event *de);
+ int cacheBlockSize() { return dmaPort->cacheBlockSize(); }
+
virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "pio") {
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
index 74f9d88d1..86f56b62e 100644
--- a/src/dev/ns_gige.cc
+++ b/src/dev/ns_gige.cc
@@ -92,28 +92,30 @@ NSGigE::NSGigE(Params *p)
: PciDev(p), ioEnable(false),
txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
- txXferLen(0), rxXferLen(0), clock(p->clock),
- txState(txIdle), txEnable(false), CTDD(false),
+ txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
+ clock(p->clock),
+ txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
- rxEnable(false), CRDD(false), rxPktBytes(0),
+ rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
- eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
+ eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
+ eepromOpcode(0), eepromAddress(0), eepromData(0),
+ dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
+ dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
+ rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
+ txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
+ rxDmaReadEvent(this), rxDmaWriteEvent(this),
txDmaReadEvent(this), txDmaWriteEvent(this),
dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
txDelay(p->tx_delay), rxDelay(p->rx_delay),
rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
- txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
- acceptMulticast(false), acceptUnicast(false),
+ txEvent(this), rxFilterEnable(p->rx_filter),
+ acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
- intrTick(0), cpuPendingIntr(false),
+ intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
intrEvent(0), interface(0)
{
- intrDelay = p->intr_delay;
- dmaReadDelay = p->dma_read_delay;
- dmaWriteDelay = p->dma_write_delay;
- dmaReadFactor = p->dma_read_factor;
- dmaWriteFactor = p->dma_write_factor;
regsReset();
memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index 1c2465dd1..f906e69cf 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -51,7 +51,7 @@
#include "sim/builder.hh"
#include "sim/byteswap.hh"
#include "sim/param.hh"
-#include "sim/root.hh"
+#include "sim/core.hh"
using namespace std;
diff --git a/src/dev/platform.hh b/src/dev/platform.hh
index 1940dcad6..aceec0970 100644
--- a/src/dev/platform.hh
+++ b/src/dev/platform.hh
@@ -55,9 +55,6 @@ class Platform : public SimObject
/** Pointer to the interrupt controller */
IntrControl *intrctrl;
- /** Pointer to the UART, set by the uart */
- Uart *uart;
-
/** Pointer to the system for info about the memory system. */
System *system;
diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc
index 77aafd9fa..c6ff9c1c6 100644
--- a/src/dev/simconsole.cc
+++ b/src/dev/simconsole.cc
@@ -56,17 +56,31 @@
using namespace std;
-////////////////////////////////////////////////////////////////////////
-//
-//
-SimConsole::Event::Event(SimConsole *c, int fd, int e)
+/*
+ * Poll event for the listen socket
+ */
+SimConsole::ListenEvent::ListenEvent(SimConsole *c, int fd, int e)
: PollEvent(fd, e), cons(c)
{
}
void
-SimConsole::Event::process(int revent)
+SimConsole::ListenEvent::process(int revent)
+{
+ cons->accept();
+}
+
+/*
+ * Poll event for the data socket
+ */
+SimConsole::DataEvent::DataEvent(SimConsole *c, int fd, int e)
+ : PollEvent(fd, e), cons(c)
+{
+}
+
+void
+SimConsole::DataEvent::process(int revent)
{
if (revent & POLLIN)
cons->data();
@@ -74,41 +88,76 @@ SimConsole::Event::process(int revent)
cons->detach();
}
-SimConsole::SimConsole(const string &name, ostream *os, int num)
- : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
- listener(NULL), txbuf(16384), rxbuf(16384), outfile(os)
+/*
+ * SimConsole code
+ */
+SimConsole::SimConsole(const string &name, ostream *os, int num, int port)
+ : SimObject(name), listenEvent(NULL), dataEvent(NULL), number(num),
+ data_fd(-1), txbuf(16384), rxbuf(16384), outfile(os)
#if TRACING_ON == 1
, linebuf(16384)
#endif
{
if (outfile)
outfile->setf(ios::unitbuf);
+
+ if (port)
+ listen(port);
}
SimConsole::~SimConsole()
{
- close();
+ if (data_fd != -1)
+ ::close(data_fd);
+
+ if (listenEvent)
+ delete listenEvent;
+
+ if (dataEvent)
+ delete dataEvent;
}
+///////////////////////////////////////////////////////////////////////
+// socket creation and console attach
+//
+
void
-SimConsole::close()
+SimConsole::listen(int port)
{
- if (in_fd != -1)
- ::close(in_fd);
+ while (!listener.listen(port, true)) {
+ DPRINTF(Console,
+ ": can't bind address console port %d inuse PID %d\n",
+ port, getpid());
+ port++;
+ }
- if (out_fd != in_fd && out_fd != -1)
- ::close(out_fd);
+ int p1, p2;
+ p2 = name().rfind('.') - 1;
+ p1 = name().rfind('.', p2);
+ ccprintf(cerr, "Listening for %s connection on port %d\n",
+ name().substr(p1+1,p2-p1), port);
+
+ listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(listenEvent);
}
void
-SimConsole::attach(int in, int out, ConsoleListener *l)
+SimConsole::accept()
{
- in_fd = in;
- out_fd = out;
- listener = l;
+ if (!listener.islistening())
+ panic("%s: cannot accept a connection if not listening!", name());
- event = new Event(this, in, POLLIN);
- pollQueue.schedule(event);
+ int fd = listener.accept(true);
+ if (data_fd != -1) {
+ char message[] = "console already attached!\n";
+ ::write(fd, message, sizeof(message));
+ ::close(fd);
+ return;
+ }
+
+ data_fd = fd;
+ dataEvent = new DataEvent(this, data_fd, POLLIN);
+ pollQueue.schedule(dataEvent);
stringstream stream;
ccprintf(stream, "==== m5 slave console: Console %d ====", number);
@@ -119,26 +168,23 @@ SimConsole::attach(int in, int out, ConsoleListener *l)
write((const uint8_t *)stream.str().c_str(), stream.str().size());
-
DPRINTFN("attach console %d\n", number);
- txbuf.readall(out);
+ txbuf.readall(data_fd);
}
void
SimConsole::detach()
{
- close();
- in_fd = -1;
- out_fd = -1;
-
- pollQueue.remove(event);
-
- if (listener) {
- listener->add(this);
- listener = NULL;
+ if (data_fd != -1) {
+ ::close(data_fd);
+ data_fd = -1;
}
+ pollQueue.remove(dataEvent);
+ delete dataEvent;
+ dataEvent = NULL;
+
DPRINTFN("detach console %d\n", number);
}
@@ -159,12 +205,12 @@ SimConsole::data()
size_t
SimConsole::read(uint8_t *buf, size_t len)
{
- if (in_fd < 0)
+ if (data_fd < 0)
panic("Console not properly attached.\n");
size_t ret;
do {
- ret = ::read(in_fd, buf, len);
+ ret = ::read(data_fd, buf, len);
} while (ret == -1 && errno == EINTR);
@@ -183,12 +229,12 @@ SimConsole::read(uint8_t *buf, size_t len)
size_t
SimConsole::write(const uint8_t *buf, size_t len)
{
- if (out_fd < 0)
+ if (data_fd < 0)
panic("Console not properly attached.\n");
size_t ret;
for (;;) {
- ret = ::write(out_fd, buf, len);
+ ret = ::write(data_fd, buf, len);
if (ret >= 0)
break;
@@ -268,7 +314,7 @@ SimConsole::out(char c)
txbuf.write(c);
- if (out_fd >= 0)
+ if (data_fd >= 0)
write(c);
if (outfile)
@@ -279,23 +325,11 @@ SimConsole::out(char c)
}
-
-void
-SimConsole::serialize(ostream &os)
-{
-}
-
-void
-SimConsole::unserialize(Checkpoint *cp, const std::string &section)
-{
-}
-
-
BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
- SimObjectParam<ConsoleListener *> listener;
SimObjectParam<IntrControl *> intr_control;
Param<string> output;
+ Param<int> port;
Param<bool> append_name;
Param<int> number;
@@ -303,9 +337,9 @@ END_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole)
- INIT_PARAM(listener, "console listener"),
INIT_PARAM(intr_control, "interrupt controller"),
INIT_PARAM(output, "file to dump output to"),
+ INIT_PARAM(port, ""),
INIT_PARAM_DFLT(append_name, "append name() to filename", true),
INIT_PARAM_DFLT(number, "console number", 0)
@@ -322,95 +356,7 @@ CREATE_SIM_OBJECT(SimConsole)
stream = simout.find(filename);
}
- SimConsole *console = new SimConsole(getInstanceName(), stream, number);
- ((ConsoleListener *)listener)->add(console);
-
- return console;
+ return new SimConsole(getInstanceName(), stream, number, port);
}
REGISTER_SIM_OBJECT("SimConsole", SimConsole)
-
-////////////////////////////////////////////////////////////////////////
-//
-//
-
-ConsoleListener::ConsoleListener(const string &name)
- : SimObject(name), event(NULL)
-{}
-
-ConsoleListener::~ConsoleListener()
-{
- if (event)
- delete event;
-}
-
-void
-ConsoleListener::Event::process(int revent)
-{
- listener->accept();
-}
-
-///////////////////////////////////////////////////////////////////////
-// socket creation and console attach
-//
-
-void
-ConsoleListener::listen(int port)
-{
- while (!listener.listen(port, true)) {
- DPRINTF(Console,
- ": can't bind address console port %d inuse PID %d\n",
- port, getpid());
- port++;
- }
-
- ccprintf(cerr, "Listening for console connection on port %d\n", port);
-
- event = new Event(this, listener.getfd(), POLLIN);
- pollQueue.schedule(event);
-}
-
-void
-ConsoleListener::add(SimConsole *cons)
-{ ConsoleList.push_back(cons);}
-
-void
-ConsoleListener::accept()
-{
- if (!listener.islistening())
- panic("%s: cannot accept a connection if not listening!", name());
-
- int sfd = listener.accept(true);
- if (sfd != -1) {
- iter_t i = ConsoleList.begin();
- iter_t end = ConsoleList.end();
- if (i == end) {
- close(sfd);
- } else {
- (*i)->attach(sfd, this);
- i = ConsoleList.erase(i);
- }
- }
-}
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
-
- Param<int> port;
-
-END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
-
- INIT_PARAM_DFLT(port, "listen port", 3456)
-
-END_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
-
-CREATE_SIM_OBJECT(ConsoleListener)
-{
- ConsoleListener *listener = new ConsoleListener(getInstanceName());
- listener->listen(port);
-
- return listener;
-}
-
-REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener)
diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh
index ec99c6028..18a193493 100644
--- a/src/dev/simconsole.hh
+++ b/src/dev/simconsole.hh
@@ -53,30 +53,47 @@ class SimConsole : public SimObject
Uart *uart;
protected:
- class Event : public PollEvent
+ class ListenEvent : public PollEvent
{
protected:
SimConsole *cons;
public:
- Event(SimConsole *c, int fd, int e);
+ ListenEvent(SimConsole *c, int fd, int e);
void process(int revent);
};
- friend class Event;
- Event *event;
+ friend class ListenEvent;
+ ListenEvent *listenEvent;
+
+ class DataEvent : public PollEvent
+ {
+ protected:
+ SimConsole *cons;
+
+ public:
+ DataEvent(SimConsole *c, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class DataEvent;
+ DataEvent *dataEvent;
protected:
int number;
- int in_fd;
- int out_fd;
- ConsoleListener *listener;
+ int data_fd;
public:
- SimConsole(const std::string &name, std::ostream *os, int num);
+ SimConsole(const std::string &name, std::ostream *os, int num, int port);
~SimConsole();
protected:
+ ListenSocket listener;
+
+ void listen(int port);
+ void accept();
+
+ protected:
CircleBuf txbuf;
CircleBuf rxbuf;
std::ostream *outfile;
@@ -88,17 +105,13 @@ class SimConsole : public SimObject
///////////////////////
// Terminal Interface
- void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); }
- void attach(int in, int out, ConsoleListener *l = NULL);
- void detach();
-
void data();
- void close();
void read(uint8_t &c) { read(&c, 1); }
size_t read(uint8_t *buf, size_t len);
void write(uint8_t c) { write(&c, 1); }
size_t write(const uint8_t *buf, size_t len);
+ void detach();
public:
/////////////////
@@ -126,43 +139,6 @@ class SimConsole : public SimObject
//Ask the console if data is available
bool dataAvailable() { return !rxbuf.empty(); }
-
- virtual void serialize(std::ostream &os);
- virtual void unserialize(Checkpoint *cp, const std::string &section);
-};
-
-class ConsoleListener : public SimObject
-{
- protected:
- class Event : public PollEvent
- {
- protected:
- ConsoleListener *listener;
-
- public:
- Event(ConsoleListener *l, int fd, int e)
- : PollEvent(fd, e), listener(l) {}
- void process(int revent);
- };
-
- friend class Event;
- Event *event;
-
- typedef std::list<SimConsole *> list_t;
- typedef list_t::iterator iter_t;
- list_t ConsoleList;
-
- protected:
- ListenSocket listener;
-
- public:
- ConsoleListener(const std::string &name);
- ~ConsoleListener();
-
- void add(SimConsole *cons);
-
- void accept();
- void listen(int port);
};
#endif // __CONSOLE_HH__
diff --git a/src/dev/sparc/SConscript b/src/dev/sparc/SConscript
index 44b082b68..8511b16fb 100644
--- a/src/dev/sparc/SConscript
+++ b/src/dev/sparc/SConscript
@@ -29,21 +29,10 @@
# Authors: Steve Reinhardt
# Gabe Black
-import os.path, sys
+Import('*')
-# Import build environment variable from SConstruct.
-Import('env')
-
-sources = []
-
-sources += Split('''
- dtod.cc
- t1000.cc
- mm_disk.cc
- ''')
-
-# Convert file names to SCons File objects. This takes care of the
-# path relative to the top of the directory tree.
-sources = [File(s) for s in sources]
-
-Return('sources')
+if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'sparc':
+ Source('dtod.cc')
+ Source('iob.cc')
+ Source('t1000.cc')
+ Source('mm_disk.cc')
diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc
new file mode 100644
index 000000000..e686e51f7
--- /dev/null
+++ b/src/dev/sparc/iob.cc
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/** @file
+ * This device implemetns the niagara I/O bridge chip. It manages incomming
+ * interrupts and posts them to the CPU when needed. It holds mask registers and
+ * various status registers for CPUs to check what interrupts are pending as
+ * well as facilities to send IPIs to other cpus.
+ */
+
+#include <cstring>
+
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/faults.hh"
+#include "base/trace.hh"
+#include "cpu/intr_control.hh"
+#include "dev/sparc/iob.hh"
+#include "dev/platform.hh"
+#include "mem/port.hh"
+#include "mem/packet_access.hh"
+#include "sim/builder.hh"
+#include "sim/faults.hh"
+#include "sim/system.hh"
+
+Iob::Iob(Params *p)
+ : PioDevice(p), ic(p->platform->intrctrl)
+{
+ iobManAddr = ULL(0x9800000000);
+ iobManSize = ULL(0x0100000000);
+ iobJBusAddr = ULL(0x9F00000000);
+ iobJBusSize = ULL(0x0100000000);
+ assert (params()->system->threadContexts.size() <= MaxNiagaraProcs);
+ // Get the interrupt controller from the platform
+ ic = platform->intrctrl;
+
+ for (int x = 0; x < NumDeviceIds; ++x) {
+ intMan[x].cpu = 0;
+ intMan[x].vector = 0;
+ intCtl[x].mask = true;
+ intCtl[x].pend = false;
+ }
+
+}
+
+Tick
+Iob::read(PacketPtr pkt)
+{
+ assert(pkt->result == Packet::Unknown);
+
+ if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
+ readIob(pkt);
+ else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
+ readJBus(pkt);
+ else
+ panic("Invalid address reached Iob\n");
+
+ pkt->result = Packet::Success;
+ return pioDelay;
+}
+
+void
+Iob::readIob(PacketPtr pkt)
+{
+ Addr accessAddr = pkt->getAddr() - iobManAddr;
+ int index;
+ uint64_t data;
+
+ if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
+ index = (accessAddr - IntManAddr) >> 3;
+ data = intMan[index].cpu << 8 | intMan[index].vector << 0;
+ pkt->set(data);
+ return;
+ }
+
+ if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
+ index = (accessAddr - IntManAddr) >> 3;
+ data = intCtl[index].mask ? 1 << 2 : 0 |
+ intCtl[index].pend ? 1 << 0 : 0;
+ pkt->set(data);
+ return;
+ }
+
+ if (accessAddr == JIntVecAddr) {
+ pkt->set(jIntVec);
+ return;
+ }
+
+ panic("Read to unknown IOB offset 0x%x\n", accessAddr);
+}
+
+void
+Iob::readJBus(PacketPtr pkt)
+{
+ Addr accessAddr = pkt->getAddr() - iobJBusAddr;
+ int cpuid = pkt->req->getCpuNum();
+ int index;
+ uint64_t data;
+
+
+
+
+ if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) {
+ index = (accessAddr - JIntData0Addr) >> 3;
+ pkt->set(jBusData0[index]);
+ return;
+ }
+
+ if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) {
+ index = (accessAddr - JIntData1Addr) >> 3;
+ pkt->set(jBusData1[index]);
+ return;
+ }
+
+ if (accessAddr == JIntDataA0Addr) {
+ pkt->set(jBusData0[cpuid]);
+ return;
+ }
+
+ if (accessAddr == JIntDataA1Addr) {
+ pkt->set(jBusData1[cpuid]);
+ return;
+ }
+
+ if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
+ index = (accessAddr - JIntBusyAddr) >> 3;
+ data = jIntBusy[index].busy ? 1 << 5 : 0 |
+ jIntBusy[index].source;
+ pkt->set(data);
+ return;
+ }
+ if (accessAddr == JIntABusyAddr) {
+ data = jIntBusy[cpuid].busy ? 1 << 5 : 0 |
+ jIntBusy[cpuid].source;
+ pkt->set(data);
+ return;
+ };
+
+ panic("Read to unknown JBus offset 0x%x\n", accessAddr);
+}
+
+Tick
+Iob::write(PacketPtr pkt)
+{
+ if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize)
+ writeIob(pkt);
+ else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize)
+ writeJBus(pkt);
+ else
+ panic("Invalid address reached Iob\n");
+
+
+ pkt->result = Packet::Success;
+ return pioDelay;
+}
+
+void
+Iob::writeIob(PacketPtr pkt)
+{
+ Addr accessAddr = pkt->getAddr() - iobManAddr;
+ int index;
+ uint64_t data;
+
+ if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) {
+ index = (accessAddr - IntManAddr) >> 3;
+ data = pkt->get<uint64_t>();
+ intMan[index].cpu = bits(data,12,8);
+ intMan[index].vector = bits(data,5,0);
+ DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index,
+ intMan[index].cpu, intMan[index].vector);
+ return;
+ }
+
+ if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) {
+ index = (accessAddr - IntManAddr) >> 3;
+ data = pkt->get<uint64_t>();
+ intCtl[index].mask = bits(data,2,2);
+ if (bits(data,1,1))
+ intCtl[index].pend = false;
+ DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index,
+ intCtl[index].pend, bits(data,2,2));
+ return;
+ }
+
+ if (accessAddr == JIntVecAddr) {
+ jIntVec = bits(pkt->get<uint64_t>(), 5,0);
+ DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec);
+ return;
+ }
+
+ if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) {
+ Type type;
+ int cpu_id;
+ int vector;
+ index = (accessAddr - IntManAddr) >> 3;
+ data = pkt->get<uint64_t>();
+ type = (Type)bits(data,17,16);
+ cpu_id = bits(data, 12,8);
+ vector = bits(data,5,0);
+ generateIpi(type,cpu_id, vector);
+ return;
+ }
+
+ panic("Write to unknown IOB offset 0x%x\n", accessAddr);
+}
+
+void
+Iob::writeJBus(PacketPtr pkt)
+{
+ Addr accessAddr = pkt->getAddr() - iobJBusAddr;
+ int cpuid = pkt->req->getCpuNum();
+ int index;
+ uint64_t data;
+
+ if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) {
+ index = (accessAddr - JIntBusyAddr) >> 3;
+ data = pkt->get<uint64_t>();
+ jIntBusy[index].busy = bits(data,5,5);
+ DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index,
+ jIntBusy[index].busy);
+ return;
+ }
+ if (accessAddr == JIntABusyAddr) {
+ data = pkt->get<uint64_t>();
+ jIntBusy[cpuid].busy = bits(data,5,5);
+ DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid,
+ jIntBusy[cpuid].busy);
+ return;
+ };
+
+ panic("Write to unknown JBus offset 0x%x\n", accessAddr);
+}
+
+void
+Iob::receiveDeviceInterrupt(DeviceId devid)
+{
+ assert(devid < NumDeviceIds);
+ if (intCtl[devid].mask)
+ return;
+ intCtl[devid].mask = true;
+ intCtl[devid].pend = true;
+ DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n",
+ devid, intMan[devid].cpu, intMan[devid].vector);
+ ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector);
+}
+
+
+void
+Iob::generateIpi(Type type, int cpu_id, int vector)
+{
+ SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
+ if (cpu_id >= sys->getNumCPUs())
+ return;
+
+ switch (type) {
+ case 0: // interrupt
+ DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n",
+ cpu_id, vector);
+ ic->post(cpu_id, SparcISA::IT_INT_VEC, vector);
+ break;
+ case 1: // reset
+ warn("Sending reset to CPU: %d\n", cpu_id);
+ if (vector != por->trapType())
+ panic("Don't know how to set non-POR reset to cpu\n");
+ por->invoke(sys->threadContexts[cpu_id]);
+ sys->threadContexts[cpu_id]->activate();
+ break;
+ case 2: // idle -- this means stop executing and don't wake on interrupts
+ DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id);
+ sys->threadContexts[cpu_id]->halt();
+ break;
+ case 3: // resume
+ DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id);
+ sys->threadContexts[cpu_id]->activate();
+ break;
+ default:
+ panic("Invalid type to generate ipi\n");
+ }
+}
+
+bool
+Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1)
+{
+ // If we are already dealing with an interrupt for that cpu we can't deal
+ // with another one right now... come back later
+ if (jIntBusy[cpu_id].busy)
+ return false;
+
+ DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n",
+ source, cpu_id, jIntVec);
+
+ jIntBusy[cpu_id].busy = true;
+ jIntBusy[cpu_id].source = source;
+ jBusData0[cpu_id] = d0;
+ jBusData1[cpu_id] = d1;
+
+ ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec);
+ return true;
+}
+
+void
+Iob::addressRanges(AddrRangeList &range_list)
+{
+ range_list.clear();
+ range_list.push_back(RangeSize(iobManAddr, iobManSize));
+ range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize));
+}
+
+
+void
+Iob::serialize(std::ostream &os)
+{
+
+ SERIALIZE_SCALAR(jIntVec);
+ SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
+ SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
+ for (int x = 0; x < NumDeviceIds; x++) {
+ nameOut(os, csprintf("%s.Int%d", name(), x));
+ paramOut(os, "cpu", intMan[x].cpu);
+ paramOut(os, "vector", intMan[x].vector);
+ paramOut(os, "mask", intCtl[x].mask);
+ paramOut(os, "pend", intCtl[x].pend);
+ };
+ for (int x = 0; x < MaxNiagaraProcs; x++) {
+ nameOut(os, csprintf("%s.jIntBusy%d", name(), x));
+ paramOut(os, "busy", jIntBusy[x].busy);
+ paramOut(os, "source", jIntBusy[x].source);
+ };
+}
+
+void
+Iob::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(jIntVec);
+ UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs);
+ UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs);
+ for (int x = 0; x < NumDeviceIds; x++) {
+ paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu);
+ paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector);
+ paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask);
+ paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend);
+ };
+ for (int x = 0; x < MaxNiagaraProcs; x++) {
+ paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy);
+ paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source);
+ };
+}
+
+
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob)
+ Param<Tick> pio_latency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+END_DECLARE_SIM_OBJECT_PARAMS(Iob)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Iob)
+
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object")
+
+END_INIT_SIM_OBJECT_PARAMS(Iob)
+
+CREATE_SIM_OBJECT(Iob)
+{
+ Iob::Params *p = new Iob::Params;
+ p->name = getInstanceName();
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->system = system;
+ return new Iob(p);
+}
+
+REGISTER_SIM_OBJECT("Iob", Iob)
diff --git a/src/dev/sparc/iob.hh b/src/dev/sparc/iob.hh
new file mode 100644
index 000000000..c05c4f2ef
--- /dev/null
+++ b/src/dev/sparc/iob.hh
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/** @file
+ * This device implements the niagara I/O Bridge chip. The device manages
+ * internal (ipi) and external (serial, pci via jbus).
+ */
+
+#ifndef __DEV_SPARC_IOB_HH__
+#define __DEV_SPARC_IOB_HH__
+
+#include "base/range.hh"
+#include "dev/io_device.hh"
+#include "dev/disk_image.hh"
+
+class IntrControl;
+
+const int MaxNiagaraProcs = 32;
+// IOB Managment Addresses
+const Addr IntManAddr = 0x0000;
+const Addr IntManSize = 0x0020;
+const Addr IntCtlAddr = 0x0400;
+const Addr IntCtlSize = 0x0020;
+const Addr JIntVecAddr = 0x0A00;
+const Addr IntVecDisAddr = 0x0800;
+const Addr IntVecDisSize = 0x0100;
+
+
+// IOB Control Addresses
+const Addr JIntData0Addr = 0x0400;
+const Addr JIntData1Addr = 0x0500;
+const Addr JIntDataA0Addr = 0x0600;
+const Addr JIntDataA1Addr = 0x0700;
+const Addr JIntBusyAddr = 0x0900;
+const Addr JIntBusySize = 0x0100;
+const Addr JIntABusyAddr = 0x0B00;
+
+
+// IOB Masks
+const uint64_t IntManMask = 0x01F3F;
+const uint64_t IntCtlMask = 0x00006;
+const uint64_t JIntVecMask = 0x0003F;
+const uint64_t IntVecDis = 0x31F3F;
+const uint64_t JIntBusyMask = 0x0003F;
+
+
+class Iob : public PioDevice
+{
+ private:
+ IntrControl *ic;
+ Addr iobManAddr;
+ Addr iobManSize;
+ Addr iobJBusAddr;
+ Addr iobJBusSize;
+ Tick pioDelay;
+
+ enum DeviceId {
+ Interal = 0,
+ Error = 1,
+ SSI = 2,
+ Reserved = 3,
+ NumDeviceIds
+ };
+
+ struct IntMan {
+ int cpu;
+ int vector;
+ };
+
+ struct IntCtl {
+ bool mask;
+ bool pend;
+ };
+
+ struct IntBusy {
+ bool busy;
+ int source;
+ };
+
+ enum Type {
+ Interrupt,
+ Reset,
+ Idle,
+ Resume
+ };
+
+ IntMan intMan[NumDeviceIds];
+ IntCtl intCtl[NumDeviceIds];
+ uint64_t jIntVec;
+ uint64_t jBusData0[MaxNiagaraProcs];
+ uint64_t jBusData1[MaxNiagaraProcs];
+ IntBusy jIntBusy[MaxNiagaraProcs];
+
+ void writeIob(PacketPtr pkt);
+ void writeJBus(PacketPtr pkt);
+ void readIob(PacketPtr pkt);
+ void readJBus(PacketPtr pkt);
+
+
+ public:
+ struct Params : public PioDevice::Params
+ {
+ Tick pio_delay;
+ };
+ protected:
+ const Params *params() const { return (const Params*)_params; }
+
+ public:
+ Iob(Params *p);
+
+ virtual Tick read(PacketPtr pkt);
+ virtual Tick write(PacketPtr pkt);
+ void generateIpi(Type type, int cpu_id, int vector);
+ void receiveDeviceInterrupt(DeviceId devid);
+ bool receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1);
+
+
+ void addressRanges(AddrRangeList &range_list);
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif //__DEV_SPARC_IOB_HH__
+
diff --git a/src/dev/sparc/mm_disk.cc b/src/dev/sparc/mm_disk.cc
index b8cabd0cf..81c5c589a 100644
--- a/src/dev/sparc/mm_disk.cc
+++ b/src/dev/sparc/mm_disk.cc
@@ -45,7 +45,7 @@
#include "sim/system.hh"
MmDisk::MmDisk(Params *p)
- : BasicPioDevice(p), image(p->image), curSector((uint64_t)-1), dirty(false)
+ : BasicPioDevice(p), image(p->image), curSector((off_t)-1), dirty(false)
{
std::memset(&diskData, 0, SectorSize);
pioSize = image->size() * SectorSize;
diff --git a/src/dev/uart.cc b/src/dev/uart.cc
index f769b720b..1c781f76d 100644
--- a/src/dev/uart.cc
+++ b/src/dev/uart.cc
@@ -47,7 +47,6 @@ Uart::Uart(Params *p)
// set back pointers
cons->uart = this;
- platform->uart = this;
}
DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart)
diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh
index a0620c7e0..c28200592 100644
--- a/src/dev/uart8250.hh
+++ b/src/dev/uart8250.hh
@@ -35,7 +35,6 @@
#ifndef __DEV_UART8250_HH__
#define __DEV_UART8250_HH__
-#include "dev/alpha/tsunamireg.h"
#include "base/range.hh"
#include "dev/io_device.hh"
#include "dev/uart.hh"
@@ -54,6 +53,18 @@ const uint8_t IIR_TXID = 0x02; /* Tx Data */
const uint8_t IIR_RXID = 0x04; /* Rx Data */
const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/
+const uint8_t UART_IER_RDI = 0x01;
+const uint8_t UART_IER_THRI = 0x02;
+const uint8_t UART_IER_RLSI = 0x04;
+
+
+const uint8_t UART_LSR_TEMT = 0x40;
+const uint8_t UART_LSR_THRE = 0x20;
+const uint8_t UART_LSR_DR = 0x01;
+
+const uint8_t UART_MCR_LOOP = 0x10;
+
+
class SimConsole;
class Platform;