summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/alpha/alpha_memory.cc72
-rw-r--r--arch/alpha/ev5.hh20
-rw-r--r--arch/alpha/vtophys.cc12
-rw-r--r--base/cprintf_formats.hh3
-rw-r--r--base/inifile.cc2
-rw-r--r--base/loader/elf_object.cc10
-rw-r--r--base/loader/symtab.cc25
-rw-r--r--base/loader/symtab.hh7
-rw-r--r--base/range.hh2
-rw-r--r--base/remote_gdb.cc12
-rw-r--r--base/stats/mysql.hh1
-rw-r--r--base/traceflags.py10
-rw-r--r--cpu/base_cpu.cc4
-rw-r--r--cpu/base_cpu.hh2
-rw-r--r--cpu/exetrace.cc10
-rw-r--r--dev/alpha_console.cc22
-rw-r--r--dev/alpha_console.hh4
-rw-r--r--dev/baddev.cc67
-rw-r--r--dev/baddev.hh85
-rw-r--r--dev/console.cc33
-rw-r--r--dev/console.hh4
-rw-r--r--dev/etherpkt.cc2
-rw-r--r--dev/etherpkt.hh68
-rw-r--r--dev/ide_ctrl.cc684
-rw-r--r--dev/ide_ctrl.hh221
-rw-r--r--dev/ide_disk.cc1165
-rw-r--r--dev/ide_disk.hh347
-rw-r--r--dev/ns_gige.cc2418
-rw-r--r--dev/ns_gige.hh404
-rw-r--r--dev/ns_gige_reg.h372
-rw-r--r--dev/pciconfigall.cc185
-rw-r--r--dev/pciconfigall.hh128
-rw-r--r--dev/pcidev.cc388
-rw-r--r--dev/pcidev.hh171
-rw-r--r--dev/platform.cc36
-rw-r--r--dev/platform.hh65
-rw-r--r--dev/tsunami.cc109
-rw-r--r--dev/tsunami.hh122
-rw-r--r--dev/tsunami_cchip.cc390
-rw-r--r--dev/tsunami_cchip.hh150
-rw-r--r--dev/tsunami_io.cc436
-rw-r--r--dev/tsunami_io.hh258
-rw-r--r--dev/tsunami_pchip.cc317
-rw-r--r--dev/tsunami_pchip.hh117
-rw-r--r--dev/tsunami_uart.cc295
-rw-r--r--dev/tsunami_uart.hh87
-rw-r--r--dev/tsunamireg.h120
-rw-r--r--kern/linux/linux.hh34
-rw-r--r--kern/linux/linux_syscalls.cc374
-rw-r--r--kern/linux/linux_syscalls.hh322
-rw-r--r--kern/linux/linux_system.cc334
-rw-r--r--kern/linux/linux_system.hh151
-rw-r--r--kern/tru64/tru64_system.cc33
-rw-r--r--kern/tru64/tru64_system.hh4
-rw-r--r--sim/sim_object.cc3
-rw-r--r--sim/system.cc3
-rw-r--r--sim/system.hh2
57 files changed, 10630 insertions, 92 deletions
diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc
index 23815bf01..31f5a9b20 100644
--- a/arch/alpha/alpha_memory.cc
+++ b/arch/alpha/alpha_memory.cc
@@ -44,6 +44,11 @@ using namespace std;
//
// Alpha TLB
//
+#ifdef DEBUG
+bool uncacheBit39 = false;
+bool uncacheBit40 = false;
+#endif
+
AlphaTLB::AlphaTLB(const string &name, int s)
: SimObject(name), size(s), nlu(0)
{
@@ -87,24 +92,27 @@ AlphaTLB::checkCacheability(MemReqPtr &req)
{
// in Alpha, cacheability is controlled by upper-level bits of the
// physical address
- if (req->paddr & PA_UNCACHED_BIT) {
- if (PA_IPR_SPACE(req->paddr)) {
- // IPR memory space not implemented
- if (!req->xc->misspeculating()) {
- switch (req->paddr) {
- case ULL(0xFFFFF00188):
- req->data = 0;
- break;
-
- default:
- panic("IPR memory space not implemented! PA=%x\n",
- req->paddr);
- }
- }
- } else {
- // mark request as uncacheable
- req->flags |= UNCACHEABLE;
- }
+
+ /*
+ * We support having the uncacheable bit in either bit 39 or bit 40.
+ * The Turbolaser platform (and EV5) support having the bit in 39, but
+ * Tsunami (which Linux assumes uses an EV6) generates accesses with
+ * the bit in 40. So we must check for both, but we have debug flags
+ * to catch a weird case where both are used, which shouldn't happen.
+ */
+
+ if (req->paddr & PA_UNCACHED_BIT_43) {
+ // IPR memory space not implemented
+ if (PA_IPR_SPACE(req->paddr))
+ if (!req->xc->misspeculating())
+ panic("IPR memory space not implemented! PA=%x\n",
+ req->paddr);
+
+ // mark request as uncacheable
+ req->flags |= UNCACHEABLE;
+
+ // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
+ req->paddr &= PA_UNCACHED_MASK;
}
}
@@ -290,10 +298,10 @@ AlphaITB::translate(MemReqPtr &req) const
return ITB_Acv_Fault;
}
- // Check for "superpage" mapping: when SP<1> is set, and
- // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
- if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
- VA_SPACE(req->vaddr) == 2) {
+
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
+ // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
+ if (VA_SPACE_EV6(req->vaddr) == 0x7e) {
// only valid in kernel mode
if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
@@ -303,6 +311,13 @@ AlphaITB::translate(MemReqPtr &req) const
}
req->paddr = req->vaddr & PA_IMPL_MASK;
+
+ // sign extend the physical address properly
+ if (req->paddr & PA_UNCACHED_BIT_40)
+ req->paddr |= ULL(0xf0000000000);
+ else
+ req->paddr &= ULL(0xffffffffff);
+
} else {
// not a physical address: need to look up pte
AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
@@ -468,10 +483,8 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
return DTB_Fault_Fault;
}
- // Check for "superpage" mapping: when SP<1> is set, and
- // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
- if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
- VA_SPACE(req->vaddr) == 2) {
+ // Check for "superpage" mapping
+ if (VA_SPACE_EV6(req->vaddr) == 0x7e) {
// only valid in kernel mode
if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) !=
@@ -484,6 +497,13 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
}
req->paddr = req->vaddr & PA_IMPL_MASK;
+
+ // sign extend the physical address properly
+ if (req->paddr & PA_UNCACHED_BIT_40)
+ req->paddr |= ULL(0xf0000000000);
+ else
+ req->paddr &= ULL(0xffffffffff);
+
} else {
if (write)
write_accesses++;
diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh
index 6947ef708..517e1111f 100644
--- a/arch/alpha/ev5.hh
+++ b/arch/alpha/ev5.hh
@@ -32,8 +32,8 @@
#define ALT_MODE_AM(X) (((X) >> 3) & 0x3)
#define DTB_CM_CM(X) (((X) >> 3) & 0x3)
-#define DTB_ASN_ASN(X) (((X) >> 57) & 0x7f)
-#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define DTB_ASN_ASN(X) (((X) >> 57) & 0xff)
+#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07fffffff)
#define DTB_PTE_XRE(X) (((X) >> 8) & 0xf)
#define DTB_PTE_XWE(X) (((X) >> 12) & 0xf)
#define DTB_PTE_FONR(X) (((X) >> 1) & 0x1)
@@ -42,8 +42,8 @@
#define DTB_PTE_ASMA(X) (((X) >> 4) & 0x1)
#define ICM_CM(X) (((X) >> 3) & 0x3)
-#define ITB_ASN_ASN(X) (((X) >> 4) & 0x7f)
-#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define ITB_ASN_ASN(X) (((X) >> 4) & 0xff)
+#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07fffffff)
#define ITB_PTE_XRE(X) (((X) >> 8) & 0xf)
#define ITB_PTE_FONR(X) (((X) >> 1) & 0x1)
#define ITB_PTE_FONW(X) (((X) >> 2) & 0x1)
@@ -54,12 +54,16 @@
#define VA_IMPL_MASK ULL(0x000007ffffffffff)
#define VA_IMPL(X) ((X) & VA_IMPL_MASK)
#define VA_VPN(X) (VA_IMPL(X) >> 13)
-#define VA_SPACE(X) (((X) >> 41) & 0x3)
+#define VA_SPACE_EV5(X) (((X) >> 41) & 0x3)
+#define VA_SPACE_EV6(X) (((X) >> 41) & 0x7f)
#define VA_POFS(X) ((X) & 0x1fff)
-#define PA_IMPL_MASK ULL(0xffffffffff)
-#define PA_UNCACHED_BIT ULL(0x8000000000)
-#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFF00000))
+#define PA_IMPL_MASK ULL(0xfffffffffff) // for Tsunami
+#define PA_UNCACHED_BIT_39 ULL(0x8000000000)
+#define PA_UNCACHED_BIT_40 ULL(0x10000000000)
+#define PA_UNCACHED_BIT_43 ULL(0x80000000000)
+#define PA_UNCACHED_MASK ULL(0x807ffffffff) // Clear PA<42:35>
+#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFFF00000))
#define PA_PFN2PA(X) ((X) << 13)
diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc
index 5e14b06d3..d91d80c83 100644
--- a/arch/alpha/vtophys.cc
+++ b/arch/alpha/vtophys.cc
@@ -96,20 +96,20 @@ vtophys(ExecContext *xc, Addr vaddr)
{
Addr ptbr = xc->regs.ipr[AlphaISA::IPR_PALtemp20];
Addr paddr = 0;
- if (PC_PAL(vaddr)) {
- paddr = vaddr & ~ULL(1);
- } else if (!ptbr) {
- paddr = vaddr;
- } else {
+// if (PC_PAL(vaddr)) {
+// paddr = vaddr & ~ULL(1);
+// } else {
if (vaddr >= ALPHA_K0SEG_BASE && vaddr <= ALPHA_K0SEG_END) {
paddr = ALPHA_K0SEG_TO_PHYS(vaddr);
+ } else if (!ptbr) {
+ paddr = vaddr;
} else {
Addr pte = kernel_pte_lookup(xc->physmem, ptbr, vaddr);
uint64_t entry = xc->physmem->phys_read_qword(pte);
if (pte && entry_valid(entry))
paddr = PMAP_PTE_PA(entry) | (vaddr & PGOFSET);
}
- }
+// }
DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
diff --git a/base/cprintf_formats.hh b/base/cprintf_formats.hh
index d8a8a552b..120dd94b1 100644
--- a/base/cprintf_formats.hh
+++ b/base/cprintf_formats.hh
@@ -279,8 +279,6 @@ template <typename T>
inline void
format_integer(std::ostream &out, const T &data, Format &fmt)
{ _format_integer(out, data, fmt); }
-
-#if 0
inline void
format_integer(std::ostream &out, char data, Format &fmt)
{ _format_integer(out, data, fmt); }
@@ -290,6 +288,7 @@ format_integer(std::ostream &out, unsigned char data, Format &fmt)
inline void
format_integer(std::ostream &out, signed char data, Format &fmt)
{ _format_integer(out, data, fmt); }
+#if 0
inline void
format_integer(std::ostream &out, short data, Format &fmt)
{ _format_integer(out, data, fmt); }
diff --git a/base/inifile.cc b/base/inifile.cc
index 74d47204e..e01032d02 100644
--- a/base/inifile.cc
+++ b/base/inifile.cc
@@ -142,7 +142,7 @@ IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
close(STDOUT_FILENO);
if (dup2(fd[1], STDOUT_FILENO) == -1)
- return 1;
+ exit(1);
execvp("g++", args);
diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc
index b8ffd2b10..a0c0c0551 100644
--- a/base/loader/elf_object.cc
+++ b/base/loader/elf_object.cc
@@ -191,7 +191,7 @@ bool
ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
{
Elf *elf;
- int secidx = 1; // there is a 0 but it is nothing, go figure
+ int sec_idx = 1; // there is a 0 but it is nothing, go figure
Elf_Scn *section;
GElf_Shdr shdr;
Elf_Data *data;
@@ -211,7 +211,7 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
assert(elf != NULL);
// Get the first section
- section = elf_getscn(elf, secidx);
+ section = elf_getscn(elf, sec_idx);
// While there are no more sections
while (section != NULL) {
@@ -226,14 +226,14 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
// loop through all the symbols, only loading global ones
for (ii = 0; ii < count; ++ii) {
gelf_getsym(data, ii, &sym);
- if (GELF_ST_BIND(sym.st_info) & binding) {
+ if (GELF_ST_BIND(sym.st_info) == binding) {
symtab->insert(sym.st_value,
elf_strptr(elf, shdr.sh_link, sym.st_name));
}
}
}
- ++secidx;
- section = elf_getscn(elf, secidx);
+ ++sec_idx;
+ section = elf_getscn(elf, sec_idx);
}
elf_end(elf);
diff --git a/base/loader/symtab.cc b/base/loader/symtab.cc
index 075c197a6..cb18d499c 100644
--- a/base/loader/symtab.cc
+++ b/base/loader/symtab.cc
@@ -95,6 +95,31 @@ SymbolTable::load(const string &filename)
}
bool
+SymbolTable::findNearestSymbol(Addr address, string &symbol) const
+{
+ ATable::const_iterator i = addrTable.lower_bound(address);
+
+ // check for PALCode
+ if (address & 0x1)
+ return false;
+
+ // first check for the end
+ if (i == addrTable.end())
+ i--;
+ else if (i == addrTable.begin() && (*i).first != address)
+ return false;
+ else if ((*i).first != address)
+ i--;
+
+ symbol = (*i).second;
+
+ if (address != (*i).first)
+ symbol += csprintf("+%d", address - (*i).first);
+
+ return true;
+}
+
+bool
SymbolTable::findSymbol(Addr address, string &symbol) const
{
ATable::const_iterator i = addrTable.find(address);
diff --git a/base/loader/symtab.hh b/base/loader/symtab.hh
index 49a811018..1502e4250 100644
--- a/base/loader/symtab.hh
+++ b/base/loader/symtab.hh
@@ -29,14 +29,14 @@
#ifndef __SYMTAB_HH__
#define __SYMTAB_HH__
-#include "base/hashmap.hh"
+#include <map>
#include "targetarch/isa_traits.hh" // for Addr
class SymbolTable
{
private:
- typedef m5::hash_map<Addr, std::string> ATable;
- typedef m5::hash_map<std::string, Addr> STable;
+ typedef std::map<Addr, std::string> ATable;
+ typedef std::map<std::string, Addr> STable;
ATable addrTable;
STable symbolTable;
@@ -49,6 +49,7 @@ class SymbolTable
bool insert(Addr address, std::string symbol);
bool load(const std::string &file);
+ bool findNearestSymbol(Addr address, std::string &symbol) const;
bool findSymbol(Addr address, std::string &symbol) const;
bool findAddress(const std::string &symbol, Addr &address) const;
diff --git a/base/range.hh b/base/range.hh
index d72aa9755..2c4a43f48 100644
--- a/base/range.hh
+++ b/base/range.hh
@@ -225,7 +225,7 @@ inline bool
operator==(const T &pos, const Range<U> &range)
{
assert(range.valid());
- return pos >= range.start && pos < range.end;
+ return pos >= range.start && pos <= range.end;
}
/**
diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc
index e20800d12..7b73d60e9 100644
--- a/base/remote_gdb.cc
+++ b/base/remote_gdb.cc
@@ -332,23 +332,21 @@ RemoteGDB::acc(Addr va, size_t len)
last_va = alpha_round_page(va + len);
do {
- if (va < ALPHA_K0SEG_BASE) {
- DPRINTF(GDBAcc, "acc: Mapping is invalid %#x < K0SEG\n", va);
- return false;
- }
-
- if (va < ALPHA_K1SEG_BASE) {
+ if (va >= ALPHA_K0SEG_BASE && va < ALPHA_K1SEG_BASE) {
if (va < (ALPHA_K0SEG_BASE + pmem->size())) {
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
"%#x < K0SEG + size\n", va);
return true;
} else {
- DPRINTF(GDBAcc, "acc: Mapping is invalid %#x < K0SEG\n",
+ DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
va);
return false;
}
}
+ if (PC_PAL(va) || va < 0x10000)
+ return true;
+
Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20];
pte = kernel_pte_lookup(pmem, ptbr, va);
if (!pte || !entry_valid(pmem->phys_read_qword(pte))) {
diff --git a/base/stats/mysql.hh b/base/stats/mysql.hh
index 4671b89dd..4aa8858b1 100644
--- a/base/stats/mysql.hh
+++ b/base/stats/mysql.hh
@@ -34,6 +34,7 @@
#include "base/stats/output.hh"
+namespace MySQL { class Connection; }
namespace Stats {
class DistDataData;
diff --git a/base/traceflags.py b/base/traceflags.py
index 69f4e7ab8..3d7623965 100644
--- a/base/traceflags.py
+++ b/base/traceflags.py
@@ -57,6 +57,7 @@ baseFlags = [
'Mbox',
'PCIA',
'PCIDEV',
+ 'PciConfigAll',
'ISP',
'BADADDR',
'Console',
@@ -104,7 +105,11 @@ baseFlags = [
'Context',
'Config',
'Sampler',
- 'WriteBarrier'
+ 'WriteBarrier',
+ 'IdeCtrl',
+ 'IdeDisk',
+ 'Tsunami',
+ 'TsunamiUart'
]
#
@@ -119,7 +124,8 @@ compoundFlagMap = {
'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ],
'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ],
'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ],
- 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' ]
+ 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' ],
+ 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ]
}
#############################################################
diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc
index 702a9afe8..4c162986e 100644
--- a/cpu/base_cpu.cc
+++ b/cpu/base_cpu.cc
@@ -209,7 +209,7 @@ BaseCPU::post_interrupt(int int_num, int index)
if (int_num < 0 || int_num >= NumInterruptLevels)
panic("int_num out of bounds\n");
- if (index < 0 || index >= sizeof(uint8_t) * 8)
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
panic("int_num out of bounds\n");
AlphaISA::check_interrupts = 1;
@@ -225,7 +225,7 @@ BaseCPU::clear_interrupt(int int_num, int index)
if (int_num < 0 || int_num >= NumInterruptLevels)
panic("int_num out of bounds\n");
- if (index < 0 || index >= sizeof(uint8_t) * 8)
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
panic("int_num out of bounds\n");
interrupts[int_num] &= ~(1 << index);
diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh
index 9c4026784..9e55d5d3c 100644
--- a/cpu/base_cpu.hh
+++ b/cpu/base_cpu.hh
@@ -48,7 +48,7 @@ class BaseCPU : public SimObject
#ifdef FULL_SYSTEM
protected:
Tick frequency;
- uint8_t interrupts[NumInterruptLevels];
+ uint64_t interrupts[NumInterruptLevels];
uint64_t intstatus;
public:
diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc
index 3e8877e93..a4aaa19db 100644
--- a/cpu/exetrace.cc
+++ b/cpu/exetrace.cc
@@ -48,11 +48,12 @@ using namespace std;
//
-const SymbolTable *debugSymbolTable = NULL;
+SymbolTable *debugSymbolTable = NULL;
void
Trace::InstRecord::dump(ostream &outs)
{
+
if (flags[PRINT_CYCLE])
ccprintf(outs, "%7d: ", cycle);
@@ -64,7 +65,12 @@ Trace::InstRecord::dump(ostream &outs)
if (flags[PRINT_THREAD_NUM])
outs << "T" << thread << " : ";
- outs << "0x" << hex << PC << " : ";
+
+ std::string str;
+ if ((debugSymbolTable) && (debugSymbolTable->findNearestSymbol(PC, str)))
+ outs << "@" << setw(17) << str << " : ";
+ else
+ outs << "0x" << hex << PC << " : ";
//
// Print decoded instruction
diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc
index 04046557a..111b23c81 100644
--- a/dev/alpha_console.cc
+++ b/dev/alpha_console.cc
@@ -49,11 +49,13 @@
#include "mem/functional_mem/memory_control.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
+#include "dev/tsunami_io.hh"
+#include "sim/sim_object.hh"
using namespace std;
AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d,
- System *system, BaseCPU *cpu, TlaserClock *clock,
+ System *system, BaseCPU *cpu, SimObject *clock,
int num_cpus, MemoryController *mmu, Addr a,
HierParams *hier, Bus *bus)
: PioDevice(name), disk(d), console(cons), addr(a)
@@ -78,8 +80,14 @@ AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d,
alphaAccess->numCPUs = num_cpus;
alphaAccess->mem_size = system->physmem->size();
alphaAccess->cpuClock = cpu->getFreq() / 1000000;
- alphaAccess->intrClockFrequency = clock->frequency();
-
+ TsunamiIO *clock_linux = dynamic_cast<TsunamiIO *>(clock);
+ TlaserClock *clock_tru64 = dynamic_cast<TlaserClock *>(clock);
+ if (clock_linux)
+ alphaAccess->intrClockFrequency = clock_linux->frequency();
+ else if (clock_tru64)
+ alphaAccess->intrClockFrequency = clock_tru64->frequency();
+ else
+ panic("clock must be of type TlaserClock or TsunamiIO\n");
alphaAccess->diskUnit = 1;
}
@@ -89,7 +97,7 @@ AlphaConsole::read(MemReqPtr &req, uint8_t *data)
memset(data, 0, req->size);
uint64_t val;
- Addr daddr = req->paddr - addr;
+ Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
switch (daddr) {
case offsetof(AlphaAccess, inputChar):
@@ -137,7 +145,7 @@ AlphaConsole::write(MemReqPtr &req, const uint8_t *data)
return Machine_Check_Fault;
}
- Addr daddr = req->paddr - addr;
+ Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
ExecContext *other_xc;
switch (daddr) {
@@ -266,7 +274,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole)
Param<Addr> addr;
SimObjectParam<System *> system;
SimObjectParam<BaseCPU *> cpu;
- SimObjectParam<TlaserClock *> clock;
+ SimObjectParam<SimObject *> clock;
SimObjectParam<Bus*> io_bus;
SimObjectParam<HierParams *> hier;
@@ -281,7 +289,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole)
INIT_PARAM(addr, "Device Address"),
INIT_PARAM(system, "system object"),
INIT_PARAM(cpu, "Processor"),
- INIT_PARAM(clock, "Turbolaser Clock"),
+ INIT_PARAM(clock, "Clock"),
INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh
index b617b64e7..4986d0e5f 100644
--- a/dev/alpha_console.hh
+++ b/dev/alpha_console.hh
@@ -37,6 +37,8 @@
#include "dev/alpha_access.h"
#include "dev/io_device.hh"
#include "sim/host.hh"
+#include "dev/tsunami_io.hh"
+#include "sim/sim_object.hh"
class BaseCPU;
class SimConsole;
@@ -89,7 +91,7 @@ class AlphaConsole : public PioDevice
public:
/** Standard Constructor */
AlphaConsole(const std::string &name, SimConsole *cons, SimpleDisk *d,
- System *system, BaseCPU *cpu, TlaserClock *clock,
+ System *system, BaseCPU *cpu, SimObject *clock,
int num_cpus, MemoryController *mmu, Addr addr,
HierParams *hier, Bus *bus);
diff --git a/dev/baddev.cc b/dev/baddev.cc
new file mode 100644
index 000000000..8a5d68533
--- /dev/null
+++ b/dev/baddev.cc
@@ -0,0 +1,67 @@
+/* $Id$ */
+
+/* @file
+ * BadDevice implemenation
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "dev/scsi_ctrl.hh"
+#include "dev/baddev.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+BadDevice::BadDevice(const string &name, Addr a, MemoryController *mmu,
+ const string &devicename)
+ : FunctionalMemory(name), addr(a), devname(devicename)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+}
+
+Fault
+BadDevice::read(MemReqPtr &req, uint8_t *data)
+{
+
+ panic("Device %s not imlpmented\n", devname);
+ return No_Fault;
+}
+
+Fault
+BadDevice::write(MemReqPtr &req, const uint8_t *data)
+{
+ panic("Device %s not imlpmented\n", devname);
+ return No_Fault;
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice)
+
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+ Param<string> devicename;
+
+END_DECLARE_SIM_OBJECT_PARAMS(BadDevice)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice)
+
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM(devicename, "Name of device to error on")
+
+END_INIT_SIM_OBJECT_PARAMS(BadDevice)
+
+CREATE_SIM_OBJECT(BadDevice)
+{
+ return new BadDevice(getInstanceName(), addr, mmu, devicename);
+}
+
+REGISTER_SIM_OBJECT("BadDevice", BadDevice)
diff --git a/dev/baddev.hh b/dev/baddev.hh
new file mode 100644
index 000000000..e0304d5d5
--- /dev/null
+++ b/dev/baddev.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * This devices just panics when touched. For example if you have a
+ * kernel that touches the frame buffer which isn't allowed.
+ */
+
+#ifndef __BADDEV_HH__
+#define __BADDEV_HH__
+
+#include "mem/functional_mem/functional_memory.hh"
+
+/**
+ * BadDevice
+ * This device just panics when accessed. It is supposed to warn
+ * the user that the kernel they are running has unsupported
+ * options (i.e. frame buffer)
+ */
+class BadDevice : public FunctionalMemory
+{
+ private:
+ Addr addr;
+ static const Addr size = 0xf;
+
+ std::string devname;
+
+ public:
+ /**
+ * Constructor for the Baddev Class.
+ * @param name name of the object
+ * @param a base address of the write
+ * @param mmu the memory controller
+ * @param devicename device that is not implemented
+ */
+ BadDevice(const std::string &name, Addr a, MemoryController *mmu,
+ const std::string &devicename);
+
+ /**
+ * On a read event we just panic aand hopefully print a
+ * meaningful error message.
+ * @param req Contains the address to read from.
+ * @param data A pointer to write the read data to.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+ /**
+ * On a write event we just panic aand hopefully print a
+ * meaningful error message.
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /** @todo add serialize/unserialize */
+};
+
+#endif // __BADDEV_HH__
diff --git a/dev/console.cc b/dev/console.cc
index 5e7b0abf6..ef3f64d8d 100644
--- a/dev/console.cc
+++ b/dev/console.cc
@@ -49,6 +49,7 @@
#include "mem/functional_mem/memory_control.hh"
#include "sim/builder.hh"
#include "targetarch/ev5.hh"
+#include "dev/platform.hh"
using namespace std;
@@ -76,7 +77,7 @@ SimConsole::SimConsole(const string &name, const string &file, int num)
#if TRACING_ON == 1
linebuf(16384),
#endif
- _status(0), _enable(0), intr(NULL)
+ _status(0), _enable(0), intr(NULL), platform(NULL)
{
if (!file.empty())
outfile = new ofstream(file.c_str());
@@ -322,8 +323,8 @@ SimConsole::clearInt(int i)
{
int old = _status;
_status &= ~i;
- if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr)
- intr->clear(TheISA::INTLEVEL_IRQ0);
+ //if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr)
+ platform->clearConsoleInt();
return old;
}
@@ -331,10 +332,10 @@ SimConsole::clearInt(int i)
void
SimConsole::raiseInt(int i)
{
- int old = _status;
+ //int old = _status;
_status |= i;
- if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr)
- intr->post(TheISA::INTLEVEL_IRQ0);
+ //if (MaskStatus(old, _enable) != MaskStatus(_status, _enable) && intr)
+ platform->postConsoleInt();
}
void
@@ -357,14 +358,21 @@ SimConsole::setInt(int bits)
old = _enable;
_enable |= bits;
- if (MaskStatus(_status, old) != MaskStatus(_status, _enable) && intr) {
+ //if (MaskStatus(_status, old) != MaskStatus(_status, _enable) && intr) {
+ if (intr) {
if (MaskStatus(_status, _enable))
- intr->post(TheISA::INTLEVEL_IRQ0);
+ platform->postConsoleInt();
else
- intr->clear(TheISA::INTLEVEL_IRQ0);
+ platform->clearConsoleInt();
}
}
+void
+SimConsole::setPlatform(Platform *p)
+{
+ platform = p;
+ platform->cons = this;
+}
void
SimConsole::serialize(ostream &os)
@@ -381,6 +389,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
SimObjectParam<ConsoleListener *> listener;
SimObjectParam<IntrControl *> intr_control;
+ SimObjectParam<Platform *> platform;
Param<string> output;
Param<bool> append_name;
Param<int> number;
@@ -391,6 +400,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole)
INIT_PARAM(listener, "console listener"),
INIT_PARAM(intr_control, "interrupt controller"),
+ INIT_PARAM(platform, "platform"),
INIT_PARAM_DFLT(output, "file to dump output to", ""),
INIT_PARAM_DFLT(append_name, "append name() to filename", true),
INIT_PARAM_DFLT(number, "console number", 0)
@@ -413,8 +423,9 @@ CREATE_SIM_OBJECT(SimConsole)
SimConsole *console = new SimConsole(getInstanceName(), filename, number);
((ConsoleListener *)listener)->add(console);
((SimConsole *)console)->initInt(intr_control);
- ((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt |
- SimConsole::ReceiveInterrupt);
+ ((SimConsole *)console)->setPlatform(platform);
+ //((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt |
+ // SimConsole::ReceiveInterrupt);
return console;
}
diff --git a/dev/console.hh b/dev/console.hh
index d2bba4612..703d05d51 100644
--- a/dev/console.hh
+++ b/dev/console.hh
@@ -103,6 +103,8 @@ class SimConsole : public SimObject
// interrupt handle
IntrControl *intr;
+ // Platform so we can post interrupts
+ Platform *platform;
public:
/////////////////
@@ -143,6 +145,8 @@ class SimConsole : public SimObject
void initInt(IntrControl *i);
void setInt(int bits);
+ void setPlatform(Platform *p);
+
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
diff --git a/dev/etherpkt.cc b/dev/etherpkt.cc
index cb6087c89..9eda89e9d 100644
--- a/dev/etherpkt.cc
+++ b/dev/etherpkt.cc
@@ -41,7 +41,7 @@ EtherPacket::serialize(ostream &os)
}
void
-EtherPacket::unserialize(Checkpoint *cp, const std::string &section)
+EtherPacket::unserialize(Checkpoint *cp, const string &section)
{
UNSERIALIZE_SCALAR(length);
data = new uint8_t[length];
diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh
index 27ac526d6..09516c427 100644
--- a/dev/etherpkt.hh
+++ b/dev/etherpkt.hh
@@ -39,8 +39,66 @@
#include "sim/host.hh"
#include "base/refcnt.hh"
+#define EADDR_LEN 6
+
class Checkpoint;
+struct pseudo_header
+{
+ uint32_t src_ip_addr;
+ uint32_t dest_ip_addr;
+ uint16_t protocol;
+ uint16_t len;
+};
+
+/** Ethernet header struct for casting purposes */
+struct eth_header
+{
+ uint8_t dest[EADDR_LEN];
+ uint8_t src[EADDR_LEN];
+ uint16_t type;
+};
+
+struct ip_header
+{
+ uint8_t vers_len;
+ uint8_t service_type;
+ uint16_t dgram_len;
+ uint16_t ID;
+ uint16_t flags_frag_offset;
+ uint8_t TTL;
+ uint8_t protocol;
+ uint16_t hdr_chksum;
+ uint32_t src_ip_addr;
+ uint32_t dest_ip_addr;
+ uint8_t *options;
+ uint8_t *transport_header;
+};
+
+struct tcp_header
+{
+ uint16_t src_port_num;
+ uint16_t dest_port_num;
+ uint32_t seq_num;
+ uint32_t ack_num;
+ uint8_t hdr_len;
+ uint8_t flags;
+ uint16_t rcv_window;
+ uint16_t chksum;
+ uint16_t urgent;
+ uint8_t *options;
+ uint8_t *data;
+};
+
+struct udp_header
+{
+ uint16_t src_port_num;
+ uint16_t dest_port_num;
+ uint16_t len;
+ uint16_t chksum;
+ uint8_t *data;
+};
+
/*
* Reference counted class containing ethernet packet data
*/
@@ -61,6 +119,16 @@ class EtherPacket : public RefCounted
bool IsMulticast() { return data[0] == 0x01; }
bool IsBroadcast() { return data[0] == 0xff; }
+ ip_header *getIpHdr() { return (ip_header *) (data + 14); }
+
+ void *getTransportHdr() {
+ ip_header *ip = getIpHdr();
+ return (void *) (ip + (ip->vers_len & 0xf));
+ }
+
+
+ typedef RefCountingPtr<EtherPacket> PacketPtr;
+
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
};
diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc
new file mode 100644
index 000000000..f78a8e1ef
--- /dev/null
+++ b/dev/ide_ctrl.cc
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/intr_control.hh"
+#include "dev/dma.hh"
+#include "dev/pcireg.h"
+#include "dev/pciconfigall.hh"
+#include "dev/ide_disk.hh"
+#include "dev/ide_ctrl.hh"
+#include "dev/tsunami_cchip.hh"
+#include "mem/bus/bus.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
+#include "mem/bus/dma_interface.hh"
+#include "dev/tsunami.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+////
+// Initialization and destruction
+////
+
+IdeController::IdeController(const string &name, IntrControl *ic,
+ const vector<IdeDisk *> &new_disks,
+ MemoryController *mmu, PciConfigAll *cf,
+ PciConfigData *cd, Tsunami *t, uint32_t bus_num,
+ uint32_t dev_num, uint32_t func_num,
+ Bus *host_bus, HierParams *hier)
+ : PciDev(name, mmu, cf, cd, bus_num, dev_num, func_num), tsunami(t)
+{
+ // put back pointer into Tsunami
+ tsunami->disk_controller = this;
+
+ // initialize the PIO interface addresses
+ pri_cmd_addr = 0;
+ pri_cmd_size = BARSize[0];
+
+ pri_ctrl_addr = 0;
+ pri_ctrl_size = BARSize[1];
+
+ sec_cmd_addr = 0;
+ sec_cmd_size = BARSize[2];
+
+ sec_ctrl_addr = 0;
+ sec_ctrl_size = BARSize[3];
+
+ // initialize the bus master interface (BMI) address to be configured
+ // via PCI
+ bmi_addr = 0;
+ bmi_size = BARSize[4];
+
+ // zero out all of the registers
+ memset(bmi_regs, 0, sizeof(bmi_regs));
+ memset(pci_regs, 0, sizeof(pci_regs));
+
+ // setup initial values
+ *(uint32_t *)&pci_regs[IDETIM] = 0x80008000; // enable both channels
+ *(uint8_t *)&bmi_regs[BMIS0] = 0x60;
+ *(uint8_t *)&bmi_regs[BMIS1] = 0x60;
+
+ // reset all internal variables
+ io_enabled = false;
+ bm_enabled = false;
+ memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
+
+ // create the PIO and DMA interfaces
+ if (host_bus) {
+ pioInterface = newPioInterface(name, hier, host_bus, this,
+ &IdeController::cacheAccess);
+
+ dmaInterface = new DMAInterface<Bus>(name + ".dma", host_bus,
+ host_bus, 1);
+ }
+
+ // setup the disks attached to controller
+ memset(disks, 0, sizeof(IdeDisk *) * 4);
+
+ if (new_disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
+
+ for (int i = 0; i < new_disks.size(); i++) {
+ disks[i] = new_disks[i];
+ disks[i]->setController(this, dmaInterface);
+ }
+}
+
+IdeController::~IdeController()
+{
+ for (int i = 0; i < 4; i++)
+ if (disks[i])
+ delete disks[i];
+}
+
+////
+// Utility functions
+///
+
+void
+IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
+ RegType_t &type)
+{
+ offset = addr;
+
+ if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
+ offset -= pri_cmd_addr;
+ type = COMMAND_BLOCK;
+ primary = true;
+ } else if (addr >= pri_ctrl_addr &&
+ addr < (pri_ctrl_addr + pri_ctrl_size)) {
+ offset -= pri_ctrl_addr;
+ type = CONTROL_BLOCK;
+ primary = true;
+ } else if (addr >= sec_cmd_addr &&
+ addr < (sec_cmd_addr + sec_cmd_size)) {
+ offset -= sec_cmd_addr;
+ type = COMMAND_BLOCK;
+ primary = false;
+ } else if (addr >= sec_ctrl_addr &&
+ addr < (sec_ctrl_addr + sec_ctrl_size)) {
+ offset -= sec_ctrl_addr;
+ type = CONTROL_BLOCK;
+ primary = false;
+ } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
+ offset -= bmi_addr;
+ type = BMI_BLOCK;
+ primary = (offset < BMIC1) ? true : false;
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
+ }
+}
+
+int
+IdeController::getDisk(bool primary)
+{
+ int disk = 0;
+ uint8_t *devBit = &dev[0];
+
+ if (!primary) {
+ disk += 2;
+ devBit = &dev[1];
+ }
+
+ disk += *devBit;
+
+ assert(*devBit == 0 || *devBit == 1);
+
+ return disk;
+}
+
+int
+IdeController::getDisk(IdeDisk *diskPtr)
+{
+ for (int i = 0; i < 4; i++) {
+ if ((long)diskPtr == (long)disks[i])
+ return i;
+ }
+ return -1;
+}
+
+////
+// Command completion
+////
+
+void
+IdeController::setDmaComplete(IdeDisk *disk)
+{
+ int diskNum = getDisk(disk);
+
+ if (diskNum < 0)
+ panic("Unable to find disk based on pointer %#x\n", disk);
+
+ if (diskNum < 2) {
+ // clear the start/stop bit in the command register
+ bmi_regs[BMIC0] &= ~SSBM;
+ // clear the bus master active bit in the status register
+ bmi_regs[BMIS0] &= ~BMIDEA;
+ // set the interrupt bit
+ bmi_regs[BMIS0] |= IDEINTS;
+ } else {
+ // clear the start/stop bit in the command register
+ bmi_regs[BMIC1] &= ~SSBM;
+ // clear the bus master active bit in the status register
+ bmi_regs[BMIS1] &= ~BMIDEA;
+ // set the interrupt bit
+ bmi_regs[BMIS1] |= IDEINTS;
+ }
+}
+
+////
+// Interrupt handling
+////
+
+void
+IdeController::intrPost()
+{
+ tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
+}
+
+void
+IdeController::intrClear()
+{
+ tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
+}
+
+////
+// Bus timing and bus access functions
+////
+
+Tick
+IdeController::cacheAccess(MemReqPtr &req)
+{
+ // @todo Add more accurate timing to cache access
+ return curTick + 1000;
+}
+
+////
+// Read and write handling
+////
+
+void
+IdeController::ReadConfig(int offset, int size, uint8_t *data)
+{
+ Addr origOffset = offset;
+
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::ReadConfig(offset, size, data);
+ } else {
+ if (offset >= PCI_IDE_TIMING && offset < (PCI_IDE_TIMING + 4)) {
+ offset -= PCI_IDE_TIMING;
+ offset += IDETIM;
+
+ if ((offset + size) > (IDETIM + 4))
+ panic("PCI read of IDETIM with invalid size\n");
+ } else if (offset == PCI_SLAVE_TIMING) {
+ offset -= PCI_SLAVE_TIMING;
+ offset += SIDETIM;
+
+ if ((offset + size) > (SIDETIM + 1))
+ panic("PCI read of SIDETIM with invalid size\n");
+ } else if (offset == PCI_UDMA33_CTRL) {
+ offset -= PCI_UDMA33_CTRL;
+ offset += UDMACTL;
+
+ if ((offset + size) > (UDMACTL + 1))
+ panic("PCI read of UDMACTL with invalid size\n");
+ } else if (offset >= PCI_UDMA33_TIMING &&
+ offset < (PCI_UDMA33_TIMING + 2)) {
+ offset -= PCI_UDMA33_TIMING;
+ offset += UDMATIM;
+
+ if ((offset + size) > (UDMATIM + 2))
+ panic("PCI read of UDMATIM with invalid size\n");
+ } else {
+ panic("PCI read of unimplemented register: %x\n", offset);
+ }
+
+ memcpy((void *)data, (void *)&pci_regs[offset], size);
+ }
+
+ DPRINTF(IdeCtrl, "IDE PCI read offset: %#x (%#x) size: %#x data: %#x\n",
+ origOffset, offset, size, *(uint32_t *)data);
+}
+
+void
+IdeController::WriteConfig(int offset, int size, uint32_t data)
+{
+ DPRINTF(IdeCtrl, "IDE PCI write offset: %#x size: %#x data: %#x\n",
+ offset, size, data);
+
+ // do standard write stuff if in standard PCI space
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::WriteConfig(offset, size, data);
+ } else {
+ if (offset >= PCI_IDE_TIMING && offset < (PCI_IDE_TIMING + 4)) {
+ offset -= PCI_IDE_TIMING;
+ offset += IDETIM;
+
+ if ((offset + size) > (IDETIM + 4))
+ panic("PCI write to IDETIM with invalid size\n");
+ } else if (offset == PCI_SLAVE_TIMING) {
+ offset -= PCI_SLAVE_TIMING;
+ offset += SIDETIM;
+
+ if ((offset + size) > (SIDETIM + 1))
+ panic("PCI write to SIDETIM with invalid size\n");
+ } else if (offset == PCI_UDMA33_CTRL) {
+ offset -= PCI_UDMA33_CTRL;
+ offset += UDMACTL;
+
+ if ((offset + size) > (UDMACTL + 1))
+ panic("PCI write to UDMACTL with invalid size\n");
+ } else if (offset >= PCI_UDMA33_TIMING &&
+ offset < (PCI_UDMA33_TIMING + 2)) {
+ offset -= PCI_UDMA33_TIMING;
+ offset += UDMATIM;
+
+ if ((offset + size) > (UDMATIM + 2))
+ panic("PCI write to UDMATIM with invalid size\n");
+ } else {
+ panic("PCI write to unimplemented register: %x\n", offset);
+ }
+
+ memcpy((void *)&pci_regs[offset], (void *)&data, size);
+ }
+
+ if (offset == PCI_COMMAND) {
+ if (config.data[offset] & IOSE)
+ io_enabled = true;
+ else
+ io_enabled = false;
+
+ if (config.data[offset] & BME)
+ bm_enabled = true;
+ else
+ bm_enabled = false;
+
+ } else if (data != 0xffffffff) {
+ switch (offset) {
+ case PCI0_BASE_ADDR0:
+ pri_cmd_addr = BARAddrs[0];
+ if (pioInterface)
+ pioInterface->addAddrRange(pri_cmd_addr,
+ pri_cmd_addr + pri_cmd_size - 1);
+
+ pri_cmd_addr = pri_cmd_addr & PA_UNCACHED_MASK;
+ break;
+
+ case PCI0_BASE_ADDR1:
+ pri_ctrl_addr = BARAddrs[1];
+ if (pioInterface)
+ pioInterface->addAddrRange(pri_ctrl_addr,
+ pri_ctrl_addr + pri_ctrl_size - 1);
+
+ pri_ctrl_addr = pri_ctrl_addr & PA_UNCACHED_MASK;
+ break;
+
+ case PCI0_BASE_ADDR2:
+ sec_cmd_addr = BARAddrs[2];
+ if (pioInterface)
+ pioInterface->addAddrRange(sec_cmd_addr,
+ sec_cmd_addr + sec_cmd_size - 1);
+
+ sec_cmd_addr = sec_cmd_addr & PA_UNCACHED_MASK;
+ break;
+
+ case PCI0_BASE_ADDR3:
+ sec_ctrl_addr = BARAddrs[3];
+ if (pioInterface)
+ pioInterface->addAddrRange(sec_ctrl_addr,
+ sec_ctrl_addr + sec_ctrl_size - 1);
+
+ sec_ctrl_addr = sec_ctrl_addr & PA_UNCACHED_MASK;
+ break;
+
+ case PCI0_BASE_ADDR4:
+ bmi_addr = BARAddrs[4];
+ if (pioInterface)
+ pioInterface->addAddrRange(bmi_addr, bmi_addr + bmi_size - 1);
+
+ bmi_addr = bmi_addr & PA_UNCACHED_MASK;
+ break;
+ }
+ }
+}
+
+Fault
+IdeController::read(MemReqPtr &req, uint8_t *data)
+{
+ Addr offset;
+ bool primary;
+ bool byte;
+ bool cmdBlk;
+ RegType_t type;
+ int disk;
+
+ parseAddr(req->paddr, offset, primary, type);
+ byte = (req->size == sizeof(uint8_t)) ? true : false;
+ cmdBlk = (type == COMMAND_BLOCK) ? true : false;
+
+ if (!io_enabled)
+ return No_Fault;
+
+ // sanity check the size (allows byte, word, or dword access)
+ if (req->size != sizeof(uint8_t) && req->size != sizeof(uint16_t) &&
+ req->size != sizeof(uint32_t))
+ panic("IDE controller read of invalid size: %#x\n", req->size);
+
+ if (type != BMI_BLOCK) {
+ assert(req->size != sizeof(uint32_t));
+
+ disk = getDisk(primary);
+ if (disks[disk])
+ disks[disk]->read(offset, byte, cmdBlk, data);
+ } else {
+ memcpy((void *)data, &bmi_regs[offset], req->size);
+ }
+
+ DPRINTF(IdeCtrl, "IDE read from offset: %#x size: %#x data: %#x\n",
+ offset, req->size, *(uint32_t *)data);
+
+ return No_Fault;
+}
+
+Fault
+IdeController::write(MemReqPtr &req, const uint8_t *data)
+{
+ Addr offset;
+ bool primary;
+ bool byte;
+ bool cmdBlk;
+ RegType_t type;
+ int disk;
+
+ parseAddr(req->paddr, offset, primary, type);
+ byte = (req->size == sizeof(uint8_t)) ? true : false;
+ cmdBlk = (type == COMMAND_BLOCK) ? true : false;
+
+ DPRINTF(IdeCtrl, "IDE write from offset: %#x size: %#x data: %#x\n",
+ offset, req->size, *(uint32_t *)data);
+
+ uint8_t oldVal, newVal;
+
+ if (!io_enabled)
+ return No_Fault;
+
+ if (type == BMI_BLOCK && !bm_enabled)
+ return No_Fault;
+
+ if (type != BMI_BLOCK) {
+ // shadow the dev bit
+ if (type == COMMAND_BLOCK && offset == IDE_SELECT_OFFSET) {
+ uint8_t *devBit = (primary ? &dev[0] : &dev[1]);
+ *devBit = ((*data & IDE_SELECT_DEV_BIT) ? 1 : 0);
+ }
+
+ assert(req->size != sizeof(uint32_t));
+
+ disk = getDisk(primary);
+ if (disks[disk])
+ disks[disk]->write(offset, byte, cmdBlk, data);
+ } else {
+ switch (offset) {
+ // Bus master IDE command register
+ case BMIC1:
+ case BMIC0:
+ if (req->size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", req->size);
+
+ // select the current disk based on DEV bit
+ disk = getDisk(primary);
+
+ oldVal = bmi_regs[offset];
+ newVal = *data;
+
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal & SSBM) {
+ if ((oldVal & RWCON) ^ (newVal & RWCON)) {
+ (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
+ }
+ }
+
+ // see if the start/stop bit is being changed
+ if ((oldVal & SSBM) ^ (newVal & SSBM)) {
+ if (oldVal & SSBM) {
+ // stopping DMA transfer
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+
+ // clear the BMIDEA bit
+ bmi_regs[offset + 0x2] &= ~BMIDEA;
+
+ if (disks[disk] == NULL)
+ panic("DMA stop for disk %d which does not exist\n",
+ disk);
+
+ // inform the disk of the DMA transfer abort
+ disks[disk]->abortDma();
+ } else {
+ // starting DMA transfer
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+
+ // set the BMIDEA bit
+ bmi_regs[offset + 0x2] |= BMIDEA;
+
+ if (disks[disk] == NULL)
+ panic("DMA start for disk %d which does not exist\n",
+ disk);
+
+ // inform the disk of the DMA transfer start
+ if (primary)
+ disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP0]);
+ else
+ disks[disk]->startDma(*(uint32_t *)&bmi_regs[BMIDTP1]);
+ }
+ }
+
+ // update the register value
+ bmi_regs[offset] = newVal;
+ break;
+
+ // Bus master IDE status register
+ case BMIS0:
+ case BMIS1:
+ if (req->size != sizeof(uint8_t))
+ panic("Invalid BMIS write size: %x\n", req->size);
+
+ oldVal = bmi_regs[offset];
+ newVal = *data;
+
+ // the BMIDEA bit is RO
+ newVal |= (oldVal & BMIDEA);
+
+ // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
+ if ((oldVal & IDEINTS) && (newVal & IDEINTS))
+ newVal &= ~IDEINTS; // clear the interrupt?
+ else
+ (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
+
+ if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
+ newVal &= ~IDEDMAE;
+ else
+ (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
+
+ bmi_regs[offset] = newVal;
+ break;
+
+ // Bus master IDE descriptor table pointer register
+ case BMIDTP0:
+ case BMIDTP1:
+ if (req->size != sizeof(uint32_t))
+ panic("Invalid BMIDTP write size: %x\n", req->size);
+
+ *(uint32_t *)&bmi_regs[offset] = *(uint32_t *)data & ~0x3;
+ break;
+
+ default:
+ if (req->size != sizeof(uint8_t) &&
+ req->size != sizeof(uint16_t) &&
+ req->size != sizeof(uint32_t))
+ panic("IDE controller write of invalid write size: %x\n",
+ req->size);
+
+ // do a default copy of data into the registers
+ memcpy((void *)&bmi_regs[offset], data, req->size);
+ }
+ }
+
+ return No_Fault;
+}
+
+////
+// Serialization
+////
+
+void
+IdeController::serialize(std::ostream &os)
+{
+ // Serialize register addresses and sizes
+ SERIALIZE_SCALAR(pri_cmd_addr);
+ SERIALIZE_SCALAR(pri_cmd_size);
+ SERIALIZE_SCALAR(pri_ctrl_addr);
+ SERIALIZE_SCALAR(pri_ctrl_size);
+ SERIALIZE_SCALAR(sec_cmd_addr);
+ SERIALIZE_SCALAR(sec_cmd_size);
+ SERIALIZE_SCALAR(sec_ctrl_addr);
+ SERIALIZE_SCALAR(sec_ctrl_size);
+ SERIALIZE_SCALAR(bmi_addr);
+ SERIALIZE_SCALAR(bmi_size);
+
+ // Serialize registers
+ SERIALIZE_ARRAY(bmi_regs, 16);
+ SERIALIZE_ARRAY(dev, 2);
+ SERIALIZE_ARRAY(pci_regs, 8);
+
+ // Serialize internal state
+ SERIALIZE_SCALAR(io_enabled);
+ SERIALIZE_SCALAR(bm_enabled);
+ SERIALIZE_ARRAY(cmd_in_progress, 4);
+}
+
+void
+IdeController::unserialize(Checkpoint *cp, const std::string &section)
+{
+ // Unserialize register addresses and sizes
+ UNSERIALIZE_SCALAR(pri_cmd_addr);
+ UNSERIALIZE_SCALAR(pri_cmd_size);
+ UNSERIALIZE_SCALAR(pri_ctrl_addr);
+ UNSERIALIZE_SCALAR(pri_ctrl_size);
+ UNSERIALIZE_SCALAR(sec_cmd_addr);
+ UNSERIALIZE_SCALAR(sec_cmd_size);
+ UNSERIALIZE_SCALAR(sec_ctrl_addr);
+ UNSERIALIZE_SCALAR(sec_ctrl_size);
+ UNSERIALIZE_SCALAR(bmi_addr);
+ UNSERIALIZE_SCALAR(bmi_size);
+
+ // Unserialize registers
+ UNSERIALIZE_ARRAY(bmi_regs, 16);
+ UNSERIALIZE_ARRAY(dev, 2);
+ UNSERIALIZE_ARRAY(pci_regs, 8);
+
+ // Unserialize internal state
+ UNSERIALIZE_SCALAR(io_enabled);
+ UNSERIALIZE_SCALAR(bm_enabled);
+ UNSERIALIZE_ARRAY(cmd_in_progress, 4);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
+
+ SimObjectParam<IntrControl *> intr_ctrl;
+ SimObjectVectorParam<IdeDisk *> disks;
+ SimObjectParam<MemoryController *> mmu;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ SimObjectParam<Tsunami *> tsunami;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+ SimObjectParam<Bus *> host_bus;
+ SimObjectParam<HierParams *> hier;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
+
+ INIT_PARAM(intr_ctrl, "Interrupt Controller"),
+ INIT_PARAM(disks, "IDE disks attached to this controller"),
+ INIT_PARAM(mmu, "Memory controller"),
+ INIT_PARAM(configspace, "PCI Configspace"),
+ INIT_PARAM(configdata, "PCI Config data"),
+ INIT_PARAM(tsunami, "Tsunami chipset pointer"),
+ INIT_PARAM(pci_bus, "PCI bus ID"),
+ INIT_PARAM(pci_dev, "PCI device number"),
+ INIT_PARAM(pci_func, "PCI function code"),
+ INIT_PARAM_DFLT(host_bus, "Host bus to attach to", NULL),
+ INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
+
+END_INIT_SIM_OBJECT_PARAMS(IdeController)
+
+CREATE_SIM_OBJECT(IdeController)
+{
+ return new IdeController(getInstanceName(), intr_ctrl, disks, mmu,
+ configspace, configdata, tsunami, pci_bus,
+ pci_dev, pci_func, host_bus, hier);
+}
+
+REGISTER_SIM_OBJECT("IdeController", IdeController)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh
new file mode 100644
index 000000000..9698724c1
--- /dev/null
+++ b/dev/ide_ctrl.hh
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/** @file
+ * Simple PCI IDE controller with bus mastering capability and UDMA
+ * modeled after controller in the Intel PIIX4 chip
+ */
+
+#ifndef __IDE_CTRL_HH__
+#define __IDE_CTRL_HH__
+
+#include "dev/pcidev.hh"
+#include "dev/pcireg.h"
+#include "dev/io_device.hh"
+
+#define BMIC0 0x0 // Bus master IDE command register
+#define BMIS0 0x2 // Bus master IDE status register
+#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register
+#define BMIC1 0x8 // Bus master IDE command register
+#define BMIS1 0xa // Bus master IDE status register
+#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register
+
+// Bus master IDE command register bit fields
+#define RWCON 0x08 // Bus master read/write control
+#define SSBM 0x01 // Start/stop bus master
+
+// Bus master IDE status register bit fields
+#define DMA1CAP 0x40 // Drive 1 DMA capable
+#define DMA0CAP 0x20 // Drive 0 DMA capable
+#define IDEINTS 0x04 // IDE Interrupt Status
+#define IDEDMAE 0x02 // IDE DMA error
+#define BMIDEA 0x01 // Bus master IDE active
+
+// IDE Command byte fields
+#define IDE_SELECT_OFFSET (6)
+#define IDE_SELECT_DEV_BIT 0x10
+
+#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
+
+// PCI device specific register byte offsets
+#define PCI_IDE_TIMING 0x40
+#define PCI_SLAVE_TIMING 0x44
+#define PCI_UDMA33_CTRL 0x48
+#define PCI_UDMA33_TIMING 0x4a
+
+#define IDETIM (0)
+#define SIDETIM (4)
+#define UDMACTL (5)
+#define UDMATIM (6)
+
+// PCI Command bit fields
+#define BME 0x04 // Bus master function enable
+#define IOSE 0x01 // I/O space enable
+
+typedef enum RegType {
+ COMMAND_BLOCK = 0,
+ CONTROL_BLOCK,
+ BMI_BLOCK
+} RegType_t;
+
+class IdeDisk;
+class IntrControl;
+class PciConfigAll;
+class Tsunami;
+class PhysicalMemory;
+class BaseInterface;
+class HierParams;
+class Bus;
+
+/**
+ * Device model for an Intel PIIX4 IDE controller
+ */
+
+class IdeController : public PciDev
+{
+ private:
+ /** Primary command block registers */
+ Addr pri_cmd_addr;
+ Addr pri_cmd_size;
+ /** Primary control block registers */
+ Addr pri_ctrl_addr;
+ Addr pri_ctrl_size;
+ /** Secondary command block registers */
+ Addr sec_cmd_addr;
+ Addr sec_cmd_size;
+ /** Secondary control block registers */
+ Addr sec_ctrl_addr;
+ Addr sec_ctrl_size;
+ /** Bus master interface (BMI) registers */
+ Addr bmi_addr;
+ Addr bmi_size;
+
+ private:
+ /** Registers used for bus master interface */
+ uint8_t bmi_regs[16];
+ /** Shadows of the device select bit */
+ uint8_t dev[2];
+ /** Registers used in PCI configuration */
+ uint8_t pci_regs[8];
+
+ // Internal management variables
+ bool io_enabled;
+ bool bm_enabled;
+ bool cmd_in_progress[4];
+
+ public:
+ /** Pointer to the chipset */
+ Tsunami *tsunami;
+
+ private:
+ /** IDE disks connected to controller */
+ IdeDisk *disks[4];
+
+ private:
+ /** Parse the access address to pass on to device */
+ void parseAddr(const Addr &addr, Addr &offset, bool &primary,
+ RegType_t &type);
+
+ /** Select the disk based on the channel and device bit */
+ int getDisk(bool primary);
+
+ /** Select the disk based on a pointer */
+ int getDisk(IdeDisk *diskPtr);
+
+ public:
+ /**
+ * Constructs and initializes this controller.
+ * @param name The name of this controller.
+ * @param ic The interrupt controller.
+ * @param mmu The memory controller
+ * @param cf PCI config space
+ * @param cd PCI config data
+ * @param bus_num The PCI bus number
+ * @param dev_num The PCI device number
+ * @param func_num The PCI function number
+ * @param host_bus The host bus to connect to
+ * @param hier The hierarchy parameters
+ */
+ IdeController(const std::string &name, IntrControl *ic,
+ const std::vector<IdeDisk *> &new_disks,
+ MemoryController *mmu, PciConfigAll *cf,
+ PciConfigData *cd, Tsunami *t,
+ uint32_t bus_num, uint32_t dev_num, uint32_t func_num,
+ Bus *host_bus, HierParams *hier);
+
+ /**
+ * Deletes the connected devices.
+ */
+ ~IdeController();
+
+ virtual void WriteConfig(int offset, int size, uint32_t data);
+ virtual void ReadConfig(int offset, int size, uint8_t *data);
+
+ void intrPost();
+ void intrClear();
+
+ void setDmaComplete(IdeDisk *disk);
+
+ /**
+ * Read a done field for a given target.
+ * @param req Contains the address of the field to read.
+ * @param data Return the field read.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+ /**
+ * Write to the mmapped I/O control registers.
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /**
+ * Cache access timing specific to device
+ * @param req Memory request
+ */
+ Tick cacheAccess(MemReqPtr &req);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+#endif // __IDE_CTRL_HH_
diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc
new file mode 100644
index 000000000..ddd4a09e7
--- /dev/null
+++ b/dev/ide_disk.cc
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/** @file
+ * Device model implementation for an IDE disk
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <deque>
+#include <string>
+
+#include "arch/alpha/pmap.h"
+#include "base/cprintf.hh" // csprintf
+#include "base/trace.hh"
+#include "dev/disk_image.hh"
+#include "dev/ide_disk.hh"
+#include "dev/ide_ctrl.hh"
+#include "dev/tsunami.hh"
+#include "dev/tsunami_pchip.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "mem/bus/bus.hh"
+#include "mem/bus/dma_interface.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+#include "sim/universe.hh"
+
+using namespace std;
+
+IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
+ int id, int delay)
+ : SimObject(name), ctrl(NULL), image(img), physmem(phys),
+ dmaTransferEvent(this), dmaReadWaitEvent(this),
+ dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
+ dmaReadEvent(this), dmaWriteEvent(this)
+{
+ // calculate disk delay in microseconds
+ diskDelay = (delay * ticksPerSecond / 100000);
+
+ // initialize the data buffer and shadow registers
+ dataBuffer = new uint8_t[MAX_DMA_SIZE];
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ memset(&cmdReg, 0, sizeof(CommandReg_t));
+ memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
+
+ dmaInterfaceBytes = 0;
+ curPrdAddr = 0;
+ curSector = 0;
+ curCommand = 0;
+ cmdBytesLeft = 0;
+ drqBytesLeft = 0;
+ dmaRead = false;
+ intrPending = false;
+
+ // fill out the drive ID structure
+ memset(&driveID, 0, sizeof(struct hd_driveid));
+
+ // Calculate LBA and C/H/S values
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
+
+ uint32_t lba_size = image->size();
+ if (lba_size >= 16383*16*63) {
+ cylinders = 16383;
+ heads = 16;
+ sectors = 63;
+ } else {
+ if (lba_size >= 63)
+ sectors = 63;
+ else
+ sectors = lba_size;
+
+ if ((lba_size / sectors) >= 16)
+ heads = 16;
+ else
+ heads = (lba_size / sectors);
+
+ cylinders = lba_size / (heads * sectors);
+ }
+
+ // Setup the model name
+ sprintf((char *)driveID.model, "5MI EDD si k");
+ // Set the maximum multisector transfer size
+ driveID.max_multsect = MAX_MULTSECT;
+ // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
+ driveID.capability = 0x7;
+ // UDMA support, EIDE support
+ driveID.field_valid = 0x6;
+ // Setup default C/H/S settings
+ driveID.cyls = cylinders;
+ driveID.sectors = sectors;
+ driveID.heads = heads;
+ // Setup the current multisector transfer size
+ driveID.multsect = MAX_MULTSECT;
+ driveID.multsect_valid = 0x1;
+ // Number of sectors on disk
+ driveID.lba_capacity = lba_size;
+ // Multiword DMA mode 2 and below supported
+ driveID.dma_mword = 0x400;
+ // Set PIO mode 4 and 3 supported
+ driveID.eide_pio_modes = 0x3;
+ // Set DMA mode 4 and below supported
+ driveID.dma_ultra = 0x10;
+ // Statically set hardware config word
+ driveID.hw_config = 0x4001;
+
+ // set the device state to idle
+ dmaState = Dma_Idle;
+
+ if (id == DEV0) {
+ devState = Device_Idle_S;
+ devID = DEV0;
+ } else if (id == DEV1) {
+ devState = Device_Idle_NS;
+ devID = DEV1;
+ } else {
+ panic("Invalid device ID: %#x\n", id);
+ }
+
+ // set the device ready bit
+ cmdReg.status |= STATUS_DRDY_BIT;
+}
+
+IdeDisk::~IdeDisk()
+{
+ // destroy the data buffer
+ delete [] dataBuffer;
+}
+
+////
+// Utility functions
+////
+
+Addr
+IdeDisk::pciToDma(Addr pciAddr)
+{
+ if (ctrl)
+ return ctrl->tsunami->pchip->translatePciToDma(pciAddr);
+ else
+ panic("Access to unset controller!\n");
+}
+
+uint32_t
+IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
+{
+ uint32_t bytesInPage = 0;
+
+ // First calculate how many bytes could be in the page
+ if (bytesLeft > ALPHA_PGBYTES)
+ bytesInPage = ALPHA_PGBYTES;
+ else
+ bytesInPage = bytesLeft;
+
+ // Next, see if we have crossed a page boundary, and adjust
+ Addr upperBound = curAddr + bytesInPage;
+ Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES;
+
+ assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
+
+ if (upperBound >= pageBound)
+ bytesInPage = pageBound - curAddr;
+
+ return bytesInPage;
+}
+
+////
+// Device registers read/write
+////
+
+void
+IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
+{
+ DevAction_t action = ACT_NONE;
+
+ if (cmdBlk) {
+ if (offset < 0 || offset > sizeof(CommandReg_t))
+ panic("Invalid disk command register offset: %#x\n", offset);
+
+ if (!byte && offset != DATA_OFFSET)
+ panic("Invalid 16-bit read, only allowed on data reg\n");
+
+ if (!byte)
+ *(uint16_t *)data = *(uint16_t *)&cmdReg.data0;
+ else
+ *data = ((uint8_t *)&cmdReg)[offset];
+
+ // determine if an action needs to be taken on the state machine
+ if (offset == STATUS_OFFSET) {
+ action = ACT_STAT_READ;
+ } else if (offset == DATA_OFFSET) {
+ if (byte)
+ action = ACT_DATA_READ_BYTE;
+ else
+ action = ACT_DATA_READ_SHORT;
+ }
+
+ } else {
+ if (offset != ALTSTAT_OFFSET)
+ panic("Invalid disk control register offset: %#x\n", offset);
+
+ if (!byte)
+ panic("Invalid 16-bit read from control block\n");
+
+ *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET];
+ }
+
+ if (action != ACT_NONE)
+ updateState(action);
+}
+
+void
+IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
+{
+ DevAction_t action = ACT_NONE;
+
+ if (cmdBlk) {
+ if (offset < 0 || offset > sizeof(CommandReg_t))
+ panic("Invalid disk command register offset: %#x\n", offset);
+
+ if (!byte && offset != DATA_OFFSET)
+ panic("Invalid 16-bit write, only allowed on data reg\n");
+
+ if (!byte)
+ *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data;
+ else
+ ((uint8_t *)&cmdReg)[offset] = *data;
+
+ // determine if an action needs to be taken on the state machine
+ if (offset == COMMAND_OFFSET) {
+ action = ACT_CMD_WRITE;
+ } else if (offset == DATA_OFFSET) {
+ if (byte)
+ action = ACT_DATA_WRITE_BYTE;
+ else
+ action = ACT_DATA_WRITE_SHORT;
+ }
+
+ } else {
+ if (offset != CONTROL_OFFSET)
+ panic("Invalid disk control register offset: %#x\n", offset);
+
+ if (!byte)
+ panic("Invalid 16-bit write to control block\n");
+
+ if (*data & CONTROL_RST_BIT)
+ panic("Software reset not supported!\n");
+
+ nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
+ }
+
+ if (action != ACT_NONE)
+ updateState(action);
+}
+
+////
+// Perform DMA transactions
+////
+
+void
+IdeDisk::doDmaTransfer()
+{
+ if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
+ panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
+ dmaState, devState);
+
+ // first read the current PRD
+ if (dmaInterface) {
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick,
+ &dmaPrdReadEvent);
+ } else {
+ dmaPrdReadDone();
+ }
+}
+
+void
+IdeDisk::dmaPrdReadDone()
+{
+ // actually copy the PRD from physical memory
+ memcpy((void *)&curPrd.entry,
+ physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
+ sizeof(PrdEntry_t));
+
+ curPrdAddr += sizeof(PrdEntry_t);
+
+ if (dmaRead)
+ doDmaRead();
+ else
+ doDmaWrite();
+}
+
+void
+IdeDisk::doDmaRead()
+{
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+
+ if (dmaInterface) {
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+ uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+ (uint32_t)curPrd.getByteCount());
+
+ dmaInterfaceBytes = bytesInPage;
+
+ dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
+ curTick + totalDiskDelay, &dmaReadEvent);
+ } else {
+ // schedule dmaReadEvent with sectorDelay (dmaReadDone)
+ dmaReadEvent.schedule(curTick + totalDiskDelay);
+ }
+}
+
+void
+IdeDisk::dmaReadDone()
+{
+
+ Addr curAddr = 0, dmaAddr = 0;
+ uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
+
+ // continue to use the DMA interface until all pages are read
+ if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+ // see if the interface is busy
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+ curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+ dmaInterfaceBytes += bytesInPage;
+
+ dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
+ curTick, &dmaReadEvent);
+
+ return;
+ }
+
+ // set initial address
+ curAddr = curPrd.getBaseAddr();
+
+ // clear out the data buffer
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ // read the data from memory via DMA into a data buffer
+ while (bytesWritten < curPrd.getByteCount()) {
+ if (cmdBytesLeft <= 0)
+ panic("DMA data is larger than # of sectors specified\n");
+
+ dmaAddr = pciToDma(curAddr);
+
+ // calculate how many bytes are in the current page
+ bytesLeft = curPrd.getByteCount() - bytesWritten;
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+
+ // copy the data from memory into the data buffer
+ memcpy((void *)(dataBuffer + bytesWritten),
+ physmem->dma_addr(dmaAddr, bytesInPage),
+ bytesInPage);
+
+ curAddr += bytesInPage;
+ bytesWritten += bytesInPage;
+ cmdBytesLeft -= bytesInPage;
+ }
+
+ // write the data to the disk image
+ for (bytesWritten = 0;
+ bytesWritten < curPrd.getByteCount();
+ bytesWritten += SectorSize) {
+
+ writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+ }
+
+#if 0
+ // actually copy the data from memory to data buffer
+ Addr dmaAddr =
+ ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
+ memcpy((void *)dataBuffer,
+ physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
+ curPrd.getByteCount());
+
+ uint32_t bytesWritten = 0;
+
+ while (bytesWritten < curPrd.getByteCount()) {
+ if (cmdBytesLeft <= 0)
+ panic("DMA data is larger than # sectors specified\n");
+
+ writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+
+ bytesWritten += SectorSize;
+ cmdBytesLeft -= SectorSize;
+ }
+#endif
+
+ // check for the EOT
+ if (curPrd.getEOT()){
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+void
+IdeDisk::doDmaWrite()
+{
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+
+ if (dmaInterface) {
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+ uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+ (uint32_t)curPrd.getByteCount());
+
+ dmaInterfaceBytes = bytesInPage;
+
+ dmaInterface->doDMA(WriteInvalidate, dmaAddr,
+ bytesInPage, curTick + totalDiskDelay,
+ &dmaWriteEvent);
+ } else {
+ // schedule event with disk delay (dmaWriteDone)
+ dmaWriteEvent.schedule(curTick + totalDiskDelay);
+ }
+}
+
+void
+IdeDisk::dmaWriteDone()
+{
+ Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
+ uint32_t bytesRead = 0, bytesInPage = 0;
+
+ // continue to use the DMA interface until all pages are read
+ if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+ // see if the interface is busy
+ if (dmaInterface->busy()) {
+ // reschedule after waiting period
+ dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ }
+
+ uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+ curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+ dmaInterfaceBytes += bytesInPage;
+
+ dmaInterface->doDMA(WriteInvalidate, dmaAddr,
+ bytesInPage, curTick,
+ &dmaWriteEvent);
+
+ return;
+ }
+
+ // setup the initial page and DMA address
+ curAddr = curPrd.getBaseAddr();
+ pageAddr = alpha_trunc_page(curAddr);
+ dmaAddr = pciToDma(curAddr);
+
+ // clear out the data buffer
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ while (bytesRead < curPrd.getByteCount()) {
+ // see if we have crossed into a new page
+ if (pageAddr != alpha_trunc_page(curAddr)) {
+ // write the data to memory
+ memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
+ (void *)(dataBuffer + (bytesRead - bytesInPage)),
+ bytesInPage);
+
+ // update the DMA address and page address
+ pageAddr = alpha_trunc_page(curAddr);
+ dmaAddr = pciToDma(curAddr);
+
+ bytesInPage = 0;
+ }
+
+ if (cmdBytesLeft <= 0)
+ panic("DMA requested data is larger than # sectors specified\n");
+
+ readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
+
+ curAddr += SectorSize;
+ bytesRead += SectorSize;
+ bytesInPage += SectorSize;
+ cmdBytesLeft -= SectorSize;
+ }
+
+ // write the last page worth read to memory
+ if (bytesInPage != 0) {
+ memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
+ (void *)(dataBuffer + (bytesRead - bytesInPage)),
+ bytesInPage);
+ }
+
+#if 0
+ Addr dmaAddr = ctrl->tsunami->pchip->
+ translatePciToDma(curPrd.getBaseAddr());
+
+ memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
+ (void *)dataBuffer, curPrd.getByteCount());
+#endif
+
+ // check for the EOT
+ if (curPrd.getEOT()) {
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+////
+// Disk utility routines
+///
+
+void
+IdeDisk::readDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesRead = image->read(data, sector);
+
+ if (bytesRead != SectorSize)
+ panic("Can't read from %s. Only %d of %d read. errno=%d\n",
+ name(), bytesRead, SectorSize, errno);
+}
+
+void
+IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesWritten = image->write(data, sector);
+
+ if (bytesWritten != SectorSize)
+ panic("Can't write to %s. Only %d of %d written. errno=%d\n",
+ name(), bytesWritten, SectorSize, errno);
+}
+
+////
+// Setup and handle commands
+////
+
+void
+IdeDisk::startDma(const uint32_t &prdTableBase)
+{
+ if (dmaState != Dma_Start)
+ panic("Inconsistent DMA state, should be in Dma_Start!\n");
+
+ if (devState != Transfer_Data_Dma)
+ panic("Inconsistent device state for DMA start!\n");
+
+ curPrdAddr = pciToDma((Addr)prdTableBase);
+
+ dmaState = Dma_Transfer;
+
+ // schedule dma transfer (doDmaTransfer)
+ dmaTransferEvent.schedule(curTick + 1);
+}
+
+void
+IdeDisk::abortDma()
+{
+ if (dmaState == Dma_Idle)
+ panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
+
+ if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
+ panic("Inconsistent device state, should be in Transfer or Prepare!\n");
+
+ updateState(ACT_CMD_ERROR);
+}
+
+void
+IdeDisk::startCommand()
+{
+ DevAction_t action = ACT_NONE;
+ uint32_t size = 0;
+ dmaRead = false;
+
+ // copy the command to the shadow
+ curCommand = cmdReg.command;
+
+ // Decode commands
+ switch (cmdReg.command) {
+ // Supported non-data commands
+ case WIN_READ_NATIVE_MAX:
+ size = image->size() - 1;
+ cmdReg.sec_num = (size & 0xff);
+ cmdReg.cyl_low = ((size & 0xff00) >> 8);
+ cmdReg.cyl_high = ((size & 0xff0000) >> 16);
+ cmdReg.head = ((size & 0xf000000) >> 24);
+
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ case WIN_RECAL:
+ case WIN_SPECIFY:
+ case WIN_STANDBYNOW1:
+ case WIN_FLUSH_CACHE:
+ case WIN_VERIFY:
+ case WIN_SEEK:
+ case WIN_SETFEATURES:
+ case WIN_SETMULT:
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ // Supported PIO data-in commands
+ case WIN_IDENTIFY:
+ cmdBytesLeft = sizeof(struct hd_driveid);
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ case WIN_MULTREAD:
+ case WIN_READ:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ /** @todo make this a scheduled event to simulate disk delay */
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported PIO data-out commands
+ case WIN_MULTWRITE:
+ case WIN_WRITE:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Out;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported DMA commands
+ case WIN_WRITEDMA:
+ dmaRead = true; // a write to the disk is a DMA read from memory
+ case WIN_READDMA:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Dma;
+ action = ACT_DMA_READY;
+ break;
+
+ default:
+ panic("Unsupported ATA command: %#x\n", cmdReg.command);
+ }
+
+ if (action != ACT_NONE) {
+ // set the BSY bit
+ cmdReg.status |= STATUS_BSY_BIT;
+ // clear the DRQ bit
+ cmdReg.status &= ~STATUS_DRQ_BIT;
+
+ updateState(action);
+ }
+}
+
+////
+// Handle setting and clearing interrupts
+////
+
+void
+IdeDisk::intrPost()
+{
+ if (intrPending)
+ panic("Attempt to post an interrupt with one pending\n");
+
+ intrPending = true;
+
+ // talk to controller to set interrupt
+ if (ctrl)
+ ctrl->intrPost();
+}
+
+void
+IdeDisk::intrClear()
+{
+ if (!intrPending)
+ panic("Attempt to clear a non-pending interrupt\n");
+
+ intrPending = false;
+
+ // talk to controller to clear interrupt
+ if (ctrl)
+ ctrl->intrClear();
+}
+
+////
+// Manage the device internal state machine
+////
+
+void
+IdeDisk::updateState(DevAction_t action)
+{
+ switch (devState) {
+ case Device_Idle_S:
+ if (!isDEVSelect())
+ devState = Device_Idle_NS;
+ else if (action == ACT_CMD_WRITE)
+ startCommand();
+
+ break;
+
+ case Device_Idle_SI:
+ if (!isDEVSelect()) {
+ devState = Device_Idle_NS;
+ intrClear();
+ } else if (action == ACT_STAT_READ || isIENSet()) {
+ devState = Device_Idle_S;
+ intrClear();
+ } else if (action == ACT_CMD_WRITE) {
+ intrClear();
+ startCommand();
+ }
+
+ break;
+
+ case Device_Idle_NS:
+ if (isDEVSelect()) {
+ if (!isIENSet() && intrPending) {
+ devState = Device_Idle_SI;
+ intrPost();
+ }
+ if (isIENSet() || !intrPending) {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Command_Execution:
+ if (action == ACT_CMD_COMPLETE) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Prepare_Data_In:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DATA_READY) {
+ // clear the BSY bit
+ cmdReg.status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ cmdReg.status |= STATUS_DRQ_BIT;
+
+ // copy the data into the data buffer
+ if (curCommand == WIN_IDENTIFY) {
+ // Reset the drqBytes for this block
+ drqBytesLeft = sizeof(struct hd_driveid);
+
+ memcpy((void *)dataBuffer, (void *)&driveID,
+ sizeof(struct hd_driveid));
+ } else {
+ // Reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ readDisk(curSector++, dataBuffer);
+ }
+
+ // put the first two bytes into the data register
+ memcpy((void *)&cmdReg.data0, (void *)dataBuffer,
+ sizeof(uint16_t));
+
+ if (!isIENSet()) {
+ devState = Data_Ready_INTRQ_In;
+ intrPost();
+ } else {
+ devState = Transfer_Data_In;
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_In:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_In;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_In:
+ if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+
+ // copy next short into data registers
+ if (drqBytesLeft)
+ memcpy((void *)&cmdReg.data0,
+ (void *)&dataBuffer[SectorSize - drqBytesLeft],
+ sizeof(uint16_t));
+ }
+
+ if (drqBytesLeft == 0) {
+ if (cmdBytesLeft == 0) {
+ // Clear the BSY bit
+ setComplete();
+ devState = Device_Idle_S;
+ } else {
+ devState = Prepare_Data_In;
+ // set the BSY_BIT
+ cmdReg.status |= STATUS_BSY_BIT;
+ // clear the DRQ_BIT
+ cmdReg.status &= ~STATUS_DRQ_BIT;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ }
+ break;
+
+ case Prepare_Data_Out:
+ if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (cmdBytesLeft != 0) {
+ // clear the BSY bit
+ cmdReg.status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ cmdReg.status |= STATUS_DRQ_BIT;
+
+ // clear the data buffer to get it ready for writes
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ if (!isIENSet()) {
+ devState = Data_Ready_INTRQ_Out;
+ intrPost();
+ } else {
+ devState = Transfer_Data_Out;
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_Out:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_Out;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_Out:
+ if (action == ACT_DATA_WRITE_BYTE ||
+ action == ACT_DATA_WRITE_SHORT) {
+
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ // copy the latest short into the data buffer
+ memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
+ (void *)&cmdReg.data0,
+ sizeof(uint16_t));
+
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+ }
+
+ if (drqBytesLeft == 0) {
+ // copy the block to the disk
+ writeDisk(curSector++, dataBuffer);
+
+ // set the BSY bit
+ cmdReg.status |= STATUS_BSY_BIT;
+ // clear the DRQ bit
+ cmdReg.status &= ~STATUS_DRQ_BIT;
+
+ devState = Prepare_Data_Out;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ break;
+
+ case Prepare_Data_Dma:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DMA_READY) {
+ // clear the BSY bit
+ cmdReg.status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ cmdReg.status |= STATUS_DRQ_BIT;
+
+ devState = Transfer_Data_Dma;
+
+ if (dmaState != Dma_Idle)
+ panic("Inconsistent DMA state, should be Dma_Idle\n");
+
+ dmaState = Dma_Start;
+ // wait for the write to the DMA start bit
+ }
+ break;
+
+ case Transfer_Data_Dma:
+ if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
+ // clear the BSY bit
+ setComplete();
+ // set the seek bit
+ cmdReg.status |= 0x10;
+ // clear the controller state for DMA transfer
+ ctrl->setDmaComplete(this);
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ default:
+ panic("Unknown IDE device state: %#x\n", devState);
+ }
+}
+
+void
+IdeDisk::serialize(ostream &os)
+{
+ // Check all outstanding events to see if they are scheduled
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ if (dmaTransferEvent.scheduled()) {
+ reschedule = dmaTransferEvent.when();
+ event = Transfer;
+ } else if (dmaReadWaitEvent.scheduled()) {
+ reschedule = dmaReadWaitEvent.when();
+ event = ReadWait;
+ } else if (dmaWriteWaitEvent.scheduled()) {
+ reschedule = dmaWriteWaitEvent.when();
+ event = WriteWait;
+ } else if (dmaPrdReadEvent.scheduled()) {
+ reschedule = dmaPrdReadEvent.when();
+ event = PrdRead;
+ } else if (dmaReadEvent.scheduled()) {
+ reschedule = dmaReadEvent.when();
+ event = DmaRead;
+ } else if (dmaWriteEvent.scheduled()) {
+ reschedule = dmaWriteEvent.when();
+ event = DmaWrite;
+ }
+
+ SERIALIZE_SCALAR(reschedule);
+ SERIALIZE_ENUM(event);
+
+ // Serialize device registers
+ SERIALIZE_SCALAR(cmdReg.data0);
+ SERIALIZE_SCALAR(cmdReg.data1);
+ SERIALIZE_SCALAR(cmdReg.sec_count);
+ SERIALIZE_SCALAR(cmdReg.sec_num);
+ SERIALIZE_SCALAR(cmdReg.cyl_low);
+ SERIALIZE_SCALAR(cmdReg.cyl_high);
+ SERIALIZE_SCALAR(cmdReg.drive);
+ SERIALIZE_SCALAR(cmdReg.status);
+ SERIALIZE_SCALAR(nIENBit);
+ SERIALIZE_SCALAR(devID);
+
+ // Serialize the PRD related information
+ SERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ SERIALIZE_SCALAR(curPrd.entry.byteCount);
+ SERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ SERIALIZE_SCALAR(curPrdAddr);
+
+ // Serialize current transfer related information
+ SERIALIZE_SCALAR(cmdBytesLeft);
+ SERIALIZE_SCALAR(drqBytesLeft);
+ SERIALIZE_SCALAR(curSector);
+ SERIALIZE_SCALAR(curCommand);
+ SERIALIZE_SCALAR(dmaRead);
+ SERIALIZE_SCALAR(dmaInterfaceBytes);
+ SERIALIZE_SCALAR(intrPending);
+ SERIALIZE_ENUM(devState);
+ SERIALIZE_ENUM(dmaState);
+ SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+void
+IdeDisk::unserialize(Checkpoint *cp, const string &section)
+{
+ // Reschedule events that were outstanding
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ UNSERIALIZE_SCALAR(reschedule);
+ UNSERIALIZE_ENUM(event);
+
+ switch (event) {
+ case None : break;
+ case Transfer : dmaTransferEvent.schedule(reschedule); break;
+ case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
+ case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
+ case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
+ case DmaRead : dmaReadEvent.schedule(reschedule); break;
+ case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
+ }
+
+ // Unserialize device registers
+ UNSERIALIZE_SCALAR(cmdReg.data0);
+ UNSERIALIZE_SCALAR(cmdReg.data1);
+ UNSERIALIZE_SCALAR(cmdReg.sec_count);
+ UNSERIALIZE_SCALAR(cmdReg.sec_num);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_low);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_high);
+ UNSERIALIZE_SCALAR(cmdReg.drive);
+ UNSERIALIZE_SCALAR(cmdReg.status);
+ UNSERIALIZE_SCALAR(nIENBit);
+ UNSERIALIZE_SCALAR(devID);
+
+ // Unserialize the PRD related information
+ UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
+ UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ UNSERIALIZE_SCALAR(curPrdAddr);
+
+ // Unserialize current transfer related information
+ UNSERIALIZE_SCALAR(cmdBytesLeft);
+ UNSERIALIZE_SCALAR(drqBytesLeft);
+ UNSERIALIZE_SCALAR(curSector);
+ UNSERIALIZE_SCALAR(curCommand);
+ UNSERIALIZE_SCALAR(dmaRead);
+ UNSERIALIZE_SCALAR(dmaInterfaceBytes);
+ UNSERIALIZE_SCALAR(intrPending);
+ UNSERIALIZE_ENUM(devState);
+ UNSERIALIZE_ENUM(dmaState);
+ UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
+
+ SimObjectParam<DiskImage *> image;
+ SimObjectParam<PhysicalMemory *> physmem;
+ Param<int> driveID;
+ Param<int> disk_delay;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
+
+ INIT_PARAM(image, "Disk image"),
+ INIT_PARAM(physmem, "Physical memory"),
+ INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
+ INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1)
+
+END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
+
+
+CREATE_SIM_OBJECT(IdeDisk)
+{
+ return new IdeDisk(getInstanceName(), image, physmem, driveID,
+ disk_delay);
+}
+
+REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh
new file mode 100644
index 000000000..35e7404d5
--- /dev/null
+++ b/dev/ide_disk.hh
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/** @file
+ * Device model for an IDE disk
+ */
+
+#ifndef __IDE_DISK_HH__
+#define __IDE_DISK_HH__
+
+#include "dev/ide.hh"
+#include "dev/disk_image.hh"
+#include "dev/io_device.hh"
+#include "sim/eventq.hh"
+
+#define DMA_BACKOFF_PERIOD 200
+
+#define MAX_DMA_SIZE (131072) // 256 * SectorSize (512)
+#define MAX_MULTSECT (128)
+
+#define PRD_BASE_MASK 0xfffffffe
+#define PRD_COUNT_MASK 0xfffe
+#define PRD_EOT_MASK 0x8000
+
+typedef struct PrdEntry {
+ uint32_t baseAddr;
+ uint16_t byteCount;
+ uint16_t endOfTable;
+} PrdEntry_t;
+
+class PrdTableEntry {
+ public:
+ PrdEntry_t entry;
+
+ uint32_t getBaseAddr()
+ {
+ return (entry.baseAddr & PRD_BASE_MASK);
+ }
+
+ uint16_t getByteCount()
+ {
+ return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
+ (entry.byteCount & PRD_COUNT_MASK));
+ }
+
+ uint16_t getEOT()
+ {
+ return (entry.endOfTable & PRD_EOT_MASK);
+ }
+};
+
+#define DATA_OFFSET (0)
+#define ERROR_OFFSET (1)
+#define FEATURES_OFFSET (1)
+#define NSECTOR_OFFSET (2)
+#define SECTOR_OFFSET (3)
+#define LCYL_OFFSET (4)
+#define HCYL_OFFSET (5)
+#define SELECT_OFFSET (6)
+#define STATUS_OFFSET (7)
+#define COMMAND_OFFSET (7)
+
+#define CONTROL_OFFSET (2)
+#define ALTSTAT_OFFSET (2)
+
+#define SELECT_DEV_BIT 0x10
+#define CONTROL_RST_BIT 0x04
+#define CONTROL_IEN_BIT 0x02
+#define STATUS_BSY_BIT 0x80
+#define STATUS_DRDY_BIT 0x40
+#define STATUS_DRQ_BIT 0x08
+#define DRIVE_LBA_BIT 0x40
+
+#define DEV0 (0)
+#define DEV1 (1)
+
+typedef struct CommandReg {
+ uint8_t data0;
+ union {
+ uint8_t data1;
+ uint8_t error;
+ uint8_t features;
+ };
+ uint8_t sec_count;
+ uint8_t sec_num;
+ uint8_t cyl_low;
+ uint8_t cyl_high;
+ union {
+ uint8_t drive;
+ uint8_t head;
+ };
+ union {
+ uint8_t status;
+ uint8_t command;
+ };
+} CommandReg_t;
+
+typedef enum Events {
+ None = 0,
+ Transfer,
+ ReadWait,
+ WriteWait,
+ PrdRead,
+ DmaRead,
+ DmaWrite
+} Events_t;
+
+typedef enum DevAction {
+ ACT_NONE = 0,
+ ACT_CMD_WRITE,
+ ACT_CMD_COMPLETE,
+ ACT_CMD_ERROR,
+ ACT_STAT_READ,
+ ACT_DATA_READY,
+ ACT_DATA_READ_BYTE,
+ ACT_DATA_READ_SHORT,
+ ACT_DATA_WRITE_BYTE,
+ ACT_DATA_WRITE_SHORT,
+ ACT_DMA_READY,
+ ACT_DMA_DONE
+} DevAction_t;
+
+typedef enum DevState {
+ // Device idle
+ Device_Idle_S = 0,
+ Device_Idle_SI,
+ Device_Idle_NS,
+
+ // Non-data commands
+ Command_Execution,
+
+ // PIO data-in (data to host)
+ Prepare_Data_In,
+ Data_Ready_INTRQ_In,
+ Transfer_Data_In,
+
+ // PIO data-out (data from host)
+ Prepare_Data_Out,
+ Data_Ready_INTRQ_Out,
+ Transfer_Data_Out,
+
+ // DMA protocol
+ Prepare_Data_Dma,
+ Transfer_Data_Dma
+} DevState_t;
+
+typedef enum DmaState {
+ Dma_Idle = 0,
+ Dma_Start,
+ Dma_Transfer
+} DmaState_t;
+
+class PhysicalMemory;
+class IdeController;
+
+/**
+ * IDE Disk device model
+ */
+class IdeDisk : public SimObject
+{
+ protected:
+ /** The IDE controller for this disk. */
+ IdeController *ctrl;
+ /** The DMA interface to use for transfers */
+ DMAInterface<Bus> *dmaInterface;
+ /** The image that contains the data of this disk. */
+ DiskImage *image;
+ /** Pointer to physical memory for DMA transfers */
+ PhysicalMemory *physmem;
+
+ protected:
+ /** The disk delay in microseconds. */
+ int diskDelay;
+
+ private:
+ /** Drive identification structure for this disk */
+ struct hd_driveid driveID;
+ /** Data buffer for transfers */
+ uint8_t *dataBuffer;
+ /** Number of bytes left in command data transfer */
+ uint32_t cmdBytesLeft;
+ /** Number of bytes left in DRQ block */
+ uint32_t drqBytesLeft;
+ /** Current sector in access */
+ uint32_t curSector;
+ /** Command block registers */
+ CommandReg_t cmdReg;
+ /** Shadow of the current command code */
+ uint8_t curCommand;
+ /** Interrupt enable bit */
+ bool nIENBit;
+ /** Device state */
+ DevState_t devState;
+ /** Dma state */
+ DmaState_t dmaState;
+ /** Dma transaction is a read */
+ bool dmaRead;
+ /** PRD table base address */
+ uint32_t curPrdAddr;
+ /** PRD entry */
+ PrdTableEntry curPrd;
+ /** Number of bytes transfered by DMA interface for current transfer */
+ uint32_t dmaInterfaceBytes;
+ /** Device ID (master=0/slave=1) */
+ int devID;
+ /** Interrupt pending */
+ bool intrPending;
+
+ public:
+ /**
+ * Create and initialize this Disk.
+ * @param name The name of this disk.
+ * @param img The disk image of this disk.
+ * @param phys Pointer to physical memory
+ * @param id The disk ID (master=0/slave=1)
+ * @param disk_delay The disk delay in milliseconds
+ */
+ IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys,
+ int id, int disk_delay);
+
+ /**
+ * Delete the data buffer.
+ */
+ ~IdeDisk();
+
+ /**
+ * Set the controller for this device
+ * @param c The IDE controller
+ */
+ void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) {
+ if (ctrl) panic("Cannot change the controller once set!\n");
+ ctrl = c;
+ dmaInterface = dmaIntr;
+ }
+
+ // Device register read/write
+ void read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data);
+ void write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data);
+
+ // Start/abort functions
+ void startDma(const uint32_t &prdTableBase);
+ void abortDma();
+
+ private:
+ void startCommand();
+
+ // Interrupt management
+ void intrPost();
+ void intrClear();
+
+ // DMA stuff
+ void doDmaTransfer();
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
+
+ void doDmaRead();
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
+
+ void doDmaWrite();
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
+
+ void dmaPrdReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
+
+ void dmaReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
+
+ void dmaWriteDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
+
+ // Disk image read/write
+ void readDisk(uint32_t sector, uint8_t *data);
+ void writeDisk(uint32_t sector, uint8_t *data);
+
+ // State machine management
+ void updateState(DevAction_t action);
+
+ // Utility functions
+ bool isBSYSet() { return (cmdReg.status & STATUS_BSY_BIT); }
+ bool isIENSet() { return nIENBit; }
+ bool isDEVSelect() { return ((cmdReg.drive & SELECT_DEV_BIT) == devID); }
+
+ void setComplete()
+ {
+ // clear out the status byte
+ cmdReg.status = 0;
+
+ // set the DRDY bit
+ cmdReg.status |= STATUS_DRDY_BIT;
+ }
+
+ uint32_t getLBABase()
+ {
+ return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
+ (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
+ }
+
+ inline Addr pciToDma(Addr pciAddr);
+
+ uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint to use.
+ * @param section The section name describing this object.
+ */
+ void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+
+#endif // __IDE_DISK_HH__
diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc
new file mode 100644
index 000000000..0b54d9210
--- /dev/null
+++ b/dev/ns_gige.cc
@@ -0,0 +1,2418 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller. Does not support priority queueing
+ */
+#include <cstdio>
+#include <deque>
+#include <string>
+
+#include "base/inet.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/intr_control.hh"
+#include "dev/dma.hh"
+#include "dev/ns_gige.hh"
+#include "dev/etherlink.hh"
+#include "mem/bus/bus.hh"
+#include "mem/bus/dma_interface.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/sim_stats.hh"
+#include "targetarch/vtophys.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/tsunami_cchip.hh"
+
+const char *NsRxStateStrings[] =
+{
+ "rxIdle",
+ "rxDescRefr",
+ "rxDescRead",
+ "rxFifoBlock",
+ "rxFragWrite",
+ "rxDescWrite",
+ "rxAdvance"
+};
+
+const char *NsTxStateStrings[] =
+{
+ "txIdle",
+ "txDescRefr",
+ "txDescRead",
+ "txFifoBlock",
+ "txFragRead",
+ "txDescWrite",
+ "txAdvance"
+};
+
+const char *NsDmaState[] =
+{
+ "dmaIdle",
+ "dmaReading",
+ "dmaWriting",
+ "dmaReadWaiting",
+ "dmaWriteWaiting"
+};
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////
+//
+// NSGigE PCI Device
+//
+NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
+ PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
+ MemoryController *mmu, HierParams *hier, Bus *header_bus,
+ Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
+ bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
+ Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
+ PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
+ uint32_t func, bool rx_filter, const int eaddr[6], Addr addr)
+ : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t),
+ addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
+ txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false),
+ txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
+ txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
+ CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
+ rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
+ rxDmaReadEvent(this), rxDmaWriteEvent(this),
+ txDmaReadEvent(this), txDmaWriteEvent(this),
+ dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
+ txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
+ txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
+ acceptMulticast(false), acceptUnicast(false),
+ acceptPerfect(false), acceptArp(false),
+ physmem(pmem), intctrl(i), intrTick(0),
+ cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+ tsunami->ethernet = this;
+
+ if (header_bus) {
+ pioInterface = newPioInterface(name, hier, header_bus, this,
+ &NSGigE::cacheAccess);
+ pioInterface->addAddrRange(addr, addr + size - 1);
+ if (payload_bus)
+ dmaInterface = new DMAInterface<Bus>(name + ".dma",
+ header_bus, payload_bus, 1);
+ else
+ dmaInterface = new DMAInterface<Bus>(name + ".dma",
+ header_bus, header_bus, 1);
+ } else if (payload_bus) {
+ pioInterface = newPioInterface(name, hier, payload_bus, this,
+ &NSGigE::cacheAccess);
+ pioInterface->addAddrRange(addr, addr + size - 1);
+ dmaInterface = new DMAInterface<Bus>(name + ".dma",
+ payload_bus, payload_bus, 1);
+
+ }
+
+
+ intrDelay = US2Ticks(intr_delay);
+ dmaReadDelay = dma_read_delay;
+ dmaWriteDelay = dma_write_delay;
+ dmaReadFactor = dma_read_factor;
+ dmaWriteFactor = dma_write_factor;
+
+ memset(&regs, 0, sizeof(regs));
+ regsReset();
+ rom.perfectMatch[0] = eaddr[0];
+ rom.perfectMatch[1] = eaddr[1];
+ rom.perfectMatch[2] = eaddr[2];
+ rom.perfectMatch[3] = eaddr[3];
+ rom.perfectMatch[4] = eaddr[4];
+ rom.perfectMatch[5] = eaddr[5];
+}
+
+NSGigE::~NSGigE()
+{}
+
+void
+NSGigE::regStats()
+{
+ txBytes
+ .name(name() + ".txBytes")
+ .desc("Bytes Transmitted")
+ .prereq(txBytes)
+ ;
+
+ rxBytes
+ .name(name() + ".rxBytes")
+ .desc("Bytes Received")
+ .prereq(rxBytes)
+ ;
+
+ txPackets
+ .name(name() + ".txPackets")
+ .desc("Number of Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ rxPackets
+ .name(name() + ".rxPackets")
+ .desc("Number of Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ txBandwidth
+ .name(name() + ".txBandwidth")
+ .desc("Transmit Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxBandwidth
+ .name(name() + ".rxBandwidth")
+ .desc("Receive Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ txPacketRate
+ .name(name() + ".txPPS")
+ .desc("Packet Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxPacketRate
+ .name(name() + ".rxPPS")
+ .desc("Packet Reception Rate (packets/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ txBandwidth = txBytes * Stats::constant(8) / simSeconds;
+ rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
+ txPacketRate = txPackets / simSeconds;
+ rxPacketRate = rxPackets / simSeconds;
+}
+
+/**
+ * This is to read the PCI general configuration registers
+ */
+void
+NSGigE::ReadConfig(int offset, int size, uint8_t *data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC)
+ PciDev::ReadConfig(offset, size, data);
+ else {
+ panic("need to do this\n");
+ }
+}
+
+/**
+ * This is to write to the PCI general configuration registers
+ */
+void
+NSGigE::WriteConfig(int offset, int size, uint32_t data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC)
+ PciDev::WriteConfig(offset, size, data);
+ else
+ panic("Need to do that\n");
+}
+
+/**
+ * This reads the device registers, which are detailed in the NS83820
+ * spec sheet
+ */
+Fault
+NSGigE::read(MemReqPtr &req, uint8_t *data)
+{
+ //The mask is to give you only the offset into the device register file
+ Addr daddr = req->paddr & 0xfff;
+ DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n",
+ daddr, req->paddr, req->vaddr, req->size);
+
+
+ //there are some reserved registers, you can see ns_gige_reg.h and
+ //the spec sheet for details
+ if (daddr > LAST && daddr <= RESERVED) {
+ panic("Accessing reserved register");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ ReadConfig(daddr & 0xff, req->size, data);
+ return No_Fault;
+ } else if (daddr >= MIB_START && daddr <= MIB_END) {
+ // don't implement all the MIB's. hopefully the kernel
+ // doesn't actually DEPEND upon their values
+ // MIB are just hardware stats keepers
+ uint32_t &reg = *(uint32_t *) data;
+ reg = 0;
+ return No_Fault;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
+
+ switch (req->size) {
+ case sizeof(uint32_t):
+ {
+ uint32_t &reg = *(uint32_t *)data;
+
+ switch (daddr) {
+ case CR:
+ reg = regs.command;
+ //these are supposed to be cleared on a read
+ reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
+ break;
+
+ case CFG:
+ reg = regs.config;
+ break;
+
+ case MEAR:
+ reg = regs.mear;
+ break;
+
+ case PTSCR:
+ reg = regs.ptscr;
+ break;
+
+ case ISR:
+ reg = regs.isr;
+ devIntrClear(ISR_ALL);
+ break;
+
+ case IMR:
+ reg = regs.imr;
+ break;
+
+ case IER:
+ reg = regs.ier;
+ break;
+
+ case IHR:
+ reg = regs.ihr;
+ break;
+
+ case TXDP:
+ reg = regs.txdp;
+ break;
+
+ case TXDP_HI:
+ reg = regs.txdp_hi;
+ break;
+
+ case TXCFG:
+ reg = regs.txcfg;
+ break;
+
+ case GPIOR:
+ reg = regs.gpior;
+ break;
+
+ case RXDP:
+ reg = regs.rxdp;
+ break;
+
+ case RXDP_HI:
+ reg = regs.rxdp_hi;
+ break;
+
+ case RXCFG:
+ reg = regs.rxcfg;
+ break;
+
+ case PQCR:
+ reg = regs.pqcr;
+ break;
+
+ case WCSR:
+ reg = regs.wcsr;
+ break;
+
+ case PCR:
+ reg = regs.pcr;
+ break;
+
+ //see the spec sheet for how RFCR and RFDR work
+ //basically, you write to RFCR to tell the machine what you want to do next
+ //then you act upon RFDR, and the device will be prepared b/c
+ //of what you wrote to RFCR
+ case RFCR:
+ reg = regs.rfcr;
+ break;
+
+ case RFDR:
+ switch (regs.rfcr & RFCR_RFADDR) {
+ case 0x000:
+ reg = rom.perfectMatch[1];
+ reg = reg << 8;
+ reg += rom.perfectMatch[0];
+ break;
+ case 0x002:
+ reg = rom.perfectMatch[3] << 8;
+ reg += rom.perfectMatch[2];
+ break;
+ case 0x004:
+ reg = rom.perfectMatch[5] << 8;
+ reg += rom.perfectMatch[4];
+ break;
+ default:
+ panic("reading from RFDR for something for other than PMATCH!\n");
+ //didn't implement other RFDR functionality b/c driver didn't use
+ }
+ break;
+
+ case SRR:
+ reg = regs.srr;
+ break;
+
+ case MIBC:
+ reg = regs.mibc;
+ reg &= ~(MIBC_MIBS | MIBC_ACLR);
+ break;
+
+ case VRCR:
+ reg = regs.vrcr;
+ break;
+
+ case VTCR:
+ reg = regs.vtcr;
+ break;
+
+ case VDR:
+ reg = regs.vdr;
+ break;
+
+ case CCSR:
+ reg = regs.ccsr;
+ break;
+
+ case TBICR:
+ reg = regs.tbicr;
+ break;
+
+ case TBISR:
+ reg = regs.tbisr;
+ break;
+
+ case TANAR:
+ reg = regs.tanar;
+ break;
+
+ case TANLPAR:
+ reg = regs.tanlpar;
+ break;
+
+ case TANER:
+ reg = regs.taner;
+ break;
+
+ case TESR:
+ reg = regs.tesr;
+ break;
+
+ default:
+ panic("reading unimplemented register: addr = %#x", daddr);
+ }
+
+ DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
+ daddr, reg, reg);
+ }
+ break;
+
+ default:
+ panic("accessing register with invalid size: addr=%#x, size=%d",
+ daddr, req->size);
+ }
+
+ return No_Fault;
+}
+
+Fault
+NSGigE::write(MemReqPtr &req, const uint8_t *data)
+{
+ Addr daddr = req->paddr & 0xfff;
+ DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
+ daddr, req->paddr, req->vaddr, req->size);
+
+ if (daddr > LAST && daddr <= RESERVED) {
+ panic("Accessing reserved register");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
+ return No_Fault;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
+
+ if (req->size == sizeof(uint32_t)) {
+ uint32_t reg = *(uint32_t *)data;
+ DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
+
+ switch (daddr) {
+ case CR:
+ regs.command = reg;
+ if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
+ txHalt = true;
+ } else if (reg & CR_TXE) {
+ //the kernel is enabling the transmit machine
+ if (txState == txIdle)
+ txKick();
+ } else if (reg & CR_TXD) {
+ txHalt = true;
+ }
+
+ if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
+ rxHalt = true;
+ } else if (reg & CR_RXE) {
+ if (rxState == rxIdle) {
+ rxKick();
+ }
+ } else if (reg & CR_RXD) {
+ rxHalt = true;
+ }
+
+ if (reg & CR_TXR)
+ txReset();
+
+ if (reg & CR_RXR)
+ rxReset();
+
+ if (reg & CR_SWI)
+ devIntrPost(ISR_SWI);
+
+ if (reg & CR_RST) {
+ txReset();
+ rxReset();
+
+ regsReset();
+ }
+ break;
+
+ case CFG:
+ if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
+ || reg & CFG_RESERVED || reg & CFG_T64ADDR
+ || reg & CFG_PCI64_DET)
+ panic("writing to read-only or reserved CFG bits!\n");
+
+ regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
+ CFG_T64ADDR | CFG_PCI64_DET);
+
+// all these #if 0's are because i don't THINK the kernel needs to have these implemented
+// if there is a problem relating to one of these, you may need to add functionality in
+#if 0
+ if (reg & CFG_TBI_EN) ;
+ if (reg & CFG_MODE_1000) ;
+#endif
+
+ if (reg & CFG_AUTO_1000)
+ panic("CFG_AUTO_1000 not implemented!\n");
+
+#if 0
+ if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
+ if (reg & CFG_TMRTEST) ;
+ if (reg & CFG_MRM_DIS) ;
+ if (reg & CFG_MWI_DIS) ;
+
+ if (reg & CFG_T64ADDR)
+ panic("CFG_T64ADDR is read only register!\n");
+
+ if (reg & CFG_PCI64_DET)
+ panic("CFG_PCI64_DET is read only register!\n");
+
+ if (reg & CFG_DATA64_EN) ;
+ if (reg & CFG_M64ADDR) ;
+ if (reg & CFG_PHY_RST) ;
+ if (reg & CFG_PHY_DIS) ;
+#endif
+
+ if (reg & CFG_EXTSTS_EN)
+ extstsEnable = true;
+ else
+ extstsEnable = false;
+
+#if 0
+ if (reg & CFG_REQALG) ;
+ if (reg & CFG_SB) ;
+ if (reg & CFG_POW) ;
+ if (reg & CFG_EXD) ;
+ if (reg & CFG_PESEL) ;
+ if (reg & CFG_BROM_DIS) ;
+ if (reg & CFG_EXT_125) ;
+ if (reg & CFG_BEM) ;
+#endif
+ break;
+
+ case MEAR:
+ regs.mear = reg;
+ /* since phy is completely faked, MEAR_MD* don't matter
+ and since the driver never uses MEAR_EE*, they don't matter */
+#if 0
+ if (reg & MEAR_EEDI) ;
+ if (reg & MEAR_EEDO) ; //this one is read only
+ if (reg & MEAR_EECLK) ;
+ if (reg & MEAR_EESEL) ;
+ if (reg & MEAR_MDIO) ;
+ if (reg & MEAR_MDDIR) ;
+ if (reg & MEAR_MDC) ;
+#endif
+ break;
+
+ case PTSCR:
+ regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
+ /* these control BISTs for various parts of chip - we don't care or do
+ just fake that the BIST is done */
+ if (reg & PTSCR_RBIST_EN)
+ regs.ptscr |= PTSCR_RBIST_DONE;
+ if (reg & PTSCR_EEBIST_EN)
+ regs.ptscr &= ~PTSCR_EEBIST_EN;
+ if (reg & PTSCR_EELOAD_EN)
+ regs.ptscr &= ~PTSCR_EELOAD_EN;
+ break;
+
+ case ISR: /* writing to the ISR has no effect */
+ panic("ISR is a read only register!\n");
+
+ case IMR:
+ regs.imr = reg;
+ devIntrChangeMask();
+ break;
+
+ case IER:
+ regs.ier = reg;
+ break;
+
+ case IHR:
+ regs.ihr = reg;
+ /* not going to implement real interrupt holdoff */
+ break;
+
+ case TXDP:
+ regs.txdp = (reg & 0xFFFFFFFC);
+ assert(txState == txIdle);
+ CTDD = false;
+ break;
+
+ case TXDP_HI:
+ regs.txdp_hi = reg;
+ break;
+
+ case TXCFG:
+ regs.txcfg = reg;
+#if 0
+ if (reg & TXCFG_CSI) ;
+ if (reg & TXCFG_HBI) ;
+ if (reg & TXCFG_MLB) ;
+ if (reg & TXCFG_ATP) ;
+ if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but
+ considering the network is just a fake
+ pipe, wouldn't make sense to do this */
+
+ if (reg & TXCFG_BRST_DIS) ;
+#endif
+
+
+ /* we handle our own DMA, ignore the kernel's exhortations */
+ if (reg & TXCFG_MXDMA) ;
+
+ break;
+
+ case GPIOR:
+ regs.gpior = reg;
+ /* these just control general purpose i/o pins, don't matter */
+ break;
+
+ case RXDP:
+ regs.rxdp = reg;
+ break;
+
+ case RXDP_HI:
+ regs.rxdp_hi = reg;
+ break;
+
+ case RXCFG:
+ regs.rxcfg = reg;
+#if 0
+ if (reg & RXCFG_AEP) ;
+ if (reg & RXCFG_ARP) ;
+ if (reg & RXCFG_STRIPCRC) ;
+ if (reg & RXCFG_RX_RD) ;
+ if (reg & RXCFG_ALP) ;
+ if (reg & RXCFG_AIRL) ;
+#endif
+
+ /* we handle our own DMA, ignore what kernel says about it */
+ if (reg & RXCFG_MXDMA) ;
+
+#if 0
+ if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
+#endif
+ break;
+
+ case PQCR:
+ /* there is no priority queueing used in the linux 2.6 driver */
+ regs.pqcr = reg;
+ break;
+
+ case WCSR:
+ /* not going to implement wake on LAN */
+ regs.wcsr = reg;
+ break;
+
+ case PCR:
+ /* not going to implement pause control */
+ regs.pcr = reg;
+ break;
+
+ case RFCR:
+ regs.rfcr = reg;
+
+ rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
+
+ acceptBroadcast = (reg & RFCR_AAB) ? true : false;
+
+ acceptMulticast = (reg & RFCR_AAM) ? true : false;
+
+ acceptUnicast = (reg & RFCR_AAU) ? true : false;
+
+ acceptPerfect = (reg & RFCR_APM) ? true : false;
+
+ acceptArp = (reg & RFCR_AARP) ? true : false;
+
+ if (reg & RFCR_APAT) ;
+// panic("RFCR_APAT not implemented!\n");
+
+ if (reg & RFCR_MHEN || reg & RFCR_UHEN)
+ panic("hash filtering not implemented!\n");
+
+ if (reg & RFCR_ULM)
+ panic("RFCR_ULM not implemented!\n");
+
+ break;
+
+ case RFDR:
+ panic("the driver never writes to RFDR, something is wrong!\n");
+
+ case BRAR:
+ panic("the driver never uses BRAR, something is wrong!\n");
+
+ case BRDR:
+ panic("the driver never uses BRDR, something is wrong!\n");
+
+ case SRR:
+ panic("SRR is read only register!\n");
+
+ case MIBC:
+ panic("the driver never uses MIBC, something is wrong!\n");
+
+ case VRCR:
+ regs.vrcr = reg;
+ break;
+
+ case VTCR:
+ regs.vtcr = reg;
+ break;
+
+ case VDR:
+ panic("the driver never uses VDR, something is wrong!\n");
+ break;
+
+ case CCSR:
+ /* not going to implement clockrun stuff */
+ regs.ccsr = reg;
+ break;
+
+ case TBICR:
+ regs.tbicr = reg;
+ if (reg & TBICR_MR_LOOPBACK)
+ panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
+
+ if (reg & TBICR_MR_AN_ENABLE) {
+ regs.tanlpar = regs.tanar;
+ regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
+ }
+
+#if 0
+ if (reg & TBICR_MR_RESTART_AN) ;
+#endif
+
+ break;
+
+ case TBISR:
+ panic("TBISR is read only register!\n");
+
+ case TANAR:
+ regs.tanar = reg;
+ if (reg & TANAR_PS2)
+ panic("this isn't used in driver, something wrong!\n");
+
+ if (reg & TANAR_PS1)
+ panic("this isn't used in driver, something wrong!\n");
+ break;
+
+ case TANLPAR:
+ panic("this should only be written to by the fake phy!\n");
+
+ case TANER:
+ panic("TANER is read only register!\n");
+
+ case TESR:
+ regs.tesr = reg;
+ break;
+
+ default:
+ panic("thought i covered all the register, what is this? addr=%#x",
+ daddr);
+ }
+ } else
+ panic("Invalid Request Size");
+
+ return No_Fault;
+}
+
+void
+NSGigE::devIntrPost(uint32_t interrupts)
+{
+ bool delay = false;
+
+ if (interrupts & ISR_RESERVE)
+ panic("Cannot set a reserved interrupt");
+
+ if (interrupts & ISR_TXRCMP)
+ regs.isr |= ISR_TXRCMP;
+
+ if (interrupts & ISR_RXRCMP)
+ regs.isr |= ISR_RXRCMP;
+
+//ISR_DPERR not implemented
+//ISR_SSERR not implemented
+//ISR_RMABT not implemented
+//ISR_RXSOVR not implemented
+//ISR_HIBINT not implemented
+//ISR_PHY not implemented
+//ISR_PME not implemented
+
+ if (interrupts & ISR_SWI)
+ regs.isr |= ISR_SWI;
+
+//ISR_MIB not implemented
+//ISR_TXURN not implemented
+
+ if (interrupts & ISR_TXIDLE)
+ regs.isr |= ISR_TXIDLE;
+
+ if (interrupts & ISR_TXERR)
+ regs.isr |= ISR_TXERR;
+
+ if (interrupts & ISR_TXDESC)
+ regs.isr |= ISR_TXDESC;
+
+ if (interrupts & ISR_TXOK) {
+ regs.isr |= ISR_TXOK;
+ delay = true;
+ }
+
+ if (interrupts & ISR_RXORN)
+ regs.isr |= ISR_RXORN;
+
+ if (interrupts & ISR_RXIDLE)
+ regs.isr |= ISR_RXIDLE;
+
+//ISR_RXEARLY not implemented
+
+ if (interrupts & ISR_RXERR)
+ regs.isr |= ISR_RXERR;
+
+ if (interrupts & ISR_RXDESC)
+ regs.isr |= ISR_RXDESC;
+
+ if (interrupts & ISR_RXOK) {
+ delay = true;
+ regs.isr |= ISR_RXOK;
+ }
+
+ if ((regs.isr & regs.imr)) {
+ Tick when = curTick;
+ if (delay)
+ when += intrDelay;
+ cpuIntrPost(when);
+ }
+
+ DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
+ interrupts, regs.isr, regs.imr);
+}
+
+void
+NSGigE::devIntrClear(uint32_t interrupts)
+{
+ if (interrupts & ISR_RESERVE)
+ panic("Cannot clear a reserved interrupt");
+
+ if (interrupts & ISR_TXRCMP)
+ regs.isr &= ~ISR_TXRCMP;
+
+ if (interrupts & ISR_RXRCMP)
+ regs.isr &= ~ISR_RXRCMP;
+
+//ISR_DPERR not implemented
+//ISR_SSERR not implemented
+//ISR_RMABT not implemented
+//ISR_RXSOVR not implemented
+//ISR_HIBINT not implemented
+//ISR_PHY not implemented
+//ISR_PME not implemented
+
+ if (interrupts & ISR_SWI)
+ regs.isr &= ~ISR_SWI;
+
+//ISR_MIB not implemented
+//ISR_TXURN not implemented
+
+ if (interrupts & ISR_TXIDLE)
+ regs.isr &= ~ISR_TXIDLE;
+
+ if (interrupts & ISR_TXERR)
+ regs.isr &= ~ISR_TXERR;
+
+ if (interrupts & ISR_TXDESC)
+ regs.isr &= ~ISR_TXDESC;
+
+ if (interrupts & ISR_TXOK)
+ regs.isr &= ~ISR_TXOK;
+
+ if (interrupts & ISR_RXORN)
+ regs.isr &= ~ISR_RXORN;
+
+ if (interrupts & ISR_RXIDLE)
+ regs.isr &= ~ISR_RXIDLE;
+
+//ISR_RXEARLY not implemented
+
+ if (interrupts & ISR_RXERR)
+ regs.isr &= ~ISR_RXERR;
+
+ if (interrupts & ISR_RXDESC)
+ regs.isr &= ~ISR_RXDESC;
+
+ if (interrupts & ISR_RXOK)
+ regs.isr &= ~ISR_RXOK;
+
+ if (!(regs.isr & regs.imr))
+ cpuIntrClear();
+
+ DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
+ interrupts, regs.isr, regs.imr);
+}
+
+void
+NSGigE::devIntrChangeMask()
+{
+ DPRINTF(Ethernet, "interrupt mask changed\n");
+
+ if (regs.isr & regs.imr)
+ cpuIntrPost(curTick);
+ else
+ cpuIntrClear();
+}
+
+void
+NSGigE::cpuIntrPost(Tick when)
+{
+ if (when > intrTick && intrTick != 0)
+ return;
+
+ intrTick = when;
+
+ if (intrEvent) {
+ intrEvent->squash();
+ intrEvent = 0;
+ }
+
+ if (when < curTick) {
+ cpuInterrupt();
+ } else {
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrTick);
+ }
+}
+
+void
+NSGigE::cpuInterrupt()
+{
+ // Don't send an interrupt if there's already one
+ if (cpuPendingIntr)
+ return;
+
+ // Don't send an interrupt if it's supposed to be delayed
+ if (intrTick > curTick)
+ return;
+
+ // Whether or not there's a pending interrupt, we don't care about
+ // it anymore
+ intrEvent = 0;
+ intrTick = 0;
+
+ // Send interrupt
+ cpuPendingIntr = true;
+ /** @todo rework the intctrl to be tsunami ok */
+ //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+ tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
+}
+
+void
+NSGigE::cpuIntrClear()
+{
+ if (cpuPendingIntr) {
+ cpuPendingIntr = false;
+ /** @todo rework the intctrl to be tsunami ok */
+ //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+ tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
+ }
+}
+
+bool
+NSGigE::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+NSGigE::txReset()
+{
+
+ DPRINTF(Ethernet, "transmit reset\n");
+
+ CTDD = false;
+ txFifoCnt = 0;
+ txFifoAvail = MAX_TX_FIFO_SIZE;
+ txHalt = false;
+ txFragPtr = 0;
+ assert(txDescCnt == 0);
+ txFifo.clear();
+ regs.command &= ~CR_TXE;
+ txState = txIdle;
+ assert(txDmaState == dmaIdle);
+}
+
+void
+NSGigE::rxReset()
+{
+ DPRINTF(Ethernet, "receive reset\n");
+
+ CRDD = false;
+ assert(rxPktBytes == 0);
+ rxFifoCnt = 0;
+ rxHalt = false;
+ rxFragPtr = 0;
+ assert(rxDescCnt == 0);
+ assert(rxDmaState == dmaIdle);
+ rxFifo.clear();
+ regs.command &= ~CR_RXE;
+ rxState = rxIdle;
+}
+
+void
+NSGigE::rxDmaReadCopy()
+{
+ assert(rxDmaState == dmaReading);
+
+ memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
+ rxDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+}
+
+bool
+NSGigE::doRxDmaRead()
+{
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
+ rxDmaState = dmaReading;
+
+ if (dmaInterface && !rxDmaFree) {
+ if (dmaInterface->busy())
+ rxDmaState = dmaReadWaiting;
+ else
+ dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
+ &rxDmaReadEvent);
+ return true;
+ }
+
+ if (dmaReadDelay == 0 && dmaReadFactor == 0) {
+ rxDmaReadCopy();
+ return false;
+ }
+
+ Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
+ Tick start = curTick + dmaReadDelay + factor;
+ rxDmaReadEvent.schedule(start);
+ return true;
+}
+
+void
+NSGigE::rxDmaReadDone()
+{
+ assert(rxDmaState == dmaReading);
+ rxDmaReadCopy();
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
+}
+
+void
+NSGigE::rxDmaWriteCopy()
+{
+ assert(rxDmaState == dmaWriting);
+
+ memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
+ rxDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+}
+
+bool
+NSGigE::doRxDmaWrite()
+{
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
+ rxDmaState = dmaWriting;
+
+ if (dmaInterface && !rxDmaFree) {
+ if (dmaInterface->busy())
+ rxDmaState = dmaWriteWaiting;
+ else
+ dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
+ &rxDmaWriteEvent);
+ return true;
+ }
+
+ if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
+ rxDmaWriteCopy();
+ return false;
+ }
+
+ Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
+ Tick start = curTick + dmaWriteDelay + factor;
+ rxDmaWriteEvent.schedule(start);
+ return true;
+}
+
+void
+NSGigE::rxDmaWriteDone()
+{
+ assert(rxDmaState == dmaWriting);
+ rxDmaWriteCopy();
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
+}
+
+void
+NSGigE::rxKick()
+{
+ DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
+ NsRxStateStrings[rxState], rxFifo.size());
+
+ if (rxKickTick > curTick) {
+ DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+ return;
+ }
+
+ next:
+ switch(rxDmaState) {
+ case dmaReadWaiting:
+ if (doRxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doRxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ // see state machine from spec for details
+ // the way this works is, if you finish work on one state and can go directly to
+ // another, you do that through jumping to the label "next". however, if you have
+ // intermediate work, like DMA so that you can't go to the next state yet, you go to
+ // exit and exit the loop. however, when the DMA is done it will trigger an
+ // event and come back to this loop.
+ switch (rxState) {
+ case rxIdle:
+ if (!regs.command & CR_RXE) {
+ DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
+ goto exit;
+ }
+
+ if (CRDD) {
+ rxState = rxDescRefr;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache + offsetof(ns_desc, link);
+ rxDmaLen = sizeof(rxDescCache.link);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
+ } else {
+ rxState = rxDescRead;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache;
+ rxDmaLen = sizeof(ns_desc);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
+ }
+ break;
+
+ case rxDescRefr:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ rxState = rxAdvance;
+ break;
+
+ case rxDescRead:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ DPRINTF(Ethernet,
+ "rxDescCache:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n"
+ ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
+ rxDescCache.extsts);
+
+ if (rxDescCache.cmdsts & CMDSTS_OWN) {
+ rxState = rxIdle;
+ } else {
+ rxState = rxFifoBlock;
+ rxFragPtr = rxDescCache.bufptr;
+ rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
+ }
+ break;
+
+ case rxFifoBlock:
+ if (!rxPacket) {
+ /**
+ * @todo in reality, we should be able to start processing
+ * the packet as it arrives, and not have to wait for the
+ * full packet ot be in the receive fifo.
+ */
+ if (rxFifo.empty())
+ goto exit;
+
+ // If we don't have a packet, grab a new one from the fifo.
+ rxPacket = rxFifo.front();
+ rxPktBytes = rxPacket->length;
+ rxPacketBufPtr = rxPacket->data;
+
+ // sanity check - i think the driver behaves like this
+ assert(rxDescCnt >= rxPktBytes);
+
+ // Must clear the value before popping to decrement the
+ // reference count
+ rxFifo.front() = NULL;
+ rxFifo.pop_front();
+ }
+
+
+ // dont' need the && rxDescCnt > 0 if driver sanity check above holds
+ if (rxPktBytes > 0) {
+ rxState = rxFragWrite;
+ // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
+ rxXferLen = rxPktBytes;
+
+ rxDmaAddr = rxFragPtr & 0x3fffffff;
+ rxDmaData = rxPacketBufPtr;
+ rxDmaLen = rxXferLen;
+ rxDmaFree = dmaDataFree;
+
+ if (doRxDmaWrite())
+ goto exit;
+
+ } else {
+ rxState = rxDescWrite;
+
+ //if (rxPktBytes == 0) { /* packet is done */
+ assert(rxPktBytes == 0);
+
+ rxDescCache.cmdsts |= CMDSTS_OWN;
+ rxDescCache.cmdsts &= ~CMDSTS_MORE;
+ rxDescCache.cmdsts |= CMDSTS_OK;
+ rxDescCache.cmdsts &= 0xffff0000;
+ rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE
+
+#if 0
+ /* all the driver uses these are for its own stats keeping
+ which we don't care about, aren't necessary for functionality
+ and doing this would just slow us down. if they end up using
+ this in a later version for functional purposes, just undef
+ */
+ if (rxFilterEnable) {
+ rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
+ if (rxFifo.front()->IsUnicast())
+ rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
+ if (rxFifo.front()->IsMulticast())
+ rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
+ if (rxFifo.front()->IsBroadcast())
+ rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
+ }
+#endif
+
+ eth_header *eth = (eth_header *) rxPacket->data;
+ // eth->type 0x800 indicated that it's an ip packet.
+ if (eth->type == 0x800 && extstsEnable) {
+ rxDescCache.extsts |= EXTSTS_IPPKT;
+ if (!ipChecksum(rxPacket, false))
+ rxDescCache.extsts |= EXTSTS_IPERR;
+ ip_header *ip = rxFifo.front()->getIpHdr();
+
+ if (ip->protocol == 6) {
+ rxDescCache.extsts |= EXTSTS_TCPPKT;
+ if (!tcpChecksum(rxPacket, false))
+ rxDescCache.extsts |= EXTSTS_TCPERR;
+ } else if (ip->protocol == 17) {
+ rxDescCache.extsts |= EXTSTS_UDPPKT;
+ if (!udpChecksum(rxPacket, false))
+ rxDescCache.extsts |= EXTSTS_UDPERR;
+ }
+ }
+
+ rxFifoCnt -= rxPacket->length;
+ rxPacket = 0;
+
+ /* the driver seems to always receive into desc buffers
+ of size 1514, so you never have a pkt that is split
+ into multiple descriptors on the receive side, so
+ i don't implement that case, hence the assert above.
+ */
+
+ DPRINTF(Ethernet, "rxDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n",
+ rxDescCache.cmdsts, rxDescCache.extsts);
+
+ rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
+ rxDmaData = &(rxDescCache.cmdsts);
+ rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaWrite())
+ goto exit;
+ }
+ break;
+
+ case rxFragWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ rxPacketBufPtr += rxXferLen;
+ rxFragPtr += rxXferLen;
+ rxPktBytes -= rxXferLen;
+
+ rxState = rxFifoBlock;
+ break;
+
+ case rxDescWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ assert(rxDescCache.cmdsts & CMDSTS_OWN);
+
+ assert(rxPacket == 0);
+ devIntrPost(ISR_RXOK);
+
+ if (rxDescCache.cmdsts & CMDSTS_INTR)
+ devIntrPost(ISR_RXDESC);
+
+ if (rxHalt) {
+ rxState = rxIdle;
+ rxHalt = false;
+ } else
+ rxState = rxAdvance;
+ break;
+
+ case rxAdvance:
+ if (rxDescCache.link == 0) {
+ rxState = rxIdle;
+ return;
+ } else {
+ rxState = rxDescRead;
+ regs.rxdp = rxDescCache.link;
+ CRDD = false;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache;
+ rxDmaLen = sizeof(ns_desc);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
+ }
+ break;
+
+ default:
+ panic("Invalid rxState!");
+ }
+
+
+ DPRINTF(Ethernet, "entering next rx state = %s\n",
+ NsRxStateStrings[rxState]);
+
+ if (rxState == rxIdle) {
+ regs.command &= ~CR_RXE;
+ devIntrPost(ISR_RXIDLE);
+ return;
+ }
+
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(Ethernet, "rx state machine exited state=%s\n",
+ NsRxStateStrings[rxState]);
+}
+
+void
+NSGigE::transmit()
+{
+ if (txFifo.empty()) {
+ DPRINTF(Ethernet, "nothing to transmit\n");
+ return;
+ }
+
+ if (interface->sendPacket(txFifo.front())) {
+ DPRINTF(Ethernet, "transmit packet\n");
+ DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
+ txBytes += txFifo.front()->length;
+ txPackets++;
+
+ txFifoCnt -= (txFifo.front()->length - txPktXmitted);
+ txPktXmitted = 0;
+ txFifo.front() = NULL;
+ txFifo.pop_front();
+
+ /* normally do a writeback of the descriptor here, and ONLY after that is
+ done, send this interrupt. but since our stuff never actually fails,
+ just do this interrupt here, otherwise the code has to stray from this
+ nice format. besides, it's functionally the same.
+ */
+ devIntrPost(ISR_TXOK);
+ }
+
+ if (!txFifo.empty() && !txEvent.scheduled()) {
+ DPRINTF(Ethernet, "reschedule transmit\n");
+ txEvent.schedule(curTick + 1000);
+ }
+}
+
+void
+NSGigE::txDmaReadCopy()
+{
+ assert(txDmaState == dmaReading);
+
+ memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
+ txDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
+}
+
+bool
+NSGigE::doTxDmaRead()
+{
+ assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
+ txDmaState = dmaReading;
+
+ if (dmaInterface && !txDmaFree) {
+ if (dmaInterface->busy())
+ txDmaState = dmaReadWaiting;
+ else
+ dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
+ &txDmaReadEvent);
+ return true;
+ }
+
+ if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
+ txDmaReadCopy();
+ return false;
+ }
+
+ Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
+ Tick start = curTick + dmaReadDelay + factor;
+ txDmaReadEvent.schedule(start);
+ return true;
+}
+
+void
+NSGigE::txDmaReadDone()
+{
+ assert(txDmaState == dmaReading);
+ txDmaReadCopy();
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
+}
+
+void
+NSGigE::txDmaWriteCopy()
+{
+ assert(txDmaState == dmaWriting);
+
+ memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
+ txDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
+}
+
+bool
+NSGigE::doTxDmaWrite()
+{
+ assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
+ txDmaState = dmaWriting;
+
+ if (dmaInterface && !txDmaFree) {
+ if (dmaInterface->busy())
+ txDmaState = dmaWriteWaiting;
+ else
+ dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
+ &txDmaWriteEvent);
+ return true;
+ }
+
+ if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
+ txDmaWriteCopy();
+ return false;
+ }
+
+ Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
+ Tick start = curTick + dmaWriteDelay + factor;
+ txDmaWriteEvent.schedule(start);
+ return true;
+}
+
+void
+NSGigE::txDmaWriteDone()
+{
+ assert(txDmaState == dmaWriting);
+ txDmaWriteCopy();
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
+}
+
+void
+NSGigE::txKick()
+{
+ DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
+
+ if (rxKickTick > curTick) {
+ DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+
+ return;
+ }
+
+ next:
+ switch(txDmaState) {
+ case dmaReadWaiting:
+ if (doTxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doTxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ switch (txState) {
+ case txIdle:
+ if (!regs.command & CR_TXE) {
+ DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n");
+ goto exit;
+ }
+
+ if (CTDD) {
+ txState = txDescRefr;
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &txDescCache + offsetof(ns_desc, link);
+ txDmaLen = sizeof(txDescCache.link);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
+
+ } else {
+ txState = txDescRead;
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &txDescCache;
+ txDmaLen = sizeof(ns_desc);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
+
+ case txDescRefr:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ txState = txAdvance;
+ break;
+
+ case txDescRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ DPRINTF(Ethernet,
+ "txDescCache data:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n"
+ ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
+ txDescCache.extsts);
+
+ if (txDescCache.cmdsts & CMDSTS_OWN) {
+ txState = txFifoBlock;
+ txFragPtr = txDescCache.bufptr;
+ txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
+ } else {
+ txState = txIdle;
+ }
+ break;
+
+ case txFifoBlock:
+ if (!txPacket) {
+ DPRINTF(Ethernet, "starting the tx of a new packet\n");
+ txPacket = new EtherPacket;
+ txPacket->data = new uint8_t[16384];
+ txPacketBufPtr = txPacket->data;
+ }
+
+ if (txDescCnt == 0) {
+ DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n");
+ if (txDescCache.cmdsts & CMDSTS_MORE) {
+ DPRINTF(Ethernet, "there are more descriptors to come\n");
+ txState = txDescWrite;
+
+ txDescCache.cmdsts &= ~CMDSTS_OWN;
+
+ txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
+ txDmaData = &(txDescCache.cmdsts);
+ txDmaLen = sizeof(txDescCache.cmdsts);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaWrite())
+ goto exit;
+
+ } else { /* this packet is totally done */
+ DPRINTF(Ethernet, "This packet is done, let's wrap it up\n");
+ /* deal with the the packet that just finished */
+ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
+ if (txDescCache.extsts & EXTSTS_UDPPKT) {
+ udpChecksum(txPacket, true);
+ } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
+ tcpChecksum(txPacket, true);
+ } else if (txDescCache.extsts & EXTSTS_IPPKT) {
+ ipChecksum(txPacket, true);
+ }
+ }
+
+ txPacket->length = txPacketBufPtr - txPacket->data;
+ /* this is just because the receive can't handle a packet bigger
+ want to make sure */
+ assert(txPacket->length <= 1514);
+ txFifo.push_back(txPacket);
+
+
+ /* this following section is not to spec, but functionally shouldn't
+ be any different. normally, the chip will wait til the transmit has
+ occurred before writing back the descriptor because it has to wait
+ to see that it was successfully transmitted to decide whether to set
+ CMDSTS_OK or not. however, in the simulator since it is always
+ successfully transmitted, and writing it exactly to spec would
+ complicate the code, we just do it here
+ */
+ txDescCache.cmdsts &= ~CMDSTS_OWN;
+ txDescCache.cmdsts |= CMDSTS_OK;
+
+ DPRINTF(Ethernet,
+ "txDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n",
+ txDescCache.cmdsts, txDescCache.extsts);
+
+ txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
+ txDmaData = &(txDescCache.cmdsts);
+ txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaWrite())
+ goto exit;
+
+ txPacket = 0;
+ transmit();
+
+ if (txHalt) {
+ txState = txIdle;
+ txHalt = false;
+ } else
+ txState = txAdvance;
+ }
+ } else {
+ DPRINTF(Ethernet, "this descriptor isn't done yet\n");
+ /* the fill thresh is in units of 32 bytes, shift right by 8 to get the
+ value, shift left by 5 to get the real number of bytes */
+ if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) {
+ DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n",
+ txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK);
+ goto exit;
+ }
+
+ txState = txFragRead;
+
+ /* The number of bytes transferred is either whatever is left
+ in the descriptor (txDescCnt), or if there is not enough
+ room in the fifo, just whatever room is left in the fifo
+ */
+ txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
+
+ txDmaAddr = txFragPtr & 0x3fffffff;
+ txDmaData = txPacketBufPtr;
+ txDmaLen = txXferLen;
+ txDmaFree = dmaDataFree;
+
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
+
+ case txFragRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ txPacketBufPtr += txXferLen;
+ txFragPtr += txXferLen;
+ txFifoCnt += txXferLen;
+ txDescCnt -= txXferLen;
+
+ txState = txFifoBlock;
+ break;
+
+ case txDescWrite:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) {
+ if (txFifo.empty()) {
+ uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted);
+ txFifoCnt -= xmitted;
+ txPktXmitted += xmitted;
+ } else {
+ transmit();
+ }
+ }
+
+ if (txDescCache.cmdsts & CMDSTS_INTR) {
+ devIntrPost(ISR_TXDESC);
+ }
+
+ txState = txAdvance;
+ break;
+
+ case txAdvance:
+ if (txDescCache.link == 0) {
+ txState = txIdle;
+ } else {
+ txState = txDescRead;
+ regs.txdp = txDescCache.link;
+ CTDD = false;
+
+ txDmaAddr = txDescCache.link & 0x3fffffff;
+ txDmaData = &txDescCache;
+ txDmaLen = sizeof(ns_desc);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
+
+ default:
+ panic("invalid state");
+ }
+
+ DPRINTF(Ethernet, "entering next tx state=%s\n",
+ NsTxStateStrings[txState]);
+
+ if (txState == txIdle) {
+ regs.command &= ~CR_TXE;
+ devIntrPost(ISR_TXIDLE);
+ return;
+ }
+
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(Ethernet, "tx state machine exited state=%s\n",
+ NsTxStateStrings[txState]);
+}
+
+void
+NSGigE::transferDone()
+{
+ if (txFifo.empty())
+ return;
+
+ DPRINTF(Ethernet, "schedule transmit\n");
+
+ if (txEvent.scheduled())
+ txEvent.reschedule(curTick + 1);
+ else
+ txEvent.schedule(curTick + 1);
+}
+
+bool
+NSGigE::rxFilter(PacketPtr packet)
+{
+ bool drop = true;
+ string type;
+
+ if (packet->IsUnicast()) {
+ type = "unicast";
+
+ // If we're accepting all unicast addresses
+ if (acceptUnicast)
+ drop = false;
+
+ // If we make a perfect match
+ if ((acceptPerfect)
+ && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
+ drop = false;
+
+ eth_header *eth = (eth_header *) packet->data;
+ if ((acceptArp) && (eth->type == 0x806))
+ drop = false;
+
+ } else if (packet->IsBroadcast()) {
+ type = "broadcast";
+
+ // if we're accepting broadcasts
+ if (acceptBroadcast)
+ drop = false;
+
+ } else if (packet->IsMulticast()) {
+ type = "multicast";
+
+ // if we're accepting all multicasts
+ if (acceptMulticast)
+ drop = false;
+
+ } else {
+ type = "unknown";
+
+ // oh well, punt on this one
+ }
+
+ if (drop) {
+ DPRINTF(Ethernet, "rxFilter drop\n");
+ DDUMP(EthernetData, packet->data, packet->length);
+ }
+
+ return drop;
+}
+
+bool
+NSGigE::recvPacket(PacketPtr packet)
+{
+ rxBytes += packet->length;
+ rxPackets++;
+
+ if (rxState == rxIdle) {
+ DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+ interface->recvDone();
+ return true;
+ }
+
+ if (rxFilterEnable && rxFilter(packet)) {
+ DPRINTF(Ethernet, "packet filtered...dropped\n");
+ interface->recvDone();
+ return true;
+ }
+
+ if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
+ DPRINTF(Ethernet,
+ "packet will not fit in receive buffer...packet dropped\n");
+ devIntrPost(ISR_RXORN);
+ return false;
+ }
+
+ rxFifo.push_back(packet);
+ rxFifoCnt += packet->length;
+ interface->recvDone();
+
+ rxKick();
+ return true;
+}
+
+/**
+ * does a udp checksum. if gen is true, then it generates it and puts it in the right place
+ * else, it just checks what it calculates against the value in the header in packet
+ */
+bool
+NSGigE::udpChecksum(PacketPtr packet, bool gen)
+{
+ udp_header *hdr = (udp_header *) packet->getTransportHdr();
+
+ ip_header *ip = packet->getIpHdr();
+
+ pseudo_header *pseudo = new pseudo_header;
+
+ pseudo->src_ip_addr = ip->src_ip_addr;
+ pseudo->dest_ip_addr = ip->dest_ip_addr;
+ pseudo->protocol = ip->protocol;
+ pseudo->len = hdr->len;
+
+ uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
+ (uint32_t) hdr->len);
+
+ delete pseudo;
+ if (gen)
+ hdr->chksum = cksum;
+ else
+ if (cksum != 0)
+ return false;
+
+ return true;
+}
+
+bool
+NSGigE::tcpChecksum(PacketPtr packet, bool gen)
+{
+ tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
+
+ ip_header *ip = packet->getIpHdr();
+
+ pseudo_header *pseudo = new pseudo_header;
+
+ pseudo->src_ip_addr = ip->src_ip_addr;
+ pseudo->dest_ip_addr = ip->dest_ip_addr;
+ pseudo->protocol = ip->protocol;
+ pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
+
+ uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
+ (uint32_t) pseudo->len);
+
+ delete pseudo;
+ if (gen)
+ hdr->chksum = cksum;
+ else
+ if (cksum != 0)
+ return false;
+
+ return true;
+}
+
+bool
+NSGigE::ipChecksum(PacketPtr packet, bool gen)
+{
+ ip_header *hdr = packet->getIpHdr();
+
+ uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
+
+ if (gen)
+ hdr->hdr_chksum = cksum;
+ else
+ if (cksum != 0)
+ return false;
+
+ return true;
+}
+
+uint16_t
+NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
+{
+ uint32_t sum = 0;
+
+ uint16_t last_pad = 0;
+ if (len & 1) {
+ last_pad = buf[len/2] & 0xff;
+ len--;
+ sum += last_pad;
+ }
+
+ if (pseudo) {
+ sum = pseudo[0] + pseudo[1] + pseudo[2] +
+ pseudo[3] + pseudo[4] + pseudo[5];
+ }
+
+ for (int i=0; i < (len/2); ++i) {
+ sum += buf[i];
+ }
+
+ while (sum >> 16)
+ sum = (sum >> 16) + (sum & 0xffff);
+
+ return ~sum;
+}
+
+//=====================================================================
+//
+//
+void
+NSGigE::serialize(ostream &os)
+{
+ /*
+ * Finalize any DMA events now.
+ */
+ if (rxDmaReadEvent.scheduled())
+ rxDmaReadCopy();
+ if (rxDmaWriteEvent.scheduled())
+ rxDmaWriteCopy();
+ if (txDmaReadEvent.scheduled())
+ txDmaReadCopy();
+ if (txDmaWriteEvent.scheduled())
+ txDmaWriteCopy();
+
+ /*
+ * Serialize the device registers
+ */
+ SERIALIZE_SCALAR(regs.command);
+ SERIALIZE_SCALAR(regs.config);
+ SERIALIZE_SCALAR(regs.mear);
+ SERIALIZE_SCALAR(regs.ptscr);
+ SERIALIZE_SCALAR(regs.isr);
+ SERIALIZE_SCALAR(regs.imr);
+ SERIALIZE_SCALAR(regs.ier);
+ SERIALIZE_SCALAR(regs.ihr);
+ SERIALIZE_SCALAR(regs.txdp);
+ SERIALIZE_SCALAR(regs.txdp_hi);
+ SERIALIZE_SCALAR(regs.txcfg);
+ SERIALIZE_SCALAR(regs.gpior);
+ SERIALIZE_SCALAR(regs.rxdp);
+ SERIALIZE_SCALAR(regs.rxdp_hi);
+ SERIALIZE_SCALAR(regs.rxcfg);
+ SERIALIZE_SCALAR(regs.pqcr);
+ SERIALIZE_SCALAR(regs.wcsr);
+ SERIALIZE_SCALAR(regs.pcr);
+ SERIALIZE_SCALAR(regs.rfcr);
+ SERIALIZE_SCALAR(regs.rfdr);
+ SERIALIZE_SCALAR(regs.srr);
+ SERIALIZE_SCALAR(regs.mibc);
+ SERIALIZE_SCALAR(regs.vrcr);
+ SERIALIZE_SCALAR(regs.vtcr);
+ SERIALIZE_SCALAR(regs.vdr);
+ SERIALIZE_SCALAR(regs.ccsr);
+ SERIALIZE_SCALAR(regs.tbicr);
+ SERIALIZE_SCALAR(regs.tbisr);
+ SERIALIZE_SCALAR(regs.tanar);
+ SERIALIZE_SCALAR(regs.tanlpar);
+ SERIALIZE_SCALAR(regs.taner);
+ SERIALIZE_SCALAR(regs.tesr);
+
+ SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+
+ /*
+ * Serialize the various helper variables
+ */
+ uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr;
+ SERIALIZE_SCALAR(txPktBufPtr);
+ uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr;
+ SERIALIZE_SCALAR(rxPktBufPtr);
+ SERIALIZE_SCALAR(txXferLen);
+ SERIALIZE_SCALAR(rxXferLen);
+ SERIALIZE_SCALAR(txPktXmitted);
+
+ bool txPacketExists = txPacket;
+ SERIALIZE_SCALAR(txPacketExists);
+ bool rxPacketExists = rxPacket;
+ SERIALIZE_SCALAR(rxPacketExists);
+
+ /*
+ * Serialize DescCaches
+ */
+ SERIALIZE_SCALAR(txDescCache.link);
+ SERIALIZE_SCALAR(txDescCache.bufptr);
+ SERIALIZE_SCALAR(txDescCache.cmdsts);
+ SERIALIZE_SCALAR(txDescCache.extsts);
+ SERIALIZE_SCALAR(rxDescCache.link);
+ SERIALIZE_SCALAR(rxDescCache.bufptr);
+ SERIALIZE_SCALAR(rxDescCache.cmdsts);
+ SERIALIZE_SCALAR(rxDescCache.extsts);
+
+ /*
+ * Serialize tx state machine
+ */
+ int txNumPkts = txFifo.size();
+ SERIALIZE_SCALAR(txNumPkts);
+ int txState = this->txState;
+ SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(CTDD);
+ SERIALIZE_SCALAR(txFifoCnt);
+ SERIALIZE_SCALAR(txFifoAvail);
+ SERIALIZE_SCALAR(txHalt);
+ SERIALIZE_SCALAR(txFragPtr);
+ SERIALIZE_SCALAR(txDescCnt);
+ int txDmaState = this->txDmaState;
+ SERIALIZE_SCALAR(txDmaState);
+
+ /*
+ * Serialize rx state machine
+ */
+ int rxNumPkts = rxFifo.size();
+ SERIALIZE_SCALAR(rxNumPkts);
+ int rxState = this->rxState;
+ SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(CRDD);
+ SERIALIZE_SCALAR(rxPktBytes);
+ SERIALIZE_SCALAR(rxFifoCnt);
+ SERIALIZE_SCALAR(rxHalt);
+ SERIALIZE_SCALAR(rxDescCnt);
+ int rxDmaState = this->rxDmaState;
+ SERIALIZE_SCALAR(rxDmaState);
+
+ SERIALIZE_SCALAR(extstsEnable);
+
+ /*
+ * If there's a pending transmit, store the time so we can
+ * reschedule it later
+ */
+ Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
+ SERIALIZE_SCALAR(transmitTick);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ SERIALIZE_SCALAR(intrTick);
+ SERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick = 0;
+ if (intrEvent)
+ intrEventTick = intrEvent->when();
+ SERIALIZE_SCALAR(intrEventTick);
+
+ int i = 0;
+ for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) {
+ nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
+ (*p)->serialize(os);
+ }
+ if (rxPacketExists) {
+ nameOut(os, csprintf("%s.rxPacket", name()));
+ rxPacket->serialize(os);
+ }
+ i = 0;
+ for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) {
+ nameOut(os, csprintf("%s.txFifo%d", name(), i++));
+ (*p)->serialize(os);
+ }
+ if (txPacketExists) {
+ nameOut(os, csprintf("%s.txPacket", name()));
+ txPacket->serialize(os);
+ }
+}
+
+void
+NSGigE::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(regs.command);
+ UNSERIALIZE_SCALAR(regs.config);
+ UNSERIALIZE_SCALAR(regs.mear);
+ UNSERIALIZE_SCALAR(regs.ptscr);
+ UNSERIALIZE_SCALAR(regs.isr);
+ UNSERIALIZE_SCALAR(regs.imr);
+ UNSERIALIZE_SCALAR(regs.ier);
+ UNSERIALIZE_SCALAR(regs.ihr);
+ UNSERIALIZE_SCALAR(regs.txdp);
+ UNSERIALIZE_SCALAR(regs.txdp_hi);
+ UNSERIALIZE_SCALAR(regs.txcfg);
+ UNSERIALIZE_SCALAR(regs.gpior);
+ UNSERIALIZE_SCALAR(regs.rxdp);
+ UNSERIALIZE_SCALAR(regs.rxdp_hi);
+ UNSERIALIZE_SCALAR(regs.rxcfg);
+ UNSERIALIZE_SCALAR(regs.pqcr);
+ UNSERIALIZE_SCALAR(regs.wcsr);
+ UNSERIALIZE_SCALAR(regs.pcr);
+ UNSERIALIZE_SCALAR(regs.rfcr);
+ UNSERIALIZE_SCALAR(regs.rfdr);
+ UNSERIALIZE_SCALAR(regs.srr);
+ UNSERIALIZE_SCALAR(regs.mibc);
+ UNSERIALIZE_SCALAR(regs.vrcr);
+ UNSERIALIZE_SCALAR(regs.vtcr);
+ UNSERIALIZE_SCALAR(regs.vdr);
+ UNSERIALIZE_SCALAR(regs.ccsr);
+ UNSERIALIZE_SCALAR(regs.tbicr);
+ UNSERIALIZE_SCALAR(regs.tbisr);
+ UNSERIALIZE_SCALAR(regs.tanar);
+ UNSERIALIZE_SCALAR(regs.tanlpar);
+ UNSERIALIZE_SCALAR(regs.taner);
+ UNSERIALIZE_SCALAR(regs.tesr);
+
+ UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+
+ /*
+ * unserialize the various helper variables
+ */
+ uint32_t txPktBufPtr;
+ UNSERIALIZE_SCALAR(txPktBufPtr);
+ txPacketBufPtr = (uint8_t *) txPktBufPtr;
+ uint32_t rxPktBufPtr;
+ UNSERIALIZE_SCALAR(rxPktBufPtr);
+ rxPacketBufPtr = (uint8_t *) rxPktBufPtr;
+ UNSERIALIZE_SCALAR(txXferLen);
+ UNSERIALIZE_SCALAR(rxXferLen);
+ UNSERIALIZE_SCALAR(txPktXmitted);
+
+ bool txPacketExists;
+ UNSERIALIZE_SCALAR(txPacketExists);
+ bool rxPacketExists;
+ UNSERIALIZE_SCALAR(rxPacketExists);
+
+ /*
+ * Unserialize DescCaches
+ */
+ UNSERIALIZE_SCALAR(txDescCache.link);
+ UNSERIALIZE_SCALAR(txDescCache.bufptr);
+ UNSERIALIZE_SCALAR(txDescCache.cmdsts);
+ UNSERIALIZE_SCALAR(txDescCache.extsts);
+ UNSERIALIZE_SCALAR(rxDescCache.link);
+ UNSERIALIZE_SCALAR(rxDescCache.bufptr);
+ UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
+ UNSERIALIZE_SCALAR(rxDescCache.extsts);
+
+ /*
+ * unserialize tx state machine
+ */
+ int txNumPkts;
+ UNSERIALIZE_SCALAR(txNumPkts);
+ int txState;
+ UNSERIALIZE_SCALAR(txState);
+ this->txState = (TxState) txState;
+ UNSERIALIZE_SCALAR(CTDD);
+ UNSERIALIZE_SCALAR(txFifoCnt);
+ UNSERIALIZE_SCALAR(txFifoAvail);
+ UNSERIALIZE_SCALAR(txHalt);
+ UNSERIALIZE_SCALAR(txFragPtr);
+ UNSERIALIZE_SCALAR(txDescCnt);
+ int txDmaState;
+ UNSERIALIZE_SCALAR(txDmaState);
+ this->txDmaState = (DmaState) txDmaState;
+
+ /*
+ * unserialize rx state machine
+ */
+ int rxNumPkts;
+ UNSERIALIZE_SCALAR(rxNumPkts);
+ int rxState;
+ UNSERIALIZE_SCALAR(rxState);
+ this->rxState = (RxState) rxState;
+ UNSERIALIZE_SCALAR(CRDD);
+ UNSERIALIZE_SCALAR(rxPktBytes);
+ UNSERIALIZE_SCALAR(rxFifoCnt);
+ UNSERIALIZE_SCALAR(rxHalt);
+ UNSERIALIZE_SCALAR(rxDescCnt);
+ int rxDmaState;
+ UNSERIALIZE_SCALAR(rxDmaState);
+ this->rxDmaState = (DmaState) rxDmaState;
+
+ UNSERIALIZE_SCALAR(extstsEnable);
+
+ /*
+ * If there's a pending transmit, store the time so we can
+ * reschedule it later
+ */
+ Tick transmitTick;
+ UNSERIALIZE_SCALAR(transmitTick);
+ if (transmitTick)
+ txEvent.schedule(curTick + transmitTick);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ UNSERIALIZE_SCALAR(intrTick);
+ UNSERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick;
+ UNSERIALIZE_SCALAR(intrEventTick);
+ if (intrEventTick) {
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrEventTick);
+ }
+
+ for (int i = 0; i < rxNumPkts; ++i) {
+ PacketPtr p = new EtherPacket;
+ p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
+ rxFifo.push_back(p);
+ }
+ rxPacket = NULL;
+ if (rxPacketExists) {
+ rxPacket = new EtherPacket;
+ rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
+ }
+ for (int i = 0; i < txNumPkts; ++i) {
+ PacketPtr p = new EtherPacket;
+ p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
+ txFifo.push_back(p);
+ }
+ if (txPacketExists) {
+ txPacket = new EtherPacket;
+ txPacket->unserialize(cp, csprintf("%s.txPacket", section));
+ }
+}
+
+
+Tick
+NSGigE::cacheAccess(MemReqPtr &req)
+{
+ DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
+ req->paddr, req->paddr - addr);
+ return curTick + pioLatency;
+}
+//=====================================================================
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<NSGigE *> device;
+
+END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM(device, "Ethernet device of this interface")
+
+END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
+
+CREATE_SIM_OBJECT(NSGigEInt)
+{
+ NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
+
+ EtherInt *p = (EtherInt *)peer;
+ if (p) {
+ dev_int->setPeer(p);
+ p->setPeer(dev_int);
+ }
+
+ return dev_int;
+}
+
+REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
+
+ Param<Tick> tx_delay;
+ Param<Tick> rx_delay;
+ SimObjectParam<IntrControl *> intr_ctrl;
+ Param<Tick> intr_delay;
+ SimObjectParam<MemoryController *> mmu;
+ SimObjectParam<PhysicalMemory *> physmem;
+ Param<Addr> addr;
+ Param<bool> rx_filter;
+ Param<string> hardware_address;
+ SimObjectParam<Bus*> header_bus;
+ SimObjectParam<Bus*> payload_bus;
+ SimObjectParam<HierParams *> hier;
+ Param<Tick> pio_latency;
+ Param<bool> dma_desc_free;
+ Param<bool> dma_data_free;
+ Param<Tick> dma_read_delay;
+ Param<Tick> dma_write_delay;
+ Param<Tick> dma_read_factor;
+ Param<Tick> dma_write_factor;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ SimObjectParam<Tsunami *> tsunami;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+
+END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
+
+ INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
+ INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
+ INIT_PARAM(intr_ctrl, "Interrupt Controller"),
+ INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(physmem, "Physical Memory"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
+ INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
+ "00:99:00:00:00:01"),
+ INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
+ INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
+ INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
+ INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
+ INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
+ INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
+ INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
+ INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
+ INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
+ INIT_PARAM(configspace, "PCI Configspace"),
+ INIT_PARAM(configdata, "PCI Config data"),
+ INIT_PARAM(tsunami, "Tsunami"),
+ INIT_PARAM(pci_bus, "PCI bus"),
+ INIT_PARAM(pci_dev, "PCI device number"),
+ INIT_PARAM(pci_func, "PCI function code")
+
+END_INIT_SIM_OBJECT_PARAMS(NSGigE)
+
+
+CREATE_SIM_OBJECT(NSGigE)
+{
+ int eaddr[6];
+ sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
+ &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
+
+ return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
+ physmem, tx_delay, rx_delay, mmu, hier, header_bus,
+ payload_bus, pio_latency, dma_desc_free, dma_data_free,
+ dma_read_delay, dma_write_delay, dma_read_factor,
+ dma_write_factor, configspace, configdata,
+ tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
+ addr);
+}
+
+REGISTER_SIM_OBJECT("NSGigE", NSGigE)
diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh
new file mode 100644
index 000000000..ff648adcf
--- /dev/null
+++ b/dev/ns_gige.hh
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller
+ */
+
+#ifndef __NS_GIGE_HH__
+#define __NS_GIGE_HH__
+
+//#include "base/range.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "sim/eventq.hh"
+#include "dev/ns_gige_reg.h"
+#include "base/statistics.hh"
+#include "dev/pcidev.hh"
+#include "dev/tsunami.hh"
+#include "dev/io_device.hh"
+#include "mem/bus/bus.hh"
+
+/** defined by the NS83820 data sheet */
+#define MAX_TX_FIFO_SIZE 8192
+#define MAX_RX_FIFO_SIZE 32768
+
+/** length of ethernet address in bytes */
+#define EADDR_LEN 6
+
+/**
+ * Ethernet device registers
+ */
+struct dp_regs {
+ uint32_t command;
+ uint32_t config;
+ uint32_t mear;
+ uint32_t ptscr;
+ uint32_t isr;
+ uint32_t imr;
+ uint32_t ier;
+ uint32_t ihr;
+ uint32_t txdp;
+ uint32_t txdp_hi;
+ uint32_t txcfg;
+ uint32_t gpior;
+ uint32_t rxdp;
+ uint32_t rxdp_hi;
+ uint32_t rxcfg;
+ uint32_t pqcr;
+ uint32_t wcsr;
+ uint32_t pcr;
+ uint32_t rfcr;
+ uint32_t rfdr;
+ uint32_t srr;
+ uint32_t mibc;
+ uint32_t vrcr;
+ uint32_t vtcr;
+ uint32_t vdr;
+ uint32_t ccsr;
+ uint32_t tbicr;
+ uint32_t tbisr;
+ uint32_t tanar;
+ uint32_t tanlpar;
+ uint32_t taner;
+ uint32_t tesr;
+};
+
+struct dp_rom {
+ /** for perfect match memory. the linux driver doesn't use any other ROM */
+ uint8_t perfectMatch[EADDR_LEN];
+};
+
+class IntrControl;
+class NSGigEInt;
+class PhysicalMemory;
+class BaseInterface;
+class HierParams;
+class Bus;
+class PciConfigAll;
+
+/**
+ * NS DP82830 Ethernet device model
+ */
+class NSGigE : public PciDev
+{
+ public:
+ /** Transmit State Machine states */
+ enum TxState
+ {
+ txIdle,
+ txDescRefr,
+ txDescRead,
+ txFifoBlock,
+ txFragRead,
+ txDescWrite,
+ txAdvance
+ };
+
+ /** Receive State Machine States */
+ enum RxState
+ {
+ rxIdle,
+ rxDescRefr,
+ rxDescRead,
+ rxFifoBlock,
+ rxFragWrite,
+ rxDescWrite,
+ rxAdvance
+ };
+
+ enum DmaState
+ {
+ dmaIdle,
+ dmaReading,
+ dmaWriting,
+ dmaReadWaiting,
+ dmaWriteWaiting
+ };
+
+ private:
+ /** pointer to the chipset */
+ Tsunami *tsunami;
+
+ private:
+ Addr addr;
+ static const Addr size = sizeof(dp_regs);
+
+ protected:
+ typedef std::deque<PacketPtr> pktbuf_t;
+ typedef pktbuf_t::iterator pktiter_t;
+
+ /** device register file */
+ dp_regs regs;
+ dp_rom rom;
+
+ /*** BASIC STRUCTURES FOR TX/RX ***/
+ /* Data FIFOs */
+ pktbuf_t txFifo;
+ pktbuf_t rxFifo;
+
+ /** various helper vars */
+ uint8_t *txPacketBufPtr;
+ uint8_t *rxPacketBufPtr;
+ uint32_t txXferLen;
+ uint32_t rxXferLen;
+ uint32_t txPktXmitted;
+ bool rxDmaFree;
+ bool txDmaFree;
+ PacketPtr txPacket;
+ PacketPtr rxPacket;
+
+ /** DescCaches */
+ ns_desc txDescCache;
+ ns_desc rxDescCache;
+
+ /* tx State Machine */
+ TxState txState;
+ /** Current Transmit Descriptor Done */
+ bool CTDD;
+ /** amt of data in the txDataFifo in bytes (logical) */
+ uint32_t txFifoCnt;
+ /** current amt of free space in txDataFifo in bytes */
+ uint32_t txFifoAvail;
+ /** halt the tx state machine after next packet */
+ bool txHalt;
+ /** ptr to the next byte in the current fragment */
+ Addr txFragPtr;
+ /** count of bytes remaining in the current descriptor */
+ uint32_t txDescCnt;
+ DmaState txDmaState;
+
+ /** rx State Machine */
+ RxState rxState;
+ /** Current Receive Descriptor Done */
+ bool CRDD;
+ /** num of bytes in the current packet being drained from rxDataFifo */
+ uint32_t rxPktBytes;
+ /** number of bytes in the rxFifo */
+ uint32_t rxFifoCnt;
+ /** halt the rx state machine after current packet */
+ bool rxHalt;
+ /** ptr to the next byte in current fragment */
+ Addr rxFragPtr;
+ /** count of bytes remaining in the current descriptor */
+ uint32_t rxDescCnt;
+ DmaState rxDmaState;
+
+ bool extstsEnable;
+
+ protected:
+ Tick dmaReadDelay;
+ Tick dmaWriteDelay;
+
+ Tick dmaReadFactor;
+ Tick dmaWriteFactor;
+
+ void *rxDmaData;
+ Addr rxDmaAddr;
+ int rxDmaLen;
+ bool doRxDmaRead();
+ bool doRxDmaWrite();
+ void rxDmaReadCopy();
+ void rxDmaWriteCopy();
+
+ void *txDmaData;
+ Addr txDmaAddr;
+ int txDmaLen;
+ bool doTxDmaRead();
+ bool doTxDmaWrite();
+ void txDmaReadCopy();
+ void txDmaWriteCopy();
+
+ void rxDmaReadDone();
+ friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>;
+ EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent;
+
+ void rxDmaWriteDone();
+ friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>;
+ EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent;
+
+ void txDmaReadDone();
+ friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>;
+ EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent;
+
+ void txDmaWriteDone();
+ friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>;
+ EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent;
+
+ bool dmaDescFree;
+ bool dmaDataFree;
+
+
+ protected:
+ Tick txDelay;
+ Tick rxDelay;
+
+ void txReset();
+ void rxReset();
+ void regsReset() {
+ memset(&regs, 0, sizeof(regs));
+ regs.config = 0x80000000;
+ regs.mear = 0x12;
+ regs.isr = 0x00608000;
+ regs.txcfg = 0x120;
+ regs.rxcfg = 0x4;
+ regs.srr = 0x0103;
+ regs.mibc = 0x2;
+ regs.vdr = 0x81;
+ regs.tesr = 0xc000;
+ }
+
+ void rxKick();
+ Tick rxKickTick;
+ typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent;
+ friend class RxKickEvent;
+
+ void txKick();
+ Tick txKickTick;
+ typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent;
+ friend class TxKickEvent;
+
+ /**
+ * Retransmit event
+ */
+ void transmit();
+ typedef EventWrapper<NSGigE, &NSGigE::transmit> TxEvent;
+ friend class TxEvent;
+ TxEvent txEvent;
+
+ void txDump() const;
+ void rxDump() const;
+
+ /**
+ * receive address filter
+ */
+ bool rxFilterEnable;
+ bool rxFilter(PacketPtr packet);
+ bool acceptBroadcast;
+ bool acceptMulticast;
+ bool acceptUnicast;
+ bool acceptPerfect;
+ bool acceptArp;
+
+ PhysicalMemory *physmem;
+
+ /**
+ * Interrupt management
+ */
+ IntrControl *intctrl;
+ void devIntrPost(uint32_t interrupts);
+ void devIntrClear(uint32_t interrupts);
+ void devIntrChangeMask();
+
+ Tick intrDelay;
+ Tick intrTick;
+ bool cpuPendingIntr;
+ void cpuIntrPost(Tick when);
+ void cpuInterrupt();
+ void cpuIntrClear();
+
+ typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent;
+ friend class IntrEvent;
+ IntrEvent *intrEvent;
+
+ /**
+ * Hardware checksum support
+ */
+ bool udpChecksum(PacketPtr packet, bool gen);
+ bool tcpChecksum(PacketPtr packet, bool gen);
+ bool ipChecksum(PacketPtr packet, bool gen);
+ uint16_t checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len);
+
+ NSGigEInt *interface;
+
+ public:
+ NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
+ PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
+ MemoryController *mmu, HierParams *hier, Bus *header_bus,
+ Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
+ bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
+ Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
+ PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
+ uint32_t func, bool rx_filter, const int eaddr[6], Addr addr);
+ ~NSGigE();
+
+ virtual void WriteConfig(int offset, int size, uint32_t data);
+ virtual void ReadConfig(int offset, int size, uint8_t *data);
+
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ bool cpuIntrPending() const;
+ void cpuIntrAck() { cpuIntrClear(); }
+
+ bool recvPacket(PacketPtr packet);
+ void transferDone();
+
+ void setInterface(NSGigEInt *i) { assert(!interface); interface = i; }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+ void regStats();
+
+ private:
+ Stats::Scalar<> txBytes;
+ Stats::Scalar<> rxBytes;
+ Stats::Scalar<> txPackets;
+ Stats::Scalar<> rxPackets;
+ Stats::Formula txBandwidth;
+ Stats::Formula rxBandwidth;
+ Stats::Formula txPacketRate;
+ Stats::Formula rxPacketRate;
+
+ private:
+ Tick pioLatency;
+
+ public:
+ Tick cacheAccess(MemReqPtr &req);
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class NSGigEInt : public EtherInt
+{
+ private:
+ NSGigE *dev;
+
+ public:
+ NSGigEInt(const std::string &name, NSGigE *d)
+ : EtherInt(name), dev(d) { dev->setInterface(this); }
+
+ virtual bool recvPacket(PacketPtr &pkt) { return dev->recvPacket(pkt); }
+ virtual void sendDone() { dev->transferDone(); }
+};
+
+#endif // __NS_GIGE_HH__
diff --git a/dev/ns_gige_reg.h b/dev/ns_gige_reg.h
new file mode 100644
index 000000000..774fec435
--- /dev/null
+++ b/dev/ns_gige_reg.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* Portions of code taken from: */
+
+/* ns83820.c by Benjamin LaHaise with contributions.
+ *
+ * Questions/comments/discussion to linux-ns83820@kvack.org.
+ *
+ * $Revision: 1.34.2.23 $
+ *
+ * Copyright 2001 Benjamin LaHaise.
+ * Copyright 2001, 2002 Red Hat.
+ *
+ * Mmmm, chocolate vanilla mocha...
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+
+
+
+/* @file
+ * Ethernet device register definitions for the National
+ * Semiconductor DP83820 Ethernet controller
+ */
+
+#ifndef _NS_GIGE_H
+#define _NS_GIGE_H_
+
+/*
+ * Configuration Register Map
+ */
+#define NS_ID 0x00 /* identification register */
+#define NS_CS 0x04 /* command and status register */
+#define NS_RID 0x08 /* revision ID register */
+#define NS_LAT 0x0C /* latency timer register */
+#define NS_IOA 0x10 /* IO base address register */
+#define NS_MA 0x14 /* memory address register */
+#define NS_MA1 0x18 /* memory address high dword register */
+#define NS_SID 0x2C /* subsystem identification register */
+#define NS_ROM 0x30 /* boot ROM configuration register */
+#define NS_CAPPTR 0x34 /* number of tx descriptors */
+#define NS_INT 0x3C /* interrupt select register */
+#define NS_PMCAP 0x40 /* power mgmt capabilities register */
+#define NS_PMCS 0x44 /* power mgmt control and status
+ register */
+/* Operational Register Map */
+#define CR 0x00
+#define CFG 0x04
+#define MEAR 0x08
+#define PTSCR 0x0c
+#define ISR 0x10
+#define IMR 0x14
+#define IER 0x18
+#define IHR 0x1c
+#define TXDP 0x20
+#define TXDP_HI 0x24
+#define TXCFG 0x28
+#define GPIOR 0x2c
+#define RXDP 0x30
+#define RXDP_HI 0x34
+#define RXCFG 0x38
+#define PQCR 0x3c
+#define WCSR 0x40
+#define PCR 0x44
+#define RFCR 0x48
+#define RFDR 0x4c
+#define BRAR 0x50
+#define BRDR 0x54
+#define SRR 0x58
+#define MIBC 0x5c
+#define MIB_START 0x60
+#define MIB_END 0x88
+#define VRCR 0xbc
+#define VTCR 0xc0
+#define VDR 0xc4
+#define CCSR 0xcc
+#define TBICR 0xe0
+#define TBISR 0xe4
+#define TANAR 0xe8
+#define TANLPAR 0xec
+#define TANER 0xf0
+#define TESR 0xf4
+#define LAST 0xf4
+#define RESERVED 0xfc
+
+/* chip command register */
+#define CR_TXE 0x00000001
+#define CR_TXD 0x00000002
+#define CR_RXE 0x00000004
+#define CR_RXD 0x00000008
+#define CR_TXR 0x00000010
+#define CR_RXR 0x00000020
+#define CR_SWI 0x00000080
+#define CR_RST 0x00000100
+
+/* configuration register */
+#define CFG_LNKSTS 0x80000000
+#define CFG_SPDSTS 0x60000000
+#define CFG_SPDSTS1 0x40000000
+#define CFG_SPDSTS0 0x20000000
+#define CFG_DUPSTS 0x10000000
+#define CFG_TBI_EN 0x01000000
+#define CFG_RESERVED 0x0e000000
+#define CFG_MODE_1000 0x00400000
+#define CFG_AUTO_1000 0x00200000
+#define CFG_PINT_CTL 0x001c0000
+#define CFG_PINT_DUPSTS 0x00100000
+#define CFG_PINT_LNKSTS 0x00080000
+#define CFG_PINT_SPDSTS 0x00040000
+#define CFG_TMRTEST 0x00020000
+#define CFG_MRM_DIS 0x00010000
+#define CFG_MWI_DIS 0x00008000
+#define CFG_T64ADDR 0x00004000
+#define CFG_PCI64_DET 0x00002000
+#define CFG_DATA64_EN 0x00001000
+#define CFG_M64ADDR 0x00000800
+#define CFG_PHY_RST 0x00000400
+#define CFG_PHY_DIS 0x00000200
+#define CFG_EXTSTS_EN 0x00000100
+#define CFG_REQALG 0x00000080
+#define CFG_SB 0x00000040
+#define CFG_POW 0x00000020
+#define CFG_EXD 0x00000010
+#define CFG_PESEL 0x00000008
+#define CFG_BROM_DIS 0x00000004
+#define CFG_EXT_125 0x00000002
+#define CFG_BEM 0x00000001
+
+/* EEPROM access register */
+#define MEAR_EEDI 0x00000001
+#define MEAR_EEDO 0x00000002
+#define MEAR_EECLK 0x00000004
+#define MEAR_EESEL 0x00000008
+#define MEAR_MDIO 0x00000010
+#define MEAR_MDDIR 0x00000020
+#define MEAR_MDC 0x00000040
+
+/* PCI test control register */
+#define PTSCR_EEBIST_FAIL 0x00000001
+#define PTSCR_EEBIST_EN 0x00000002
+#define PTSCR_EELOAD_EN 0x00000004
+#define PTSCR_RBIST_FAIL 0x000001b8
+#define PTSCR_RBIST_DONE 0x00000200
+#define PTSCR_RBIST_EN 0x00000400
+#define PTSCR_RBIST_RST 0x00002000
+#define PTSCR_RBIST_RDONLY 0x000003f9
+
+/* interrupt status register */
+#define ISR_RESERVE 0x80000000
+#define ISR_TXDESC3 0x40000000
+#define ISR_TXDESC2 0x20000000
+#define ISR_TXDESC1 0x10000000
+#define ISR_TXDESC0 0x08000000
+#define ISR_RXDESC3 0x04000000
+#define ISR_RXDESC2 0x02000000
+#define ISR_RXDESC1 0x01000000
+#define ISR_RXDESC0 0x00800000
+#define ISR_TXRCMP 0x00400000
+#define ISR_RXRCMP 0x00200000
+#define ISR_DPERR 0x00100000
+#define ISR_SSERR 0x00080000
+#define ISR_RMABT 0x00040000
+#define ISR_RTABT 0x00020000
+#define ISR_RXSOVR 0x00010000
+#define ISR_HIBINT 0x00008000
+#define ISR_PHY 0x00004000
+#define ISR_PME 0x00002000
+#define ISR_SWI 0x00001000
+#define ISR_MIB 0x00000800
+#define ISR_TXURN 0x00000400
+#define ISR_TXIDLE 0x00000200
+#define ISR_TXERR 0x00000100
+#define ISR_TXDESC 0x00000080
+#define ISR_TXOK 0x00000040
+#define ISR_RXORN 0x00000020
+#define ISR_RXIDLE 0x00000010
+#define ISR_RXEARLY 0x00000008
+#define ISR_RXERR 0x00000004
+#define ISR_RXDESC 0x00000002
+#define ISR_RXOK 0x00000001
+#define ISR_ALL 0x7FFFFFFF
+
+/* transmit configuration register */
+#define TXCFG_CSI 0x80000000
+#define TXCFG_HBI 0x40000000
+#define TXCFG_MLB 0x20000000
+#define TXCFG_ATP 0x10000000
+#define TXCFG_ECRETRY 0x00800000
+#define TXCFG_BRST_DIS 0x00080000
+#define TXCFG_MXDMA1024 0x00000000
+#define TXCFG_MXDMA512 0x00700000
+#define TXCFG_MXDMA256 0x00600000
+#define TXCFG_MXDMA128 0x00500000
+#define TXCFG_MXDMA64 0x00400000
+#define TXCFG_MXDMA32 0x00300000
+#define TXCFG_MXDMA16 0x00200000
+#define TXCFG_MXDMA8 0x00100000
+#define TXCFG_MXDMA 0x00700000
+
+#define TXCFG_FLTH_MASK 0x0000ff00
+#define TXCFG_DRTH_MASK 0x000000ff
+
+/*general purpose I/O control register */
+#define GPIOR_GP5_OE 0x00000200
+#define GPIOR_GP4_OE 0x00000100
+#define GPIOR_GP3_OE 0x00000080
+#define GPIOR_GP2_OE 0x00000040
+#define GPIOR_GP1_OE 0x00000020
+#define GPIOR_GP3_OUT 0x00000004
+#define GPIOR_GP1_OUT 0x00000001
+
+/* receive configuration register */
+#define RXCFG_AEP 0x80000000
+#define RXCFG_ARP 0x40000000
+#define RXCFG_STRIPCRC 0x20000000
+#define RXCFG_RX_FD 0x10000000
+#define RXCFG_ALP 0x08000000
+#define RXCFG_AIRL 0x04000000
+#define RXCFG_MXDMA512 0x00700000
+#define RXCFG_MXDMA 0x00700000
+#define RXCFG_DRTH 0x0000003e
+#define RXCFG_DRTH0 0x00000002
+
+/* pause control status register */
+#define PCR_PSEN (1 << 31)
+#define PCR_PS_MCAST (1 << 30)
+#define PCR_PS_DA (1 << 29)
+#define PCR_STHI_8 (3 << 23)
+#define PCR_STLO_4 (1 << 23)
+#define PCR_FFHI_8K (3 << 21)
+#define PCR_FFLO_4K (1 << 21)
+#define PCR_PAUSE_CNT 0xFFFE
+
+/*receive filter/match control register */
+#define RFCR_RFEN 0x80000000
+#define RFCR_AAB 0x40000000
+#define RFCR_AAM 0x20000000
+#define RFCR_AAU 0x10000000
+#define RFCR_APM 0x08000000
+#define RFCR_APAT 0x07800000
+#define RFCR_APAT3 0x04000000
+#define RFCR_APAT2 0x02000000
+#define RFCR_APAT1 0x01000000
+#define RFCR_APAT0 0x00800000
+#define RFCR_AARP 0x00400000
+#define RFCR_MHEN 0x00200000
+#define RFCR_UHEN 0x00100000
+#define RFCR_ULM 0x00080000
+#define RFCR_RFADDR 0x000003ff
+
+/* receive filter/match data register */
+#define RFDR_BMASK 0x00030000
+#define RFDR_RFDATA0 0x000000ff
+#define RFDR_RFDATA1 0x0000ff00
+
+/* management information base control register */
+#define MIBC_MIBS 0x00000008
+#define MIBC_ACLR 0x00000004
+#define MIBC_FRZ 0x00000002
+#define MIBC_WRN 0x00000001
+
+/* VLAN/IP receive control register */
+#define VRCR_RUDPE 0x00000080
+#define VRCR_RTCPE 0x00000040
+#define VRCR_RIPE 0x00000020
+#define VRCR_IPEN 0x00000010
+#define VRCR_DUTF 0x00000008
+#define VRCR_DVTF 0x00000004
+#define VRCR_VTREN 0x00000002
+#define VRCR_VTDEN 0x00000001
+
+/* VLAN/IP transmit control register */
+#define VTCR_PPCHK 0x00000008
+#define VTCR_GCHK 0x00000004
+#define VTCR_VPPTI 0x00000002
+#define VTCR_VGTI 0x00000001
+
+/* Clockrun Control/Status Register */
+#define CCSR_CLKRUN_EN 0x00000001
+
+/* TBI control register */
+#define TBICR_MR_LOOPBACK 0x00004000
+#define TBICR_MR_AN_ENABLE 0x00001000
+#define TBICR_MR_RESTART_AN 0x00000200
+
+/* TBI status register */
+#define TBISR_MR_LINK_STATUS 0x00000020
+#define TBISR_MR_AN_COMPLETE 0x00000004
+
+/* TBI auto-negotiation advertisement register */
+#define TANAR_PS2 0x00000100
+#define TANAR_PS1 0x00000080
+#define TANAR_HALF_DUP 0x00000040
+#define TANAR_FULL_DUP 0x00000020
+
+/*
+ * descriptor format currently assuming link and bufptr
+ * are set for 32 bits,( may be wrong ) ASSUME32
+ */
+struct ns_desc {
+ uint32_t link; /* link field to next descriptor in linked list */
+ uint32_t bufptr; /* pointer to the first fragment or buffer */
+ uint32_t cmdsts; /* command/status field */
+ uint32_t extsts; /* extended status field for VLAN and IP info */
+};
+
+/* cmdsts flags for descriptors */
+#define CMDSTS_OWN 0x80000000
+#define CMDSTS_MORE 0x40000000
+#define CMDSTS_INTR 0x20000000
+#define CMDSTS_ERR 0x10000000
+#define CMDSTS_OK 0x08000000
+#define CMDSTS_LEN_MASK 0x0000ffff
+
+#define CMDSTS_DEST_MASK 0x01800000
+#define CMDSTS_DEST_SELF 0x00800000
+#define CMDSTS_DEST_MULTI 0x01000000
+
+/* extended flags for descriptors */
+#define EXTSTS_UDPERR 0x00400000
+#define EXTSTS_UDPPKT 0x00200000
+#define EXTSTS_TCPERR 0x00100000
+#define EXTSTS_TCPPKT 0x00080000
+#define EXTSTS_IPERR 0x00040000
+#define EXTSTS_IPPKT 0x00020000
+
+
+/* speed status */
+#define SPDSTS_POLARITY (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
+
+#endif /* _NS_GIGE_H_ */
diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc
new file mode 100644
index 000000000..226fd2749
--- /dev/null
+++ b/dev/pciconfigall.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * PCI Configspace implementation
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "dev/scsi_ctrl.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/pcidev.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+PciConfigAll::PciConfigAll(const string &name, Addr a,
+ MemoryController *mmu)
+ : FunctionalMemory(name), addr(a)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+
+ // Make all the pointers to devices null
+ for(int x=0; x < MAX_PCI_DEV; x++)
+ for(int y=0; y < MAX_PCI_FUNC; y++)
+ devices[x][y] = NULL;
+}
+
+Fault
+PciConfigAll::read(MemReqPtr &req, uint8_t *data)
+{
+ DPRINTF(PciConfigAll, "read va=%#x size=%d\n",
+ req->vaddr, req->size);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+
+ int device = (daddr >> 11) & 0x1F;
+ int func = (daddr >> 8) & 0x7;
+ int reg = daddr & 0xFF;
+
+ if (devices[device][func] == NULL) {
+ switch (req->size) {
+ // case sizeof(uint64_t):
+ // *(uint64_t*)data = 0xFFFFFFFFFFFFFFFF;
+ // return No_Fault;
+ case sizeof(uint32_t):
+ *(uint32_t*)data = 0xFFFFFFFF;
+ return No_Fault;
+ case sizeof(uint16_t):
+ *(uint16_t*)data = 0xFFFF;
+ return No_Fault;
+ case sizeof(uint8_t):
+ *(uint8_t*)data = 0xFF;
+ return No_Fault;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ } else {
+ switch (req->size) {
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ devices[device][func]->ReadConfig(reg, req->size, data);
+ return No_Fault;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ }
+
+ DPRINTFN("PCI Configspace ERROR: read daddr=%#x size=%d\n",
+ daddr, req->size);
+
+ return No_Fault;
+}
+
+Fault
+PciConfigAll::write(MemReqPtr &req, const uint8_t *data)
+{
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+
+ int device = (daddr >> 11) & 0x1F;
+ int func = (daddr >> 8) & 0x7;
+ int reg = daddr & 0xFF;
+
+ union {
+ uint8_t byte_value;
+ uint16_t half_value;
+ uint32_t word_value;
+ };
+
+ if (devices[device][func] == NULL)
+ panic("Attempting to write to config space on non-existant device\n");
+ else {
+ switch (req->size) {
+ case sizeof(uint8_t):
+ byte_value = *(uint8_t*)data;
+ break;
+ case sizeof(uint16_t):
+ half_value = *(uint16_t*)data;
+ break;
+ case sizeof(uint32_t):
+ word_value = *(uint32_t*)data;
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ }
+
+ DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
+ req->vaddr, req->size, word_value);
+
+ devices[device][func]->WriteConfig(reg, req->size, word_value);
+
+ return No_Fault;
+}
+
+void
+PciConfigAll::serialize(std::ostream &os)
+{
+ // code should be written
+}
+
+void
+PciConfigAll::unserialize(Checkpoint *cp, const std::string &section)
+{
+ //code should be written
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
+
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+ Param<Addr> mask;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
+
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM(mask, "Address Mask")
+
+END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
+
+CREATE_SIM_OBJECT(PciConfigAll)
+{
+ return new PciConfigAll(getInstanceName(), addr, mmu);
+}
+
+REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/dev/pciconfigall.hh b/dev/pciconfigall.hh
new file mode 100644
index 000000000..6a31a9e73
--- /dev/null
+++ b/dev/pciconfigall.hh
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/*
+ * @file
+ * PCI Config space implementation.
+ */
+
+#ifndef __PCICONFIGALL_HH__
+#define __PCICONFIGALL_HH__
+
+#include "mem/functional_mem/functional_memory.hh"
+#include "dev/pcireg.h"
+
+static const uint32_t MAX_PCI_DEV = 32;
+static const uint32_t MAX_PCI_FUNC = 8;
+
+class PciDev;
+
+/**
+ * PCI Config Space
+ * All of PCI config space needs to return -1 on Tsunami, except
+ * the devices that exist. This device maps the entire bus config
+ * space and passes the requests on to TsunamiPCIDev devices as
+ * appropriate.
+ */
+class PciConfigAll : public FunctionalMemory
+{
+ private:
+ Addr addr;
+ static const Addr size = 0xffffff;
+
+ /**
+ * Pointers to all the devices that are registered with this
+ * particular config space.
+ */
+ PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC];
+
+ public:
+ /**
+ * Constructor for PCIConfigAll
+ * @param name name of the object
+ * @param a base address of the write
+ * @param mmu the memory controller
+ */
+ PciConfigAll(const std::string &name, Addr a, MemoryController *mmu);
+
+
+ /**
+ * Check if a device exists.
+ * @param pcidev PCI device to check
+ * @param pcifunc PCI function to check
+ * @return true if device exists, false otherwise
+ */
+ bool deviceExists(uint32_t pcidev, uint32_t pcifunc)
+ { return devices[pcidev][pcifunc] != NULL ? true : false; }
+
+ /**
+ * Registers a device with the config space object.
+ * @param pcidev PCI device to register
+ * @param pcifunc PCI function to register
+ * @param device device to register
+ */
+ void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device)
+ { devices[pcidev][pcifunc] = device; }
+
+ /**
+ * Read something in PCI config space. If the device does not exist
+ * -1 is returned, if the device does exist its PciDev::ReadConfig (or the
+ * virtual function that overrides) it is called.
+ * @param req Contains the address of the field to read.
+ * @param data Return the field read.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+ /**
+ * Write to PCI config spcae. If the device does not exit the simulator
+ * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual
+ * function that overrides it).
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif // __PCICONFIGALL_HH__
diff --git a/dev/pcidev.cc b/dev/pcidev.cc
new file mode 100644
index 000000000..8d2828809
--- /dev/null
+++ b/dev/pcidev.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * A single PCI device configuration space entry.
+ */
+
+#include <list>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/str.hh" // for to_number
+#include "base/trace.hh"
+#include "dev/pciareg.h"
+#include "dev/pcidev.hh"
+#include "dev/pciconfigall.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "sim/param.hh"
+#include "sim/universe.hh"
+#include "dev/tsunamireg.h"
+
+using namespace std;
+
+PciDev::PciDev(const string &name, MemoryController *mmu, PciConfigAll *cf,
+ PciConfigData *cd, uint32_t bus, uint32_t dev, uint32_t func)
+ : DmaDevice(name), mmu(mmu), configSpace(cf), configData(cd), busNum(bus),
+ deviceNum(dev), functionNum(func)
+{
+ // copy the config data from the PciConfigData object
+ if (cd) {
+ memcpy(config.data, cd->config.data, sizeof(config.data));
+ memcpy(BARSize, cd->BARSize, sizeof(BARSize));
+ memcpy(BARAddrs, cd->BARAddrs, sizeof(BARAddrs));
+ } else
+ panic("NULL pointer to configuration data");
+
+ // Setup pointer in config space to point to this entry
+ if (cf->deviceExists(dev,func))
+ panic("Two PCI devices occuping same dev: %#x func: %#x", dev, func);
+ else
+ cf->registerDevice(dev, func, this);
+}
+
+void
+PciDev::ReadConfig(int offset, int size, uint8_t *data)
+{
+ switch(size) {
+ case sizeof(uint32_t):
+ memcpy((uint32_t*)data, config.data + offset, sizeof(uint32_t));
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
+ deviceNum, functionNum, offset, size,
+ *(uint32_t*)(config.data + offset));
+ break;
+
+ case sizeof(uint16_t):
+ memcpy((uint16_t*)data, config.data + offset, sizeof(uint16_t));
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
+ deviceNum, functionNum, offset, size,
+ *(uint16_t*)(config.data + offset));
+ break;
+
+ case sizeof(uint8_t):
+ memcpy((uint8_t*)data, config.data + offset, sizeof(uint8_t));
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n",
+ deviceNum, functionNum, offset, size,
+ (uint16_t)(*(uint8_t*)(config.data + offset)));
+ break;
+
+ default:
+ panic("Invalid Read Size");
+ }
+}
+
+void
+PciDev::WriteConfig(int offset, int size, uint32_t data)
+{
+ uint32_t barnum;
+
+ union {
+ uint8_t byte_value;
+ uint16_t half_value;
+ uint32_t word_value;
+ };
+ word_value = data;
+
+ DPRINTF(PCIDEV,
+ "write device: %#x function: %#x reg: %#x size: %d data: %#x\n",
+ deviceNum, functionNum, offset, size, word_value);
+
+ barnum = (offset - PCI0_BASE_ADDR0) >> 2;
+
+ switch (size) {
+ case sizeof(uint8_t): // 1-byte access
+ switch (offset) {
+ case PCI0_INTERRUPT_LINE:
+ case PCI_CACHE_LINE_SIZE:
+ case PCI_LATENCY_TIMER:
+ *(uint8_t *)&config.data[offset] = byte_value;
+ break;
+
+ default:
+ panic("writing to a read only register");
+ }
+ break;
+
+ case sizeof(uint16_t): // 2-byte access
+ switch (offset) {
+ case PCI_COMMAND:
+ case PCI_STATUS:
+ case PCI_CACHE_LINE_SIZE:
+ *(uint16_t *)&config.data[offset] = half_value;
+ break;
+
+ default:
+ panic("writing to a read only register");
+ }
+ break;
+
+ case sizeof(uint16_t)+1: // 3-byte access
+ panic("invalid access size");
+
+ case sizeof(uint32_t): // 4-byte access
+ switch (offset) {
+ case PCI0_BASE_ADDR0:
+ case PCI0_BASE_ADDR1:
+ case PCI0_BASE_ADDR2:
+ case PCI0_BASE_ADDR3:
+ case PCI0_BASE_ADDR4:
+ case PCI0_BASE_ADDR5:
+ // Writing 0xffffffff to a BAR tells the card to set the
+ // value of the bar
+ // to size of memory it needs
+ if (word_value == 0xffffffff) {
+ // This is I/O Space, bottom two bits are read only
+ if (config.data[offset] & 0x1) {
+ *(uint32_t *)&config.data[offset] =
+ ~(BARSize[barnum] - 1) |
+ (config.data[offset] & 0x3);
+ } else {
+ // This is memory space, bottom four bits are read only
+ *(uint32_t *)&config.data[offset] =
+ ~(BARSize[barnum] - 1) |
+ (config.data[offset] & 0xF);
+ }
+ } else {
+ // This is I/O Space, bottom two bits are read only
+ if(config.data[offset] & 0x1) {
+ *(uint32_t *)&config.data[offset] = (word_value & ~0x3) |
+ (config.data[offset] & 0x3);
+
+ if (word_value & ~0x1) {
+ Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO;
+ Addr base_size = BARSize[barnum]-1;
+
+ // It's never been set
+ if (BARAddrs[barnum] == 0)
+ mmu->add_child((FunctionalMemory *)this,
+ Range<Addr>(base_addr,
+ base_addr + base_size));
+ else
+ mmu->update_child((FunctionalMemory *)this,
+ Range<Addr>(BARAddrs[barnum],
+ BARAddrs[barnum] +
+ base_size),
+ Range<Addr>(base_addr,
+ base_addr +
+ base_size));
+
+ BARAddrs[barnum] = base_addr;
+ }
+
+ } else {
+ // This is memory space, bottom four bits are read only
+ *(uint32_t *)&config.data[offset] = (word_value & ~0xF) |
+ (config.data[offset] & 0xF);
+
+ if (word_value & ~0x3) {
+ Addr base_addr = (word_value & ~0x3) +
+ TSUNAMI_PCI0_MEMORY;
+
+ Addr base_size = BARSize[barnum]-1;
+
+ // It's never been set
+ if (BARAddrs[barnum] == 0)
+ mmu->add_child((FunctionalMemory *)this,
+ Range<Addr>(base_addr,
+ base_addr + base_size));
+ else
+ mmu->update_child((FunctionalMemory *)this,
+ Range<Addr>(BARAddrs[barnum],
+ BARAddrs[barnum] +
+ base_size),
+ Range<Addr>(base_addr,
+ base_addr +
+ base_size));
+
+ BARAddrs[barnum] = base_addr;
+ }
+ }
+ }
+ break;
+
+ case PCI0_ROM_BASE_ADDR:
+ if (word_value == 0xfffffffe)
+ *(uint32_t *)&config.data[offset] = 0xffffffff;
+ else
+ *(uint32_t *)&config.data[offset] = word_value;
+ break;
+
+ case PCI_COMMAND:
+ // This could also clear some of the error bits in the Status
+ // register. However they should never get set, so lets ignore
+ // it for now
+ *(uint16_t *)&config.data[offset] = half_value;
+ break;
+
+ default:
+ DPRINTF(PCIDEV, "Writing to a read only register");
+ }
+ break;
+ }
+}
+
+void
+PciDev::serialize(ostream &os)
+{
+ SERIALIZE_ARRAY(config.data, 64);
+}
+
+void
+PciDev::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(config.data, 64);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
+
+ Param<int> VendorID;
+ Param<int> DeviceID;
+ Param<int> Command;
+ Param<int> Status;
+ Param<int> Revision;
+ Param<int> ProgIF;
+ Param<int> SubClassCode;
+ Param<int> ClassCode;
+ Param<int> CacheLineSize;
+ Param<int> LatencyTimer;
+ Param<int> HeaderType;
+ Param<int> BIST;
+ Param<uint32_t> BAR0;
+ Param<uint32_t> BAR1;
+ Param<uint32_t> BAR2;
+ Param<uint32_t> BAR3;
+ Param<uint32_t> BAR4;
+ Param<uint32_t> BAR5;
+ Param<uint32_t> CardbusCIS;
+ Param<int> SubsystemVendorID;
+ Param<int> SubsystemID;
+ Param<uint32_t> ExpansionROM;
+ Param<int> InterruptLine;
+ Param<int> InterruptPin;
+ Param<int> MinimumGrant;
+ Param<int> MaximumLatency;
+ Param<uint32_t> BAR0Size;
+ Param<uint32_t> BAR1Size;
+ Param<uint32_t> BAR2Size;
+ Param<uint32_t> BAR3Size;
+ Param<uint32_t> BAR4Size;
+ Param<uint32_t> BAR5Size;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData)
+
+ INIT_PARAM(VendorID, "Vendor ID"),
+ INIT_PARAM(DeviceID, "Device ID"),
+ INIT_PARAM_DFLT(Command, "Command Register", 0x00),
+ INIT_PARAM_DFLT(Status, "Status Register", 0x00),
+ INIT_PARAM_DFLT(Revision, "Device Revision", 0x00),
+ INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00),
+ INIT_PARAM(SubClassCode, "Sub-Class Code"),
+ INIT_PARAM(ClassCode, "Class Code"),
+ INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00),
+ INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00),
+ INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00),
+ INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00),
+ INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00),
+ INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00),
+ INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00),
+ INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00),
+ INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00),
+ INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00),
+ INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00),
+ INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00),
+ INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00),
+ INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00),
+ INIT_PARAM(InterruptLine, "Interrupt Line Register"),
+ INIT_PARAM(InterruptPin, "Interrupt Pin Register"),
+ INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00),
+ INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00),
+ INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00),
+ INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00),
+ INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00),
+ INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00),
+ INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00),
+ INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00)
+
+END_INIT_SIM_OBJECT_PARAMS(PciConfigData)
+
+CREATE_SIM_OBJECT(PciConfigData)
+{
+ PciConfigData *data = new PciConfigData(getInstanceName());
+
+ data->config.hdr.vendor = VendorID;
+ data->config.hdr.device = DeviceID;
+ data->config.hdr.command = Command;
+ data->config.hdr.status = Status;
+ data->config.hdr.revision = Revision;
+ data->config.hdr.progIF = ProgIF;
+ data->config.hdr.subClassCode = SubClassCode;
+ data->config.hdr.classCode = ClassCode;
+ data->config.hdr.cacheLineSize = CacheLineSize;
+ data->config.hdr.latencyTimer = LatencyTimer;
+ data->config.hdr.headerType = HeaderType;
+ data->config.hdr.bist = BIST;
+
+ data->config.hdr.pci0.baseAddr0 = BAR0;
+ data->config.hdr.pci0.baseAddr1 = BAR1;
+ data->config.hdr.pci0.baseAddr2 = BAR2;
+ data->config.hdr.pci0.baseAddr3 = BAR3;
+ data->config.hdr.pci0.baseAddr4 = BAR4;
+ data->config.hdr.pci0.baseAddr5 = BAR5;
+ data->config.hdr.pci0.cardbusCIS = CardbusCIS;
+ data->config.hdr.pci0.subsystemVendorID = SubsystemVendorID;
+ data->config.hdr.pci0.subsystemID = SubsystemVendorID;
+ data->config.hdr.pci0.expansionROM = ExpansionROM;
+ data->config.hdr.pci0.interruptLine = InterruptLine;
+ data->config.hdr.pci0.interruptPin = InterruptPin;
+ data->config.hdr.pci0.minimumGrant = MinimumGrant;
+ data->config.hdr.pci0.maximumLatency = MaximumLatency;
+
+ data->BARSize[0] = BAR0Size;
+ data->BARSize[1] = BAR1Size;
+ data->BARSize[2] = BAR2Size;
+ data->BARSize[3] = BAR3Size;
+ data->BARSize[4] = BAR4Size;
+ data->BARSize[5] = BAR5Size;
+
+ return data;
+}
+
+REGISTER_SIM_OBJECT("PciConfigData", PciConfigData)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/dev/pcidev.hh b/dev/pcidev.hh
new file mode 100644
index 000000000..1c4de18ad
--- /dev/null
+++ b/dev/pcidev.hh
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Interface for devices using PCI configuration
+ */
+
+#ifndef __PCI_DEV_HH__
+#define __PCI_DEV_HH__
+
+#include "dev/pcireg.h"
+#include "dev/io_device.hh"
+
+class PciConfigAll;
+class MemoryController;
+
+
+/**
+ * This class encapulates the first 64 bytes of a singles PCI
+ * devices config space that in configured by the configuration file.
+ */
+class PciConfigData : public SimObject
+{
+ public:
+ /**
+ * Constructor to initialize the devices config space to 0.
+ */
+ PciConfigData(const std::string &name)
+ : SimObject(name)
+ {
+ memset(config.data, 0, sizeof(config.data));
+ memset(BARAddrs, 0, sizeof(BARAddrs));
+ memset(BARSize, 0, sizeof(BARSize));
+ }
+
+ /** The first 64 bytes */
+ PCIConfig config;
+
+ /** The size of the BARs */
+ uint32_t BARSize[6];
+
+ /** The addresses of the BARs */
+ Addr BARAddrs[6];
+};
+
+/**
+ * PCI device, base implemnation is only config space.
+ * Each device is connected to a PCIConfigSpace device
+ * which returns -1 for everything but the pcidevs that
+ * register with it. This object registers with the PCIConfig space
+ * object.
+ */
+class PciDev : public DmaDevice
+{
+ protected:
+ MemoryController *mmu;
+ /** A pointer to the configspace all object that calls
+ * us when a read comes to this particular device/function.
+ */
+ PciConfigAll *configSpace;
+
+ /**
+ * A pointer to the object that contains the first 64 bytes of
+ * config space
+ */
+ PciConfigData *configData;
+
+ /** The bus number we are on */
+ uint32_t busNum;
+
+ /** The device number we have */
+ uint32_t deviceNum;
+
+ /** The function number */
+ uint32_t functionNum;
+
+ /** The current config space. Unlike the PciConfigData this is updated
+ * during simulation while continues to refelect what was in the config file.
+ */
+ PCIConfig config;
+
+ /** The size of the BARs */
+ uint32_t BARSize[6];
+
+ /** The current address mapping of the BARs */
+ Addr BARAddrs[6];
+
+ public:
+ /**
+ * Constructor for PCI Dev. This function copies data from the config file
+ * object PCIConfigData and registers the device with a PciConfigAll object.
+ * @param name name of the object
+ * @param mmu a pointer to the memory controller
+ * @param cf a pointer to the config space object that this device need to
+ * register with
+ * @param cd A pointer to the config space values specified in the conig file
+ * @param bus the bus this device is on
+ * @param dev the device id of this device
+ * @param func the function number of this device
+ */
+ PciDev(const std::string &name, MemoryController *mmu, PciConfigAll *cf,
+ PciConfigData *cd, uint32_t bus, uint32_t dev, uint32_t func);
+
+ virtual Fault read(MemReqPtr &req, uint8_t *data) {
+ return No_Fault;
+ }
+ virtual Fault write(MemReqPtr &req, const uint8_t *data) {
+ return No_Fault;
+ }
+
+ /**
+ * Write to the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param offset the offset into config space
+ * @param size the size of the write
+ * @param data the data to write
+ */
+ virtual void WriteConfig(int offset, int size, uint32_t data);
+
+
+ /**
+ * Read from the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param offset the offset into config space
+ * @param size the size of the read
+ * @param data pointer to the location where the read value should be stored
+ */
+ virtual void ReadConfig(int offset, int size, uint8_t *data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __PCI_DEV_HH__
diff --git a/dev/platform.cc b/dev/platform.cc
new file mode 100644
index 000000000..c39849162
--- /dev/null
+++ b/dev/platform.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#include "dev/platform.hh"
+#include "sim/builder.hh"
+#include "sim/sim_exit.hh"
+
+using namespace std;
+
+DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform)
+
diff --git a/dev/platform.hh b/dev/platform.hh
new file mode 100644
index 000000000..407f58406
--- /dev/null
+++ b/dev/platform.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/**
+ * @file
+ * Generic interface for platforms
+ */
+
+#ifndef __PLATFORM_HH_
+#define __PLATFORM_HH_
+
+#include "sim/sim_object.hh"
+
+class PciConfigAll;
+class IntrControl;
+class SimConsole;
+
+class Platform : public SimObject
+{
+ public:
+ /** Pointer to the interrupt controller */
+ IntrControl *intrctrl;
+ /** Pointer to the simulation console */
+ SimConsole *cons;
+ /** Pointer to the PCI configuration space */
+ PciConfigAll *pciconfig;
+
+ int interrupt_frequency;
+
+ public:
+ Platform(const std::string &name, IntrControl *intctrl,
+ PciConfigAll *pci, int intrFreq)
+ : SimObject(name), intrctrl(intctrl), pciconfig(pci),
+ interrupt_frequency(intrFreq) {}
+ virtual ~Platform() {}
+ virtual void postConsoleInt() = 0;
+ virtual void clearConsoleInt() = 0;
+};
+
+#endif // __PLATFORM_HH_
diff --git a/dev/tsunami.cc b/dev/tsunami.cc
new file mode 100644
index 000000000..8956ee557
--- /dev/null
+++ b/dev/tsunami.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "cpu/intr_control.hh"
+#include "dev/console.hh"
+#include "dev/etherdev.hh"
+#include "dev/ide_ctrl.hh"
+#include "dev/tlaser_clock.hh"
+#include "dev/tsunami_cchip.hh"
+#include "dev/tsunami_pchip.hh"
+#include "dev/tsunami_io.hh"
+#include "dev/tsunami.hh"
+#include "dev/pciconfigall.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+Tsunami::Tsunami(const string &name, System *s,
+ IntrControl *ic, PciConfigAll *pci, int intr_freq)
+ : Platform(name, ic, pci, intr_freq), system(s)
+{
+ // set the back pointer from the system to myself
+ system->platform = this;
+
+ for (int i = 0; i < Tsunami::Max_CPUs; i++)
+ intr_sum_type[i] = 0;
+}
+
+void
+Tsunami::postConsoleInt()
+{
+ io->postPIC(0x10);
+}
+
+void
+Tsunami::clearConsoleInt()
+{
+ io->clearPIC(0x10);
+}
+
+void
+Tsunami::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
+}
+
+void
+Tsunami::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
+
+ SimObjectParam<System *> system;
+ SimObjectParam<SimConsole *> cons;
+ SimObjectParam<IntrControl *> intrctrl;
+ SimObjectParam<PciConfigAll *> pciconfig;
+ Param<int> interrupt_frequency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami)
+
+ INIT_PARAM(system, "system"),
+ INIT_PARAM(cons, "system console"),
+ INIT_PARAM(intrctrl, "interrupt controller"),
+ INIT_PARAM(pciconfig, "PCI configuration"),
+ INIT_PARAM_DFLT(interrupt_frequency, "frequency of interrupts", 1024)
+
+END_INIT_SIM_OBJECT_PARAMS(Tsunami)
+
+CREATE_SIM_OBJECT(Tsunami)
+{
+ return new Tsunami(getInstanceName(), system, intrctrl, pciconfig,
+ interrupt_frequency);
+}
+
+REGISTER_SIM_OBJECT("Tsunami", Tsunami)
diff --git a/dev/tsunami.hh b/dev/tsunami.hh
new file mode 100644
index 000000000..c5dbe797b
--- /dev/null
+++ b/dev/tsunami.hh
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/**
+ * @file
+ * Declaration of top level class for the Tsunami chipset. This class just
+ * retains pointers to all its children so the children can communicate.
+ */
+
+#ifndef __TSUNAMI_HH__
+#define __TSUNAMI_HH__
+
+#include "dev/platform.hh"
+
+class IdeController;
+class TlaserClock;
+class NSGigE;
+class TsunamiCChip;
+class TsunamiPChip;
+class TsunamiIO;
+class PciConfigAll;
+class System;
+
+/**
+ * Top level class for Tsunami Chipset emulation.
+ * This structure just contains pointers to all the
+ * children so the children can commnicate to do the
+ * read work
+ */
+
+class Tsunami : public Platform
+{
+ public:
+
+ /** Max number of CPUs in a Tsunami */
+ static const int Max_CPUs = 4;
+
+ /** Pointer to the system */
+ System *system;
+ /** Pointer to the TsunamiIO device which has the RTC */
+ TsunamiIO *io;
+ /** Pointer to the disk controller device */
+ IdeController *disk_controller;
+ /** Pointer to the ethernet controller device */
+ NSGigE *ethernet;
+
+ /** Pointer to the Tsunami CChip.
+ * The chip contains some configuration information and
+ * all the interrupt mask and status registers
+ */
+ TsunamiCChip *cchip;
+
+ /** Pointer to the Tsunami PChip.
+ * The pchip is the interface to the PCI bus, in our case
+ * it does not have to do much.
+ */
+ TsunamiPChip *pchip;
+
+ int intr_sum_type[Tsunami::Max_CPUs];
+ int ipi_pending[Tsunami::Max_CPUs];
+
+ public:
+ /**
+ * Constructor for the Tsunami Class.
+ * @param name name of the object
+ * @param con pointer to the console
+ * @param intrcontrol pointer to the interrupt controller
+ * @param intrFreq frequency that interrupts happen
+ */
+ Tsunami(const std::string &name, System *s, IntrControl *intctrl,
+ PciConfigAll *pci, int intrFreq);
+
+ /**
+ * Cause the cpu to post a serial interrupt to the CPU.
+ */
+ virtual void postConsoleInt();
+
+ /**
+ * Clear a posted CPU interrupt (id=55)
+ */
+ virtual void clearConsoleInt();
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __TSUNAMI_HH__
diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc
new file mode 100644
index 000000000..ba49c361b
--- /dev/null
+++ b/dev/tsunami_cchip.cc
@@ -0,0 +1,390 @@
+/* $Id$ */
+
+/* @file
+ * Emulation of the Tsunami CChip CSRs
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "dev/console.hh"
+#include "dev/tsunami_cchip.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "cpu/intr_control.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
+ MemoryController *mmu)
+ : FunctionalMemory(name), addr(a), tsunami(t)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+
+ for(int i=0; i < Tsunami::Max_CPUs; i++) {
+ dim[i] = 0;
+ dir[i] = 0;
+ dirInterrupting[i] = false;
+ ipiInterrupting[i] = false;
+ RTCInterrupting[i] = false;
+ }
+
+ drir = 0;
+ misc = 0;
+
+ //Put back pointer in tsunami
+ tsunami->cchip = this;
+}
+
+Fault
+TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
+{
+ DPRINTF(Tsunami, "read va=%#x size=%d\n",
+ req->vaddr, req->size);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
+ ExecContext *xc = req->xc;
+
+ switch (req->size) {
+
+ case sizeof(uint64_t):
+ switch(daddr) {
+ case TSDEV_CC_CSR:
+ *(uint64_t*)data = 0x0;
+ return No_Fault;
+ case TSDEV_CC_MTR:
+ panic("TSDEV_CC_MTR not implemeted\n");
+ return No_Fault;
+ case TSDEV_CC_MISC:
+ *(uint64_t*)data = misc | (xc->cpu_id & 0x3);
+ return No_Fault;
+ case TSDEV_CC_AAR0:
+ case TSDEV_CC_AAR1:
+ case TSDEV_CC_AAR2:
+ case TSDEV_CC_AAR3:
+ panic("TSDEV_CC_AARx not implemeted\n");
+ return No_Fault;
+ case TSDEV_CC_DIM0:
+ *(uint64_t*)data = dim[0];
+ return No_Fault;
+ case TSDEV_CC_DIM1:
+ *(uint64_t*)data = dim[1];
+ return No_Fault;
+ case TSDEV_CC_DIM2:
+ *(uint64_t*)data = dim[2];
+ return No_Fault;
+ case TSDEV_CC_DIM3:
+ *(uint64_t*)data = dim[3];
+ return No_Fault;
+ case TSDEV_CC_DIR0:
+ *(uint64_t*)data = dir[0];
+ return No_Fault;
+ case TSDEV_CC_DIR1:
+ *(uint64_t*)data = dir[1];
+ return No_Fault;
+ case TSDEV_CC_DIR2:
+ *(uint64_t*)data = dir[2];
+ return No_Fault;
+ case TSDEV_CC_DIR3:
+ *(uint64_t*)data = dir[3];
+ return No_Fault;
+ case TSDEV_CC_DRIR:
+ *(uint64_t*)data = drir;
+ return No_Fault;
+ case TSDEV_CC_PRBEN:
+ panic("TSDEV_CC_PRBEN not implemented\n");
+ return No_Fault;
+ case TSDEV_CC_IIC0:
+ case TSDEV_CC_IIC1:
+ case TSDEV_CC_IIC2:
+ case TSDEV_CC_IIC3:
+ panic("TSDEV_CC_IICx not implemented\n");
+ return No_Fault;
+ case TSDEV_CC_MPR0:
+ case TSDEV_CC_MPR1:
+ case TSDEV_CC_MPR2:
+ case TSDEV_CC_MPR3:
+ panic("TSDEV_CC_MPRx not implemented\n");
+ return No_Fault;
+ default:
+ panic("default in cchip read reached, accessing 0x%x\n");
+ } // uint64_t
+
+ break;
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ default:
+ panic("invalid access size(?) for tsunami register!\n");
+ }
+ DPRINTFN("Tsunami CChip ERROR: read daddr=%#x size=%d\n", daddr, req->size);
+
+ return No_Fault;
+}
+
+Fault
+TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
+{
+ DPRINTF(Tsunami, "write - va=%#x size=%d \n",
+ req->vaddr, req->size);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
+
+ bool supportedWrite = false;
+ uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+
+ switch (req->size) {
+
+ case sizeof(uint64_t):
+ switch(daddr) {
+ case TSDEV_CC_CSR:
+ panic("TSDEV_CC_CSR write\n");
+ return No_Fault;
+ case TSDEV_CC_MTR:
+ panic("TSDEV_CC_MTR write not implemented\n");
+ return No_Fault;
+ case TSDEV_CC_MISC:
+ //If it is the 4-7th bit, clear the RTC interrupt
+ uint64_t itintr;
+ if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
+ //Clear the bits in ITINTR
+ misc &= ~(itintr);
+ for (int i=0; i < size; i++) {
+ if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
+ tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
+ RTCInterrupting[i] = false;
+ DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
+ }
+ }
+ supportedWrite = true;
+ }
+ //If it is 12th-15th bit, IPI sent to Processor 1
+ uint64_t ipreq;
+ if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) {
+ //Set the bits in IPINTR
+ misc |= (ipreq >> 4);
+ for (int i=0; i < size; i++) {
+ if ((ipreq & (1 << (i + 12)))) {
+ if (!ipiInterrupting[i])
+ tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0);
+ ipiInterrupting[i]++;
+ DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i,
+ ipiInterrupting[i], req->cpu_num);
+ }
+ }
+ supportedWrite = true;
+ }
+ //If it is bits 8-11, then clearing IPI's
+ uint64_t ipintr;
+ if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) {
+ //Clear the bits in IPINTR
+ misc &= ~(ipintr);
+ for (int i=0; i < size; i++) {
+ if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) {
+ if (!(--ipiInterrupting[i]))
+ tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0);
+ DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i,
+ ipiInterrupting[i] + 1, req->cpu_num);
+ }
+ }
+ supportedWrite = true;
+ }
+ if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n");
+ return No_Fault;
+ case TSDEV_CC_AAR0:
+ case TSDEV_CC_AAR1:
+ case TSDEV_CC_AAR2:
+ case TSDEV_CC_AAR3:
+ panic("TSDEV_CC_AARx write not implemeted\n");
+ return No_Fault;
+ case TSDEV_CC_DIM0:
+ case TSDEV_CC_DIM1:
+ case TSDEV_CC_DIM2:
+ case TSDEV_CC_DIM3:
+ int number;
+ if(daddr == TSDEV_CC_DIM0)
+ number = 0;
+ else if(daddr == TSDEV_CC_DIM1)
+ number = 1;
+ else if(daddr == TSDEV_CC_DIM2)
+ number = 2;
+ else
+ number = 3;
+
+ uint64_t bitvector;
+ uint64_t olddim;
+ uint64_t olddir;
+
+ olddim = dim[number];
+ olddir = dir[number];
+ dim[number] = *(uint64_t*)data;
+ dir[number] = dim[number] & drir;
+ for(int x = 0; x < 64; x++)
+ {
+ bitvector = (uint64_t)1 << x;
+ // Figure out which bits have changed
+ if ((dim[number] & bitvector) != (olddim & bitvector))
+ {
+ // The bit is now set and it wasn't before (set)
+ if((dim[number] & bitvector) && (dir[number] & bitvector))
+ {
+ tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
+ }
+ else if ((olddir & bitvector) &&
+ !(dir[number] & bitvector))
+ {
+ // The bit was set and now its now clear and
+ // we were interrupting on that bit before
+ tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "dim write resulting in clear"
+ "dir interrupt to cpu 0\n");
+
+ }
+
+
+ }
+ }
+ return No_Fault;
+ case TSDEV_CC_DIR0:
+ case TSDEV_CC_DIR1:
+ case TSDEV_CC_DIR2:
+ case TSDEV_CC_DIR3:
+ panic("TSDEV_CC_DIR write not implemented\n");
+ case TSDEV_CC_DRIR:
+ panic("TSDEV_CC_DRIR write not implemented\n");
+ case TSDEV_CC_PRBEN:
+ panic("TSDEV_CC_PRBEN write not implemented\n");
+ case TSDEV_CC_IIC0:
+ case TSDEV_CC_IIC1:
+ case TSDEV_CC_IIC2:
+ case TSDEV_CC_IIC3:
+ panic("TSDEV_CC_IICx write not implemented\n");
+ case TSDEV_CC_MPR0:
+ case TSDEV_CC_MPR1:
+ case TSDEV_CC_MPR2:
+ case TSDEV_CC_MPR3:
+ panic("TSDEV_CC_MPRx write not implemented\n");
+ default:
+ panic("default in cchip read reached, accessing 0x%x\n");
+ }
+
+ break;
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ default:
+ panic("invalid access size(?) for tsunami register!\n");
+ }
+
+ DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
+
+ return No_Fault;
+}
+
+void
+TsunamiCChip::postRTC()
+{
+ int size = tsunami->intrctrl->cpu->system->execContexts.size();
+
+ for (int i = 0; i < size; i++) {
+ if (!RTCInterrupting[i]) {
+ misc |= 16 << i;
+ RTCInterrupting[i] = true;
+ tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
+ DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
+ }
+ }
+
+}
+
+void
+TsunamiCChip::postDRIR(uint32_t interrupt)
+{
+ uint64_t bitvector = (uint64_t)0x1 << interrupt;
+ drir |= bitvector;
+ uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ for(int i=0; i < size; i++) {
+ dir[i] = dim[i] & drir;
+ if (dim[i] & bitvector) {
+ tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
+ DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
+ "interrupt %d\n",i, interrupt);
+ }
+ }
+}
+
+void
+TsunamiCChip::clearDRIR(uint32_t interrupt)
+{
+ uint64_t bitvector = (uint64_t)0x1 << interrupt;
+ uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ if (drir & bitvector)
+ {
+ drir &= ~bitvector;
+ for(int i=0; i < size; i++) {
+ if (dir[i] & bitvector) {
+ tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
+ DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
+ "interrupt %d\n",i, interrupt);
+
+ }
+ dir[i] = dim[i] & drir;
+ }
+ }
+ else
+ DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
+}
+
+void
+TsunamiCChip::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
+ SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
+ SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
+ SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
+ SERIALIZE_SCALAR(drir);
+ SERIALIZE_SCALAR(misc);
+ SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
+}
+
+void
+TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
+ UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
+ UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
+ UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
+ UNSERIALIZE_SCALAR(drir);
+ UNSERIALIZE_SCALAR(misc);
+ UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+ SimObjectParam<Tsunami *> tsunami;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+ INIT_PARAM(tsunami, "Tsunami"),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+CREATE_SIM_OBJECT(TsunamiCChip)
+{
+ return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu);
+}
+
+REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
diff --git a/dev/tsunami_cchip.hh b/dev/tsunami_cchip.hh
new file mode 100644
index 000000000..79fadf06a
--- /dev/null
+++ b/dev/tsunami_cchip.hh
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Emulation of the Tsunami CChip CSRs
+ */
+
+#ifndef __TSUNAMI_CCHIP_HH__
+#define __TSUNAMI_CCHIP_HH__
+
+#include "mem/functional_mem/functional_memory.hh"
+#include "dev/tsunami.hh"
+
+/*
+ * Tsunami CChip
+ */
+class TsunamiCChip : public FunctionalMemory
+{
+ private:
+ /** The base address of this device */
+ Addr addr;
+
+ /** The size of mappad from the above address */
+ static const Addr size = 0xfff;
+
+ protected:
+ /**
+ * pointer to the tsunami object.
+ * This is our access to all the other tsunami
+ * devices.
+ */
+ Tsunami *tsunami;
+
+ /**
+ * The dims are device interrupt mask registers.
+ * One exists for each CPU, the DRIR X DIM = DIR
+ */
+ uint64_t dim[Tsunami::Max_CPUs];
+
+ /**
+ * The dirs are device interrupt registers.
+ * One exists for each CPU, the DRIR X DIM = DIR
+ */
+ uint64_t dir[Tsunami::Max_CPUs];
+ bool dirInterrupting[Tsunami::Max_CPUs];
+
+ /**
+ * This register contains bits for each PCI interrupt
+ * that can occur.
+ */
+ uint64_t drir;
+
+ /**
+ * The MISC register contains the CPU we are currently on
+ * as well as bits to ack RTC and IPI interrupts.
+ */
+ uint64_t misc;
+
+ /** Count of the number of pending IPIs on a CPU */
+ uint64_t ipiInterrupting[Tsunami::Max_CPUs];
+
+ /** Indicator of which CPUs have had an RTC interrupt */
+ bool RTCInterrupting[Tsunami::Max_CPUs];
+
+ public:
+ /**
+ * Initialize the Tsunami CChip by setting all of the
+ * device register to 0.
+ * @param name name of this device.
+ * @param t pointer back to the Tsunami object that we belong to.
+ * @param a address we are mapped at.
+ * @param mmu pointer to the memory controller that sends us events.
+ */
+ TsunamiCChip(const std::string &name, Tsunami *t, Addr a,
+ MemoryController *mmu);
+
+ /**
+ * Process a read to the CChip.
+ * @param req Contains the address to read from.
+ * @param data A pointer to write the read data to.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+
+ /**
+ * Process a write to the CChip.
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /**
+ * post an RTC interrupt to the CPU
+ */
+ void postRTC();
+
+ /**
+ * post an interrupt to the CPU.
+ * @param interrupt the interrupt number to post (0-64)
+ */
+ void postDRIR(uint32_t interrupt);
+
+ /**
+ * clear an interrupt previously posted to the CPU.
+ * @param interrupt the interrupt number to post (0-64)
+ */
+ void clearDRIR(uint32_t interrupt);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __TSUNAMI_CCHIP_HH__
diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc
new file mode 100644
index 000000000..2dda86fbc
--- /dev/null
+++ b/dev/tsunami_io.cc
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Tsunami I/O including PIC, PIT, RTC, DMA
+ */
+
+#include <sys/time.h>
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "dev/console.hh"
+#include "dev/tlaser_clock.hh"
+#include "dev/tsunami_io.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "dev/tsunami_cchip.hh"
+
+using namespace std;
+
+#define UNIX_YEAR_OFFSET 52
+
+// Timer Event for Periodic interrupt of RTC
+TsunamiIO::RTCEvent::RTCEvent(Tsunami* t)
+ : Event(&mainEventQueue), tsunami(t)
+{
+ DPRINTF(MC146818, "RTC Event Initilizing\n");
+ schedule(curTick + ticksPerSecond/RTC_RATE);
+}
+
+void
+TsunamiIO::RTCEvent::process()
+{
+ DPRINTF(MC146818, "RTC Timer Interrupt\n");
+ schedule(curTick + ticksPerSecond/RTC_RATE);
+ //Actually interrupt the processor here
+ tsunami->cchip->postRTC();
+
+}
+
+const char *
+TsunamiIO::RTCEvent::description()
+{
+ return "tsunami RTC 1024Hz interrupt";
+}
+
+// Timer Event for PIT Timers
+TsunamiIO::ClockEvent::ClockEvent()
+ : Event(&mainEventQueue)
+{
+ DPRINTF(Tsunami, "Clock Event Initilizing\n");
+ mode = 0;
+}
+
+void
+TsunamiIO::ClockEvent::process()
+{
+ DPRINTF(Tsunami, "Timer Interrupt\n");
+ if (mode == 0)
+ status = 0x20; // set bit that linux is looking for
+ else
+ schedule(curTick + interval);
+}
+
+void
+TsunamiIO::ClockEvent::Program(int count)
+{
+ DPRINTF(Tsunami, "Timer set to curTick + %d\n", count);
+ // should be count * (cpufreq/pitfreq)
+ interval = count * ticksPerSecond/1193180UL;
+ schedule(curTick + interval);
+ status = 0;
+}
+
+const char *
+TsunamiIO::ClockEvent::description()
+{
+ return "tsunami 8254 Interval timer";
+}
+
+void
+TsunamiIO::ClockEvent::ChangeMode(uint8_t md)
+{
+ mode = md;
+}
+
+uint8_t
+TsunamiIO::ClockEvent::Status()
+{
+ return status;
+}
+
+TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time,
+ Addr a, MemoryController *mmu)
+ : FunctionalMemory(name), addr(a), tsunami(t), rtc(t)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+
+ // set the back pointer from tsunami to myself
+ tsunami->io = this;
+
+ timerData = 0;
+ set_time(init_time == 0 ? time(NULL) : init_time);
+ uip = 1;
+ picr = 0;
+ picInterrupting = false;
+}
+
+void
+TsunamiIO::set_time(time_t t)
+{
+ gmtime_r(&t, &tm);
+ DPRINTFN("Real-time clock set to %s", asctime(&tm));
+}
+
+Fault
+TsunamiIO::read(MemReqPtr &req, uint8_t *data)
+{
+ DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n",
+ req->vaddr, req->size, req->vaddr & 0xfff);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+
+
+ switch(req->size) {
+ case sizeof(uint8_t):
+ switch(daddr) {
+ case TSDEV_PIC1_ISR:
+ // !!! If this is modified 64bit case needs to be too
+ // Pal code has to do a 64 bit physical read because there is
+ // no load physical byte instruction
+ *(uint8_t*)data = picr;
+ return No_Fault;
+ case TSDEV_PIC2_ISR:
+ // PIC2 not implemnted... just return 0
+ *(uint8_t*)data = 0x00;
+ return No_Fault;
+ case TSDEV_TMR_CTL:
+ *(uint8_t*)data = timer2.Status();
+ return No_Fault;
+ case TSDEV_RTC_DATA:
+ switch(RTCAddress) {
+ case RTC_CONTROL_REGISTERA:
+ *(uint8_t*)data = uip << 7 | 0x26;
+ uip = !uip;
+ return No_Fault;
+ case RTC_CONTROL_REGISTERB:
+ // DM and 24/12 and UIE
+ *(uint8_t*)data = 0x46;
+ return No_Fault;
+ case RTC_CONTROL_REGISTERC:
+ // If we want to support RTC user access in linux
+ // This won't work, but for now it's fine
+ *(uint8_t*)data = 0x00;
+ return No_Fault;
+ case RTC_CONTROL_REGISTERD:
+ panic("RTC Control Register D not implemented");
+ case RTC_SECOND:
+ *(uint8_t *)data = tm.tm_sec;
+ return No_Fault;
+ case RTC_MINUTE:
+ *(uint8_t *)data = tm.tm_min;
+ return No_Fault;
+ case RTC_HOUR:
+ *(uint8_t *)data = tm.tm_hour;
+ return No_Fault;
+ case RTC_DAY_OF_WEEK:
+ *(uint8_t *)data = tm.tm_wday;
+ return No_Fault;
+ case RTC_DAY_OF_MONTH:
+ *(uint8_t *)data = tm.tm_mday;
+ case RTC_MONTH:
+ *(uint8_t *)data = tm.tm_mon + 1;
+ return No_Fault;
+ case RTC_YEAR:
+ *(uint8_t *)data = tm.tm_year - UNIX_YEAR_OFFSET;
+ return No_Fault;
+ default:
+ panic("Unknown RTC Address\n");
+ }
+
+ default:
+ panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
+ }
+ case sizeof(uint16_t):
+ case sizeof(uint32_t):
+ panic("I/O Read - invalid size - va %#x size %d\n",
+ req->vaddr, req->size);
+
+ case sizeof(uint64_t):
+ switch(daddr) {
+ case TSDEV_PIC1_ISR:
+ // !!! If this is modified 8bit case needs to be too
+ // Pal code has to do a 64 bit physical read because there is
+ // no load physical byte instruction
+ *(uint64_t*)data = (uint64_t)picr;
+ return No_Fault;
+ default:
+ panic("I/O Read - invalid size - va %#x size %d\n",
+ req->vaddr, req->size);
+ }
+
+ default:
+ panic("I/O Read - invalid size - va %#x size %d\n",
+ req->vaddr, req->size);
+ }
+ panic("I/O Read - va%#x size %d\n", req->vaddr, req->size);
+
+ return No_Fault;
+}
+
+Fault
+TsunamiIO::write(MemReqPtr &req, const uint8_t *data)
+{
+ uint8_t dt = *(uint8_t*)data;
+ uint64_t dt64 = dt;
+
+ DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
+ req->vaddr, req->size, req->vaddr & 0xfff, dt64);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK));
+
+ switch(req->size) {
+ case sizeof(uint8_t):
+ switch(daddr) {
+ case TSDEV_PIC1_MASK:
+ mask1 = ~(*(uint8_t*)data);
+ if ((picr & mask1) && !picInterrupting) {
+ picInterrupting = true;
+ tsunami->cchip->postDRIR(55);
+ DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
+ }
+ if ((!(picr & mask1)) && picInterrupting) {
+ picInterrupting = false;
+ tsunami->cchip->clearDRIR(55);
+ DPRINTF(Tsunami, "clearing pic interrupt\n");
+ }
+ return No_Fault;
+ case TSDEV_PIC2_MASK:
+ mask2 = *(uint8_t*)data;
+ //PIC2 Not implemented to interrupt
+ return No_Fault;
+ case TSDEV_PIC1_ACK:
+ // clear the interrupt on the PIC
+ picr &= ~(1 << (*(uint8_t*)data & 0xF));
+ if (!(picr & mask1))
+ tsunami->cchip->clearDRIR(55);
+ return No_Fault;
+ case TSDEV_PIC2_ACK:
+ return No_Fault;
+ case TSDEV_DMA1_RESET:
+ return No_Fault;
+ case TSDEV_DMA2_RESET:
+ return No_Fault;
+ case TSDEV_DMA1_MODE:
+ mode1 = *(uint8_t*)data;
+ return No_Fault;
+ case TSDEV_DMA2_MODE:
+ mode2 = *(uint8_t*)data;
+ return No_Fault;
+ case TSDEV_DMA1_MASK:
+ case TSDEV_DMA2_MASK:
+ return No_Fault;
+ case TSDEV_TMR_CTL:
+ return No_Fault;
+ case TSDEV_TMR2_CTL:
+ if ((*(uint8_t*)data & 0x30) != 0x30)
+ panic("Only L/M write supported\n");
+
+ switch(*(uint8_t*)data >> 6) {
+ case 0:
+ timer0.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
+ break;
+ case 2:
+ timer2.ChangeMode((*(uint8_t*)data & 0xF) >> 1);
+ break;
+ default:
+ panic("Read Back Command not implemented\n");
+ }
+ return No_Fault;
+ case TSDEV_TMR2_DATA:
+ /* two writes before we actually start the Timer
+ so I set a flag in the timerData */
+ if(timerData & 0x1000) {
+ timerData &= 0x1000;
+ timerData += *(uint8_t*)data << 8;
+ timer2.Program(timerData);
+ } else {
+ timerData = *(uint8_t*)data;
+ timerData |= 0x1000;
+ }
+ return No_Fault;
+ case TSDEV_TMR0_DATA:
+ /* two writes before we actually start the Timer
+ so I set a flag in the timerData */
+ if(timerData & 0x1000) {
+ timerData &= 0x1000;
+ timerData += *(uint8_t*)data << 8;
+ timer0.Program(timerData);
+ } else {
+ timerData = *(uint8_t*)data;
+ timerData |= 0x1000;
+ }
+ return No_Fault;
+ case TSDEV_RTC_ADDR:
+ RTCAddress = *(uint8_t*)data;
+ return No_Fault;
+ case TSDEV_RTC_DATA:
+ panic("RTC Write not implmented (rtc.o won't work)\n");
+ default:
+ panic("I/O Write - va%#x size %d\n", req->vaddr, req->size);
+ }
+ case sizeof(uint16_t):
+ case sizeof(uint32_t):
+ case sizeof(uint64_t):
+ default:
+ panic("I/O Write - invalid size - va %#x size %d\n",
+ req->vaddr, req->size);
+ }
+
+
+ return No_Fault;
+}
+
+void
+TsunamiIO::postPIC(uint8_t bitvector)
+{
+ //PIC2 Is not implemented, because nothing of interest there
+ picr |= bitvector;
+ if (picr & mask1) {
+ tsunami->cchip->postDRIR(55);
+ DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
+ }
+}
+
+void
+TsunamiIO::clearPIC(uint8_t bitvector)
+{
+ //PIC2 Is not implemented, because nothing of interest there
+ picr &= ~bitvector;
+ if (!(picr & mask1)) {
+ tsunami->cchip->clearDRIR(55);
+ DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
+ }
+}
+
+void
+TsunamiIO::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(timerData);
+ SERIALIZE_SCALAR(uip);
+ SERIALIZE_SCALAR(picr);
+ SERIALIZE_SCALAR(picInterrupting);
+ Tick time0when = timer0.when();
+ Tick time2when = timer2.when();
+ Tick rtcwhen = rtc.when();
+ SERIALIZE_SCALAR(time0when);
+ SERIALIZE_SCALAR(time2when);
+ SERIALIZE_SCALAR(rtcwhen);
+
+}
+
+void
+TsunamiIO::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(timerData);
+ UNSERIALIZE_SCALAR(uip);
+ UNSERIALIZE_SCALAR(picr);
+ UNSERIALIZE_SCALAR(picInterrupting);
+ Tick time0when;
+ Tick time2when;
+ Tick rtcwhen;
+ UNSERIALIZE_SCALAR(time0when);
+ UNSERIALIZE_SCALAR(time2when);
+ UNSERIALIZE_SCALAR(rtcwhen);
+ timer0.reschedule(time0when);
+ timer2.reschedule(time2when);
+ rtc.reschedule(rtcwhen);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
+
+ SimObjectParam<Tsunami *> tsunami;
+ Param<time_t> time;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
+
+ INIT_PARAM(tsunami, "Tsunami"),
+ INIT_PARAM_DFLT(time, "System time to use "
+ "(0 for actual time, default is 1/1/06", ULL(1136073600)),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
+
+CREATE_SIM_OBJECT(TsunamiIO)
+{
+ return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu);
+}
+
+REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh
new file mode 100644
index 000000000..1dd7762e3
--- /dev/null
+++ b/dev/tsunami_io.hh
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Tsunami Fake I/O Space mapping including RTC/timer interrupts
+ */
+
+#ifndef __TSUNAMI_DMA_HH__
+#define __TSUNAMI_DMA_HH__
+
+#include "mem/functional_mem/functional_memory.hh"
+#include "dev/tsunami.hh"
+
+/** How often the RTC interrupts */
+static const int RTC_RATE = 1024;
+
+/*
+ * Tsunami I/O device is a catch all for all the south bridge stuff we care
+ * to implement.
+ */
+class TsunamiIO : public FunctionalMemory
+{
+ private:
+ /** The base address of this device */
+ Addr addr;
+
+ /** The size of mappad from the above address */
+ static const Addr size = 0xff;
+
+ struct tm tm;
+
+ /** In Tsunami RTC only has two i/o ports one for data and one for address,
+ * so you write the address and then read/write the data. This store the
+ * address you are going to be reading from on a read.
+ */
+ uint8_t RTCAddress;
+
+ protected:
+
+ /**
+ * The ClockEvent is handles the PIT interrupts
+ */
+ class ClockEvent : public Event
+ {
+ protected:
+ /** how often the PIT fires */
+ Tick interval;
+ /** The mode of the PIT */
+ uint8_t mode;
+ /** The status of the PIT */
+ uint8_t status;
+
+ public:
+ /**
+ * Just set the mode to 0
+ */
+ ClockEvent();
+
+ /**
+ * processs the timer event
+ */
+ virtual void process();
+
+ /**
+ * Returns a description of this event
+ * @return the description
+ */
+ virtual const char *description();
+
+ /**
+ * Schedule a timer interrupt to occur sometime in the future.
+ */
+ void Program(int count);
+
+ /**
+ * Write the mode bits of the PIT.
+ * @param mode the new mode
+ */
+ void ChangeMode(uint8_t mode);
+
+ /**
+ * The current PIT status.
+ * @return the status of the PIT
+ */
+ uint8_t Status();
+
+ };
+
+ /**
+ * Process RTC timer events and generate interrupts appropriately.
+ */
+ class RTCEvent : public Event
+ {
+ protected:
+ /** A pointer back to tsunami to create interrupt the processor. */
+ Tsunami* tsunami;
+ public:
+ /** RTC Event initializes the RTC event by scheduling an event
+ * RTC_RATE times pre second. */
+ RTCEvent(Tsunami* t);
+
+ /**
+ * Interrupth the processor and reschedule the event.
+ * */
+ virtual void process();
+
+ /**
+ * Return a description of this event.
+ * @return a description
+ */
+ virtual const char *description();
+ };
+
+ /** uip UpdateInProgess says that the rtc is updating, but we just fake it
+ * by alternating it on every read of the bit since we are going to
+ * override the loop_per_jiffy time that it is trying to use the UIP to
+ * calculate.
+ */
+ uint8_t uip;
+
+ /** Mask of the PIC1 */
+ uint8_t mask1;
+
+ /** Mask of the PIC2 */
+ uint8_t mask2;
+
+ /** Mode of PIC1. Not used for anything */
+ uint8_t mode1;
+
+ /** Mode of PIC2. Not used for anything */
+ uint8_t mode2;
+
+ /** Raw PIC interrupt register before masking */
+ uint8_t picr; //Raw PIC interrput register
+
+ /** Is the pic interrupting right now or not. */
+ bool picInterrupting;
+
+ /** A pointer to the Tsunami device which be belong to */
+ Tsunami *tsunami;
+
+ /**
+ * This timer is initilized, but after I wrote the code
+ * it doesn't seem to be used again, and best I can tell
+ * it too is not connected to any interrupt port
+ */
+ ClockEvent timer0;
+
+ /**
+ * This timer is used to control the speaker, which
+ * we normally could care less about, however it is
+ * also used to calculated the clockspeed and hense
+ * bogomips which is kinda important to the scheduler
+ * so we need to implemnt it although after boot I can't
+ * imagine we would be playing with the PC speaker much
+ */
+ ClockEvent timer2;
+
+ /** This is the event used to interrupt the cpu like an RTC. */
+ RTCEvent rtc;
+
+ /** The interval is set via two writes to the PIT.
+ * This variable contains a flag as to how many writes have happened, and
+ * the time so far.
+ */
+ uint32_t timerData;
+
+
+ public:
+ /** Return the freqency of the RTC */
+ uint32_t frequency() const { return RTC_RATE; }
+
+
+ /**
+ * Initialize all the data for devices supported by Tsunami I/O.
+ * @param name name of this device.
+ * @param t pointer back to the Tsunami object that we belong to.
+ * @param init_time Time (as in seconds since 1970) to set RTC to.
+ * @param a address we are mapped at.
+ * @param mmu pointer to the memory controller that sends us events.
+ */
+ TsunamiIO(const std::string &name, Tsunami *t, time_t init_time,
+ Addr a, MemoryController *mmu);
+
+ /**
+ * Create the tm struct from seconds since 1970
+ */
+ void set_time(time_t t);
+
+ /**
+ * Process a read to one of the devices we are emulating.
+ * @param req Contains the address to read from.
+ * @param data A pointer to write the read data to.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+ /**
+ * Process a write to one of the devices we emulate.
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /**
+ * Post an PIC interrupt to the CPU via the CChip
+ * @param bitvector interrupt to post.
+ */
+ void postPIC(uint8_t bitvector);
+
+ /**
+ * Clear a posted interrupt
+ * @param bitvector interrupt to clear
+ */
+ void clearPIC(uint8_t bitvector);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __TSUNAMI_IO_HH__
diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc
new file mode 100644
index 000000000..2ac3cae86
--- /dev/null
+++ b/dev/tsunami_pchip.cc
@@ -0,0 +1,317 @@
+/* $Id$ */
+
+/* @file
+ * Tsunami PChip (pci)
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "dev/console.hh"
+#include "dev/etherdev.hh"
+#include "dev/scsi_ctrl.hh"
+#include "dev/tlaser_clock.hh"
+#include "dev/tsunami_pchip.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a,
+ MemoryController *mmu)
+ : FunctionalMemory(name), addr(a), tsunami(t)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+
+ for (int i = 0; i < 4; i++) {
+ wsba[i] = 0;
+ wsm[i] = 0;
+ tba[i] = 0;
+ }
+
+ //Set back pointer in tsunami
+ tsunami->pchip = this;
+}
+
+Fault
+TsunamiPChip::read(MemReqPtr &req, uint8_t *data)
+{
+ DPRINTF(Tsunami, "read va=%#x size=%d\n",
+ req->vaddr, req->size);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
+
+ switch (req->size) {
+
+ case sizeof(uint64_t):
+ switch(daddr) {
+ case TSDEV_PC_WSBA0:
+ *(uint64_t*)data = wsba[0];
+ return No_Fault;
+ case TSDEV_PC_WSBA1:
+ *(uint64_t*)data = wsba[1];
+ return No_Fault;
+ case TSDEV_PC_WSBA2:
+ *(uint64_t*)data = wsba[2];
+ return No_Fault;
+ case TSDEV_PC_WSBA3:
+ *(uint64_t*)data = wsba[3];
+ return No_Fault;
+ case TSDEV_PC_WSM0:
+ *(uint64_t*)data = wsm[0];
+ return No_Fault;
+ case TSDEV_PC_WSM1:
+ *(uint64_t*)data = wsm[1];
+ return No_Fault;
+ case TSDEV_PC_WSM2:
+ *(uint64_t*)data = wsm[2];
+ return No_Fault;
+ case TSDEV_PC_WSM3:
+ *(uint64_t*)data = wsm[3];
+ return No_Fault;
+ case TSDEV_PC_TBA0:
+ *(uint64_t*)data = tba[0];
+ return No_Fault;
+ case TSDEV_PC_TBA1:
+ *(uint64_t*)data = tba[1];
+ return No_Fault;
+ case TSDEV_PC_TBA2:
+ *(uint64_t*)data = tba[2];
+ return No_Fault;
+ case TSDEV_PC_TBA3:
+ *(uint64_t*)data = tba[3];
+ return No_Fault;
+ case TSDEV_PC_PCTL:
+ // might want to change the clock??
+ *(uint64_t*)data = 0x00; // try this
+ return No_Fault;
+ case TSDEV_PC_PLAT:
+ panic("PC_PLAT not implemented\n");
+ case TSDEV_PC_RES:
+ panic("PC_RES not implemented\n");
+ case TSDEV_PC_PERROR:
+ panic("PC_PERROR not implemented\n");
+ case TSDEV_PC_PERRMASK:
+ panic("PC_PERRMASK not implemented\n");
+ case TSDEV_PC_PERRSET:
+ panic("PC_PERRSET not implemented\n");
+ case TSDEV_PC_TLBIV:
+ panic("PC_TLBIV not implemented\n");
+ case TSDEV_PC_TLBIA:
+ *(uint64_t*)data = 0x00; // shouldn't be readable, but linux
+ return No_Fault;
+ case TSDEV_PC_PMONCTL:
+ panic("PC_PMONCTL not implemented\n");
+ case TSDEV_PC_PMONCNT:
+ panic("PC_PMONCTN not implemented\n");
+ default:
+ panic("Default in PChip Read reached reading 0x%x\n", daddr);
+
+ } // uint64_t
+
+ break;
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ default:
+ panic("invalid access size(?) for tsunami register!\n\n");
+ }
+ DPRINTFN("Tsunami PChip ERROR: read daddr=%#x size=%d\n", daddr, req->size);
+
+ return No_Fault;
+}
+
+Fault
+TsunamiPChip::write(MemReqPtr &req, const uint8_t *data)
+{
+ DPRINTF(Tsunami, "write - va=%#x size=%d \n",
+ req->vaddr, req->size);
+
+ Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
+
+ switch (req->size) {
+
+ case sizeof(uint64_t):
+ switch(daddr) {
+ case TSDEV_PC_WSBA0:
+ wsba[0] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSBA1:
+ wsba[1] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSBA2:
+ wsba[2] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSBA3:
+ wsba[3] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSM0:
+ wsm[0] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSM1:
+ wsm[1] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSM2:
+ wsm[2] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_WSM3:
+ wsm[3] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_TBA0:
+ tba[0] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_TBA1:
+ tba[1] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_TBA2:
+ tba[2] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_TBA3:
+ tba[3] = *(uint64_t*)data;
+ return No_Fault;
+ case TSDEV_PC_PCTL:
+ // might want to change the clock??
+ //*(uint64_t*)data; // try this
+ return No_Fault;
+ case TSDEV_PC_PLAT:
+ panic("PC_PLAT not implemented\n");
+ case TSDEV_PC_RES:
+ panic("PC_RES not implemented\n");
+ case TSDEV_PC_PERROR:
+ panic("PC_PERROR not implemented\n");
+ case TSDEV_PC_PERRMASK:
+ panic("PC_PERRMASK not implemented\n");
+ case TSDEV_PC_PERRSET:
+ panic("PC_PERRSET not implemented\n");
+ case TSDEV_PC_TLBIV:
+ panic("PC_TLBIV not implemented\n");
+ case TSDEV_PC_TLBIA:
+ return No_Fault; // value ignored, supposted to invalidate SG TLB
+ case TSDEV_PC_PMONCTL:
+ panic("PC_PMONCTL not implemented\n");
+ case TSDEV_PC_PMONCNT:
+ panic("PC_PMONCTN not implemented\n");
+ default:
+ panic("Default in PChip Read reached reading 0x%x\n", daddr);
+
+ } // uint64_t
+
+ break;
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ default:
+ panic("invalid access size(?) for tsunami register!\n\n");
+ }
+
+ DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size);
+
+ return No_Fault;
+}
+
+#define DMA_ADDR_MASK ULL(0x3ffffffff)
+
+Addr
+TsunamiPChip::translatePciToDma(Addr busAddr)
+{
+ // compare the address to the window base registers
+ uint64_t tbaMask = 0;
+ uint64_t baMask = 0;
+
+ uint64_t windowMask = 0;
+ uint64_t windowBase = 0;
+
+ uint64_t pteEntry = 0;
+
+ Addr pteAddr;
+ Addr dmaAddr;
+
+ for (int i = 0; i < 4; i++) {
+ windowBase = wsba[i];
+ windowMask = ~wsm[i] & (0x7ff << 20);
+
+ if ((busAddr & windowMask) == (windowBase & windowMask)) {
+
+
+ if (wsba[i] & 0x1) { // see if enabled
+ if (wsba[i] & 0x2) { // see if SG bit is set
+ /** @todo
+ This currently is faked by just doing a direct
+ read from memory, however, to be realistic, this
+ needs to actually do a bus transaction. The process
+ is explained in the tsunami documentation on page
+ 10-12 and basically munges the address to look up a
+ PTE from a table in memory and then uses that mapping
+ to create an address for the SG page
+ */
+
+ tbaMask = ~(((wsm[i] & (0x7ff << 20)) >> 10) | 0x3ff);
+ baMask = (wsm[i] & (0x7ff << 20)) | (0x7f << 13);
+ pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
+
+ memcpy((void *)&pteEntry,
+ tsunami->system->
+ physmem->dma_addr(pteAddr, sizeof(uint64_t)),
+ sizeof(uint64_t));
+
+ dmaAddr = ((pteEntry & ~0x1) << 12) | (busAddr & 0x1fff);
+
+ } else {
+ baMask = (wsm[i] & (0x7ff << 20)) | 0xfffff;
+ tbaMask = ~baMask;
+ dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
+ }
+
+ return (dmaAddr & DMA_ADDR_MASK);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void
+TsunamiPChip::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(wsba, 4);
+ SERIALIZE_ARRAY(wsm, 4);
+ SERIALIZE_ARRAY(tba, 4);
+}
+
+void
+TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(wsba, 4);
+ UNSERIALIZE_ARRAY(wsm, 4);
+ UNSERIALIZE_ARRAY(tba, 4);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+ SimObjectParam<Tsunami *> tsunami;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+ INIT_PARAM(tsunami, "Tsunami"),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+CREATE_SIM_OBJECT(TsunamiPChip)
+{
+ return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu);
+}
+
+REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)
diff --git a/dev/tsunami_pchip.hh b/dev/tsunami_pchip.hh
new file mode 100644
index 000000000..44f145a60
--- /dev/null
+++ b/dev/tsunami_pchip.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Tsunami PChip
+ */
+
+#ifndef __TSUNAMI_PCHIP_HH__
+#define __TSUNAMI_PCHIP_HH__
+
+#include "mem/functional_mem/functional_memory.hh"
+#include "dev/tsunami.hh"
+
+/*
+ * Tsunami PChip
+ */
+class TsunamiPChip : public FunctionalMemory
+{
+ private:
+ /** The base address of this device */
+ Addr addr;
+
+ /** The size of mappad from the above address */
+ static const Addr size = 0xfff;
+
+ protected:
+ /**
+ * pointer to the tsunami object.
+ * This is our access to all the other tsunami
+ * devices.
+ */
+ Tsunami *tsunami;
+
+ /** Window Base addresses */
+ uint64_t wsba[4];
+
+ /** Window masks */
+ uint64_t wsm[4];
+
+ /** Translated Base Addresses */
+ uint64_t tba[4];
+
+ public:
+ /**
+ * Register the PChip with the mmu and init all wsba, wsm, and tba to 0
+ * @param name the name of thes device
+ * @param t a pointer to the tsunami device
+ * @param a the address which we respond to
+ * @param mmu the mmu we are to register with
+ */
+ TsunamiPChip(const std::string &name, Tsunami *t, Addr a,
+ MemoryController *mmu);
+
+ /**
+ * Translate a PCI bus address to a memory address for DMA.
+ * @todo Andrew says this needs to be fixed. What's wrong with it?
+ * @param busAddr PCI address to translate.
+ * @return memory system address
+ */
+ Addr translatePciToDma(Addr busAddr);
+
+ /**
+ * Process a read to the PChip.
+ * @param req Contains the address to read from.
+ * @param data A pointer to write the read data to.
+ * @return The fault condition of the access.
+ */
+ virtual Fault read(MemReqPtr &req, uint8_t *data);
+
+ /**
+ * Process a write to the PChip.
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+ virtual Fault write(MemReqPtr &req, const uint8_t *data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __TSUNAMI_PCHIP_HH__
diff --git a/dev/tsunami_uart.cc b/dev/tsunami_uart.cc
new file mode 100644
index 000000000..1eef24926
--- /dev/null
+++ b/dev/tsunami_uart.cc
@@ -0,0 +1,295 @@
+/* $Id$ */
+
+/* @file
+ * Tsunami UART
+ */
+
+/*
+ * Copyright (C) 1998 by the Board of Trustees
+ * of Leland Stanford Junior University.
+ * Copyright (C) 1998 Digital Equipment Corporation
+ *
+ * This file is part of the SimOS distribution.
+ * See LICENSE file for terms of the license.
+ *
+ */
+
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/str.hh" // for to_number
+#include "base/trace.hh"
+#include "dev/console.hh"
+#include "dev/tsunami_uart.hh"
+#include "mem/bus/bus.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "sim/builder.hh"
+#include "targetarch/ev5.hh"
+
+using namespace std;
+
+#define CONS_INT_TX 0x01 // interrupt enable / state bits
+#define CONS_INT_RX 0x02
+
+
+TsunamiUart::IntrEvent::IntrEvent(TsunamiUart *u)
+ : Event(&mainEventQueue), uart(u)
+{
+ DPRINTF(TsunamiUart, "UART Interrupt Event Initilizing\n");
+}
+
+const char *
+TsunamiUart::IntrEvent::description()
+{
+ return "tsunami uart interrupt delay event";
+}
+
+void
+TsunamiUart::IntrEvent::process()
+{
+ if (UART_IER_THRI & uart->IER) {
+ DPRINTF(TsunamiUart, "UART InterEvent, interrupting\n");
+ uart->cons->raiseInt(CONS_INT_TX);
+ }
+ else
+ DPRINTF(TsunamiUart, "UART InterEvent, not interrupting\n");
+
+}
+
+void
+TsunamiUart::IntrEvent::scheduleIntr()
+{
+ DPRINTF(TsunamiUart, "Scheduling IER interrupt\n");
+ if (!scheduled())
+ schedule(curTick + 300);
+ else
+ reschedule(curTick + 300);
+}
+
+
+
+TsunamiUart::TsunamiUart(const string &name, SimConsole *c,
+ MemoryController *mmu, Addr a,
+ HierParams *hier, Bus *bus)
+ : PioDevice(name), addr(a), cons(c), status_store(0), valid_char(false),
+ intrEvent(this)
+{
+ mmu->add_child(this, Range<Addr>(addr, addr + size));
+
+ if (bus) {
+ pioInterface = newPioInterface(name, hier, bus, this,
+ &TsunamiUart::cacheAccess);
+ pioInterface->addAddrRange(addr, addr + size - 1);
+ }
+
+ IER = 0;
+}
+
+Fault
+TsunamiUart::read(MemReqPtr &req, uint8_t *data)
+{
+ Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
+ DPRINTF(TsunamiUart, " read register %#x\n", daddr);
+
+ switch (req->size) {
+ case sizeof(uint64_t):
+ *(uint64_t *)data = 0;
+ break;
+ case sizeof(uint32_t):
+ *(uint32_t *)data = 0;
+ break;
+ case sizeof(uint16_t):
+ *(uint16_t *)data = 0;
+ break;
+ case sizeof(uint8_t):
+ *(uint8_t *)data = 0;
+ break;
+ }
+
+
+ switch(daddr) {
+ case 0x5: // Status Register
+ {
+ int status = cons->intStatus();
+ if (!valid_char) {
+ valid_char = cons->in(next_char);
+ if (!valid_char)
+ status &= ~CONS_INT_RX;
+ } else {
+ status |= CONS_INT_RX;
+ }
+
+ if (status_store == 3) {
+ // RR3 stuff? Don't really understand it, btw
+ status_store = 0;
+ if (status & CONS_INT_TX) {
+ *data = (1 << 4);
+ return No_Fault;
+ } else if (status & CONS_INT_RX) {
+ *data = (1 << 5);
+ return No_Fault;
+ } else {
+ DPRINTF(TsunamiUart, "spurious read\n");
+ return No_Fault;
+ }
+ } else {
+ int reg = (1 << 2) | (1 << 5) | (1 << 6);
+ if (status & CONS_INT_RX)
+ reg |= (1 << 0);
+ *data = reg;
+ return No_Fault;
+ }
+ break;
+ }
+
+ case 0x0: // Data register (RX)
+ DPRINTF(TsunamiUart, "read data register \'%c\' %#02x\n",
+ isprint(next_char) ? next_char : ' ', next_char);
+
+ *data = next_char;
+ valid_char = false;
+ return No_Fault;
+
+ case 0x1: // Interrupt Enable Register
+ // This is the lovely way linux checks there is actually a serial
+ // port at the desired address
+ if (IER == 0)
+ *data = 0;
+ else if (IER == 0x0F)
+ *data = 0x0F;
+ else
+ *data = 0;
+ return No_Fault;
+ case 0x2:
+ // High two bits need to be clear for an 8250 (simple) serial port
+ // Low bit of IIR is 0 for a pending interrupt, 1 otherwise.
+ int status = cons->intStatus();
+ status = (status & 0x1) | (status >> 1);
+ *data = (~status) & 0x1 ;
+ return No_Fault;
+ }
+ *data = 0;
+ // panic("%s: read daddr=%#x type=read *data=%#x\n", name(), daddr, *data);
+
+ return No_Fault;
+}
+
+Fault
+TsunamiUart::write(MemReqPtr &req, const uint8_t *data)
+{
+ Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
+
+ DPRINTF(TsunamiUart, " write register %#x value %#x\n", daddr, *(uint8_t*)data);
+
+ switch (daddr) {
+ case 0x3:
+ status_store = *data;
+ switch (*data) {
+ case 0x03: // going to read RR3
+ return No_Fault;
+
+ case 0x28: // Ack of TX
+ {
+ if ((cons->intStatus() & CONS_INT_TX) == 0)
+ panic("Ack of transmit, though there was no interrupt");
+
+ cons->clearInt(CONS_INT_TX);
+ return No_Fault;
+ }
+
+ case 0x00:
+ case 0x01:
+ case 0x12:
+ // going to write data???
+ return No_Fault;
+
+ default:
+ DPRINTF(TsunamiUart, "writing status register %#x \n",
+ *(uint8_t *)data);
+ return No_Fault;
+ }
+
+ case 0x0: // Data register (TX)
+ char ourchar;
+ ourchar = *(uint64_t *)data;
+ if ((isprint(ourchar) || iscntrl(ourchar)) && (ourchar != 0x0C))
+ cons->out(ourchar);
+ cons->clearInt(CONS_INT_TX);
+ intrEvent.scheduleIntr();
+ return No_Fault;
+ break;
+ case 0x1: // IER
+ IER = *(uint8_t*)data;
+ DPRINTF(TsunamiUart, "writing to IER [%#x]\n", IER);
+ if (UART_IER_THRI & IER)
+ cons->raiseInt(CONS_INT_TX);
+ else {
+ cons->clearInt(CONS_INT_TX);
+ if (intrEvent.scheduled())
+ intrEvent.deschedule();
+ }
+ return No_Fault;
+ break;
+ case 0x4: // MCR
+ DPRINTF(TsunamiUart, "writing to MCR %#x\n", *(uint8_t*)data);
+ return No_Fault;
+
+ }
+
+ return No_Fault;
+}
+
+Tick
+TsunamiUart::cacheAccess(MemReqPtr &req)
+{
+ return curTick + 1000;
+}
+
+void
+TsunamiUart::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(status_store);
+ SERIALIZE_SCALAR(next_char);
+ SERIALIZE_SCALAR(valid_char);
+ SERIALIZE_SCALAR(IER);
+}
+
+void
+TsunamiUart::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(status_store);
+ UNSERIALIZE_SCALAR(next_char);
+ UNSERIALIZE_SCALAR(valid_char);
+ UNSERIALIZE_SCALAR(IER);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
+
+ SimObjectParam<SimConsole *> console;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+ SimObjectParam<Bus*> io_bus;
+ SimObjectParam<HierParams *> hier;
+
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
+
+ INIT_PARAM(console, "The console"),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
+ INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
+
+CREATE_SIM_OBJECT(TsunamiUart)
+{
+ return new TsunamiUart(getInstanceName(), console, mmu, addr, hier, io_bus);
+}
+
+REGISTER_SIM_OBJECT("TsunamiUart", TsunamiUart)
diff --git a/dev/tsunami_uart.hh b/dev/tsunami_uart.hh
new file mode 100644
index 000000000..84e415067
--- /dev/null
+++ b/dev/tsunami_uart.hh
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/* @file
+ * Tsunami UART
+ */
+
+#ifndef __TSUNAMI_UART_HH__
+#define __TSUNAMI_UART_HH__
+
+#include "dev/tsunamireg.h"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+class SimConsole;
+
+/*
+ * Tsunami UART
+ */
+class TsunamiUart : public PioDevice
+{
+ private:
+ Addr addr;
+ static const Addr size = 0x8;
+
+
+ protected:
+ SimConsole *cons;
+ int status_store;
+ uint8_t next_char;
+ bool valid_char;
+ uint8_t IER;
+
+ class IntrEvent : public Event
+ {
+ protected:
+ TsunamiUart *uart;
+ public:
+ IntrEvent(TsunamiUart *u);
+ virtual void process();
+ virtual const char *description();
+ void scheduleIntr();
+ };
+
+ IntrEvent intrEvent;
+
+ public:
+ TsunamiUart(const string &name, SimConsole *c, MemoryController *mmu,
+ Addr a, HierParams *hier, Bus *bus);
+
+ Fault read(MemReqPtr &req, uint8_t *data);
+ Fault write(MemReqPtr &req, const uint8_t *data);
+
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+ Tick cacheAccess(MemReqPtr &req);
+};
+
+#endif // __TSUNAMI_UART_HH__
diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h
new file mode 100644
index 000000000..927dd60c9
--- /dev/null
+++ b/dev/tsunamireg.h
@@ -0,0 +1,120 @@
+
+#ifndef __TSUNAMIREG_H__
+#define __TSUNAMIREG_H__
+
+#define ALPHA_K0SEG_BASE 0xfffffc0000000000ULL
+
+// CChip Registers
+#define TSDEV_CC_CSR 0x00
+#define TSDEV_CC_MTR 0x01
+#define TSDEV_CC_MISC 0x02
+
+#define TSDEV_CC_AAR0 0x04
+#define TSDEV_CC_AAR1 0x05
+#define TSDEV_CC_AAR2 0x06
+#define TSDEV_CC_AAR3 0x07
+#define TSDEV_CC_DIM0 0x08
+#define TSDEV_CC_DIM1 0x09
+#define TSDEV_CC_DIR0 0x0A
+#define TSDEV_CC_DIR1 0x0B
+#define TSDEV_CC_DRIR 0x0C
+#define TSDEV_CC_PRBEN 0x0D
+#define TSDEV_CC_IIC0 0x0E
+#define TSDEV_CC_IIC1 0x0F
+#define TSDEV_CC_MPR0 0x10
+#define TSDEV_CC_MPR1 0x11
+#define TSDEV_CC_MPR2 0x12
+#define TSDEV_CC_MPR3 0x13
+
+#define TSDEV_CC_DIM2 0x18
+#define TSDEV_CC_DIM3 0x19
+#define TSDEV_CC_DIR2 0x1A
+#define TSDEV_CC_DIR3 0x1B
+#define TSDEV_CC_IIC2 0x1C
+#define TSDEV_CC_IIC3 0x1D
+
+
+// PChip Registers
+#define TSDEV_PC_WSBA0 0x00
+#define TSDEV_PC_WSBA1 0x01
+#define TSDEV_PC_WSBA2 0x02
+#define TSDEV_PC_WSBA3 0x03
+#define TSDEV_PC_WSM0 0x04
+#define TSDEV_PC_WSM1 0x05
+#define TSDEV_PC_WSM2 0x06
+#define TSDEV_PC_WSM3 0x07
+#define TSDEV_PC_TBA0 0x08
+#define TSDEV_PC_TBA1 0x09
+#define TSDEV_PC_TBA2 0x0A
+#define TSDEV_PC_TBA3 0x0B
+#define TSDEV_PC_PCTL 0x0C
+#define TSDEV_PC_PLAT 0x0D
+#define TSDEV_PC_RES 0x0E
+#define TSDEV_PC_PERROR 0x0F
+#define TSDEV_PC_PERRMASK 0x10
+#define TSDEV_PC_PERRSET 0x11
+#define TSDEV_PC_TLBIV 0x12
+#define TSDEV_PC_TLBIA 0x13
+#define TSDEV_PC_PMONCTL 0x14
+#define TSDEV_PC_PMONCNT 0x15
+
+#define TSDEV_PC_SPST 0x20
+
+
+// DChip Registers
+#define TSDEV_DC_DSC 0x20
+#define TSDEV_DC_STR 0x21
+#define TSDEV_DC_DREV 0x22
+#define TSDEV_DC_DSC2 0x23
+
+// I/O Ports
+#define TSDEV_PIC1_MASK 0x21
+#define TSDEV_PIC2_MASK 0xA1
+#define TSDEV_PIC1_ISR 0x20
+#define TSDEV_PIC2_ISR 0xA0
+#define TSDEV_PIC1_ACK 0x20
+#define TSDEV_PIC2_ACK 0xA0
+#define TSDEV_DMA1_RESET 0x0D
+#define TSDEV_DMA2_RESET 0xDA
+#define TSDEV_DMA1_MODE 0x0B
+#define TSDEV_DMA2_MODE 0xD6
+#define TSDEV_DMA1_MASK 0x0A
+#define TSDEV_DMA2_MASK 0xD4
+#define TSDEV_TMR_CTL 0x61
+#define TSDEV_TMR2_CTL 0x43
+#define TSDEV_TMR2_DATA 0x42
+#define TSDEV_TMR0_DATA 0x40
+
+#define TSDEV_RTC_ADDR 0x70
+#define TSDEV_RTC_DATA 0x71
+
+// RTC defines
+#define RTC_SECOND 0 // second of minute [0..59]
+#define RTC_SECOND_ALARM 1 // seconds to alarm
+#define RTC_MINUTE 2 // minute of hour [0..59]
+#define RTC_MINUTE_ALARM 3 // minutes to alarm
+#define RTC_HOUR 4 // hour of day [0..23]
+#define RTC_HOUR_ALARM 5 // hours to alarm
+#define RTC_DAY_OF_WEEK 6 // day of week [1..7]
+#define RTC_DAY_OF_MONTH 7 // day of month [1..31]
+#define RTC_MONTH 8 // month of year [1..12]
+#define RTC_YEAR 9 // year [00..99]
+#define RTC_CONTROL_REGISTERA 10 // control register A
+#define RTC_CONTROL_REGISTERB 11 // control register B
+#define RTC_CONTROL_REGISTERC 12 // control register C
+#define RTC_CONTROL_REGISTERD 13 // control register D
+#define RTC_REGNUMBER_RTC_CR1 0x6A // control register 1
+
+#define PCHIP_PCI0_MEMORY ULL(0x10000000000)
+#define PCHIP_PCI0_IO ULL(0x101FC000000)
+#define TSUNAMI_PCI0_MEMORY ALPHA_K0SEG_BASE + PCHIP_PCI0_MEMORY
+#define TSUNAMI_PCI0_IO ALPHA_K0SEG_BASE + PCHIP_PCI0_IO
+
+
+// UART Defines
+
+
+#define UART_IER_THRI 0x02
+#define UART_IER_RLSI 0x04
+
+#endif // __TSUNAMIREG_H__
diff --git a/kern/linux/linux.hh b/kern/linux/linux.hh
new file mode 100644
index 000000000..a3cb94e91
--- /dev/null
+++ b/kern/linux/linux.hh
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#ifndef __LINUX_HH__
+#define __LINUX_HH__
+
+class Linux {};
+
+#endif // __LINUX_HH__
diff --git a/kern/linux/linux_syscalls.cc b/kern/linux/linux_syscalls.cc
new file mode 100644
index 000000000..d67725050
--- /dev/null
+++ b/kern/linux/linux_syscalls.cc
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#include "kern/linux/linux_syscalls.hh"
+
+namespace {
+ const char *
+ standard_strings[SystemCalls<Linux>::Number] = {
+
+
+ "llseek", //0
+ "newselect", //1
+ "sysctl", //2
+ "access", //3
+ "acct", //4
+ "adjtimex", //5
+ "afs_syscall", //6
+ "alarm", //7
+ "bdflush", //8
+ "break", //9
+
+
+ "brk", //10
+ "capget", //11
+ "capset", //12
+ "chdir", //13
+ "chmod", //14
+ "chown", //15
+ "chown32", //16
+ "chroot", //17
+ "clock_getres", //18
+ "clock_gettime", //19
+
+
+ "clock_nanosleep", //20
+ "clock_settime", //21
+ "clone", //22
+ "close", //23
+ "creat", //24
+ "create_module", //25
+ "delete_module", //26
+ "dup", //27
+ "dup2", //28
+ "epoll_create", //29
+
+
+ "epoll_ctl", //30
+ "epoll_wait", //31
+ "execve", //32
+ "exit", //33
+ "exit_group", //34
+ "fadvise64", //35
+ "fadvise64_64", //36
+ "fchdir", //37
+ "fchmod", //38
+ "fchown", //39
+
+
+ "fchown32", //40
+ "fcntl", //41
+ "fcntl64", //42
+ "fdatasync", //43
+ "fgetxattr", //44
+ "flistxattr", //45
+ "flock", //46
+ "fork", //47
+ "fremovexattr", //48
+ "fsetxattr", //49
+
+
+ "fstat", //50
+ "fstat64", //51
+ "fstatfs", //52
+ "fstatfs64", //53
+ "fsync", //54
+ "ftime", //55
+ "ftruncate", //56
+ "ftruncate64", //57
+ "futex", //58
+ "get_kernel_syms", //59
+
+
+ "get_thread_area", //60
+ "getcwd", //61
+ "getdents", //62
+ "getdents64", //63
+ "getegid", //64
+ "getegid32", //65
+ "geteuid", //66
+ "geteuid32", //67
+ "getgid", //68
+ "getgid32", //69
+
+
+ "getgroups", //70
+ "getgroups32", //71
+ "getitimer", //72
+ "getpgid", //73
+ "getpgrp", //74
+ "getpid", //75
+ "getpmsg", //76
+ "getppid", //77
+ "getpriority", //78
+ "getresgid", //79
+
+
+ "getresgid32", //80
+ "getresuid", //81
+ "getresuid32", //82
+ "getrlimit", //83
+ "getrusage", //84
+ "getsid", //85
+ "gettid", //86
+ "gettimeofday", //87
+ "getuid", //88
+ "getuid32", //89
+
+
+ "getxattr", //90
+ "gtty", //91
+ "idle", //92
+ "init_module", //93
+ "io_cancel", //94
+ "io_destroy", //95
+ "io_getevents", //96
+ "io_setup", //97
+ "io_submit", //98
+ "ioctl", //99
+
+
+ "ioperm", //100
+ "iopl", //101
+ "ipc", //102
+ "kill", //103
+ "lchown", //104
+ "lchown32", //105
+ "lgetxattr", //106
+ "link", //107
+ "listxattr", //108
+ "llistxattr", //109
+
+
+ "lock", //110
+ "lookup_dcookie", //111
+ "lremovexattr", //112
+ "lseek", //113
+ "lsetxattr", //114
+ "lstat", //115
+ "lstat64", //116
+ "madvise", //117
+ "madvise1", //118
+ "mincore", //119
+
+
+ "mkdir", //120
+ "mknod", //121
+ "mlock", //122
+ "mlockall", //123
+ "mmap", //124
+ "mmap2", //125
+ "modify_ldt", //126
+ "mount", //127
+ "mprotect", //128
+ "mpx", //129
+
+
+ "mremap", //130
+ "msync", //131
+ "munlock", //132
+ "munlockall", //133
+ "munmap", //134
+ "nanosleep", //135
+ "nfsservctl", //136
+ "nice", //137
+ "oldfstat", //138
+ "oldlstat", //139
+
+
+ "oldolduname", //140
+ "oldstat", //141
+ "olduname", //142
+ "open", //143
+ "pause", //144
+ "personality", //145
+ "pipe", //146
+ "pivot_root", //147
+ "poll", //148
+ "prctl", //149
+
+
+ "pread64", //150
+ "prof", //151
+ "profil", //152
+ "ptrace", //153
+ "putpmsg", //154
+ "pwrite64", //155
+ "query_module", //156
+ "quotactl", //157
+ "read", //158
+ "readahead", //159
+
+
+ "readdir", //160
+ "readlink", //161
+ "readv", //162
+ "reboot", //163
+ "remap_file_pages", //164
+ "removexattr", //165
+ "rename", //166
+ "restart_syscall", //167
+ "rmdir", //168
+ "rt_sigaction", //169
+
+
+ "rt_sigpending", //170
+ "rt_sigprocmask", //171
+ "rt_sigqueueinfo", //172
+ "rt_sigreturn", //173
+ "rt_sigsuspend", //174
+ "rt_sigtimedwait", //175
+ "sched_get_priority_max", //176
+ "sched_get_priority_min", //177
+ "sched_getaffinity", //178
+ "sched_getparam", //179
+
+
+ "sched_getscheduler", //180
+ "sched_rr_get_interval", //181
+ "sched_setaffinity", //182
+ "sched_setparam", //183
+ "sched_setscheduler", //184
+ "sched_yield", //185
+ "select", //186
+ "sendfile", //187
+ "sendfile64", //188
+ "set_thread_area", //189
+
+
+ "set_tid_address", //190
+ "setdomainname", //191
+ "setfsgid", //192
+ "setfsgid32", //193
+ "setfsuid", //194
+ "setfsuid32", //195
+ "setgid", //196
+ "setgid32", //197
+ "setgroups", //198
+ "setgroups32", //199
+
+
+ "sethostname", //200
+ "setitimer", //201
+ "setpgid", //202
+ "setpriority", //203
+ "setregid", //204
+ "setregid32", //205
+ "setresgid", //206
+ "setresgid32", //207
+ "setresuid", //208
+ "setresuid32", //209
+
+
+ "setreuid", //210
+ "setreuid32", //211
+ "setrlimit", //212
+ "setsid", //213
+ "settimeofday", //214
+ "setuid", //215
+ "setuid32", //216
+ "setxattr", //217
+ "sgetmask", //218
+ "sigaction", //219
+
+
+ "sigaltstack", //220
+ "signal", //221
+ "sigpending", //222
+ "sigprocmask", //223
+ "sigreturn", //224
+ "sigsuspend", //225
+ "socketcall", //226
+ "ssetmask", //227
+ "stat", //228
+ "stat64", //229
+
+
+ "statfs", //230
+ "statfs64", //231
+ "stime", //232
+ "stty", //233
+ "swapoff", //234
+ "swapon", //235
+ "symlink", //236
+ "sync", //237
+ "sysfs", //238
+ "sysinfo", //239
+
+
+ "syslog", //240
+ "tgkill", //241
+ "time", //242
+ "timer_create", //243
+ "timer_delete", //244
+ "timer_getoverrun", //245
+ "timer_gettime", //246
+ "timer_settime", //247
+ "times", //248
+ "tkill", //249
+
+
+ "truncate", //250
+ "truncate64", //251
+ "ugetrlimit", //252
+ "ulimit", //253
+ "umask", //254
+ "umount", //255
+ "umount2", //256
+ "uname", //257
+ "unlink", //258
+ "uselib", //259
+
+
+ "ustat", //260
+ "utime", //261
+ "utimes", //262
+ "vfork", //263
+ "vhangup", //264
+ "vm86", //265
+ "vm86old", //266
+ "vserver", //267
+ "wait4", //268
+ "waitpid", //269
+
+
+ "write", //270
+ "writev", //271
+ };
+
+
+}
+
+const char *
+SystemCalls<Linux>::name(int num)
+{
+ if ((num >= 0) && (num < Number))
+ return standard_strings[num];
+ else
+ return 0;
+}
diff --git a/kern/linux/linux_syscalls.hh b/kern/linux/linux_syscalls.hh
new file mode 100644
index 000000000..86ccdd12d
--- /dev/null
+++ b/kern/linux/linux_syscalls.hh
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#ifndef __LINUX_SYSCALLS_HH__
+#define __LINUX_SYSCALLS_HH__
+
+#include "targetarch/syscalls.hh"
+#include "kern/linux/linux.hh"
+
+struct SystemCalls<Linux>
+{
+ enum {
+ syscall = 0,
+ llseek = 1,
+ newselect = 2,
+ sysctl = 3,
+ access = 4,
+ acct = 5,
+ adjtimex = 6,
+ afs_syscall = 7,
+ alarm = 8,
+ bdflush = 9,
+ _break = 10, /*renamed from break*/
+ brk = 11,
+ capget = 12,
+ capset = 13,
+ chdir = 14,
+ chmod = 15,
+ chown = 16,
+ chown32 = 17,
+ chroot = 18,
+ clock_getres = 19,
+ clock_gettime = 20,
+ clock_nanosleep = 21,
+ clock_settime = 22,
+ clone = 23,
+ close = 24,
+ creat = 25,
+ create_module = 26,
+ delete_module = 27,
+ dup = 28,
+ dup2 = 29,
+ epoll_create = 30,
+ epoll_ctl = 31,
+ epoll_wait = 32,
+ execve = 33,
+ exit = 34,
+ exit_group = 35,
+ fadvise64 = 36,
+ fadvise64_64 = 37,
+ fchdir = 38,
+ fchmod = 39,
+ fchown = 40,
+ fchown32 = 41,
+ fcntl = 42,
+ fcntl64 = 43,
+ fdatasync = 44,
+ fgetxattr = 45,
+ flistxattr = 46,
+ flock = 47,
+ fork = 48,
+ fremovexattr = 49,
+ fsetxattr = 50,
+ fstat = 51,
+ fstat64 = 52,
+ fstatfs = 53,
+ fstatfs64 = 54,
+ fsync = 55,
+ ftime = 56,
+ ftruncate = 57,
+ ftruncate64 = 58,
+ futex = 59,
+ get_kernel_syms = 60,
+ get_thread_area = 61,
+ getcwd = 62,
+ getdents = 63,
+ getdents64 = 64,
+ getegid = 65,
+ getegid32 = 66,
+ geteuid = 67,
+ geteuid32 = 68,
+ getgid = 69,
+ getgid32 = 70,
+ getgroups = 71,
+ getgroups32 = 72,
+ getitimer = 73,
+ getpgid = 74,
+ getpgrp = 75,
+ getpid = 76,
+ getpmsg = 77,
+ getppid = 78,
+ getpriority = 79,
+ getresgid = 80,
+ getresgid32 = 81,
+ getresuid = 82,
+ getresuid32 = 83,
+ getrlimit = 84,
+ getrusage = 85,
+ getsid = 86,
+ gettid = 87,
+ gettimeofday = 88,
+ getuid = 89,
+ getuid32 = 90,
+ getxattr = 91,
+ gtty = 92,
+ idle = 93,
+ init_module = 94,
+ io_cancel = 95,
+ io_destroy = 96,
+ io_getevents = 97,
+ io_setup = 98,
+ io_submit = 99,
+ ioctl = 100,
+ ioperm = 101,
+ iopl = 102,
+ ipc = 103,
+ kill = 104,
+ lchown = 105,
+ lchown32 = 106,
+ lgetxattr = 107,
+ link = 108,
+ listxattr = 109,
+ llistxattr = 110,
+ lock = 111,
+ lookup_dcookie = 112,
+ lremovexattr = 113,
+ lseek = 114,
+ lsetxattr = 115,
+ lstat = 116,
+ lstat64 = 117,
+ madvise = 118,
+ madvise1 = 119,
+ mincore = 120,
+ mkdir = 121,
+ mknod = 122,
+ mlock = 123,
+ mlockall = 124,
+ mmap = 125,
+ mmap2 = 126,
+ modify_ldt = 127,
+ mount = 128,
+ mprotect = 129,
+ mpx = 130,
+ mremap = 131,
+ msync = 132,
+ munlock = 133,
+ munlockall = 134,
+ munmap = 135,
+ nanosleep = 136,
+ nfsservctl = 137,
+ nice = 138,
+ oldfstat = 139,
+ oldlstat = 140,
+ oldolduname = 141,
+ oldstat = 142,
+ olduname = 143,
+ open = 144,
+ pause = 145,
+ personality = 146,
+ pipe = 147,
+ pivot_root = 148,
+ poll = 149,
+ prctl = 150,
+ pread64 = 151,
+ prof = 152,
+ profil = 153,
+ ptrace = 154,
+ putpmsg = 155,
+ pwrite64 = 156,
+ query_module = 157,
+ quotactl = 158,
+ read = 159,
+ readahead = 160,
+ readdir = 161,
+ readlink = 162,
+ readv = 163,
+ reboot = 164,
+ remap_file_pages = 165,
+ removexattr = 166,
+ rename = 167,
+ restart_syscall = 168,
+ rmdir = 169,
+ rt_sigaction = 170,
+ rt_sigpending = 171,
+ rt_sigprocmask = 172,
+ rt_sigqueueinfo = 173,
+ rt_sigreturn = 174,
+ rt_sigsuspend = 175,
+ rt_sigtimedwait = 176,
+ sched_get_priority_max = 177,
+ sched_get_priority_min = 178,
+ sched_getaffinity = 179,
+ sched_getparam = 180,
+ sched_getscheduler = 181,
+ sched_rr_get_interval = 182,
+ sched_setaffinity = 183,
+ sched_setparam = 184,
+ sched_setscheduler = 185,
+ sched_yield = 186,
+ select = 187,
+ sendfile = 188,
+ sendfile64 = 189,
+ set_thread_area = 190,
+ set_tid_address = 191,
+ setdomainname = 192,
+ setfsgid = 193,
+ setfsgid32 = 194,
+ setfsuid = 195,
+ setfsuid32 = 196,
+ setgid = 197,
+ setgid32 = 198,
+ setgroups = 199,
+ setgroups32 = 200,
+ sethostname = 201,
+ setitimer = 202,
+ setpgid = 203,
+ setpriority = 204,
+ setregid = 205,
+ setregid32 = 206,
+ setresgid = 207,
+ setresgid32 = 208,
+ setresuid = 209,
+ setresuid32 = 210,
+ setreuid = 211,
+ setreuid32 = 212,
+ setrlimit = 213,
+ setsid = 214,
+ settimeofday = 215,
+ setuid = 216,
+ setuid32 = 217,
+ setxattr = 218,
+ sgetmask = 219,
+ sigaction = 220,
+ sigaltstack = 221,
+ signal = 222,
+ sigpending = 223,
+ sigprocmask = 224,
+ sigreturn = 225,
+ sigsuspend = 226,
+ socketcall = 227,
+ ssetmask = 228,
+ stat = 229,
+ stat64 = 230,
+ statfs = 231,
+ statfs64 = 232,
+ stime = 233,
+ stty = 234,
+ swapoff = 235,
+ swapon = 236,
+ symlink = 237,
+ sync = 238,
+ sysfs = 239,
+ sysinfo = 240,
+ syslog = 241,
+ tgkill = 242,
+ time = 243,
+ timer_create = 244,
+ timer_delete = 245,
+ timer_getoverrun = 246,
+ timer_gettime = 247,
+ timer_settime = 248,
+ times = 249,
+ tkill = 250,
+ truncate = 251,
+ truncate64 = 252,
+ ugetrlimit = 253,
+ ulimit = 254,
+ umask = 255,
+ umount = 256,
+ umount2 = 257,
+ uname = 258,
+ unlink = 259,
+ uselib = 260,
+ ustat = 261,
+ utime = 262,
+ utimes = 263,
+ vfork = 264,
+ vhangup = 265,
+ vm86 = 266,
+ vm86old = 267,
+ vserver = 268,
+ wait4 = 269,
+ waitpid = 270,
+ write = 271,
+ writev = 272,
+ Number
+ };
+
+ static const char *name(int num);
+
+ static bool validSyscallNumber(int num) {
+ return num < Number;
+ }
+
+};
+
+#endif // __LINUX_SYSCALLS_HH__
diff --git a/kern/linux/linux_system.cc b/kern/linux/linux_system.cc
new file mode 100644
index 000000000..89688772c
--- /dev/null
+++ b/kern/linux/linux_system.cc
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+/**
+ * @file
+ * linux_system.cc loads the linux kernel, console, pal and patches certain functions.
+ * The symbol tables are loaded so that traces can show the executing function and we can
+ * skip functions. Various delay loops are skipped and their final values manually computed to
+ * speed up boot time.
+ */
+
+#include "base/loader/aout_object.hh"
+#include "base/loader/elf_object.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/remote_gdb.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base_cpu.hh"
+#include "kern/linux/linux_events.hh"
+#include "kern/linux/linux_system.hh"
+#include "kern/system_events.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "sim/builder.hh"
+#include "dev/platform.hh"
+#include "targetarch/isa_traits.hh"
+#include "targetarch/vtophys.hh"
+
+extern SymbolTable *debugSymbolTable;
+
+using namespace std;
+
+LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param,
+ MemoryController *_memCtrl, PhysicalMemory *_physmem,
+ const string &kernel_path, const string &console_path,
+ const string &palcode, const string &boot_osflags,
+ const bool _bin, const vector<string> &_binned_fns)
+ : System(_name, _init_param, _memCtrl, _physmem, _bin, _binned_fns),
+ bin(_bin), binned_fns(_binned_fns)
+{
+ kernelSymtab = new SymbolTable;
+ consoleSymtab = new SymbolTable;
+
+ /**
+ * Load the kernel, pal, and console code into memory
+ */
+ // Load kernel code
+ ObjectFile *kernel = createObjectFile(kernel_path);
+ if (kernel == NULL)
+ fatal("Could not load kernel file %s", kernel_path);
+
+ // Load Console Code
+ ObjectFile *console = createObjectFile(console_path);
+ if (console == NULL)
+ fatal("Could not load console file %s", console_path);
+
+ // Load pal file
+ ObjectFile *pal = createObjectFile(palcode);
+ if (pal == NULL)
+ fatal("Could not load PALcode file %s", palcode);
+ pal->loadSections(physmem, true);
+
+ // Load console file
+ console->loadSections(physmem, true);
+
+ // Load kernel file
+ kernel->loadSections(physmem, true);
+ kernelStart = kernel->textBase();
+ kernelEnd = kernel->bssBase() + kernel->bssSize();
+ kernelEntry = kernel->entryPoint();
+
+ // load symbols
+ if (!kernel->loadGlobalSymbols(kernelSymtab))
+ panic("could not load kernel symbols\n");
+ debugSymbolTable = kernelSymtab;
+
+ if (!kernel->loadLocalSymbols(kernelSymtab))
+ panic("could not load kernel local symbols\n");
+
+ if (!console->loadGlobalSymbols(consoleSymtab))
+ panic("could not load console symbols\n");
+
+ DPRINTF(Loader, "Kernel start = %#x\n"
+ "Kernel end = %#x\n"
+ "Kernel entry = %#x\n",
+ kernelStart, kernelEnd, kernelEntry);
+
+ DPRINTF(Loader, "Kernel loaded...\n");
+
+
+#ifdef DEBUG
+ kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic");
+ consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic");
+#endif
+
+ skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue,
+ "ide_delay_50ms");
+
+ skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue,
+ "calibrate_delay");
+
+ skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue,
+ "determine_cpu_caches");
+
+ Addr addr = 0;
+
+ /**
+ * find the address of the est_cycle_freq variable and insert it so we don't
+ * through the lengthly process of trying to calculated it by using the PIT,
+ * RTC, etc.
+ */
+ if (kernelSymtab->findAddress("est_cycle_freq", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ uint8_t *est_cycle_frequency =
+ physmem->dma_addr(paddr, sizeof(uint64_t));
+
+ if (est_cycle_frequency)
+ *(uint64_t *)est_cycle_frequency = ticksPerSecond;
+ }
+
+
+ /**
+ * Copy the osflags (kernel arguments) into the consoles memory. Presently
+ * Linux does use the console service routine to get these command line
+ * arguments, but we might as well make them available just in case.
+ */
+ if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ if (osflags)
+ strcpy(osflags, boot_osflags.c_str());
+ }
+
+ /**
+ * Since we aren't using a bootloader, we have to copy the kernel arguments
+ * directly into the kernels memory.
+ */
+ {
+ Addr paddr = vtophys(physmem, PARAM_ADDR);
+ char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t));
+ if (commandline)
+ strcpy(commandline, boot_osflags.c_str());
+ }
+
+
+ /**
+ * Set the hardware reset parameter block system type and revision information
+ * to Tsunami.
+ */
+ if (consoleSymtab->findAddress("xxm_rpb", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ char *hwprb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
+
+ if (hwprb) {
+ *(uint64_t*)(hwprb+0x50) = 34; // Tsunami
+ *(uint64_t*)(hwprb+0x58) = (1<<10); // Plain DP264
+ }
+ else
+ panic("could not translate hwprb addr to set system type/variation\n");
+
+ } else
+ panic("could not find hwprb to set system type/variation\n");
+
+#ifdef DEBUG
+ if (kernelSymtab->findAddress("panic", addr))
+ kernelPanicEvent->schedule(addr);
+ else
+ panic("could not find kernel symbol \'panic\'");
+
+ if (consoleSymtab->findAddress("panic", addr))
+ consolePanicEvent->schedule(addr);
+#endif
+
+ /**
+ * Any time ide_delay_50ms, calibarte_delay or determine_cpu_caches is called
+ * just skip the function. Currently determine_cpu_caches only is used put
+ * information in proc, however if that changes in the future we will have to
+ * fill in the cache size variables appropriately.
+ */
+ if (kernelSymtab->findAddress("ide_delay_50ms", addr))
+ skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst));
+
+ if (kernelSymtab->findAddress("calibrate_delay", addr))
+ skipDelayLoopEvent->schedule(addr+sizeof(MachInst));
+
+ if (kernelSymtab->findAddress("determine_cpu_caches", addr))
+ skipCacheProbeEvent->schedule(addr+sizeof(MachInst));
+}
+
+LinuxSystem::~LinuxSystem()
+{
+ delete kernel;
+ delete console;
+
+ delete kernelSymtab;
+ delete consoleSymtab;
+
+ delete kernelPanicEvent;
+ delete consolePanicEvent;
+ delete skipIdeDelay50msEvent;
+ delete skipDelayLoopEvent;
+ delete skipCacheProbeEvent;
+}
+
+
+void
+LinuxSystem::setDelayLoop(ExecContext *xc)
+{
+ Addr addr = 0;
+ if (kernelSymtab->findAddress("loops_per_jiffy", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+
+ uint8_t *loops_per_jiffy =
+ physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ Tick cpuFreq = xc->cpu->getFreq();
+ Tick intrFreq = platform->interrupt_frequency;
+ *(uint32_t *)loops_per_jiffy =
+ (uint32_t)((cpuFreq / intrFreq) * 0.9988);
+ }
+}
+
+int
+LinuxSystem::registerExecContext(ExecContext *xc)
+{
+ int xcIndex = System::registerExecContext(xc);
+
+ if (xcIndex == 0) {
+ // activate with zero delay so that we start ticking right
+ // away on cycle 0
+ xc->activate(0);
+ }
+
+ RemoteGDB *rgdb = new RemoteGDB(this, xc);
+ GDBListener *gdbl = new GDBListener(rgdb, 7000 + xcIndex);
+ gdbl->listen();
+ /**
+ * Uncommenting this line waits for a remote debugger to connect
+ * to the simulator before continuing.
+ */
+ //gdbl->accept();
+
+ if (remoteGDB.size() <= xcIndex) {
+ remoteGDB.resize(xcIndex+1);
+ }
+
+ remoteGDB[xcIndex] = rgdb;
+
+ return xcIndex;
+}
+
+
+void
+LinuxSystem::replaceExecContext(ExecContext *xc, int xcIndex)
+{
+ System::replaceExecContext(xcIndex, xc);
+ remoteGDB[xcIndex]->replaceExecContext(xc);
+}
+
+bool
+LinuxSystem::breakpoint()
+{
+ return remoteGDB[0]->trap(ALPHA_KENTRY_IF);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)
+
+ Param<bool> bin;
+ SimObjectParam<MemoryController *> mem_ctl;
+ SimObjectParam<PhysicalMemory *> physmem;
+ Param<uint64_t> init_param;
+
+ Param<string> kernel_code;
+ Param<string> console_code;
+ Param<string> pal_code;
+ Param<string> boot_osflags;
+ VectorParam<string> binned_fns;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxSystem)
+
+
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(mem_ctl, "memory controller"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM(kernel_code, "file that contains the code"),
+ INIT_PARAM(console_code, "file that contains the console code"),
+ INIT_PARAM(pal_code, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned")
+
+
+END_INIT_SIM_OBJECT_PARAMS(LinuxSystem)
+
+CREATE_SIM_OBJECT(LinuxSystem)
+{
+ LinuxSystem *sys = new LinuxSystem(getInstanceName(), init_param, mem_ctl,
+ physmem, kernel_code, console_code,
+ pal_code, boot_osflags, bin, binned_fns);
+
+ return sys;
+}
+
+REGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem)
diff --git a/kern/linux/linux_system.hh b/kern/linux/linux_system.hh
new file mode 100644
index 000000000..83775cb92
--- /dev/null
+++ b/kern/linux/linux_system.hh
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2003 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.
+ */
+
+#ifndef __LINUX_SYSTEM_HH__
+#define __LINUX_SYSTEM_HH__
+
+#include <vector>
+
+#include "sim/system.hh"
+#include "sim/host.hh"
+#include "targetarch/isa_traits.hh"
+
+#include <map>
+
+/**
+ * MAGIC address where the kernel arguments should go. Defined as
+ * PARAM in linux kernel alpha-asm.
+ */
+const Addr PARAM_ADDR = ULL(0xfffffc000030a000);
+
+class ExecContext;
+class ElfObject;
+class SymbolTable;
+
+class BreakPCEvent;
+class LinuxSkipDelayLoopEvent;
+class SkipFuncEvent;
+class FnEvent;
+class AlphaArguments;
+
+/**
+ * This class contains linux specific system code (Loading, Events, Binning).
+ * It points to objects that are the system binaries to load and patches them
+ * appropriately to work in simulator.
+ */
+class LinuxSystem : public System
+{
+ private:
+ /** Object pointer for the kernel code */
+ ElfObject *kernel;
+
+ /** Object pointer for the console code */
+ ElfObject *console;
+
+ /** kernel Symbol table */
+ SymbolTable *kernelSymtab;
+
+ /** console symbol table */
+ SymbolTable *consoleSymtab;
+
+ /** Event to halt the simulator if the kernel calls panic() */
+ BreakPCEvent *kernelPanicEvent;
+
+ /** Event to halt the simulator if the console calls panic() */
+ BreakPCEvent *consolePanicEvent;
+
+ /** Event to skip determine_cpu_caches() because we don't support the
+ * IPRs that the code can access to figure out cache sizes
+ */
+ SkipFuncEvent *skipCacheProbeEvent;
+
+ /** PC based event to skip the ide_delay_50ms() call */
+ SkipFuncEvent *skipIdeDelay50msEvent;
+
+ /** Skip calculate_delay_loop() rather than waiting for this to be
+ * calculated
+ */
+ LinuxSkipDelayLoopEvent *skipDelayLoopEvent;
+
+ /** Begining of kernel code */
+ Addr kernelStart;
+
+ /** End of kernel code */
+ Addr kernelEnd;
+
+ /** Entry point in the kernel to start at */
+ Addr kernelEntry;
+
+ bool bin;
+ std::vector<string> binned_fns;
+
+ public:
+ std::vector<RemoteGDB *> remoteGDB;
+ std::vector<GDBListener *> gdbListen;
+
+ LinuxSystem(const std::string _name,
+ const uint64_t _init_param,
+ MemoryController *_memCtrl,
+ PhysicalMemory *_physmem,
+ const std::string &kernel_path,
+ const std::string &console_path,
+ const std::string &palcode,
+ const std::string &boot_osflags,
+ const bool _bin,
+ const std::vector<std::string> &_binned_fns);
+
+ ~LinuxSystem();
+
+ void setDelayLoop(ExecContext *xc);
+
+ int registerExecContext(ExecContext *xc);
+ void replaceExecContext(ExecContext *xc, int xcIndex);
+
+ /**
+ * Returns the addess the kernel starts at.
+ * @return address the kernel starts at
+ */
+ Addr getKernelStart() const { return kernelStart; }
+
+ /**
+ * Returns the addess the kernel ends at.
+ * @return address the kernel ends at
+ */
+ Addr getKernelEnd() const { return kernelEnd; }
+
+ /**
+ * Returns the addess the entry point to the kernel code.
+ * @return entry point of the kernel code
+ */
+ Addr getKernelEntry() const { return kernelEntry; }
+
+
+ bool breakpoint();
+};
+
+#endif // __LINUX_SYSTEM_HH__
diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc
index 0717bcbbe..c02b4f684 100644
--- a/kern/tru64/tru64_system.cc
+++ b/kern/tru64/tru64_system.cc
@@ -42,18 +42,22 @@
#include "targetarch/isa_traits.hh"
#include "targetarch/vtophys.hh"
+extern SymbolTable *debugSymbolTable;
+
using namespace std;
Tru64System::Tru64System(const string _name, const uint64_t _init_param,
MemoryController *_memCtrl, PhysicalMemory *_physmem,
const string &kernel_path, const string &console_path,
const string &palcode, const string &boot_osflags,
- const bool _bin, const vector<string> &binned_fns)
- : System(_name, _init_param, _memCtrl, _physmem, _bin, binned_fns),
- bin(_bin), binned_fns(binned_fns)
+ const bool _bin, const vector<string> &_binned_fns,
+ const uint64_t system_type, const uint64_t system_rev)
+ : System(_name, _init_param, _memCtrl, _physmem, _bin,_binned_fns),
+ bin(_bin), binned_fns(_binned_fns)
{
kernelSymtab = new SymbolTable;
consoleSymtab = new SymbolTable;
+ debugSymbolTable = kernelSymtab;
ObjectFile *kernel = createObjectFile(kernel_path);
if (kernel == NULL)
@@ -125,6 +129,20 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param,
strcpy(osflags, boot_osflags.c_str());
}
+ if (consoleSymtab->findAddress("xxm_rpb", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ char *hwprb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
+
+ if (hwprb) {
+ *(uint64_t*)(hwprb+0x50) = system_type;
+ *(uint64_t*)(hwprb+0x58) = system_rev;
+ }
+ else
+ panic("could not translate hwprb addr to set system type/variation\n");
+ } else
+ panic("could not find hwprb to set system type/variation\n");
+
+
#ifdef DEBUG
if (kernelSymtab->findAddress("panic", addr))
kernelPanicEvent->schedule(addr);
@@ -246,6 +264,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System)
Param<string> pal_code;
Param<string> boot_osflags;
VectorParam<string> binned_fns;
+ Param<uint64_t> system_type;
+ Param<uint64_t> system_rev;
END_DECLARE_SIM_OBJECT_PARAMS(Tru64System)
@@ -260,7 +280,10 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64System)
INIT_PARAM(pal_code, "file that contains palcode"),
INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
"a"),
- INIT_PARAM(binned_fns, "functions to be broken down and binned")
+ INIT_PARAM(binned_fns, "functions to be broken down and binned"),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1)
+
END_INIT_SIM_OBJECT_PARAMS(Tru64System)
@@ -269,7 +292,7 @@ CREATE_SIM_OBJECT(Tru64System)
Tru64System *sys = new Tru64System(getInstanceName(), init_param, mem_ctl,
physmem, kernel_code, console_code,
pal_code, boot_osflags, bin,
- binned_fns);
+ binned_fns, system_type, system_rev);
return sys;
}
diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh
index 144febbf9..b97f7760c 100644
--- a/kern/tru64/tru64_system.hh
+++ b/kern/tru64/tru64_system.hh
@@ -89,7 +89,9 @@ class Tru64System : public System
const std::string &palcode,
const std::string &boot_osflags,
const bool _bin,
- const std::vector<string> &binned_fns);
+ const std::vector<string> &binned_fns,
+ const uint64_t system_type,
+ const uint64_t system_rev);
~Tru64System();
int registerExecContext(ExecContext *xc);
diff --git a/sim/sim_object.cc b/sim/sim_object.cc
index 7f756858c..96c0b197e 100644
--- a/sim/sim_object.cc
+++ b/sim/sim_object.cc
@@ -36,6 +36,7 @@
#include "sim/host.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
+#include "sim/param.hh"
using namespace std;
@@ -168,3 +169,5 @@ SimObject::serializeAll(ostream &os)
obj->serialize(os);
}
}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject)
diff --git a/sim/system.cc b/sim/system.cc
index 619593abd..b801cb254 100644
--- a/sim/system.cc
+++ b/sim/system.cc
@@ -52,6 +52,9 @@ System::System(const std::string _name,
bin(_bin),
binned_fns(binned_fns)
{
+ // increment the number of running systems
+ numSystemsRunning++;
+
// add self to global system list
systemList.push_back(this);
if (bin == true) {
diff --git a/sim/system.hh b/sim/system.hh
index b83945884..f9909019b 100644
--- a/sim/system.hh
+++ b/sim/system.hh
@@ -41,6 +41,7 @@
class MemoryController;
class PhysicalMemory;
+class Platform;
class RemoteGDB;
class GDBListener;
@@ -87,6 +88,7 @@ class System : public SimObject
const uint64_t init_param;
MemoryController *memCtrl;
PhysicalMemory *physmem;
+ Platform *platform;
bool bin;
std::vector<string> binned_fns;