diff options
151 files changed, 7707 insertions, 2982 deletions
diff --git a/SConscript b/SConscript index 8a9b99cb5..9d3a41964 100644 --- a/SConscript +++ b/SConscript @@ -47,6 +47,7 @@ base_sources = Split(''' arch/alpha/alpha_full_cpu_exec.cc arch/alpha/fast_cpu_exec.cc arch/alpha/simple_cpu_exec.cc + arch/alpha/inorder_cpu_exec.cc arch/alpha/full_cpu_exec.cc arch/alpha/faults.cc arch/alpha/isa_traits.cc @@ -65,6 +66,7 @@ base_sources = Split(''' base/pollevent.cc base/python.cc base/range.cc + base/random.cc base/sat_counter.cc base/socket.cc base/statistics.cc @@ -131,6 +133,7 @@ base_sources = Split(''' cpu/full_cpu/issue.cc cpu/full_cpu/ls_queue.cc cpu/full_cpu/machine_queue.cc + cpu/full_cpu/pc_sample_profile.cc cpu/full_cpu/pipetrace.cc cpu/full_cpu/readyq.cc cpu/full_cpu/reg_info.cc @@ -150,6 +153,7 @@ base_sources = Split(''' cpu/full_cpu/iq/standard/iq_standard.cc cpu/sampling_cpu/sampling_cpu.cc cpu/simple_cpu/simple_cpu.cc + cpu/inorder_cpu/inorder_cpu.cc cpu/trace/reader/mem_trace_reader.cc cpu/trace/reader/ibm_reader.cc cpu/trace/reader/itx_reader.cc @@ -196,6 +200,7 @@ base_sources = Split(''' mem/timing_mem/base_memory.cc mem/timing_mem/memory_builder.cc mem/timing_mem/simple_mem_bank.cc + mem/trace/itx_writer.cc mem/trace/mem_trace_writer.cc mem/trace/m5_writer.cc @@ -209,11 +214,10 @@ base_sources = Split(''' sim/serialize.cc sim/sim_events.cc sim/sim_exit.cc - sim/sim_init.cc sim/sim_object.cc + sim/startup.cc sim/stat_context.cc sim/stat_control.cc - sim/sw_context.cc sim/trace_context.cc sim/universe.cc sim/pyconfig/pyconfig.cc @@ -233,6 +237,7 @@ base_obj_desc_files = Split(''' cpu/full_cpu/PipeTrace.od cpu/sampling_cpu/SamplingCPU.od cpu/simple_cpu/SimpleCPU.od + cpu/inorder_cpu/InorderCPU.od cpu/BaseCPU.od cpu/IntrControl.od mem/bus/Bus.od @@ -267,6 +272,7 @@ full_system_sources = Split(''' arch/alpha/pseudo_inst.cc arch/alpha/vtophys.cc + base/crc.cc base/inet.cc base/remote_gdb.cc @@ -290,10 +296,12 @@ full_system_sources = Split(''' dev/etherdev.cc dev/pciconfigall.cc dev/pcidev.cc + dev/pktfifo.cc dev/scsi.cc dev/scsi_ctrl.cc dev/scsi_disk.cc dev/scsi_none.cc + dev/sinic.cc dev/simple_disk.cc dev/tlaser_clock.cc dev/tlaser_ipi.cc @@ -311,6 +319,7 @@ full_system_sources = Split(''' dev/tsunami_pchip.cc dev/uart.cc + kern/kernel_binning.cc kern/kernel_stats.cc kern/system_events.cc kern/linux/linux_events.cc @@ -374,6 +383,7 @@ syscall_emulation_sources = Split(''' arch/alpha/alpha_linux_process.cc arch/alpha/alpha_tru64_process.cc cpu/memtest/memtest.cc + cpu/trace/opt_cpu.cc cpu/trace/trace_cpu.cc eio/eio.cc eio/exolex.cc @@ -389,6 +399,32 @@ syscall_emulation_obj_desc_files = Split(''' sim/Process.od ''') +targetarch_files = Split(''' + alpha_common_syscall_emul.hh + alpha_linux_process.hh + alpha_memory.hh + alpha_tru64_process.hh + aout_machdep.h + arguments.hh + byte_swap.hh + ecoff_machdep.h + elf_machdep.h + ev5.hh + faults.hh + isa_fullsys_traits.hh + isa_traits.hh + machine_exo.h + osfpal.hh + pseudo_inst.hh + vptr.hh + vtophys.hh + ''') + +for f in targetarch_files: + env.Command('targetarch/' + f, 'arch/alpha/' + f, + '''echo '#include "arch/alpha/%s"' > $TARGET''' % f) + + # Set up complete list of sources based on configuration. sources = base_sources obj_desc_files = base_obj_desc_files @@ -400,8 +436,19 @@ else: sources += syscall_emulation_sources obj_desc_files += syscall_emulation_obj_desc_files +extra_libraries = [] +env.Append(LIBS=['z']) if env['USE_MYSQL']: sources += mysql_sources + env.Append(CPPDEFINES = 'USE_MYSQL') + env.Append(CPPDEFINES = 'STATS_BINNING') + env.Append(CPPPATH=['/usr/local/include/mysql', '/usr/include/mysql']) + if os.path.isdir('/usr/lib64'): + env.Append(LIBPATH=['/usr/lib64/mysql']) + else: + env.Append(LIBPATH=['/usr/lib/mysql/']) + env.Append(LIBS=['mysqlclient']) + ################################################### # @@ -421,28 +468,13 @@ env.Command(Split('''arch/alpha/decoder.cc arch/alpha/alpha_full_cpu_exec.cc arch/alpha/fast_cpu_exec.cc arch/alpha/simple_cpu_exec.cc + arch/alpha/inorder_cpu_exec.cc arch/alpha/full_cpu_exec.cc'''), Split('''arch/alpha/isa_desc arch/isa_parser.py'''), '$SRCDIR/arch/isa_parser.py $SOURCE $TARGET.dir arch/alpha') -# 'targetarch' is a symlink to arch/$TARGET_ISA. -def link_targetarch(target, source, env): - link_target = str(target[0]) - link_source = env.subst('$SRCDIR/arch/$TARGET_ISA') - if not os.path.isdir(link_target): - print "symlinking", link_source, "to", link_target - try: - os.symlink(link_source, link_target) - except OSError, desc: - print "Error creating symlink %s: %s" % (link_target, desc) - sys.exit(-1) - -# Tell SCons to use the link_targetarch function to make 'targetarch' -env.Command('targetarch', None, link_targetarch) - - # libelf build is described in its own SConscript file. # SConscript-local is the per-config build, which just copies some # header files into a place where they can be found. @@ -456,16 +488,15 @@ SConscript('sim/pyconfig/SConscript', exports = ['env', 'obj_desc_files'], # environment, and returns a list of all the corresponding SCons # Object nodes (including an extra one for date.cc). We explicitly # add the Object nodes so we can set up special dependencies for -# targetarch and date.cc. +# date.cc. def make_objs(sources, env): objs = [env.Object(s) for s in sources] - # make all objects depend on the targetarch link so it gets made first. - env.Depends(objs, 'targetarch') # make date.cc depend on all other objects so it always gets # recompiled whenever anything else does date_obj = env.Object('base/date.cc') env.Depends(date_obj, objs) objs.append(date_obj) + objs.extend(extra_libraries) return objs ################################################### diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc index 9f5ab185e..81a1902a0 100644 --- a/arch/alpha/alpha_memory.cc +++ b/arch/alpha/alpha_memory.cc @@ -30,15 +30,15 @@ #include <string> #include <vector> +#include "arch/alpha/alpha_memory.hh" #include "base/inifile.hh" #include "base/str.hh" #include "base/trace.hh" #include "cpu/exec_context.hh" #include "sim/builder.hh" -#include "targetarch/alpha_memory.hh" -#include "targetarch/ev5.hh" using namespace std; +using namespace EV5; /////////////////////////////////////////////////////////////////////// // @@ -49,6 +49,8 @@ bool uncacheBit39 = false; bool uncacheBit40 = false; #endif +#define MODE2MASK(X) (1 << (X)) + AlphaTLB::AlphaTLB(const string &name, int s) : SimObject(name), size(s), nlu(0) { @@ -103,12 +105,12 @@ AlphaTLB::checkCacheability(MemReqPtr &req) #ifdef ALPHA_TLASER - if (req->paddr & PA_UNCACHED_BIT_39) { + if (req->paddr & PAddrUncachedBit39) { #else - if (req->paddr & PA_UNCACHED_BIT_43) { + if (req->paddr & PAddrUncachedBit43) { #endif // IPR memory space not implemented - if (PA_IPR_SPACE(req->paddr)) { + if (PAddrIprSpace(req->paddr)) { if (!req->xc->misspeculating()) { switch (req->paddr) { case ULL(0xFFFFF00188): @@ -126,7 +128,7 @@ AlphaTLB::checkCacheability(MemReqPtr &req) #ifndef ALPHA_TLASER // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) - req->paddr &= PA_UNCACHED_MASK; + req->paddr &= PAddrUncachedMask; #endif } } @@ -135,8 +137,9 @@ AlphaTLB::checkCacheability(MemReqPtr &req) // insert a new TLB entry void -AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte) +AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte) { + AlphaISA::VAddr vaddr = addr; if (table[nlu].valid) { Addr oldvpn = table[nlu].tag; PageTable::iterator i = lookupTable.find(oldvpn); @@ -157,14 +160,13 @@ AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte) lookupTable.erase(i); } - Addr vpn = VA_VPN(vaddr); - DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn); + DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); table[nlu] = pte; - table[nlu].tag = vpn; + table[nlu].tag = vaddr.vpn(); table[nlu].valid = true; - lookupTable.insert(make_pair(vpn, nlu)); + lookupTable.insert(make_pair(vaddr.vpn(), nlu)); nextnlu(); } @@ -197,21 +199,22 @@ AlphaTLB::flushProcesses() } void -AlphaTLB::flushAddr(Addr vaddr, uint8_t asn) +AlphaTLB::flushAddr(Addr addr, uint8_t asn) { - Addr vpn = VA_VPN(vaddr); + AlphaISA::VAddr vaddr = addr; - PageTable::iterator i = lookupTable.find(vpn); + PageTable::iterator i = lookupTable.find(vaddr.vpn()); if (i == lookupTable.end()) return; - while (i->first == vpn) { + while (i->first == vaddr.vpn()) { int index = i->second; AlphaISA::PTE *pte = &table[index]; assert(pte->valid); - if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { - DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn); + if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { + DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), + pte->ppn); // invalidate this entry pte->valid = false; @@ -287,7 +290,7 @@ AlphaITB::fault(Addr pc, ExecContext *xc) const if (!xc->misspeculating()) { ipr[AlphaISA::IPR_ITB_TAG] = pc; ipr[AlphaISA::IPR_IFAULT_VA_FORM] = - ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3); + ipr[AlphaISA::IPR_IVPTBR] | (AlphaISA::VAddr(pc).vpn() << 3); } } @@ -297,9 +300,9 @@ AlphaITB::translate(MemReqPtr &req) const { InternalProcReg *ipr = req->xc->regs.ipr; - if (PC_PAL(req->vaddr)) { + if (AlphaISA::PcPAL(req->vaddr)) { // strip off PAL PC marker (lsb is 1) - req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK; + req->paddr = (req->vaddr & ~3) & PAddrImplMask; hits++; return No_Fault; } @@ -319,24 +322,23 @@ AlphaITB::translate(MemReqPtr &req) const // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 #ifdef ALPHA_TLASER if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && - VA_SPACE_EV5(req->vaddr) == 2) { + VAddrSpaceEV5(req->vaddr) == 2) { #else - if (VA_SPACE_EV6(req->vaddr) == 0x7e) { + if (VAddrSpaceEV6(req->vaddr) == 0x7e) { #endif - - // only valid in kernel mode - if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) { + if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != + AlphaISA::mode_kernel) { fault(req->vaddr, req->xc); acv++; return ITB_Acv_Fault; } - req->paddr = req->vaddr & PA_IMPL_MASK; + req->paddr = req->vaddr & PAddrImplMask; #ifndef ALPHA_TLASER // sign extend the physical address properly - if (req->paddr & PA_UNCACHED_BIT_40) + if (req->paddr & PAddrUncachedBit40) req->paddr |= ULL(0xf0000000000); else req->paddr &= ULL(0xffffffffff); @@ -344,8 +346,8 @@ AlphaITB::translate(MemReqPtr &req) const } else { // not a physical address: need to look up pte - AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), - DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), + DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); if (!pte) { fault(req->vaddr, req->xc); @@ -353,7 +355,8 @@ AlphaITB::translate(MemReqPtr &req) const return ITB_Fault_Fault; } - req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3); + req->paddr = (pte->ppn << AlphaISA::PageShift) + + (AlphaISA::VAddr(req->vaddr).offset() & ~3); // check permissions for this access if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) { @@ -368,7 +371,7 @@ AlphaITB::translate(MemReqPtr &req) const } // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PA_IMPL_MASK) + if (req->paddr & ~PAddrImplMask) return Machine_Check_Fault; checkCacheability(req); @@ -457,7 +460,7 @@ void AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const { ExecContext *xc = req->xc; - Addr vaddr = req->vaddr; + AlphaISA::VAddr vaddr = req->vaddr; uint64_t *ipr = xc->regs.ipr; // Set fault address and flags. Even though we're modeling an @@ -468,16 +471,17 @@ AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const if (!xc->misspeculating() && !(req->flags & VPTE) && !(req->flags & NO_FAULT)) { // set VA register with faulting address - ipr[AlphaISA::IPR_VA] = vaddr; + ipr[AlphaISA::IPR_VA] = req->vaddr; // set MM_STAT register flags - ipr[AlphaISA::IPR_MM_STAT] = (((OPCODE(xc->getInst()) & 0x3f) << 11) - | ((RA(xc->getInst()) & 0x1f) << 6) - | (flags & 0x3f)); + ipr[AlphaISA::IPR_MM_STAT] = + (((Opcode(xc->getInst()) & 0x3f) << 11) + | ((Ra(xc->getInst()) & 0x1f) << 6) + | (flags & 0x3f)); // set VA_FORM register with faulting formatted address ipr[AlphaISA::IPR_VA_FORM] = - ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3); + ipr[AlphaISA::IPR_MVPTBR] | (vaddr.vpn() << 3); } } @@ -492,14 +496,15 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]); - /* @todo this should actually be in there but for whatever reason - * Its not working at present. + /** + * Check for alignment faults */ if (req->vaddr & (req->size - 1)) { + fault(req, write ? MM_STAT_WR_MASK : 0); return Alignment_Fault; } - if (PC_PAL(pc)) { + if (pc & 0x1) { mode = (req->flags & ALTMODE) ? (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]) : AlphaISA::mode_kernel; @@ -510,8 +515,9 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const } else { // verify that this is a good virtual address if (!validVirtualAddress(req->vaddr)) { - fault(req, ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK | - MM_STAT_ACV_MASK)); + fault(req, (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_BAD_VA_MASK | + MM_STAT_ACV_MASK); if (write) { write_acv++; } else { read_acv++; } return DTB_Fault_Fault; @@ -520,24 +526,25 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const // Check for "superpage" mapping #ifdef ALPHA_TLASER if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && - VA_SPACE_EV5(req->vaddr) == 2) { + VAddrSpaceEV5(req->vaddr) == 2) { #else - if (VA_SPACE_EV6(req->vaddr) == 0x7e) { + if (VAddrSpaceEV6(req->vaddr) == 0x7e) { #endif // only valid in kernel mode if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) { - fault(req, ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK)); + fault(req, ((write ? MM_STAT_WR_MASK : 0) | + MM_STAT_ACV_MASK)); if (write) { write_acv++; } else { read_acv++; } return DTB_Acv_Fault; } - req->paddr = req->vaddr & PA_IMPL_MASK; + req->paddr = req->vaddr & PAddrImplMask; #ifndef ALPHA_TLASER // sign extend the physical address properly - if (req->paddr & PA_UNCACHED_BIT_40) + if (req->paddr & PAddrUncachedBit40) req->paddr |= ULL(0xf0000000000); else req->paddr &= ULL(0xffffffffff); @@ -550,36 +557,39 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const read_accesses++; // not a physical address: need to look up pte - AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), - DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), + DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); if (!pte) { // page fault - fault(req, - (write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK); + fault(req, (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_DTB_MISS_MASK); if (write) { write_misses++; } else { read_misses++; } return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault; } - req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr); + req->paddr = (pte->ppn << AlphaISA::PageShift) + + AlphaISA::VAddr(req->vaddr).offset(); if (write) { if (!(pte->xwe & MODE2MASK(mode))) { // declare the instruction access fault - fault(req, (MM_STAT_WR_MASK | MM_STAT_ACV_MASK | - (pte->fonw ? MM_STAT_FONW_MASK : 0))); + fault(req, MM_STAT_WR_MASK | + MM_STAT_ACV_MASK | + (pte->fonw ? MM_STAT_FONW_MASK : 0)); write_acv++; return DTB_Fault_Fault; } if (pte->fonw) { - fault(req, MM_STAT_WR_MASK | MM_STAT_FONW_MASK); + fault(req, MM_STAT_WR_MASK | + MM_STAT_FONW_MASK); write_acv++; return DTB_Fault_Fault; } } else { if (!(pte->xre & MODE2MASK(mode))) { - fault(req, (MM_STAT_ACV_MASK | - (pte->fonr ? MM_STAT_FONR_MASK : 0))); + fault(req, MM_STAT_ACV_MASK | + (pte->fonr ? MM_STAT_FONR_MASK : 0)); read_acv++; return DTB_Acv_Fault; } @@ -598,7 +608,7 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const } // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PA_IMPL_MASK) + if (req->paddr & ~PAddrImplMask) return Machine_Check_Fault; checkCacheability(req); diff --git a/arch/alpha/alpha_memory.hh b/arch/alpha/alpha_memory.hh index 42bc03ddd..0d4b8d1f2 100644 --- a/arch/alpha/alpha_memory.hh +++ b/arch/alpha/alpha_memory.hh @@ -31,9 +31,10 @@ #include <map> +#include "arch/alpha/isa_traits.hh" +#include "base/statistics.hh" #include "mem/mem_req.hh" #include "sim/sim_object.hh" -#include "base/statistics.hh" class ExecContext; @@ -66,8 +67,8 @@ class AlphaTLB : public SimObject // static helper functions... really EV5 VM traits static bool validVirtualAddress(Addr vaddr) { // unimplemented bits must be all 0 or all 1 - Addr unimplBits = vaddr & VA_UNIMPL_MASK; - return (unimplBits == 0) || (unimplBits == VA_UNIMPL_MASK); + Addr unimplBits = vaddr & EV5::VAddrUnImplMask; + return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); } static void checkCacheability(MemReqPtr &req); diff --git a/arch/alpha/arguments.cc b/arch/alpha/arguments.cc index 2dca3f51e..905d6b9ae 100644 --- a/arch/alpha/arguments.cc +++ b/arch/alpha/arguments.cc @@ -26,10 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "arch/alpha/arguments.hh" +#include "arch/alpha/vtophys.hh" #include "cpu/exec_context.hh" #include "mem/functional_mem/physical_memory.hh" -#include "targetarch/arguments.hh" -#include "targetarch/vtophys.hh" AlphaArguments::Data::~Data() { diff --git a/arch/alpha/arguments.hh b/arch/alpha/arguments.hh index 78e66b3fd..b4dc0eea8 100644 --- a/arch/alpha/arguments.hh +++ b/arch/alpha/arguments.hh @@ -31,9 +31,9 @@ #include <assert.h> +#include "arch/alpha/vtophys.hh" #include "base/refcnt.hh" #include "sim/host.hh" -#include "targetarch/vtophys.hh" class ExecContext; diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index b043ed0ee..2e32da531 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -9,14 +9,13 @@ #include "cpu/base_cpu.hh" #include "cpu/exec_context.hh" #include "cpu/fast_cpu/fast_cpu.hh" +#include "kern/kernel_stats.hh" #include "sim/debug.hh" #include "sim/sim_events.hh" #ifdef FULL_SYSTEM -#ifndef SYSTEM_EV5 -#error This code is only valid for EV5 systems -#endif +using namespace EV5; //////////////////////////////////////////////////////////////////////// // @@ -95,22 +94,22 @@ AlphaISA::initIPRs(RegFile *regs) uint64_t *ipr = regs->ipr; bzero((char *)ipr, NumInternalProcRegs * sizeof(InternalProcReg)); - ipr[IPR_PAL_BASE] = PAL_BASE; + ipr[IPR_PAL_BASE] = PalBase; ipr[IPR_MCSR] = 0x6; } -template <class XC> +template <class CPU> void -AlphaISA::processInterrupts(XC *xc) +AlphaISA::processInterrupts(CPU *cpu) { //Check if there are any outstanding interrupts //Handle the interrupts int ipl = 0; int summary = 0; - IntReg *ipr = xc->getIprPtr(); + IntReg *ipr = cpu->getIprPtr(); - check_interrupts = 0; + cpu->checkInterrupts = false; if (ipr[IPR_ASTRR]) panic("asynchronous traps not implemented\n"); @@ -126,7 +125,7 @@ AlphaISA::processInterrupts(XC *xc) } } - uint64_t interrupts = xc->intr_status(); + uint64_t interrupts = cpu->intr_status(); if (interrupts) { for (int i = INTLEVEL_EXTERNAL_MIN; @@ -142,32 +141,32 @@ AlphaISA::processInterrupts(XC *xc) if (ipl && ipl > ipr[IPR_IPLR]) { ipr[IPR_ISR] = summary; ipr[IPR_INTID] = ipl; - xc->trap(Interrupt_Fault); + cpu->trap(Interrupt_Fault); DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", ipr[IPR_IPLR], ipl, summary); } } -template <class XC> +template <class CPU> void -AlphaISA::zeroRegisters(XC *xc) +AlphaISA::zeroRegisters(CPU *cpu) { // Insure ISA semantics // (no longer very clean due to the change in setIntReg() in the // cpu model. Consider changing later.) - xc->xc->setIntReg(ZeroReg, 0); - xc->xc->setFloatRegDouble(ZeroReg, 0.0); + cpu->xc->setIntReg(ZeroReg, 0); + cpu->xc->setFloatRegDouble(ZeroReg, 0.0); } void ExecContext::ev5_trap(Fault fault) { - DPRINTF(Fault, "Fault %s\n", FaultName(fault)); + DPRINTF(Fault, "Fault %s at PC: %#x\n", FaultName(fault), regs.pc); cpu->recordEvent(csprintf("Fault %s", FaultName(fault))); assert(!misspeculating()); - kernelStats.fault(fault); + kernelStats->fault(fault); if (fault == Arithmetic_Fault) panic("Arithmetic traps are unimplemented!"); @@ -175,16 +174,16 @@ ExecContext::ev5_trap(Fault fault) AlphaISA::InternalProcReg *ipr = regs.ipr; // exception restart address - if (fault != Interrupt_Fault || !PC_PAL(regs.pc)) + if (fault != Interrupt_Fault || !inPalMode()) ipr[AlphaISA::IPR_EXC_ADDR] = regs.pc; if (fault == Pal_Fault || fault == Arithmetic_Fault /* || - fault == Interrupt_Fault && !PC_PAL(regs.pc) */) { + fault == Interrupt_Fault && !inPalMode() */) { // traps... skip faulting instruction ipr[AlphaISA::IPR_EXC_ADDR] += 4; } - if (!PC_PAL(regs.pc)) + if (!inPalMode()) AlphaISA::swap_palshadow(®s, true); regs.pc = ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; @@ -219,25 +218,23 @@ AlphaISA::intr_post(RegFile *regs, Fault fault, Addr pc) // that's it! (orders of magnitude less painful than x86) } -bool AlphaISA::check_interrupts = false; - Fault ExecContext::hwrei() { uint64_t *ipr = regs.ipr; - if (!PC_PAL(regs.pc)) + if (!inPalMode()) return Unimplemented_Opcode_Fault; setNextPC(ipr[AlphaISA::IPR_EXC_ADDR]); if (!misspeculating()) { - kernelStats.hwrei(); + kernelStats->hwrei(); if ((ipr[AlphaISA::IPR_EXC_ADDR] & 1) == 0) AlphaISA::swap_palshadow(®s, false); - AlphaISA::check_interrupts = true; + cpu->checkInterrupts = true; } // FIXME: XXX check for interrupts? XXX @@ -415,7 +412,7 @@ ExecContext::setIpr(int idx, uint64_t val) // write entire quad w/ no side-effect old = ipr[idx]; ipr[idx] = val; - kernelStats.context(old, val); + kernelStats->context(old, val); break; case AlphaISA::IPR_DTB_PTE: @@ -442,11 +439,14 @@ ExecContext::setIpr(int idx, uint64_t val) // only write least significant five bits - interrupt level ipr[idx] = val & 0x1f; - kernelStats.swpipl(ipr[idx]); + kernelStats->swpipl(ipr[idx]); break; case AlphaISA::IPR_DTB_CM: - kernelStats.mode((val & 0x18) != 0); + if (val & 0x18) + kernelStats->mode(Kernel::user); + else + kernelStats->mode(Kernel::kernel); case AlphaISA::IPR_ICM: // only write two mode bits - processor mode @@ -622,7 +622,7 @@ ExecContext::setIpr(int idx, uint64_t val) bool ExecContext::simPalCheck(int palFunc) { - kernelStats.callpal(palFunc); + kernelStats->callpal(palFunc); switch (palFunc) { case PAL::halt: diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh index f49eadeb0..317f3d19d 100644 --- a/arch/alpha/ev5.hh +++ b/arch/alpha/ev5.hh @@ -1,128 +1,79 @@ /* $Id$ */ -#ifndef __EV5_H__ -#define __EV5_H__ +#ifndef __ARCH_ALPHA_EV5_HH__ +#define __ARCH_ALPHA_EV5_HH__ -#ifndef SYSTEM_EV5 -#error This code is only valid for EV5 systems -#endif - -#include "targetarch/isa_traits.hh" - -//////////////////////////////////////////////////////////////////////// -// -// -// - -//////////////////////////////////////////////////////////////////////// -// -// -// - -#define MODE2MASK(X) (1 << (X)) - -// Alpha IPR register accessors -#define PC_PAL(X) ((X) & 0x1) -#define MCSR_SP(X) (((X) >> 1) & 0x3) - -#define ICSR_SDE(X) (((X) >> 30) & 0x1) -#define ICSR_SPE(X) (((X) >> 28) & 0x3) -#define ICSR_FPE(X) (((X) >> 26) & 0x1) - -#define ALT_MODE_AM(X) (((X) >> 3) & 0x3) - -#define DTB_CM_CM(X) (((X) >> 3) & 0x3) - -#ifdef ALPHA_TLASER -#define DTB_ASN_ASN(X) (((X) >> 57) & 0x7f) -#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff) -#else -#define DTB_ASN_ASN(X) (((X) >> 57) & 0xff) -#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07fffffff) -#endif - -#define DTB_PTE_XRE(X) (((X) >> 8) & 0xf) -#define DTB_PTE_XWE(X) (((X) >> 12) & 0xf) -#define DTB_PTE_FONR(X) (((X) >> 1) & 0x1) -#define DTB_PTE_FONW(X) (((X) >> 2) & 0x1) -#define DTB_PTE_GH(X) (((X) >> 5) & 0x3) -#define DTB_PTE_ASMA(X) (((X) >> 4) & 0x1) - -#define ICM_CM(X) (((X) >> 3) & 0x3) +namespace EV5 { #ifdef ALPHA_TLASER -#define ITB_ASN_ASN(X) (((X) >> 4) & 0x7f) -#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff) +const uint64_t AsnMask = ULL(0x7f); #else -#define ITB_ASN_ASN(X) (((X) >> 4) & 0xff) -#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07fffffff) +const uint64_t AsnMask = ULL(0xff); #endif -#define ITB_PTE_XRE(X) (((X) >> 8) & 0xf) -#define ITB_PTE_FONR(X) (((X) >> 1) & 0x1) -#define ITB_PTE_FONW(X) (((X) >> 2) & 0x1) -#define ITB_PTE_GH(X) (((X) >> 5) & 0x3) -#define ITB_PTE_ASMA(X) (((X) >> 4) & 0x1) +const int VAddrImplBits = 43; +const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1; +const Addr VAddrUnImplMask = ~VAddrImplMask; +inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; } +inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; } +inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; } +inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; } +inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; } -#define VA_UNIMPL_MASK ULL(0xfffff80000000000) -#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_EV5(X) (((X) >> 41) & 0x3) -#define VA_SPACE_EV6(X) (((X) >> 41) & 0x7f) -#define VA_POFS(X) ((X) & 0x1fff) - -#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> #ifdef ALPHA_TLASER -#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFF00000)) -#define PA_IMPL_MASK ULL(0xffffffffff) +inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFF00000); } +const int PAddrImplBits = 40; #else -#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFFF00000)) -#define PA_IMPL_MASK ULL(0xfffffffffff) // for Tsunami +inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFFF00000); } +const int PAddrImplBits = 44; // for Tsunami #endif - -#define PA_PFN2PA(X) ((X) << 13) - - -#define MM_STAT_BAD_VA_MASK 0x0020 -#define MM_STAT_DTB_MISS_MASK 0x0010 -#define MM_STAT_FONW_MASK 0x0008 -#define MM_STAT_FONR_MASK 0x0004 -#define MM_STAT_ACV_MASK 0x0002 -#define MM_STAT_WR_MASK 0x0001 - -#define OPCODE(X) (X >> 26) & 0x3f -#define RA(X) (X >> 21) & 0x1f - -//////////////////////////////////////////////////////////////////////// -// -// -// - -// VPTE size for HW_LD/HW_ST -#define HW_VPTE ((inst >> 11) & 0x1) - -// QWORD size for HW_LD/HW_ST -#define HW_QWORD ((inst >> 12) & 0x1) - -// ALT mode for HW_LD/HW_ST -#define HW_ALT (((inst >> 14) & 0x1) ? ALTMODE : 0) - -// LOCK/COND mode for HW_LD/HW_ST -#define HW_LOCK (((inst >> 10) & 0x1) ? LOCKED : 0) -#define HW_COND (((inst >> 10) & 0x1) ? LOCKED : 0) - -// PHY size for HW_LD/HW_ST -#define HW_PHY (((inst >> 15) & 0x1) ? PHYSICAL : 0) - -// OFFSET for HW_LD/HW_ST -#define HW_OFS (inst & 0x3ff) - - -#define PAL_BASE 0x4000 -#define PAL_MAX 0x10000 - -#endif //__EV5_H__ +const Addr PAddrImplMask = (ULL(1) << PAddrImplBits) - 1; +const Addr PAddrUncachedBit39 = ULL(0x8000000000); +const Addr PAddrUncachedBit40 = ULL(0x10000000000); +const Addr PAddrUncachedBit43 = ULL(0x80000000000); +const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35> + +inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; } +inline Addr DTB_PTE_PPN(uint64_t reg) +{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } +inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; } +inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } +inline int DTB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } +inline int DTB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } +inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } + +inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; } +inline Addr ITB_PTE_PPN(uint64_t reg) +{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } +inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } +inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } +inline int ITB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } +inline bool ITB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } + +inline uint64_t MCSR_SP(uint64_t reg) { return reg >> 1 & 0x3; } + +inline bool ICSR_SDE(uint64_t reg) { return reg >> 30 & 0x1; } +inline int ICSR_SPE(uint64_t reg) { return reg >> 28 & 0x3; } +inline bool ICSR_FPE(uint64_t reg) { return reg >> 26 & 0x1; } + +inline uint64_t ALT_MODE_AM(uint64_t reg) { return reg >> 3 & 0x3; } +inline uint64_t DTB_CM_CM(uint64_t reg) { return reg >> 3 & 0x3; } +inline uint64_t ICM_CM(uint64_t reg) { return reg >> 3 & 0x3; } + +const uint64_t MM_STAT_BAD_VA_MASK = ULL(0x0020); +const uint64_t MM_STAT_DTB_MISS_MASK = ULL(0x0010); +const uint64_t MM_STAT_FONW_MASK = ULL(0x0008); +const uint64_t MM_STAT_FONR_MASK = ULL(0x0004); +const uint64_t MM_STAT_ACV_MASK = ULL(0x0002); +const uint64_t MM_STAT_WR_MASK = ULL(0x0001); +inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; } +inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; } + +const Addr PalBase = 0x4000; +const Addr PalMax = 0x10000; + +/* namespace EV5 */ } + +#endif // __ARCH_ALPHA_EV5_HH__ diff --git a/arch/alpha/faults.cc b/arch/alpha/faults.cc index a800f9886..c98bb91a5 100644 --- a/arch/alpha/faults.cc +++ b/arch/alpha/faults.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "targetarch/faults.hh" +#include "arch/alpha/faults.hh" namespace { const char * diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index eaf3aa379..fbd4cfe60 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -38,14 +38,12 @@ output exec {{ #include <fenv.h> #endif -#include "cpu/base_cpu.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" - #ifdef FULL_SYSTEM -#include "arch/alpha/ev5.hh" #include "arch/alpha/pseudo_inst.hh" #endif +#include "cpu/base_cpu.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" }}; //////////////////////////////////////////////////////////////////// @@ -515,7 +513,7 @@ output exec {{ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) { Fault fault = No_Fault; // dummy... this ipr access should not fault - if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) { + if (!EV5::ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) { fault = Fen_Fault; } return fault; @@ -1842,7 +1840,7 @@ decode OPCODE default Unknown::unknown() { 0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED); 0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED); 0x20: copy_load({{EA = Ra;}}, - {{ fault = xc->copySrcTranslate(EA);}}, + {{fault = xc->copySrcTranslate(EA);}}, IsMemRef, IsLoad, IsCopy); } @@ -1864,7 +1862,7 @@ decode OPCODE default Unknown::unknown() { 0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }}); 0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }}); 0x24: copy_store({{EA = Rb;}}, - {{ fault = xc->copy(EA);}}, + {{fault = xc->copy(EA);}}, IsMemRef, IsStore, IsCopy); } diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh index 6559368e4..ff3da1502 100644 --- a/arch/alpha/isa_traits.hh +++ b/arch/alpha/isa_traits.hh @@ -26,12 +26,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __ISA_TRAITS_HH__ -#define __ISA_TRAITS_HH__ +#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__ +#define __ARCH_ALPHA_ISA_TRAITS_HH__ -#include "sim/host.hh" -#include "targetarch/faults.hh" +#include "arch/alpha/faults.hh" #include "base/misc.hh" +#include "sim/host.hh" class FastCPU; class FullCPU; @@ -42,6 +42,11 @@ class Checkpoint; template <class ISA> class StaticInst; template <class ISA> class StaticInstPtr; +namespace EV5 { +int DTB_ASN_ASN(uint64_t reg); +int ITB_ASN_ASN(uint64_t reg); +} + class AlphaISA { public: @@ -121,11 +126,16 @@ class AlphaISA Addr lock_addr; // lock address for LL/SC } MiscRegFile; +static const Addr PageShift = 13; +static const Addr PageBytes = ULL(1) << PageShift; +static const Addr PageMask = ~(PageBytes - 1); +static const Addr PageOffset = PageBytes - 1; + #ifdef FULL_SYSTEM typedef uint64_t InternalProcReg; -#include "targetarch/isa_fullsys_traits.hh" +#include "arch/alpha/isa_fullsys_traits.hh" #else enum { @@ -155,6 +165,8 @@ class AlphaISA InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs int intrflag; // interrupt flag bool pal_shadow; // using pal_shadow registers + inline int instAsid() { return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } + inline int dataAsid() { return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } #endif // FULL_SYSTEM void serialize(std::ostream &os); @@ -276,9 +288,7 @@ typedef TheISA::InternalProcReg InternalProcReg; const int NumInternalProcRegs = TheISA::NumInternalProcRegs; const int NumInterruptLevels = TheISA::NumInterruptLevels; -// more stuff that should be imported here, but I'm too tired to do it -// right now... -#include "targetarch/ev5.hh" +#include "arch/alpha/ev5.hh" #endif -#endif // __ALPHA_ISA_H__ +#endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/arch/alpha/osfpal.cc b/arch/alpha/osfpal.cc index 2717079ab..3cdc3864a 100644 --- a/arch/alpha/osfpal.cc +++ b/arch/alpha/osfpal.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "targetarch/osfpal.hh" +#include "arch/alpha/osfpal.hh" namespace { const char *strings[PAL::NumCodes] = { diff --git a/arch/alpha/pseudo_inst.cc b/arch/alpha/pseudo_inst.cc index fd6742801..95c85b45a 100644 --- a/arch/alpha/pseudo_inst.cc +++ b/arch/alpha/pseudo_inst.cc @@ -37,6 +37,7 @@ #include "cpu/base_cpu.hh" #include "cpu/sampling_cpu/sampling_cpu.hh" #include "cpu/exec_context.hh" +#include "kern/kernel_stats.hh" #include "sim/param.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" @@ -60,7 +61,7 @@ namespace AlphaPseudo void arm(ExecContext *xc) { - xc->kernelStats.arm(); + xc->kernelStats->arm(); } void @@ -70,13 +71,13 @@ namespace AlphaPseudo return; xc->suspend(); - xc->kernelStats.quiesce(); + xc->kernelStats->quiesce(); } void ivlb(ExecContext *xc) { - xc->kernelStats.ivlb(); + xc->kernelStats->ivlb(); } void @@ -164,7 +165,7 @@ namespace AlphaPseudo void readfile(ExecContext *xc) { - const string &file = xc->cpu->system->readfile; + const string &file = xc->cpu->system->params->readfile; if (file.empty()) { xc->regs.intRegFile[0] = ULL(0); return; diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc index 5468d4b07..e26721aab 100644 --- a/arch/alpha/vtophys.cc +++ b/arch/alpha/vtophys.cc @@ -28,61 +28,47 @@ #include <string> -#include "targetarch/pmap.h" - +#include "arch/alpha/vtophys.hh" +#include "base/trace.hh" #include "cpu/exec_context.hh" #include "mem/functional_mem/physical_memory.hh" -#include "base/trace.hh" -#include "targetarch/vtophys.hh" using namespace std; -inline Addr -level3_index(Addr vaddr) -{ return (vaddr >> ALPHA_PGSHIFT) & PTEMASK; } - -inline Addr -level2_index(Addr vaddr) -{ return (vaddr >> (ALPHA_PGSHIFT + NPTEPG_SHIFT)) & PTEMASK; } - -inline Addr -level1_index(Addr vaddr) -{ return (vaddr >> (ALPHA_PGSHIFT + 2 * NPTEPG_SHIFT)) & PTEMASK; } - -Addr -kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr) +AlphaISA::PageTableEntry +kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr) { - uint64_t level1_map = ptbr; - Addr level1_pte = level1_map + (level1_index(vaddr) << PTESHIFT); - - uint64_t level1 = pmem->phys_read_qword(level1_pte); - if (!entry_valid(level1)) { + Addr level1_pte = ptbr + vaddr.level1(); + AlphaISA::PageTableEntry level1 = pmem->phys_read_qword(level1_pte); + if (!level1.valid()) { DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); return 0; } - uint64_t level2_map = PMAP_PTE_PA(level1); - Addr level2_pte = level2_map + (level2_index(vaddr) << PTESHIFT); - uint64_t level2 = pmem->phys_read_qword(level2_pte); - if (!entry_valid(level2)) { + Addr level2_pte = level1.paddr() + vaddr.level2(); + AlphaISA::PageTableEntry level2 = pmem->phys_read_qword(level2_pte); + if (!level2.valid()) { DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); return 0; } - uint64_t level3_map = PMAP_PTE_PA(level2); - Addr level3_pte = level3_map + (level3_index(vaddr) << PTESHIFT); - - return level3_pte; + Addr level3_pte = level2.paddr() + vaddr.level3(); + AlphaISA::PageTableEntry level3 = pmem->phys_read_qword(level3_pte); + if (!level3.valid()) { + DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); + return 0; + } + return level3; } Addr vtophys(PhysicalMemory *xc, Addr vaddr) { Addr paddr = 0; - if (vaddr < ALPHA_K0SEG_BASE) + if (AlphaISA::IsUSeg(vaddr)) DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); - else if (vaddr < ALPHA_K1SEG_BASE) - paddr = ALPHA_K0SEG_TO_PHYS(vaddr); + else if (AlphaISA::IsK0Seg(vaddr)) + paddr = AlphaISA::K0Seg2Phys(vaddr); else panic("vtophys: ptbr is not set on virtual lookup"); @@ -92,24 +78,25 @@ vtophys(PhysicalMemory *xc, Addr vaddr) } Addr -vtophys(ExecContext *xc, Addr vaddr) +vtophys(ExecContext *xc, Addr addr) { + AlphaISA::VAddr vaddr = addr; Addr ptbr = xc->regs.ipr[AlphaISA::IPR_PALtemp20]; Addr paddr = 0; //@todo Andrew couldn't remember why he commented some of this code //so I put it back in. Perhaps something to do with gdb debugging? - if (PC_PAL(vaddr) && (vaddr < PAL_MAX)) { + if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { paddr = vaddr & ~ULL(1); } else { - if (vaddr >= ALPHA_K0SEG_BASE && vaddr <= ALPHA_K0SEG_END) { - paddr = ALPHA_K0SEG_TO_PHYS(vaddr); + if (AlphaISA::IsK0Seg(vaddr)) { + paddr = AlphaISA::K0Seg2Phys(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); + AlphaISA::PageTableEntry pte = + kernel_pte_lookup(xc->physmem, ptbr, vaddr); + if (pte.valid()) + paddr = pte.paddr() | vaddr.offset(); } } @@ -141,7 +128,8 @@ CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) int len; paddr = vtophys(xc, src); - len = min((int)(ALPHA_PGBYTES - (paddr & PGOFSET)), (int)cplen); + len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), + (int)cplen); dmaaddr = (char *)xc->physmem->dma_addr(paddr, len); assert(dmaaddr); @@ -153,15 +141,15 @@ CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) dst += len; src += len; - while (cplen > ALPHA_PGBYTES) { + while (cplen > AlphaISA::PageBytes) { paddr = vtophys(xc, src); - dmaaddr = (char *)xc->physmem->dma_addr(paddr, ALPHA_PGBYTES); + dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes); assert(dmaaddr); - memcpy(dst, dmaaddr, ALPHA_PGBYTES); - cplen -= ALPHA_PGBYTES; - dst += ALPHA_PGBYTES; - src += ALPHA_PGBYTES; + memcpy(dst, dmaaddr, AlphaISA::PageBytes); + cplen -= AlphaISA::PageBytes; + dst += AlphaISA::PageBytes; + src += AlphaISA::PageBytes; } if (cplen > 0) { @@ -182,7 +170,8 @@ CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) int len; paddr = vtophys(xc, dest); - len = min((int)(ALPHA_PGBYTES - (paddr & PGOFSET)), (int)cplen); + len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), + (int)cplen); dmaaddr = (char *)xc->physmem->dma_addr(paddr, len); assert(dmaaddr); @@ -194,15 +183,15 @@ CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) src += len; dest += len; - while (cplen > ALPHA_PGBYTES) { + while (cplen > AlphaISA::PageBytes) { paddr = vtophys(xc, dest); - dmaaddr = (char *)xc->physmem->dma_addr(paddr, ALPHA_PGBYTES); + dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes); assert(dmaaddr); - memcpy(dmaaddr, src, ALPHA_PGBYTES); - cplen -= ALPHA_PGBYTES; - src += ALPHA_PGBYTES; - dest += ALPHA_PGBYTES; + memcpy(dmaaddr, src, AlphaISA::PageBytes); + cplen -= AlphaISA::PageBytes; + src += AlphaISA::PageBytes; + dest += AlphaISA::PageBytes; } if (cplen > 0) { @@ -222,7 +211,8 @@ CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) int len; paddr = vtophys(xc, vaddr); - len = min((int)(ALPHA_PGBYTES - (paddr & PGOFSET)), (int)maxlen); + len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), + (int)maxlen); dmaaddr = (char *)xc->physmem->dma_addr(paddr, len); assert(dmaaddr); @@ -239,21 +229,21 @@ CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) dst += len; vaddr += len; - while (maxlen > ALPHA_PGBYTES) { + while (maxlen > AlphaISA::PageBytes) { paddr = vtophys(xc, vaddr); - dmaaddr = (char *)xc->physmem->dma_addr(paddr, ALPHA_PGBYTES); + dmaaddr = (char *)xc->physmem->dma_addr(paddr, AlphaISA::PageBytes); assert(dmaaddr); - char *term = (char *)memchr(dmaaddr, 0, ALPHA_PGBYTES); - len = term ? (term - dmaaddr + 1) : ALPHA_PGBYTES; + char *term = (char *)memchr(dmaaddr, 0, AlphaISA::PageBytes); + len = term ? (term - dmaaddr + 1) : AlphaISA::PageBytes; memcpy(dst, dmaaddr, len); if (term) return; - maxlen -= ALPHA_PGBYTES; - dst += ALPHA_PGBYTES; - vaddr += ALPHA_PGBYTES; + maxlen -= AlphaISA::PageBytes; + dst += AlphaISA::PageBytes; + vaddr += AlphaISA::PageBytes; } if (maxlen > 0) { diff --git a/arch/alpha/vtophys.hh b/arch/alpha/vtophys.hh index 7c22e3371..8e47a0031 100644 --- a/arch/alpha/vtophys.hh +++ b/arch/alpha/vtophys.hh @@ -26,19 +26,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __VTOPHYS_H__ -#define __VTOPHYS_H__ +#ifndef __ARCH_ALPHA_VTOPHYS_H__ +#define __ARCH_ALPHA_VTOPHYS_H__ -#include "targetarch/isa_traits.hh" -#include "targetarch/pmap.h" - -inline bool entry_valid(uint64_t entry) -{ return (entry & ALPHA_PTE_VALID) != 0; } +#include "arch/alpha/isa_traits.hh" class ExecContext; class PhysicalMemory; -Addr kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr); +AlphaISA::PageTableEntry +kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr); + Addr vtophys(PhysicalMemory *xc, Addr vaddr); Addr vtophys(ExecContext *xc, Addr vaddr); uint8_t *vtomem(ExecContext *xc, Addr vaddr, size_t len); @@ -48,5 +46,5 @@ void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len); void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len); void CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen); -#endif // __VTOPHYS_H__ +#endif // __ARCH_ALPHA_VTOPHYS_H__ diff --git a/arch/isa_parser.py b/arch/isa_parser.py index f86e6193d..7228f99b6 100755 --- a/arch/isa_parser.py +++ b/arch/isa_parser.py @@ -627,6 +627,9 @@ class CpuModel: # Define CPU models. The following lines should contain the only # CPU-model-specific information in this file. Note that the ISA # description itself should have *no* CPU-model-specific content. +CpuModel('InorderCPU', 'inorder_cpu_exec.cc', + '#include "cpu/inorder_cpu/inorder_cpu.hh"', + { 'CPU_exec_context': 'InorderCPU' }) CpuModel('SimpleCPU', 'simple_cpu_exec.cc', '#include "cpu/simple_cpu/simple_cpu.hh"', { 'CPU_exec_context': 'SimpleCPU' }) diff --git a/base/bitfield.hh b/base/bitfield.hh index ee5ea72cf..bdc3fb13e 100644 --- a/base/bitfield.hh +++ b/base/bitfield.hh @@ -26,10 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __BITFIELD_HH -#define __BITFIELD_HH +#ifndef __BASE_BITFIELD_HH__ +#define __BASE_BITFIELD_HH__ -#include <inttypes.h> +#include "sim/host.hh" /** * Generate a 64-bit mask of 'nbits' 1s, right justified. @@ -66,4 +66,4 @@ sext(uint64_t val) return sign_bit ? (val | ~mask(N)) : val; } -#endif +#endif // __BASE_BITFIELD_HH__ diff --git a/base/callback.hh b/base/callback.hh index eee629cf5..cc2a2f429 100644 --- a/base/callback.hh +++ b/base/callback.hh @@ -32,7 +32,7 @@ #include <list> /** - * Generic callback class. This base class provides a virutal process + * Generic callback class. This base class provides a virtual process * function that gets called when the callback queue is processed. */ class Callback @@ -103,4 +103,20 @@ class CallbackQueue } }; +/// Helper template class to turn a simple class member function into +/// a callback. +template <class T, void (T::* F)()> +class MakeCallback : public Callback +{ + private: + T *object; + + public: + MakeCallback(T *o) + : object(o) + { } + + void process() { (object->*F)(); } +}; + #endif // __CALLBACK_HH__ diff --git a/base/compression/null_compression.hh b/base/compression/null_compression.hh index 195498f1b..63364a955 100644 --- a/base/compression/null_compression.hh +++ b/base/compression/null_compression.hh @@ -26,16 +26,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __NULL_COMPRESSION_HH__ -#define __NULL_COMPRESSION_HH__ +#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__ +#define __BASE_COMPRESSION_NULL_COMPRESSION_HH__ /** * @file * This file defines a doNothing compression algorithm. */ -#include <inttypes.h> // for uint8_t #include "base/misc.hh" // for fatal() +#include "sim/host.hh" /** @@ -73,4 +73,4 @@ class NullCompression } }; -#endif //__NULL_COMPRESSION_HH__ +#endif //__BASE_COMPRESSION_NULL_COMPRESSION_HH__ diff --git a/base/crc.cc b/base/crc.cc new file mode 100644 index 000000000..8bff4b868 --- /dev/null +++ b/base/crc.cc @@ -0,0 +1,117 @@ +/* $Id$ */ + +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sstream> +#include <string> + +#include "sim/host.hh" +#include "base/crc.hh" + +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); + crc >>= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + } + + return (crc); +} +#else +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc; + int i; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +crc32be(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); + crc <<= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} diff --git a/base/crc.hh b/base/crc.hh new file mode 100644 index 000000000..bd6719b98 --- /dev/null +++ b/base/crc.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-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 __BASE_CRC_HH__ +#define __BASE_CRC_HH__ + +#include "sim/host.hh" + +uint32_t crc32be(const uint8_t *buf, size_t len); +uint32_t crc32le(const uint8_t *buf, size_t len); + +#endif // __BASE_CRC_HH__ diff --git a/base/inet.cc b/base/inet.cc index e2bdd19ff..eca7238ff 100644 --- a/base/inet.cc +++ b/base/inet.cc @@ -26,6 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <cstdio> #include <sstream> #include <string> @@ -33,129 +34,175 @@ #include "sim/host.hh" #include "base/inet.hh" -using namespace::std; +using namespace std; +namespace Net { + +EthAddr::EthAddr() +{ + memset(data, 0, ETH_ADDR_LEN); +} + +EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) +{ + *data = *ea; +} + +EthAddr::EthAddr(const eth_addr &ea) +{ + *data = *ea.data; +} + +EthAddr::EthAddr(const std::string &addr) +{ + parse(addr); +} + +const EthAddr & +EthAddr::operator=(const eth_addr &ea) +{ + *data = *ea.data; + return *this; +} + +const EthAddr & +EthAddr::operator=(const std::string &addr) +{ + parse(addr); + return *this; +} + +void +EthAddr::parse(const std::string &addr) +{ + // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise + // the sscanf function won't work. + int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; + if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], + &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + for (int i = 0; i < ETH_ADDR_LEN; ++i) { + if (bytes[i] & ~0xff) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + data[i] = bytes[i]; + } +} + string -eaddr_string(const uint8_t a[6]) +EthAddr::string() const { stringstream stream; + stream << *this; + return stream.str(); +} + +bool +operator==(const EthAddr &left, const EthAddr &right) +{ + return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); +} + +ostream & +operator<<(ostream &stream, const EthAddr &ea) +{ + const uint8_t *a = ea.addr(); ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); + return stream; +} - return stream.str(); +uint16_t +cksum(const IpPtr &ptr) +{ + int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); + return ip_cksum_carry(sum); } -/* - * Copyright (c) 1988, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/*********************************************************************** - This section of code taken from NetBSD -***********************************************************************/ +uint16_t +__tu_cksum(const IpPtr &ip) +{ + int tcplen = ip->len() - ip->hlen(); + int sum = ip_cksum_add(ip->payload(), tcplen, 0); + sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination + sum += htons(ip->ip_p + tcplen); + return ip_cksum_carry(sum); +} -#define ETHER_CRC_POLY_LE 0xedb88320 -#define ETHER_CRC_POLY_BE 0x04c11db6 +uint16_t +cksum(const TcpPtr &tcp) +{ return __tu_cksum(IpPtr(tcp.packet())); } -#if 0 -/* - * This is for reference. We have a table-driven version - * of the little-endian crc32 generator, which is faster - * than the double-loop. - */ -uint32_t -crc32le(const uint8_t *buf, size_t len) +uint16_t +cksum(const UdpPtr &udp) +{ return __tu_cksum(IpPtr(udp.packet())); } + +bool +IpHdr::options(vector<const IpOpt *> &vec) const { - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); - crc >>= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_LE); - } + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct ip_hdr); + int all = hlen() - sizeof(struct ip_hdr); + while (all > 0) { + const IpOpt *opt = (const IpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; } - return (crc); + return true; } -#else -uint32_t -crc32le(const uint8_t *buf, size_t len) + +bool +TcpHdr::options(vector<const TcpOpt *> &vec) const { - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - uint32_t crc; - int i; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = off() - sizeof(struct tcp_hdr); + while (all > 0) { + const TcpOpt *opt = (const TcpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; } - return (crc); + return true; } -#endif -uint32_t -crc32be(const uint8_t *buf, size_t len) +bool +TcpOpt::sack(vector<SackRange> &vec) const { - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = len() - offsetof(tcp_opt, opt_data.sack); + while (all > 0) { + const uint16_t *sack = (const uint16_t *)data; + int len = sizeof(uint16_t) * 2; + if (all < len) { + vec.clear(); + return false; } + + vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); + all -= len; + data += len; } - return (crc); + return false; } -/*********************************************************************** - This is the end of the NetBSD code -***********************************************************************/ +/* namespace Net */ } diff --git a/base/inet.hh b/base/inet.hh index 67ac5a504..4f3857a15 100644 --- a/base/inet.hh +++ b/base/inet.hh @@ -26,12 +26,382 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __INET_HH__ -#define __INET_HH__ +#ifndef __BASE_INET_HH__ +#define __BASE_INET_HH__ +#include <iosfwd> +#include <string> +#include <utility> +#include <vector> + +#include "base/range.hh" +#include "dev/etherpkt.hh" #include "sim/host.hh" -uint32_t crc32be(const uint8_t *buf, size_t len); -uint32_t crc32le(const uint8_t *buf, size_t len); -std::string eaddr_string(const uint8_t a[6]); -#endif // __INET_HH__ +#include "dnet/os.h" +#include "dnet/eth.h" +#include "dnet/ip.h" +#include "dnet/ip6.h" +#include "dnet/addr.h" +#include "dnet/arp.h" +#include "dnet/icmp.h" +#include "dnet/tcp.h" +#include "dnet/udp.h" +#include "dnet/intf.h" +#include "dnet/route.h" +#include "dnet/fw.h" +#include "dnet/blob.h" +#include "dnet/rand.h" + +namespace Net { + +/* + * Ethernet Stuff + */ +struct EthAddr : protected eth_addr +{ + protected: + void parse(const std::string &addr); + + public: + EthAddr(); + EthAddr(const uint8_t ea[ETH_ADDR_LEN]); + EthAddr(const eth_addr &ea); + EthAddr(const std::string &addr); + const EthAddr &operator=(const eth_addr &ea); + const EthAddr &operator=(const std::string &addr); + + int size() const { return sizeof(eth_addr); } + + const uint8_t *bytes() const { return &data[0]; } + uint8_t *bytes() { return &data[0]; } + + const uint8_t *addr() const { return &data[0]; } + bool unicast() const { return data[0] == 0x00; } + bool multicast() const { return data[0] == 0x01; } + bool broadcast() const { return data[0] == 0xff; } + std::string string() const; + + operator uint64_t() const + { + uint64_t reg = 0; + reg |= ((uint64_t)data[0]) << 40; + reg |= ((uint64_t)data[1]) << 32; + reg |= ((uint64_t)data[2]) << 24; + reg |= ((uint64_t)data[3]) << 16; + reg |= ((uint64_t)data[4]) << 8; + reg |= ((uint64_t)data[5]) << 0; + return reg; + } + +}; + +std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); +bool operator==(const EthAddr &left, const EthAddr &right); + +struct EthHdr : public eth_hdr +{ + uint16_t type() const { return ntohs(eth_type); } + const EthAddr &src() const { return *(EthAddr *)ð_src; } + const EthAddr &dst() const { return *(EthAddr *)ð_dst; } + + int size() const { return sizeof(eth_hdr); } + + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class EthPtr +{ + protected: + friend class IpPtr; + PacketPtr p; + + public: + EthPtr() {} + EthPtr(const PacketPtr &ptr) : p(ptr) { } + + EthHdr *operator->() { return (EthHdr *)p->data; } + EthHdr &operator*() { return *(EthHdr *)p->data; } + operator EthHdr *() { return (EthHdr *)p->data; } + + const EthHdr *operator->() const { return (const EthHdr *)p->data; } + const EthHdr &operator*() const { return *(const EthHdr *)p->data; } + operator const EthHdr *() const { return (const EthHdr *)p->data; } + + const EthPtr &operator=(const PacketPtr &ptr) { p = ptr; return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } +}; + +/* + * IP Stuff + */ +struct IpOpt; +struct IpHdr : public ip_hdr +{ + uint8_t version() const { return ip_v; } + uint8_t hlen() const { return ip_hl * 4; } + uint8_t tos() const { return ip_tos; } + uint16_t len() const { return ntohs(ip_len); } + uint16_t id() const { return ntohs(ip_id); } + uint16_t frag_flags() const { return ntohs(ip_off) >> 13; } + uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; } + uint8_t ttl() const { return ip_ttl; } + uint8_t proto() const { return ip_p; } + uint16_t sum() const { return ip_sum; } + uint32_t src() const { return ntohl(ip_src); } + uint32_t dst() const { return ntohl(ip_dst); } + + void sum(uint16_t sum) { ip_sum = sum; } + + bool options(std::vector<const IpOpt *> &vec) const; + + int size() const { return hlen(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class IpPtr +{ + protected: + friend class TcpPtr; + friend class UdpPtr; + PacketPtr p; + + const IpHdr *h() const + { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } + IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } + + void set(const PacketPtr &ptr) + { + EthHdr *eth = (EthHdr *)ptr->data; + if (eth->type() == ETH_TYPE_IP) + p = ptr; + else + p = 0; + } + + public: + IpPtr() {} + IpPtr(const PacketPtr &ptr) { set(ptr); } + IpPtr(const EthPtr &ptr) { set(ptr.p); } + IpPtr(const IpPtr &ptr) : p(ptr.p) { } + + IpHdr *operator->() { return h(); } + IpHdr &operator*() { return *h(); } + operator IpHdr *() { return h(); } + + const IpHdr *operator->() const { return h(); } + const IpHdr &operator*() const { return *h(); } + operator const IpHdr *() const { return h(); } + + const IpPtr &operator=(const PacketPtr &ptr) { set(ptr); return *this; } + const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } + const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const IpPtr &ptr); + +struct IpOpt : public ip_opt +{ + uint8_t type() const { return opt_type; } + uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } + uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } + uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } + uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } + bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } + bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } + + const uint8_t *data() const { return opt_data.data8; } + void sec(ip_opt_data_sec &sec) const; + void lsrr(ip_opt_data_rr &rr) const; + void ssrr(ip_opt_data_rr &rr) const; + void ts(ip_opt_data_ts &ts) const; + uint16_t satid() const { return ntohs(opt_data.satid); } + uint16_t mtup() const { return ntohs(opt_data.mtu); } + uint16_t mtur() const { return ntohs(opt_data.mtu); } + void tr(ip_opt_data_tr &tr) const; + const uint32_t *addext() const { return &opt_data.addext[0]; } + uint16_t rtralt() const { return ntohs(opt_data.rtralt); } + void sdb(std::vector<uint32_t> &vec) const; +}; + +/* + * TCP Stuff + */ +struct TcpOpt; +struct TcpHdr : public tcp_hdr +{ + uint16_t sport() const { return ntohs(th_sport); } + uint16_t dport() const { return ntohs(th_dport); } + uint32_t seq() const { return ntohl(th_seq); } + uint32_t ack() const { return ntohl(th_ack); } + uint8_t off() const { return th_off; } + uint8_t flags() const { return th_flags & 0x3f; } + uint16_t win() const { return ntohs(th_win); } + uint16_t sum() const { return th_sum; } + uint16_t urp() const { return ntohs(th_urp); } + + void sum(uint16_t sum) { th_sum = sum; } + + bool options(std::vector<const TcpOpt *> &vec) const; + + int size() const { return off(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class TcpPtr +{ + protected: + PacketPtr p; + int off; + + const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } + TcpHdr *h() { return (TcpHdr *)(p->data + off); } + + void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_TCP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + TcpPtr() {} + TcpPtr(const IpPtr &ptr) { set(ptr); } + TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + TcpHdr *operator->() { return h(); } + TcpHdr &operator*() { return *h(); } + operator TcpHdr *() { return h(); } + + const TcpHdr *operator->() const { return h(); } + const TcpHdr &operator*() const { return *h(); } + operator const TcpHdr *() const { return h(); } + + const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const TcpPtr &ptr); + +typedef Range<uint16_t> SackRange; + +struct TcpOpt : public tcp_opt +{ + uint8_t type() const { return opt_type; } + uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isopt(int opt) const { return type() == opt; } + + const uint8_t *data() const { return opt_data.data8; } + + uint16_t mss() const { return ntohs(opt_data.mss); } + uint8_t wscale() const { return opt_data.wscale; } + bool sack(std::vector<SackRange> &vec) const; + uint32_t echo() const { return ntohl(opt_data.echo); } + uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } + uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } + uint32_t cc() const { return ntohl(opt_data.cc); } + uint8_t cksum() const{ return opt_data.cksum; } + const uint8_t *md5() const { return opt_data.md5; } + + int size() const { return len(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +/* + * UDP Stuff + */ +struct UdpHdr : public udp_hdr +{ + uint16_t sport() const { return ntohs(uh_sport); } + uint16_t dport() const { return ntohs(uh_dport); } + uint16_t len() const { return ntohs(uh_ulen); } + uint16_t sum() const { return uh_sum; } + + void sum(uint16_t sum) { uh_sum = sum; } + + int size() const { return sizeof(udp_hdr); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class UdpPtr +{ + protected: + PacketPtr p; + int off; + + const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } + UdpHdr *h() { return (UdpHdr *)(p->data + off); } + + void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_UDP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + UdpPtr() {} + UdpPtr(const IpPtr &ptr) { set(ptr); } + UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + UdpHdr *operator->() { return h(); } + UdpHdr &operator*() { return *h(); } + operator UdpHdr *() { return h(); } + + const UdpHdr *operator->() const { return h(); } + const UdpHdr &operator*() const { return *h(); } + operator const UdpHdr *() const { return h(); } + + const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } + + const PacketPtr packet() const { return p; } + PacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const UdpPtr &ptr); + +/* namespace Net */ } + +#endif // __BASE_INET_HH__ diff --git a/base/intmath.hh b/base/intmath.hh index 821514668..5ffe27103 100644 --- a/base/intmath.hh +++ b/base/intmath.hh @@ -120,7 +120,7 @@ FloorLog2(int64_t x) } #if defined(__APPLE__) -int +inline int FloorLog2(size_t x) { assert(x > 0); diff --git a/base/loader/ecoff_object.cc b/base/loader/ecoff_object.cc index bab75944d..714f1d7b8 100644 --- a/base/loader/ecoff_object.cc +++ b/base/loader/ecoff_object.cc @@ -108,14 +108,14 @@ EcoffObject::loadGlobalSymbols(SymbolTable *symtab) return false; if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - cprintf("wrong magic\n"); + warn("loadGlobalSymbols: wrong magic on %s\n", filename); return false; } ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); if (syms->magic != magicSym2) { - cprintf("bad symbol header magic\n"); - exit(1); + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; } ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); @@ -137,14 +137,14 @@ EcoffObject::loadLocalSymbols(SymbolTable *symtab) return false; if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - cprintf("wrong magic\n"); + warn("loadGlobalSymbols: wrong magic on %s\n", filename); return false; } ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); if (syms->magic != magicSym2) { - cprintf("bad symbol header magic\n"); - exit(1); + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; } ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); diff --git a/base/loader/symtab.cc b/base/loader/symtab.cc index f6abf7e3d..2a29a8575 100644 --- a/base/loader/symtab.cc +++ b/base/loader/symtab.cc @@ -38,6 +38,8 @@ using namespace std; +SymbolTable *debugSymbolTable = NULL; + bool SymbolTable::insert(Addr address, string symbol) { @@ -95,26 +97,20 @@ SymbolTable::load(const string &filename) } bool -SymbolTable::findNearestSymbol(Addr address, string &symbol) const +SymbolTable::findNearestSymbol(Addr address, string &symbol, + Addr &sym_address, Addr &next_sym_address) const { - ATable::const_iterator i = addrTable.lower_bound(address); - - // check for PALCode - if (address & 0x1) - return false; + // find first key *larger* than desired address + ATable::const_iterator i = addrTable.upper_bound(address); - // first check for the end - if (i == addrTable.end()) - i--; - else if (i == addrTable.begin() && (*i).first != address) + // if very first key is larger, we're out of luck + if (i == addrTable.begin()) return false; - else if ((*i).first != address) - i--; - - symbol = (*i).second; - if (address != (*i).first) - symbol += csprintf("+%d", address - (*i).first); + next_sym_address = i->first; + --i; + sym_address = i->first; + symbol = i->second; return true; } @@ -140,19 +136,3 @@ SymbolTable::findAddress(const string &symbol, Addr &address) const address = (*i).second; return true; } - -string -SymbolTable::find(Addr addr) const -{ - string s; - findSymbol(addr, s); - return s; -} - -Addr -SymbolTable::find(const string &symbol) const -{ - Addr a = 0; - findAddress(symbol, a); - return a; -} diff --git a/base/loader/symtab.hh b/base/loader/symtab.hh index 48230c7a2..5ae29b057 100644 --- a/base/loader/symtab.hh +++ b/base/loader/symtab.hh @@ -49,12 +49,35 @@ class SymbolTable bool insert(Addr address, std::string symbol); bool load(const std::string &file); - bool findNearestSymbol(Addr address, std::string &symbol) const; + /// Find the nearest symbol equal to or less than the supplied + /// address (e.g., the label for the enclosing function). + /// @param address The address to look up. + /// @param symbol Return reference for symbol string. + /// @param sym_address Return reference for symbol address. + /// @param next_sym_address Address of following symbol (for + /// determining valid range of symbol). + /// @retval True if a symbol was found. + bool findNearestSymbol(Addr address, std::string &symbol, + Addr &sym_address, Addr &next_sym_address) const; + + /// Overload for findNearestSymbol() for callers who don't care + /// about next_sym_address. + bool findNearestSymbol(Addr address, std::string &symbol, + Addr &sym_address) const + { + Addr dummy; + return findNearestSymbol(address, symbol, sym_address, dummy); + } + + bool findSymbol(Addr address, std::string &symbol) const; bool findAddress(const std::string &symbol, Addr &address) const; - - std::string find(Addr addr) const; - Addr find(const std::string &symbol) const; }; +/// Global unified debugging symbol table (for target). Conceptually +/// there should be one of these per System object for full system, +/// and per Process object for non-full-system, but so far one big +/// global one has worked well enough. +extern SymbolTable *debugSymbolTable; + #endif // __SYMTAB_HH__ diff --git a/base/random.cc b/base/random.cc index f18ed546d..9a4562e8a 100644 --- a/base/random.cc +++ b/base/random.cc @@ -39,7 +39,7 @@ class RandomContext : public ParamContext public: RandomContext(const string &_iniSection) : ::ParamContext(_iniSection) {} - ~RandomContext(); + ~RandomContext() {} void checkParams(); }; diff --git a/base/random.hh b/base/random.hh index 5169c548a..0bfed100c 100644 --- a/base/random.hh +++ b/base/random.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __RANDOM_HH__ -#define __RANDOM_HH__ +#ifndef __BASE_RANDOM_HH__ +#define __BASE_RANDOM_HH__ #include "sim/host.hh" @@ -45,56 +45,56 @@ struct Random<int8_t> struct Random<uint8_t> { - uint8_t get() + static uint8_t get() { return getLong() & (uint8_t)-1; } }; struct Random<int16_t> { - int16_t get() + static int16_t get() { return getLong() & (int16_t)-1; } }; struct Random<uint16_t> { - uint16_t get() + static uint16_t get() { return getLong() & (uint16_t)-1; } }; struct Random<int32_t> { - int32_t get() + static int32_t get() { return (int32_t)getLong(); } }; struct Random<uint32_t> { - uint32_t get() + static uint32_t get() { return (uint32_t)getLong(); } }; struct Random<int64_t> { - int64_t get() + static int64_t get() { return (int64_t)getLong() << 32 || (uint64_t)getLong(); } }; struct Random<uint64_t> { - uint64_t get() + static uint64_t get() { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); } }; struct Random<float> { - float get() + static float get() { return getDouble(); } }; struct Random<double> { - double get() + static double get() { return getDouble(); } }; -#endif // __RANDOM_HH__ +#endif // __BASE_RANDOM_HH__ diff --git a/base/range.cc b/base/range.cc index 4453ecc9f..1087c02c8 100644 --- a/base/range.cc +++ b/base/range.cc @@ -34,12 +34,12 @@ using namespace std; template <class T> bool -__x_parse_range(const std::string &str, T &start, T &end) +__x_parse_range(const std::string &str, T &first, T &last) { std::vector<std::string> values; tokenize(values, str, ':'); - T thestart, theend; + T thefirst, thelast; if (values.size() != 2) return false; @@ -47,29 +47,29 @@ __x_parse_range(const std::string &str, T &start, T &end) std::string s = values[0]; std::string e = values[1]; - if (!to_number(s, thestart)) + if (!to_number(s, thefirst)) return false; bool increment = (e[0] == '+'); if (increment) e = e.substr(1); - if (!to_number(e, theend)) + if (!to_number(e, thelast)) return false; if (increment) - theend += thestart; + thelast += thefirst - 1; - start = thestart; - end = theend; + first = thefirst; + last = thelast; return true; } #define RANGE_PARSE(type) \ template<> bool \ -__parse_range(const std::string &s, type &start, type &end) \ -{ return __x_parse_range(s, start, end); } +__parse_range(const std::string &s, type &first, type &last) \ +{ return __x_parse_range(s, first, last); } RANGE_PARSE(unsigned long long); RANGE_PARSE(signed long long); diff --git a/base/range.hh b/base/range.hh index 2197e2f86..9289792ea 100644 --- a/base/range.hh +++ b/base/range.hh @@ -26,44 +26,32 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __RANGE_HH__ -#define __RANGE_HH__ +#ifndef __BASE_RANGE_HH__ +#define __BASE_RANGE_HH__ #include <cassert> #include <string> +/** + * @param s range string + * EndExclusive Ranges are in the following format: + * <range> := {<start_val>}:{<end>} + * <start> := <end_val> | +<delta> + */ template <class T> bool __parse_range(const std::string &s, T &start, T &end); template <class T> struct Range { - private: - /** - * @param s range string - * Ranges are in the following format: - * <range> := {<start_val>}:{<end>} - * <end> := <end_val> | +<delta> - */ - void - parse(const std::string &s) - { - if (!__parse_range(s, start, end)) - invalidate(); - } - - public: T start; T end; - public: - Range() - { - invalidate(); - } + Range() { invalidate(); } - Range(T first, T second) - : start(first), end(second) + template <class U> + Range(const std::pair<U, U> &r) + : start(r.first), end(r.second) {} template <class U> @@ -71,14 +59,10 @@ struct Range : start(r.start), end(r.end) {} - template <class U> - Range(const std::pair<U, U> &r) - : start(r.first), end(r.second) - {} - Range(const std::string &s) { - parse(s); + if (!__parse_range(s, start, end)) + invalidate(); } template <class U> @@ -99,32 +83,39 @@ struct Range const Range &operator=(const std::string &s) { - parse(s); + if (!__parse_range(s, start, end)) + invalidate(); return *this; } - void invalidate() { start = 0; end = 0; } - T size() const { return end - start; } + void invalidate() { start = 1; end = 0; } + T size() const { return end - start + 1; } bool valid() const { return start < end; } }; template <class T> -inline Range<T> -make_range(T start, T end) -{ - return Range<T>(start, end); -} - -template <class T> inline std::ostream & operator<<(std::ostream &o, const Range<T> &r) { - // don't currently support output of invalid ranges - assert(r.valid()); - o << r.start << ":" << r.end; + o << '[' << r.start << "," << r.end << ']'; return o; } +template <class T> +inline Range<T> +RangeEx(T start, T end) +{ return std::make_pair(start, end - 1); } + +template <class T> +inline Range<T> +RangeIn(T start, T end) +{ return std::make_pair(start, end); } + +template <class T, class U> +inline Range<T> +RangeSize(T start, U size) +{ return std::make_pair(start, start + size - 1); } + //////////////////////////////////////////////////////////////////////// // // Range to Range Comparisons @@ -139,7 +130,6 @@ template <class T, class U> inline bool operator==(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); return range1.start == range2.start && range1.end == range2.end; } @@ -152,7 +142,6 @@ template <class T, class U> inline bool operator!=(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); return range1.start != range2.start || range1.end != range2.end; } @@ -165,8 +154,7 @@ template <class T, class U> inline bool operator<(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); - return range1.end <= range2.start; + return range1.start < range2.start; } /** @@ -179,8 +167,7 @@ template <class T, class U> inline bool operator<=(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); - return range1.start <= range2.start && range1.end <= range2.end; + return range1.start <= range2.start; } /** @@ -192,8 +179,7 @@ template <class T, class U> inline bool operator>(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); - return range1.start >= range2.end; + return range1.start > range2.start; } /** @@ -206,8 +192,7 @@ template <class T, class U> inline bool operator>=(const Range<T> &range1, const Range<U> &range2) { - assert(range1.valid() && range2.valid()); - return range1.start >= range2.start && range1.end >= range2.end; + return range1.start >= range2.start; } //////////////////////////////////////////////////////////////////////// @@ -224,7 +209,6 @@ template <class T, class U> inline bool operator==(const T &pos, const Range<U> &range) { - assert(range.valid()); return pos >= range.start && pos <= range.end; } @@ -237,8 +221,7 @@ template <class T, class U> 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; } /** @@ -250,7 +233,6 @@ template <class T, class U> inline bool operator<(const T &pos, const Range<U> &range) { - assert(range.valid()); return pos < range.start; } @@ -263,8 +245,7 @@ template <class T, class U> inline bool operator<=(const T &pos, const Range<U> &range) { - assert(range.valid()); - return pos < range.end; + return pos <= range.end; } /** @@ -276,8 +257,7 @@ template <class T, class U> inline bool operator>(const T &pos, const Range<U> &range) { - assert(range.valid()); - return pos >= range.end; + return pos > range.end; } /** @@ -289,7 +269,6 @@ template <class T, class U> inline bool operator>=(const T &pos, const Range<U> &range) { - assert(range.valid()); return pos >= range.start; } @@ -307,8 +286,7 @@ template <class T, class U> inline bool operator==(const Range<T> &range, const U &pos) { - assert(range.valid()); - return pos >= range.start && pos < range.end; + return pos >= range.start && pos <= range.end; } /** @@ -320,8 +298,7 @@ template <class T, class U> inline bool operator!=(const Range<T> &range, const U &pos) { - assert(range.valid()); - return pos < range.start || pos >= range.end; + return pos < range.start || pos > range.end; } /** @@ -333,8 +310,7 @@ template <class T, class U> inline bool operator<(const Range<T> &range, const U &pos) { - assert(range.valid()); - return range.end <= pos; + return range.end < pos; } /** @@ -346,7 +322,6 @@ template <class T, class U> inline bool operator<=(const Range<T> &range, const U &pos) { - assert(range.valid()); return range.start <= pos; } @@ -359,7 +334,6 @@ template <class T, class U> inline bool operator>(const Range<T> &range, const U &pos) { - assert(range.valid()); return range.start > pos; } @@ -372,8 +346,7 @@ template <class T, class U> inline bool operator>=(const Range<T> &range, const U &pos) { - assert(range.valid()); - return range.end > pos; + return range.end >= pos; } -#endif // __RANGE_HH__ +#endif // __BASE_RANGE_HH__ diff --git a/base/refcnt.hh b/base/refcnt.hh index d308dd0cf..00ba8fa4a 100644 --- a/base/refcnt.hh +++ b/base/refcnt.hh @@ -48,18 +48,29 @@ class RefCounted template <class T> class RefCountingPtr { - private: + protected: T *data; - void copy(T *d) { + void copy(T *d) + { data = d; if (data) data->incref(); } - void del() { + void del() + { if (data) data->decref(); } + void set(T *d) + { + if (data == d) + return; + + del(); + copy(d); + } + public: RefCountingPtr() : data(NULL) {} @@ -75,21 +86,9 @@ class RefCountingPtr const T &operator*() const { return *data; } const T *get() const { return data; } - RefCountingPtr &operator=(T *p) { - if (data != p) { - del(); - copy(p); - } - return *this; - } - - RefCountingPtr &operator=(const RefCountingPtr &r) { - if (data != r.data) { - del(); - copy(r.data); - } - return *this; - } + RefCountingPtr &operator=(T *p) { set(p); return *this; } + RefCountingPtr &operator=(const RefCountingPtr &r) + { return operator=(r.data); } bool operator!() const { return data == 0; } operator bool() const { return data != 0; } diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc index 41f11005d..484a01944 100644 --- a/base/remote_gdb.cc +++ b/base/remote_gdb.cc @@ -326,14 +326,13 @@ bool RemoteGDB::acc(Addr va, size_t len) { Addr last_va; - Addr pte; - va = alpha_trunc_page(va); - last_va = alpha_round_page(va + len); + va = TheISA::TruncPage(va); + last_va = TheISA::RoundPage(va + len); do { - if (va >= ALPHA_K0SEG_BASE && va < ALPHA_K1SEG_BASE) { - if (va < (ALPHA_K0SEG_BASE + pmem->size())) { + if (TheISA::IsK0Seg(va)) { + if (va < (TheISA::K0SegBase + pmem->size())) { DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " "%#x < K0SEG + size\n", va); return true; @@ -351,16 +350,16 @@ RemoteGDB::acc(Addr va, size_t len) * but there is no easy way to do it. */ - if (PC_PAL(va) || va < 0x10000) + if (AlphaISA::PcPAL(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))) { + TheISA::PageTableEntry pte = kernel_pte_lookup(pmem, ptbr, va); + if (!pte.valid()) { DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); return false; } - va += ALPHA_PGBYTES; + va += TheISA::PageBytes; } while (va < last_va); DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); diff --git a/base/socket.cc b/base/socket.cc index aa6a183a9..ee87dc057 100644 --- a/base/socket.cc +++ b/base/socket.cc @@ -64,7 +64,7 @@ ListenSocket::listen(int port, bool reuse) fd = ::socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) - panic("Can't create socket!"); + panic("Can't create socket:%s !", strerror(errno)); if (reuse) { int i = 1; diff --git a/base/stats/types.hh b/base/stats/types.hh index fbabfb118..8e45531fb 100644 --- a/base/stats/types.hh +++ b/base/stats/types.hh @@ -30,7 +30,7 @@ #define __BASE_STATS_TYPES_HH__ #include <vector> -#include <inttypes.h> +#include "sim/host.hh" namespace Stats { diff --git a/base/trace.hh b/base/trace.hh index 1aadb36cf..5e05d6e5e 100644 --- a/base/trace.hh +++ b/base/trace.hh @@ -157,8 +157,16 @@ namespace Trace { extern const std::string DefaultName; }; -inline const std::string &name() { return Trace::DefaultName; } +// This silly little class allows us to wrap a string in a functor +// object so that we can give a name() that DPRINTF will like +struct StringWrap +{ + std::string str; + StringWrap(const std::string &s) : str(s) {} + const std::string &operator()() const { return str; } +}; +inline const std::string &name() { return Trace::DefaultName; } std::ostream &DebugOut(); // diff --git a/base/traceflags.py b/base/traceflags.py index eb404fa54..1f69e5e88 100644 --- a/base/traceflags.py +++ b/base/traceflags.py @@ -123,6 +123,7 @@ baseFlags = [ 'Uart', 'Split', 'SQL', + 'Thread', 'Fetch', 'Decode', 'Rename', diff --git a/build/SConstruct b/build/SConstruct index 22f39b72c..a1f1cdc5c 100644 --- a/build/SConstruct +++ b/build/SConstruct @@ -93,7 +93,7 @@ def AlphaConfig(env): def KernelConfig(env): env.Replace(TARGET_ISA = 'alpha') env.Replace(FULL_SYSTEM = True) - env.Append(CPPDEFINES = ['FULL_SYSTEM', 'SYSTEM_EV5']) + env.Append(CPPDEFINES = ['FULL_SYSTEM']) # Base configurations map. configs_map = { @@ -244,12 +244,24 @@ default_env = Environment(ENV = os.environ, # inherit user's enviroment vars FULL_SYSTEM = False, USE_MYSQL = False) +default_env.SConsignFile("sconsign") + +# For some reason, the CC and CXX variables don't get passed into the +# environment correctly. This is probably some sort of scons bug that +# will eventually be fixed. +if os.environ.has_key('CC'): + default_env.Replace(CC=os.environ['CC']) + +if os.environ.has_key('CXX'): + default_env.Replace(CXX=os.environ['CXX']) + # M5_EXT is used by isa_parser.py to find the PLY package. default_env.Append(ENV = { 'M5_EXT' : EXT_SRCDIR }) default_env.Append(CCFLAGS='-pipe') default_env.Append(CCFLAGS='-fno-strict-aliasing') default_env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) +default_env.Append(CPPPATH=[os.path.join(EXT_SRCDIR + '/dnet')]) # libelf build is described in its own SConscript file. Using a # dictionary for exports lets us export "default_env" so the diff --git a/configs/boot/nat-netperf-maerts-client.rcS b/configs/boot/nat-netperf-maerts-client.rcS new file mode 100644 index 000000000..fa3e174e7 --- /dev/null +++ b/configs/boot/nat-netperf-maerts-client.rcS @@ -0,0 +1,48 @@ +#!/bin/sh +SERVER=192.168.0.1 +CLIENT=10.0.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $CLIENT txqueuelen 1000 + +echo "modifying route table..." +route add default gw 10.0.0.1 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +BINARY=/benchmarks/netperf/netperf +TEST="TCP_MAERTS" +SHORT_ARGS="-l -100k" +LONG_ARGS="-k16384,0 -K16384,0 -- -m 65536 -M 65536 -s 262144 -S 262144" + + +SHORT="$BINARY -H $SERVER -t $TEST $SHORT_ARGS" +LONG="$BINARY -H $SERVER -t $TEST $LONG_ARGS" + +echo "starting test..." +echo "netperf warmup" +echo $SHORT +eval $SHORT + +echo "netperf benchmark" +echo $LONG +/sbin/m5 ivlb 1 +/sbin/m5 resetstats +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 +eval $LONG +/sbin/m5 exit diff --git a/configs/boot/nat-netperf-server.rcS b/configs/boot/nat-netperf-server.rcS new file mode 100644 index 000000000..c0646b61c --- /dev/null +++ b/configs/boot/nat-netperf-server.rcS @@ -0,0 +1,30 @@ +#!/bin/sh +SERVER=192.168.0.1 +CLIENT=10.0.0.2 +NATBOX=192.168.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $SERVER txqueuelen 1000 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo "running netserver..." +/benchmarks/netperf/netserver + +echo -n "signal client to begin..." +echo "server ready" | /usr/bin/netcat -c $NATBOX 8000 +echo "done." + +echo "starting bash..." +exec /bin/bash diff --git a/configs/boot/nat-netperf-stream-client.rcS b/configs/boot/nat-netperf-stream-client.rcS new file mode 100644 index 000000000..f0f3a23ce --- /dev/null +++ b/configs/boot/nat-netperf-stream-client.rcS @@ -0,0 +1,48 @@ +#!/bin/sh +SERVER=192.168.0.1 +CLIENT=10.0.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $CLIENT txqueuelen 1000 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo "modifying route table" +route add default gw 10.0.0.1 + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +BINARY=/benchmarks/netperf/netperf +TEST="TCP_STREAM" +SHORT_ARGS="-l -100k" +LONG_ARGS="-k16384,0 -K16384,0 -- -m 65536 -M 65536 -s 262144 -S 262144" + + +SHORT="$BINARY -H $SERVER -t $TEST $SHORT_ARGS" +LONG="$BINARY -H $SERVER -t $TEST $LONG_ARGS" + +echo "starting test..." +echo "netperf warmup" +echo $SHORT +eval $SHORT + +echo "netperf benchmark" +echo $LONG +/sbin/m5 ivlb 1 +/sbin/m5 resetstats +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 +eval $LONG +/sbin/m5 exit diff --git a/configs/boot/nat-spec-surge-client.rcS b/configs/boot/nat-spec-surge-client.rcS new file mode 100644 index 000000000..2c0b46607 --- /dev/null +++ b/configs/boot/nat-spec-surge-client.rcS @@ -0,0 +1,51 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# +CLIENT=10.0.0.2 +SERVER=192.168.0.1 + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 $CLIENT txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo "changing route table..." +route add default gw 10.0.0.1 + +echo "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "running surge client..." +/bin/bash -c "cd /benchmarks/surge && ./spec-m5 1 20 1 $SERVER 5 40000 1000000000 1000" +echo "done." + +echo -n "halting machine" +m5 exit + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/nat-spec-surge-server.rcS b/configs/boot/nat-spec-surge-server.rcS new file mode 100755 index 000000000..ed0e96a44 --- /dev/null +++ b/configs/boot/nat-spec-surge-server.rcS @@ -0,0 +1,56 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# +NATBOX=192.168.0.7 + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 192.168.0.1 txqueuelen 1000 +/sbin/ifconfig eth0:1 192.168.0.2 txqueuelen 1000 +/sbin/ifconfig eth0:2 192.168.0.3 txqueuelen 1000 +/sbin/ifconfig eth0:3 192.168.0.4 txqueuelen 1000 +/sbin/ifconfig eth0:4 192.168.0.5 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "mounting file set..." +mkdir -p /z/htdocs +mount /dev/hdb1 /z/htdocs +echo "done." + +echo -n "starting httpd..." +/benchmarks/apache2/bin/apachectl start +sleep 2 +cat /benchmarks/apache2/logs/error_log +echo "done." + +echo "notifying natbox..." +echo "server ready" | /usr/bin/netcat -c $NATBOX 8000 +echo "done" + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/natbox-netperf.rcS b/configs/boot/natbox-netperf.rcS new file mode 100644 index 000000000..d665670fe --- /dev/null +++ b/configs/boot/natbox-netperf.rcS @@ -0,0 +1,51 @@ +#!/bin/sh +EXTIF=192.168.0.2 +INTIF=10.0.0.1 +CLIENT=10.0.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $EXTIF txqueuelen 1000 +ifconfig eth1 $INTIF txqueuelen 1000 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo "1" > /proc/sys/net/ipv4/ip_forward + +echo "waiting for netserver..." +/usr/bin/netcat -c -l -p 8000 + +echo "setting up iptables..." +IPTABLES=/sbin/iptables +EXTIF=eth0 +INTIF=eth1 + +$IPTABLES -P INPUT ACCEPT +$IPTABLES -F INPUT +$IPTABLES -P OUTPUT ACCEPT +$IPTABLES -F OUTPUT +$IPTABLES -P FORWARD DROP +$IPTABLES -F FORWARD +$IPTABLES -t nat -F + +$IPTABLES -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT +$IPTABLES -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT +$IPTABLES -A FORWARD -j LOG + +$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE + +echo "informing client..." +echo "server ready" | /usr/bin/netcat -c $CLIENT 8000 + +echo "starting bash..." +exec /bin/bash diff --git a/configs/boot/natbox-spec-surge.rcS b/configs/boot/natbox-spec-surge.rcS new file mode 100644 index 000000000..ed74b71bd --- /dev/null +++ b/configs/boot/natbox-spec-surge.rcS @@ -0,0 +1,51 @@ +#!/bin/sh +EXTIF=192.168.0.7 +INTIF=10.0.0.1 +CLIENT=10.0.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $EXTIF txqueuelen 1000 +ifconfig eth1 $INTIF txqueuelen 1000 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo "1" > /proc/sys/net/ipv4/ip_forward + +echo "waiting for netserver..." +/usr/bin/netcat -c -l -p 8000 + +echo "setting up iptables..." +IPTABLES=/sbin/iptables +EXTIF=eth0 +INTIF=eth1 + +$IPTABLES -P INPUT ACCEPT +$IPTABLES -F INPUT +$IPTABLES -P OUTPUT ACCEPT +$IPTABLES -F OUTPUT +$IPTABLES -P FORWARD DROP +$IPTABLES -F FORWARD +$IPTABLES -t nat -F + +$IPTABLES -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT +$IPTABLES -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT +$IPTABLES -A FORWARD -j LOG + +$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE + +echo "informing client..." +echo "server ready" | /usr/bin/netcat -c $CLIENT 8000 + +echo "starting bash..." +exec /bin/bash diff --git a/configs/boot/client.netperf.maerts b/configs/boot/netperf-maerts-client.rcS index 916bb25ab..bd56dafc3 100644 --- a/configs/boot/client.netperf.maerts +++ b/configs/boot/netperf-maerts-client.rcS @@ -39,7 +39,7 @@ echo "netperf benchmark" echo $LONG /sbin/m5 ivlb 1 /sbin/m5 resetstats -/sbin/m5 dumpresetstats 2000000000 2000000000 -/sbin/m5 checkpoint 2000000000 2000000000 +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 eval $LONG /sbin/m5 exit diff --git a/configs/boot/client.netperf.rr b/configs/boot/netperf-rr.rcS index b2128bed4..8c5ea050c 100644 --- a/configs/boot/client.netperf.rr +++ b/configs/boot/netperf-rr.rcS @@ -39,7 +39,7 @@ echo "netperf benchmark" echo $LONG /sbin/m5 ivlb 1 /sbin/m5 resetstats -/sbin/m5 dumpresetstats 2000000000 2000000000 -/sbin/m5 checkpoint 2000000000 2000000000 +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 eval $LONG /sbin/m5 exit diff --git a/configs/boot/server.netperf b/configs/boot/netperf-server.rcS index f77ff0ce8..f77ff0ce8 100644 --- a/configs/boot/server.netperf +++ b/configs/boot/netperf-server.rcS diff --git a/configs/boot/client.netperf.stream b/configs/boot/netperf-stream-client.rcS index 0dba6f1a2..430ac265c 100644 --- a/configs/boot/client.netperf.stream +++ b/configs/boot/netperf-stream-client.rcS @@ -39,7 +39,7 @@ echo "netperf benchmark" echo $LONG /sbin/m5 ivlb 1 /sbin/m5 resetstats -/sbin/m5 dumpresetstats 2000000000 2000000000 -/sbin/m5 checkpoint 2000000000 2000000000 +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 eval $LONG /sbin/m5 exit diff --git a/configs/boot/netperf-stream-nt-client.rcS b/configs/boot/netperf-stream-nt-client.rcS new file mode 100644 index 000000000..96b6b38c3 --- /dev/null +++ b/configs/boot/netperf-stream-nt-client.rcS @@ -0,0 +1,45 @@ +#!/bin/sh +SERVER=10.0.0.1 +CLIENT=10.0.0.2 + +echo "setting up network..." +ifconfig lo 127.0.0.1 +ifconfig eth0 $CLIENT txqueuelen 1000 + +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_rmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_wmem +echo "5000000 5000000 5000000" > /proc/sys/net/ipv4/tcp_mem +echo "262143" > /proc/sys/net/core/rmem_max +echo "262143" > /proc/sys/net/core/wmem_max +echo "262143" > /proc/sys/net/core/rmem_default +echo "262143" > /proc/sys/net/core/wmem_default +echo "262143" > /proc/sys/net/core/optmem_max +echo "100000" > /proc/sys/net/core/netdev_max_backlog + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +BINARY=/benchmarks/netperf/netperf +TEST="TCP_STREAM" +SHORT_ARGS="-l -100k" +LONG_ARGS="-- -m 65536 -M 65536 -s 262144 -S 262144" + + +SHORT="$BINARY -H $SERVER -t $TEST $SHORT_ARGS" +LONG="$BINARY -H $SERVER -t $TEST $LONG_ARGS" + +echo "starting test..." +echo "netperf warmup" +echo $SHORT +eval $SHORT + +echo "netperf benchmark" +echo $LONG +/sbin/m5 ivlb 1 +/sbin/m5 resetstats +/sbin/m5 dumpresetstats 200000000 2000000000 +/sbin/m5 checkpoint 200000000 2000000000 +eval $LONG +/sbin/m5 exit diff --git a/configs/boot/nfs-client-smallb.rcS b/configs/boot/nfs-client-smallb.rcS new file mode 100755 index 000000000..22e2107eb --- /dev/null +++ b/configs/boot/nfs-client-smallb.rcS @@ -0,0 +1,50 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 10.0.0.2 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "starting nfs client..." +/sbin/portmap & +/sbin/lockd & +echo "done." + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "mounting remote share..." +mkdir /nfs +mount -o rsize=1460,wsize=1460 10.0.0.1:/nfs /nfs +echo "done." + +/bin/bonnie++ -u 99 -s 700 -r 0 -n 0 -f -F -d /nfs + +/sbin/m5 exit diff --git a/configs/boot/nfs-client-tcp-smallb.rcS b/configs/boot/nfs-client-tcp-smallb.rcS new file mode 100755 index 000000000..2ee232158 --- /dev/null +++ b/configs/boot/nfs-client-tcp-smallb.rcS @@ -0,0 +1,50 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 10.0.0.2 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "starting nfs client..." +/sbin/portmap & +/sbin/lockd & +echo "done." + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "mounting remote share..." +mkdir /nfs +mount -o rsize=1460,wsize=1460,tcp 10.0.0.1:/nfs /nfs +echo "done." + +/bin/bonnie++ -u 99 -s 700 -r 0 -n 0 -f -F -d /nfs + +/sbin/m5 exit diff --git a/configs/boot/nfs-client-tcp.rcS b/configs/boot/nfs-client-tcp.rcS new file mode 100755 index 000000000..a67facbb2 --- /dev/null +++ b/configs/boot/nfs-client-tcp.rcS @@ -0,0 +1,50 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 10.0.0.2 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "starting nfs client..." +/sbin/portmap & +/sbin/lockd & +echo "done." + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "mounting remote share..." +mkdir /nfs +mount -o tcp 10.0.0.1:/nfs /nfs +echo "done." + +/bin/bonnie++ -u 99 -s 700 -r 0 -n 0 -f -F -d /nfs + +/sbin/m5 exit diff --git a/configs/boot/nfs-client.rcS b/configs/boot/nfs-client.rcS new file mode 100755 index 000000000..a999fb72c --- /dev/null +++ b/configs/boot/nfs-client.rcS @@ -0,0 +1,50 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 10.0.0.2 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "starting nfs client..." +/sbin/portmap & +/sbin/lockd & +echo "done." + +echo -n "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "mounting remote share..." +mkdir /nfs +mount 10.0.0.1:/nfs /nfs +echo "done." + +/bin/bonnie++ -u 99 -s 700 -r 0 -n 0 -f -F -d /nfs + +/sbin/m5 exit diff --git a/configs/boot/nfs-server.rcS b/configs/boot/nfs-server.rcS new file mode 100755 index 000000000..21b7ab83c --- /dev/null +++ b/configs/boot/nfs-server.rcS @@ -0,0 +1,70 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 10.0.0.1 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +#if [ ! -x /dev/sda ] +#then +# mknod /dev/sda b 8 0 +# mknod /dev/sda1 b 8 1 +#fi + +/sbin/insmod /modules/scsi_debug.ko dev_size_mb=768 + +echo -n "creating partition and formatting..." +#echo "1,767,L" > /tmp/sfdisk.run +#/usr/sbin/sfdisk -uM --force /dev/sda < /tmp/sfdisk.run +/sbin/mke2fs -F /dev/sda +mkdir /nfs +/bin/mount /dev/sda /nfs +chmod a+rwx /nfs +#/usr/sbin/sfdisk -uM -l /dev/sda +echo "done." + +echo "/nfs 10.0.0.0/255.0.0.0(rw,sync,no_root_squash)" > /etc/exports +echo -n "starting nfs kernel server..." +/sbin/portmap +/sbin/lockd +/sbin/statd +/sbin/nfsd 8 +/sbin/mountd +echo "done." + +echo "Exporting shares..." +/sbin/exportfs -r -v + +echo -n "signal client to mount..." +echo "server ready" | /usr/bin/netcat -c 10.0.0.2 8000 +echo "done." + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/spec-surge-client.rcS b/configs/boot/spec-surge-client.rcS new file mode 100644 index 000000000..6ce2ce9de --- /dev/null +++ b/configs/boot/spec-surge-client.rcS @@ -0,0 +1,46 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 192.168.0.10 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "running surge client..." +/bin/bash -c "cd /benchmarks/surge && ./spec-m5 1 20 1 192.168.0.1 5 40000 1000000000 1000" +echo "done." + +echo -n "halting machine" +m5 exit + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/spec-surge-server.rcS b/configs/boot/spec-surge-server.rcS new file mode 100755 index 000000000..12e31696b --- /dev/null +++ b/configs/boot/spec-surge-server.rcS @@ -0,0 +1,55 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 192.168.0.1 txqueuelen 1000 +/sbin/ifconfig eth0:1 192.168.0.2 txqueuelen 1000 +/sbin/ifconfig eth0:2 192.168.0.3 txqueuelen 1000 +/sbin/ifconfig eth0:3 192.168.0.4 txqueuelen 1000 +/sbin/ifconfig eth0:4 192.168.0.5 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "mounting file set..." +mkdir -p /z/htdocs +mount /dev/hdb1 /z/htdocs +echo "done." + +echo -n "starting httpd..." +/benchmarks/apache2/bin/apachectl start +sleep 2 +cat /benchmarks/apache2/logs/error_log +echo "done." + +echo "notifying client..." +echo "server ready" | /usr/bin/netcat -c 192.168.0.10 8000 +echo "done" + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/surge-client.rcS b/configs/boot/surge-client.rcS new file mode 100755 index 000000000..208524a9c --- /dev/null +++ b/configs/boot/surge-client.rcS @@ -0,0 +1,46 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 192.168.0.10 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo "waiting for server..." +/usr/bin/netcat -c -l -p 8000 + +echo -n "running surge client..." +/bin/bash -c "cd /benchmarks/surge && ./Surge 2 100 1 192.168.0.1 5" +echo "done." + +echo -n "halting machine" +m5 exit + +echo -n "starting bash shell..." +/bin/bash diff --git a/configs/boot/surge-server.rcS b/configs/boot/surge-server.rcS new file mode 100755 index 000000000..3feb7b581 --- /dev/null +++ b/configs/boot/surge-server.rcS @@ -0,0 +1,54 @@ +#!/bin/sh +# +# /etc/init.d/rcS +# + + +echo -n "mounting swap..." +/sbin/swapon /dev/hdc +echo "done." + +echo -n "setting up network..." +/sbin/ifconfig eth0 192.168.0.1 txqueuelen 1000 +/sbin/ifconfig eth0:1 192.168.0.2 txqueuelen 1000 +/sbin/ifconfig eth0:2 192.168.0.3 txqueuelen 1000 +/sbin/ifconfig eth0:3 192.168.0.4 txqueuelen 1000 +/sbin/ifconfig eth0:4 192.168.0.5 txqueuelen 1000 +/sbin/ifconfig lo 127.0.0.1 + +echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle +echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse +echo "1" > /proc/sys/net/ipv4/tcp_window_scaling +echo "0" > /proc/sys/net/ipv4/tcp_timestamps +echo "0" > /proc/sys/net/ipv4/tcp_sack +echo "15" > /proc/sys/net/ipv4/tcp_fin_timeout +echo "16384" > /proc/sys/net/ipv4/tcp_max_syn_backlog + +echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_rmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_wmem +echo "10000000 10000000 10000000" > /proc/sys/net/ipv4/tcp_mem + +echo "524287" > /proc/sys/net/core/rmem_max +echo "524287" > /proc/sys/net/core/wmem_max +echo "524287" > /proc/sys/net/core/optmem_max +echo "300000" > /proc/sys/net/core/netdev_max_backlog + +echo "131072" > /proc/sys/fs/file-max +echo "done." + +echo -n "mounting file set..." +mkdir -p /z/htdocs +mount /dev/hdb1 /z/htdocs +echo "done." + +echo -n "starting httpd..." +/benchmarks/apache2/bin/apachectl start +sleep 2 +cat /benchmarks/apache2/logs/error_log +echo "done." + +echo "server ready" | /usr/bin/netcat -c 192.168.10 8000 + +echo -n "starting bash shell..." +/bin/bash diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index 988c7a602..2275f12e3 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -30,10 +30,11 @@ #include <sstream> #include <iostream> -#include "cpu/base_cpu.hh" #include "base/cprintf.hh" -#include "cpu/exec_context.hh" +#include "base/loader/symtab.hh" #include "base/misc.hh" +#include "cpu/base_cpu.hh" +#include "cpu/exec_context.hh" #include "sim/param.hh" #include "sim/sim_events.hh" @@ -50,21 +51,25 @@ int maxThreadsPerCPU = 1; extern void debug_break(); #ifdef FULL_SYSTEM -BaseCPU::BaseCPU(const string &_name, int _number_of_threads, +BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, Tick freq) - : SimObject(_name), frequency(freq), - number_of_threads(_number_of_threads), system(_system) + System *_system, Tick freq, + bool _function_trace, Tick _function_trace_start) + : SimObject(_name), frequency(freq), checkInterrupts(true), + deferRegistration(_def_reg), number_of_threads(_number_of_threads), + system(_system) #else -BaseCPU::BaseCPU(const string &_name, int _number_of_threads, +BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, - Counter max_loads_all_threads) - : SimObject(_name), number_of_threads(_number_of_threads) + Counter max_loads_all_threads, + bool _function_trace, Tick _function_trace_start) + : SimObject(_name), deferRegistration(_def_reg), + number_of_threads(_number_of_threads) #endif { DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); @@ -134,10 +139,47 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, memset(interrupts, 0, sizeof(interrupts)); intstatus = 0; #endif + + functionTracingEnabled = false; + if (_function_trace) { + std::string filename = csprintf("ftrace.%s", name()); + functionTraceStream = makeOutputStream(filename); + currentFunctionStart = currentFunctionEnd = 0; + functionEntryTick = _function_trace_start; + + if (_function_trace_start == 0) { + functionTracingEnabled = true; + } else { + Event *e = + new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, + true); + e->schedule(_function_trace_start); + } + } +} + + +void +BaseCPU::enableFunctionTrace() +{ + functionTracingEnabled = true; +} + +BaseCPU::~BaseCPU() +{ + if (functionTracingEnabled) + closeOutputStream(functionTraceStream); } void +BaseCPU::init() +{ + if (!deferRegistration) + registerExecContexts(); +} + +void BaseCPU::regStats() { using namespace Stats; @@ -195,10 +237,10 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU) newXC->takeOverFrom(oldXC); assert(newXC->cpu_id == oldXC->cpu_id); #ifdef FULL_SYSTEM - system->replaceExecContext(newXC->cpu_id, newXC); + system->replaceExecContext(newXC, newXC->cpu_id); #else assert(newXC->process == oldXC->process); - newXC->process->replaceExecContext(newXC->cpu_id, newXC); + newXC->process->replaceExecContext(newXC, newXC->cpu_id); #endif } @@ -222,7 +264,7 @@ BaseCPU::post_interrupt(int int_num, int index) if (index < 0 || index >= sizeof(uint64_t) * 8) panic("int_num out of bounds\n"); - AlphaISA::check_interrupts = 1; + checkInterrupts = true; interrupts[int_num] |= 1 << index; intstatus |= (ULL(1) << int_num); } @@ -269,4 +311,32 @@ BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) #endif // FULL_SYSTEM +void +BaseCPU::traceFunctionsInternal(Addr pc) +{ + if (!debugSymbolTable) + return; + + // if pc enters different function, print new function symbol and + // update saved range. Otherwise do nothing. + if (pc < currentFunctionStart || pc >= currentFunctionEnd) { + string sym_str; + bool found = debugSymbolTable->findNearestSymbol(pc, sym_str, + currentFunctionStart, + currentFunctionEnd); + + if (!found) { + // no symbol found: use addr as label + sym_str = csprintf("0x%x", pc); + currentFunctionStart = pc; + currentFunctionEnd = pc + 1; + } + + ccprintf(*functionTraceStream, " (%d)\n%d: %s", + curTick - functionEntryTick, curTick, sym_str); + functionEntryTick = curTick; + } +} + + DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh index f75f00409..baa956aa8 100644 --- a/cpu/base_cpu.hh +++ b/cpu/base_cpu.hh @@ -55,6 +55,7 @@ class BaseCPU : public SimObject virtual void post_interrupt(int int_num, int index); virtual void clear_interrupt(int int_num, int index); virtual void clear_interrupts(); + bool checkInterrupts; bool check_interrupt(int int_num) const { if (int_num > NumInterruptLevels) @@ -91,22 +92,26 @@ class BaseCPU : public SimObject public: #ifdef FULL_SYSTEM - BaseCPU(const std::string &_name, int _number_of_threads, + BaseCPU(const std::string &_name, int _number_of_threads, bool _def_reg, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, Tick freq); + System *_system, Tick freq, + bool _function_trace = false, Tick _function_trace_start = 0); #else - BaseCPU(const std::string &_name, int _number_of_threads, + BaseCPU(const std::string &_name, int _number_of_threads, bool _def_reg, Counter max_insts_any_thread = 0, Counter max_insts_all_threads = 0, Counter max_loads_any_thread = 0, - Counter max_loads_all_threads = 0); + Counter max_loads_all_threads = 0, + bool _function_trace = false, Tick _function_trace_start = 0); #endif - virtual ~BaseCPU() {} + virtual ~BaseCPU(); + virtual void init(); virtual void regStats(); + bool deferRegistration; void registerExecContexts(); /// Prepare for another CPU to take over execution. Called by @@ -140,7 +145,6 @@ class BaseCPU : public SimObject #ifdef FULL_SYSTEM System *system; - /** * Serialize this object to the given output stream. * @param os The stream to serialize to. @@ -164,6 +168,23 @@ class BaseCPU : public SimObject virtual Counter totalInstructions() const { return 0; } + // Function tracing + private: + bool functionTracingEnabled; + std::ostream *functionTraceStream; + Addr currentFunctionStart; + Addr currentFunctionEnd; + Tick functionEntryTick; + void enableFunctionTrace(); + void traceFunctionsInternal(Addr pc); + + protected: + void traceFunctions(Addr pc) + { + if (functionTracingEnabled) + traceFunctionsInternal(pc); + } + private: static std::vector<BaseCPU *> cpuList; //!< Static global cpu list diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc index 9c21b3a56..1cb33f13e 100644 --- a/cpu/exec_context.cc +++ b/cpu/exec_context.cc @@ -32,6 +32,9 @@ #include "cpu/exec_context.hh" #ifdef FULL_SYSTEM +#include "base/cprintf.hh" +#include "kern/kernel_stats.hh" +#include "sim/serialize.hh" #include "sim/system.hh" #else #include "sim/process.hh" @@ -44,12 +47,13 @@ using namespace std; ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_mem) - : _status(ExecContext::Unallocated), - kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), + : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), cpu_id(-1), mem(_mem), itb(_itb), dtb(_dtb), system(_sys), - memCtrl(_sys->memCtrl), physmem(_sys->physmem), - swCtx(NULL), func_exe_inst(0), storeCondFailures(0) + memctrl(_sys->memctrl), physmem(_sys->physmem), + kernelBinning(system->kernelBinning), bin(kernelBinning->bin), + fnbin(kernelBinning->fnbin), func_exe_inst(0), storeCondFailures(0) { + kernelStats = new Kernel::Statistics(this); memset(®s, 0, sizeof(RegFile)); } #else @@ -72,6 +76,13 @@ ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, } #endif +ExecContext::~ExecContext() +{ +#ifdef FULL_SYSTEM + delete kernelStats; +#endif +} + void ExecContext::takeOverFrom(ExecContext *oldContext) @@ -86,9 +97,6 @@ ExecContext::takeOverFrom(ExecContext *oldContext) // copy over functional state _status = oldContext->_status; -#ifdef FULL_SYSTEM - kernelStats = oldContext->kernelStats; -#endif regs = oldContext->regs; cpu_id = oldContext->cpu_id; func_exe_inst = oldContext->func_exe_inst; @@ -98,6 +106,14 @@ ExecContext::takeOverFrom(ExecContext *oldContext) oldContext->_status = ExecContext::Unallocated; } +#ifdef FULL_SYSTEM +void +ExecContext::execute(const StaticInstBase *inst) +{ + assert(kernelStats); + system->kernelBinning->execute(this, inst); +} +#endif void ExecContext::serialize(ostream &os) @@ -109,31 +125,8 @@ ExecContext::serialize(ostream &os) SERIALIZE_SCALAR(inst); #ifdef FULL_SYSTEM - bool ctx = false; - if (swCtx) { - ctx = true; - SERIALIZE_SCALAR(ctx); - SERIALIZE_SCALAR(swCtx->calls); - std::stack<fnCall *> *stack = &(swCtx->callStack); - fnCall *top; - int size = stack->size(); - SERIALIZE_SCALAR(size); - - for (int j=0; j<size; ++j) { - top = stack->top(); - paramOut(os, csprintf("stackpos[%d]",j), top->name); - delete top; - stack->pop(); - } - } else { - SERIALIZE_SCALAR(ctx); - } - if (system->bin) { - Stats::MainBin *cur = Stats::MainBin::curBin(); - string bin_name = cur->name(); - SERIALIZE_SCALAR(bin_name); - } -#endif //FULL_SYSTEM + kernelStats->serialize(os); +#endif } @@ -147,35 +140,8 @@ ExecContext::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(inst); #ifdef FULL_SYSTEM - bool ctx; - UNSERIALIZE_SCALAR(ctx); - if (ctx) { - swCtx = new SWContext; - UNSERIALIZE_SCALAR(swCtx->calls); - int size; - UNSERIALIZE_SCALAR(size); - - vector<fnCall *> calls; - fnCall *call; - for (int i=0; i<size; ++i) { - call = new fnCall; - paramIn(cp, section, csprintf("stackpos[%d]",i), call->name); - call->myBin = system->getBin(call->name); - calls.push_back(call); - } - - for (int i=size-1; i>=0; --i) { - swCtx->callStack.push(calls[i]); - } - - } - - if (system->bin) { - string bin_name; - UNSERIALIZE_SCALAR(bin_name); - system->getBin(bin_name)->activate(); - } -#endif //FULL_SYSTEM + kernelStats->unserialize(cp, section); +#endif } @@ -232,7 +198,7 @@ void ExecContext::regStats(const string &name) { #ifdef FULL_SYSTEM - kernelStats.regStats(name + ".kern"); + kernelStats->regStats(name + ".kern"); #endif } diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index b47f5cd08..8437a5585 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -42,12 +42,12 @@ class BaseCPU; #ifdef FULL_SYSTEM +#include "sim/system.hh" #include "targetarch/alpha_memory.hh" -class MemoryController; -#include "kern/kernel_stats.hh" -#include "sim/system.hh" -#include "sim/sw_context.hh" +class MemoryController; +class StaticInstBase; +namespace Kernel { class Binning; class Statistics; } #else // !FULL_SYSTEM @@ -105,11 +105,6 @@ class ExecContext /// Set the status to Halted. void halt(); -#ifdef FULL_SYSTEM - public: - KernelStats kernelStats; -#endif - public: RegFile regs; // correct-path register context @@ -127,7 +122,6 @@ class ExecContext int cpu_id; #ifdef FULL_SYSTEM - FunctionalMemory *mem; AlphaITB *itb; AlphaDTB *dtb; @@ -136,10 +130,15 @@ class ExecContext // the following two fields are redundant, since we can always // look them up through the system pointer, but we'll leave them // here for now for convenience - MemoryController *memCtrl; + MemoryController *memctrl; PhysicalMemory *physmem; - SWContext *swCtx; + Kernel::Binning *kernelBinning; + Kernel::Statistics *kernelStats; + bool bin; + bool fnbin; + void execute(const StaticInstBase *inst); + #else Process *process; @@ -185,7 +184,7 @@ class ExecContext ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, int _asid); #endif - virtual ~ExecContext() {} + virtual ~ExecContext(); virtual void takeOverFrom(ExecContext *oldContext); @@ -197,8 +196,8 @@ class ExecContext #ifdef FULL_SYSTEM bool validInstAddr(Addr addr) { return true; } bool validDataAddr(Addr addr) { return true; } - int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); } - int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); } + int getInstAsid() { return regs.instAsid(); } + int getDataAsid() { return regs.dataAsid(); } Fault translateInstReq(MemReqPtr &req) { @@ -411,7 +410,7 @@ class ExecContext int readIntrFlag() { return regs.intrflag; } void setIntrFlag(int val) { regs.intrflag = val; } Fault hwrei(); - bool inPalMode() { return PC_PAL(regs.pc); } + bool inPalMode() { return AlphaISA::PcPAL(regs.pc); } void ev5_trap(Fault fault); bool simPalCheck(int palFunc); #endif diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc index e31c3590c..ff7e90c9e 100644 --- a/cpu/exetrace.cc +++ b/cpu/exetrace.cc @@ -48,8 +48,6 @@ using namespace std; // -SymbolTable *debugSymbolTable = NULL; - void Trace::InstRecord::dump(ostream &outs) { @@ -66,11 +64,17 @@ Trace::InstRecord::dump(ostream &outs) outs << "T" << thread << " : "; - std::string str; - if ((debugSymbolTable) && (debugSymbolTable->findNearestSymbol(PC, str))) - outs << "@" << setw(17) << str << " : "; - else + std::string sym_str; + Addr sym_addr; + if (debugSymbolTable + && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { + if (PC != sym_addr) + sym_str += csprintf("+%d", PC - sym_addr); + outs << "@" << sym_str << " : "; + } + else { outs << "0x" << hex << PC << " : "; + } // // Print decoded instruction diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc index b55af332a..e967c79da 100644 --- a/cpu/memtest/memtest.cc +++ b/cpu/memtest/memtest.cc @@ -28,9 +28,10 @@ // FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded -#include <string> -#include <sstream> #include <iomanip> +#include <set> +#include <sstream> +#include <string> #include <vector> #include "base/misc.hh" @@ -44,6 +45,8 @@ using namespace std; +int TESTER_ALLOCATOR=0; + MemTest::MemTest(const string &name, MemInterface *_cache_interface, FunctionalMemory *main_mem, @@ -58,7 +61,8 @@ MemTest::MemTest(const string &name, Addr _traceAddr, Counter max_loads_any_thread, Counter max_loads_all_threads) - : BaseCPU(name, 1, 0, 0, max_loads_any_thread, max_loads_all_threads), + : BaseCPU(name, 1, true, 0, 0, max_loads_any_thread, + max_loads_all_threads), tickEvent(this), cacheInterface(_cache_interface), mainMem(main_mem), @@ -110,6 +114,8 @@ MemTest::MemTest(const string &name, noResponseCycles = 0; numReads = 0; tickEvent.schedule(0); + + id = TESTER_ALLOCATOR++; } static void @@ -126,6 +132,11 @@ printData(ostream &os, uint8_t *data, int nbytes) void MemTest::completeRequest(MemReqPtr &req, uint8_t *data) { + //Remove the address from the list of outstanding + std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); + switch (req->cmd) { case Read: if (memcmp(req->data, data, req->size) != 0) { @@ -157,6 +168,10 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data) break; case Copy: + //Also remove dest from outstanding list + removeAddr = outstandingAddrs.find(req->dest); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); numCopiesStat++; break; @@ -211,7 +226,7 @@ MemTest::tick() if (!tickEvent.scheduled()) tickEvent.schedule(curTick + 1); - if (++noResponseCycles >= 5000) { + if (++noResponseCycles >= 500000) { cerr << name() << ": deadlocked at cycle " << curTick << endl; fatal(""); } @@ -231,6 +246,16 @@ MemTest::tick() unsigned source_align = rand() % 100; unsigned dest_align = rand() % 100; + //If we aren't doing copies, use id as offset, and do a false sharing + //mem tester + if (percentCopies == 0) { + //We can eliminate the lower bits of the offset, and then use the id + //to offset within the blks + offset1 &= ~63; //Not the low order bits + offset1 += id; + access_size = 0; + } + MemReqPtr req = new MemReq(); if (cacheable < percentUncacheable) { @@ -250,6 +275,13 @@ MemTest::tick() if (cmd < percentReads) { // read + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + req->cmd = Read; uint8_t *result = new uint8_t[8]; checkMem->access(Read, req->paddr, result, req->size); @@ -272,6 +304,13 @@ MemTest::tick() } } else if (cmd < (100 - percentCopies)){ // write + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + req->cmd = Write; memcpy(req->data, &data, req->size); checkMem->access(Write, req->paddr, req->data, req->size); @@ -297,6 +336,11 @@ MemTest::tick() // copy Addr source = ((base) ? baseAddr1 : baseAddr2) + offset1; Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; + if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(source); + if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(dest); + if (source_align >= percentSourceUnaligned) { source = blockAddr(source); } diff --git a/cpu/memtest/memtest.hh b/cpu/memtest/memtest.hh index 72e0709d9..43b17a713 100644 --- a/cpu/memtest/memtest.hh +++ b/cpu/memtest/memtest.hh @@ -29,13 +29,14 @@ #ifndef __MEMTEST_HH__ #define __MEMTEST_HH__ -#include "sim/sim_object.hh" -#include "mem/mem_interface.hh" -#include "mem/functional_mem/functional_memory.hh" -#include "cpu/base_cpu.hh" -#include "cpu/exec_context.hh" +#include <set> #include "base/statistics.hh" +#include "cpu/base_cpu.hh" +#include "cpu/exec_context.hh" +#include "mem/functional_mem/functional_memory.hh" +#include "mem/mem_interface.hh" +#include "sim/sim_object.hh" #include "sim/stats.hh" class MemTest : public BaseCPU @@ -87,6 +88,10 @@ class MemTest : public BaseCPU unsigned percentCopies; // target percentage of copy accesses unsigned percentUncacheable; + int id; + + std::set<unsigned> outstandingAddrs; + unsigned blockSize; Addr blockAddrMask; diff --git a/cpu/pc_event.cc b/cpu/pc_event.cc index a86c017d4..8f046a7a4 100644 --- a/cpu/pc_event.cc +++ b/cpu/pc_event.cc @@ -77,7 +77,7 @@ PCEventQueue::schedule(PCEvent *event) bool PCEventQueue::doService(ExecContext *xc) { - Addr pc = xc->regs.pc; + Addr pc = xc->regs.pc & ~0x3; int serviced = 0; range_t range = equal_range(pc); for (iterator i = range.first; i != range.second; ++i) { @@ -85,7 +85,7 @@ PCEventQueue::doService(ExecContext *xc) // another event. This for example, prevents two invocations // of the SkipFuncEvent. Maybe we should have separate PC // event queues for each processor? - if (pc != xc->regs.pc) + if (pc != (xc->regs.pc & ~0x3)) continue; DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n", diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh index 131016fc6..9983d679b 100644 --- a/cpu/pc_event.hh +++ b/cpu/pc_event.hh @@ -143,7 +143,7 @@ PCEvent::schedule(Addr pc) { if (evpc != badpc) panic("cannot switch PC"); - evpc = pc; + evpc = pc & ~0x3; return schedule(); } @@ -158,7 +158,7 @@ PCEvent::schedule(PCEventQueue *q, Addr pc) panic("cannot switch addresses"); queue = q; - evpc = pc; + evpc = pc & ~0x3; return schedule(); } diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 6c22d7c81..d48f93663 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -123,11 +123,12 @@ SimpleCPU::SimpleCPU(const string &_name, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - bool _def_reg, Tick freq) - : BaseCPU(_name, /* number_of_threads */ 1, + bool _def_reg, Tick freq, + bool _function_trace, Tick _function_trace_start) + : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, max_insts_any_thread, max_insts_all_threads, max_loads_any_thread, max_loads_all_threads, - _system, freq), + _system, freq, _function_trace, _function_trace_start), #else SimpleCPU::SimpleCPU(const string &_name, Process *_process, Counter max_insts_any_thread, @@ -136,13 +137,14 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process, Counter max_loads_all_threads, MemInterface *icache_interface, MemInterface *dcache_interface, - bool _def_reg) - : BaseCPU(_name, /* number_of_threads */ 1, + bool _def_reg, + bool _function_trace, Tick _function_trace_start) + : BaseCPU(_name, /* number_of_threads */ 1, _def_reg, max_insts_any_thread, max_insts_all_threads, - max_loads_any_thread, max_loads_all_threads), + max_loads_any_thread, max_loads_all_threads, + _function_trace, _function_trace_start), #endif - tickEvent(this), xc(NULL), defer_registration(_def_reg), - cacheCompletionEvent(this) + tickEvent(this), xc(NULL), cacheCompletionEvent(this) { _status = Idle; #ifdef FULL_SYSTEM @@ -176,13 +178,6 @@ SimpleCPU::~SimpleCPU() { } -void SimpleCPU::init() -{ - if (!defer_registration) { - this->registerExecContexts(); - } -} - void SimpleCPU::switchOut() { @@ -338,16 +333,30 @@ change_thread_state(int thread_number, int activate, int priority) Fault SimpleCPU::copySrcTranslate(Addr src) { - memReq->reset(src, (dcacheInterface) ? - dcacheInterface->getBlockSize() - : 64); + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); // translate to physical address Fault fault = xc->translateDataReadReq(memReq); + assert(fault != Alignment_Fault); + if (fault == No_Fault) { xc->copySrcAddr = src; - xc->copySrcPhysAddr = memReq->paddr; + xc->copySrcPhysAddr = memReq->paddr + offset; } else { xc->copySrcAddr = 0; xc->copySrcPhysAddr = 0; @@ -358,19 +367,44 @@ SimpleCPU::copySrcTranslate(Addr src) Fault SimpleCPU::copy(Addr dest) { + static bool no_warn = true; int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); uint8_t data[blk_size]; - assert(xc->copySrcAddr); - memReq->reset(dest, blk_size); + //assert(xc->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); // translate to physical address Fault fault = xc->translateDataWriteReq(memReq); + + assert(fault != Alignment_Fault); + if (fault == No_Fault) { - Addr dest_addr = memReq->paddr; + Addr dest_addr = memReq->paddr + offset; // Need to read straight from memory since we have more than 8 bytes. memReq->paddr = xc->copySrcPhysAddr; xc->mem->read(memReq, data); memReq->paddr = dest_addr; xc->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = xc->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + dcacheInterface->access(memReq); + } } return fault; } @@ -610,13 +644,11 @@ SimpleCPU::tick() Fault fault = No_Fault; #ifdef FULL_SYSTEM - if (AlphaISA::check_interrupts && - xc->cpu->check_interrupts() && - !PC_PAL(xc->regs.pc) && + if (checkInterrupts && check_interrupts() && !xc->inPalMode() && status() != IcacheMissComplete) { int ipl = 0; int summary = 0; - AlphaISA::check_interrupts = 0; + checkInterrupts = false; IntReg *ipr = xc->regs.ipr; if (xc->regs.ipr[TheISA::IPR_SIRR]) { @@ -733,9 +765,8 @@ SimpleCPU::tick() fault = si->execute(this, traceData); #ifdef FULL_SYSTEM - SWContext *ctx = xc->swCtx; - if (ctx) - ctx->process(xc, si.get()); + if (xc->fnbin) + xc->execute(si.get()); #endif if (si->isMemRef()) { @@ -750,6 +781,8 @@ SimpleCPU::tick() if (traceData) traceData->finalize(); + traceFunctions(xc->regs.pc); + } // if (fault == No_Fault) if (fault != No_Fault) { @@ -808,6 +841,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) Param<bool> defer_registration; Param<int> multiplier; + Param<bool> function_trace; + Param<Tick> function_trace_start; END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) @@ -841,7 +876,9 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) INIT_PARAM_DFLT(defer_registration, "defer registration with system " "(for sampling)", false), - INIT_PARAM_DFLT(multiplier, "clock multiplier", 1) + INIT_PARAM_DFLT(multiplier, "clock multiplier", 1), + INIT_PARAM_DFLT(function_trace, "Enable function trace", false), + INIT_PARAM_DFLT(function_trace_start, "Cycle to start function trace", 0) END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) @@ -860,7 +897,8 @@ CREATE_SIM_OBJECT(SimpleCPU) (icache) ? icache->getInterface() : NULL, (dcache) ? dcache->getInterface() : NULL, defer_registration, - ticksPerSecond * mult); + ticksPerSecond * mult, + function_trace, function_trace_start); #else cpu = new SimpleCPU(getInstanceName(), workload, @@ -868,7 +906,8 @@ CREATE_SIM_OBJECT(SimpleCPU) max_loads_any_thread, max_loads_all_threads, (icache) ? icache->getInterface() : NULL, (dcache) ? dcache->getInterface() : NULL, - defer_registration); + defer_registration, + function_trace, function_trace_start); #endif // FULL_SYSTEM diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 6ab231e7e..341a0da23 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -31,7 +31,6 @@ #include "cpu/base_cpu.hh" #include "sim/eventq.hh" -#include "base/loader/symtab.hh" #include "cpu/pc_event.hh" #include "base/statistics.hh" #include "cpu/exec_context.hh" @@ -40,7 +39,6 @@ // forward declarations #ifdef FULL_SYSTEM class Processor; -class Kernel; class AlphaITB; class AlphaDTB; class PhysicalMemory; @@ -144,7 +142,8 @@ class SimpleCPU : public BaseCPU Counter max_loads_any_thread, Counter max_loads_all_threads, AlphaITB *itb, AlphaDTB *dtb, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - bool _def_reg, Tick freq); + bool _def_reg, Tick freq, + bool _function_trace, Tick _function_trace_start); #else @@ -154,12 +153,12 @@ class SimpleCPU : public BaseCPU Counter max_loads_any_thread, Counter max_loads_all_threads, MemInterface *icache_interface, MemInterface *dcache_interface, - bool _def_reg); + bool _def_reg, + bool _function_trace, Tick _function_trace_start); #endif virtual ~SimpleCPU(); - virtual void init(); // execution context ExecContext *xc; @@ -179,8 +178,6 @@ class SimpleCPU : public BaseCPU // L1 data cache MemInterface *dcacheInterface; - bool defer_registration; - // current instruction MachInst inst; @@ -250,8 +247,7 @@ class SimpleCPU : public BaseCPU Fault read(Addr addr, T &data, unsigned flags); template <class T> - Fault write(T data, Addr addr, unsigned flags, - uint64_t *res); + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); void prefetch(Addr addr, unsigned flags) { diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index 71e9ef441..c47fa32db 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -48,6 +48,7 @@ class AlphaDynInst; class FastCPU; class SimpleCPU; +class InorderCPU; class SymbolTable; namespace Trace { diff --git a/cpu/trace/opt_cpu.cc b/cpu/trace/opt_cpu.cc new file mode 100644 index 000000000..77211e382 --- /dev/null +++ b/cpu/trace/opt_cpu.cc @@ -0,0 +1,240 @@ + +/* + * Copyright (c) 2004 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 + * Definition of a memory trace CPU object for optimal caches. Uses a memory + * trace to access a fully associative cache with optimal replacement. + */ + +#include <algorithm> // For heap functions. + +#include "cpu/trace/opt_cpu.hh" +#include "cpu/trace/reader/mem_trace_reader.hh" + +#include "sim/builder.hh" +#include "sim/sim_events.hh" + +using namespace std; + +OptCPU::OptCPU(const string &name, + MemTraceReader *_trace, + int block_size, + int cache_size, + int _assoc) + : BaseCPU(name, 1, true), tickEvent(this), trace(_trace), + numBlks(cache_size/block_size), assoc(_assoc), numSets(numBlks/assoc), + setMask(numSets - 1) +{ + int log_block_size = 0; + int tmp_block_size = block_size; + while (tmp_block_size > 1) { + ++log_block_size; + tmp_block_size = tmp_block_size >> 1; + } + assert(1<<log_block_size == block_size); + MemReqPtr req; + trace->getNextReq(req); + refInfo.resize(numSets); + while (req) { + RefInfo temp; + temp.addr = req->paddr >> log_block_size; + int set = temp.addr & setMask; + refInfo[set].push_back(temp); + trace->getNextReq(req); + } + + // Initialize top level of lookup table. + lookupTable.resize(16); + + // Annotate references with next ref time. + for (int k = 0; k < numSets; ++k) { + for (RefIndex i = refInfo[k].size() - 1; i >= 0; --i) { + Addr addr = refInfo[k][i].addr; + initTable(addr, InfiniteRef); + refInfo[k][i].nextRefTime = lookupValue(addr); + setValue(addr, i); + } + } + + // Reset the lookup table + for (int j = 0; j < 16; ++j) { + if (lookupTable[j].size() == (1<<16)) { + for (int k = 0; k < (1<<16); ++k) { + if (lookupTable[j][k].size() == (1<<16)) { + for (int l = 0; l < (1<<16); ++l) { + lookupTable[j][k][l] = -1; + } + } + } + } + } + + tickEvent.schedule(0); + + hits = 0; + misses = 0; +} + +void +OptCPU::processSet(int set) +{ + // Initialize cache + int blks_in_cache = 0; + RefIndex i = 0; + cacheHeap.clear(); + cacheHeap.resize(assoc); + + while (blks_in_cache < assoc) { + RefIndex cache_index = lookupValue(refInfo[set][i].addr); + if (cache_index == -1) { + // First reference to this block + misses++; + cache_index = blks_in_cache++; + setValue(refInfo[set][i].addr, cache_index); + } else { + hits++; + } + // update cache heap to most recent reference + cacheHeap[cache_index] = i; + if (++i >= refInfo[set].size()) { + return; + } + } + for (int start = assoc/2; start >= 0; --start) { + heapify(set,start); + } + //verifyHeap(set,0); + + for (; i < refInfo[set].size(); ++i) { + RefIndex cache_index = lookupValue(refInfo[set][i].addr); + if (cache_index == -1) { + // miss + misses++; + // replace from cacheHeap[0] + // mark replaced block as absent + setValue(refInfo[set][cacheHeap[0]].addr, -1); + setValue(refInfo[set][i].addr, 0); + cacheHeap[0] = i; + heapify(set, 0); + // Make sure its in the cache + assert(lookupValue(refInfo[set][i].addr) != -1); + } else { + // hit + hits++; + assert(refInfo[set][cacheHeap[cache_index]].addr == + refInfo[set][i].addr); + assert(refInfo[set][cacheHeap[cache_index]].nextRefTime == i); + assert(heapLeft(cache_index) >= assoc); + + cacheHeap[cache_index] = i; + processRankIncrease(set, cache_index); + assert(lookupValue(refInfo[set][i].addr) != -1); + } + } +} +void +OptCPU::tick() +{ + // Do opt simulation + + int references = 0; + for (int set = 0; set < numSets; ++set) { + if (!refInfo[set].empty()) { + processSet(set); + } + references += refInfo[set].size(); + } + // exit; + fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses); + fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits); + fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references); + new SimExitEvent("Finshed Memory Trace"); +} + +void +OptCPU::initTable(Addr addr, RefIndex index) +{ + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + assert(l1_index == addr >> 32); + if (lookupTable[l1_index].size() != (1<<16)) { + lookupTable[l1_index].resize(1<<16); + } + if (lookupTable[l1_index][l2_index].size() != (1<<16)) { + lookupTable[l1_index][l2_index].resize(1<<16, index); + } +} + +OptCPU::TickEvent::TickEvent(OptCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +void +OptCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +OptCPU::TickEvent::description() +{ + return "OptCPU tick event"; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(OptCPU) + + SimObjectParam<MemTraceReader *> data_trace; + Param<int> size; + Param<int> block_size; +Param<int> assoc; + +END_DECLARE_SIM_OBJECT_PARAMS(OptCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(OptCPU) + + INIT_PARAM_DFLT(data_trace, "memory trace", NULL), + INIT_PARAM(size, "cache size"), + INIT_PARAM(block_size, "block size"), + INIT_PARAM(assoc,"associativity") + +END_INIT_SIM_OBJECT_PARAMS(OptCPU) + +CREATE_SIM_OBJECT(OptCPU) +{ + return new OptCPU(getInstanceName(), + data_trace, + block_size, + size, + assoc); +} + +REGISTER_SIM_OBJECT("OptCPU", OptCPU) diff --git a/cpu/trace/opt_cpu.hh b/cpu/trace/opt_cpu.hh new file mode 100644 index 000000000..847147b3c --- /dev/null +++ b/cpu/trace/opt_cpu.hh @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2004 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 a memory trace CPU object for optimal caches. Uses a memory + * trace to access a fully associative cache with optimal replacement. + */ + +#ifndef __OPT_CPU_HH__ +#define __OPT_CPU_HH__ + +#include <vector> + +#include "cpu/base_cpu.hh" +#include "mem/mem_req.hh" // for MemReqPtr +#include "sim/eventq.hh" // for Event + +// Forward Declaration +class MemTraceReader; + +/** + * A CPU object to simulate a fully-associative cache with optimal replacement. + */ +class OptCPU : public BaseCPU +{ + typedef int RefIndex; + + typedef std::vector<RefIndex> L3Table; + typedef std::vector<L3Table> L2Table; + typedef std::vector<L2Table> L1Table; + + /** + * Event to call OptCPU::tick + */ + class TickEvent : public Event + { + private: + /** The associated CPU */ + OptCPU *cpu; + + public: + /** + * Construct this event; + */ + TickEvent(OptCPU *c); + + /** + * Call the tick function. + */ + void process(); + + /** + * Return a string description of this event. + */ + const char *description(); + }; + + TickEvent tickEvent; + + class RefInfo + { + public: + RefIndex nextRefTime; + Addr addr; + }; + + /** Reference Information, per set. */ + std::vector<std::vector<RefInfo> > refInfo; + + /** Lookup table to track blocks in the cache heap */ + L1Table lookupTable; + + /** + * Return the correct value in the lookup table. + */ + RefIndex lookupValue(Addr addr) + { + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + int l3_index = addr & 0xffff; + assert(l1_index == addr >> 32); + return lookupTable[l1_index][l2_index][l3_index]; + } + + /** + * Set the value in the lookup table. + */ + void setValue(Addr addr, RefIndex index) + { + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + int l3_index = addr & 0xffff; + assert(l1_index == addr >> 32); + lookupTable[l1_index][l2_index][l3_index]=index; + } + + /** + * Initialize the lookup table to the given value. + */ + void initTable(Addr addr, RefIndex index); + + void heapSwap(int set, int a, int b) { + RefIndex tmp = cacheHeap[a]; + cacheHeap[a] = cacheHeap[b]; + cacheHeap[b] = tmp; + + setValue(refInfo[set][cacheHeap[a]].addr, a); + setValue(refInfo[set][cacheHeap[b]].addr, b); + } + + int heapLeft(int index) { return index + index + 1; } + int heapRight(int index) { return index + index + 2; } + int heapParent(int index) { return (index - 1) >> 1; } + + RefIndex heapRank(int set, int index) { + return refInfo[set][cacheHeap[index]].nextRefTime; + } + + void heapify(int set, int start){ + int left = heapLeft(start); + int right = heapRight(start); + int max = start; + if (left < assoc && heapRank(set, left) > heapRank(set, start)) { + max = left; + } + if (right < assoc && heapRank(set, right) > heapRank(set, max)) { + max = right; + } + + if (max != start) { + heapSwap(set, start, max); + heapify(set, max); + } + } + + void verifyHeap(int set, int start) { + int left = heapLeft(start); + int right = heapRight(start); + + if (left < assoc) { + assert(heapRank(set, start) >= heapRank(set, left)); + verifyHeap(set, left); + } + if (right < assoc) { + assert(heapRank(set, start) >= heapRank(set, right)); + verifyHeap(set, right); + } + } + + void processRankIncrease(int set, int start) { + int parent = heapParent(start); + while (start > 0 && heapRank(set,parent) < heapRank(set,start)) { + heapSwap(set, parent, start); + start = parent; + parent = heapParent(start); + } + } + + void processSet(int set); + + static const RefIndex InfiniteRef = 0x7fffffff; + + /** Memory reference trace. */ + MemTraceReader *trace; + + /** Cache heap for replacement. */ + std::vector<RefIndex> cacheHeap; + + /** The number of blocks in the cache. */ + const int numBlks; + + const int assoc; + const int numSets; + const int setMask; + + + int misses; + int hits; + + public: + /** + * Construct a OptCPU object. + */ + OptCPU(const std::string &name, + MemTraceReader *_trace, + int block_size, + int cache_size, + int assoc); + + /** + * Perform the optimal replacement simulation. + */ + void tick(); +}; + +#endif diff --git a/cpu/trace/reader/itx_reader.cc b/cpu/trace/reader/itx_reader.cc index 593d383ec..006fcc9dd 100644 --- a/cpu/trace/reader/itx_reader.cc +++ b/cpu/trace/reader/itx_reader.cc @@ -102,6 +102,7 @@ ITXReader::getNextReq(MemReqPtr &req) } else { codePhysAddr += tmp_req->size; } + assert(tmp_req->paddr >> 36 == 0); } else { codePhysValid = false; } @@ -130,12 +131,13 @@ ITXReader::getNextReq(MemReqPtr &req) // Get the page offset from the virtual address. tmp_req->paddr = tmp_req->vaddr & 0xfff; tmp_req->paddr |= (c & 0xf0) << 8; + tmp_req->paddr |= (Addr)(c & 0x0f) << 32; for (int i = 2; i < 4; ++i) { c = getc(trace); if (c == EOF) { fatal("Unexpected end of trace file."); } - tmp_req->paddr |= (c & 0xff) << (8 * i); + tmp_req->paddr |= (Addr)(c & 0xff) << (8 * i); } if (type == ITXCode) { if (((tmp_req->paddr & 0xfff) + tmp_req->size) @@ -148,6 +150,7 @@ ITXReader::getNextReq(MemReqPtr &req) codePhysValid = true; } } + assert(tmp_req->paddr >> 36 == 0); } else if (type == ITXCode) { codePhysValid = false; } @@ -158,8 +161,12 @@ ITXReader::getNextReq(MemReqPtr &req) case ITXWrite: tmp_req->cmd = Write; break; + case ITXWriteback: + tmp_req->cmd = Writeback; + break; case ITXCode: tmp_req->cmd = Read; + tmp_req->flags |= INST_READ; break; default: fatal("Unknown ITX type"); @@ -173,6 +180,7 @@ ITXReader::getNextReq(MemReqPtr &req) } } while (!phys_val); req = tmp_req; + assert(!req || (req->paddr >> 36) == 0); return 0; } diff --git a/cpu/trace/reader/itx_reader.hh b/cpu/trace/reader/itx_reader.hh index 0e08d5db5..d45a16a69 100644 --- a/cpu/trace/reader/itx_reader.hh +++ b/cpu/trace/reader/itx_reader.hh @@ -35,6 +35,7 @@ #define __ITX_READER_HH__ #include <stdio.h> +#include <string> #include "cpu/trace/reader/mem_trace_reader.hh" #include "mem/mem_req.hh" diff --git a/cpu/trace/trace_cpu.cc b/cpu/trace/trace_cpu.cc index 94f311d4b..f1160337a 100644 --- a/cpu/trace/trace_cpu.cc +++ b/cpu/trace/trace_cpu.cc @@ -46,23 +46,13 @@ using namespace std; TraceCPU::TraceCPU(const string &name, MemInterface *icache_interface, MemInterface *dcache_interface, - MemTraceReader *inst_trace, - MemTraceReader *data_trace, - int icache_ports, - int dcache_ports) - : BaseCPU(name, 4), icacheInterface(icache_interface), - dcacheInterface(dcache_interface), instTrace(inst_trace), - dataTrace(data_trace), icachePorts(icache_ports), - dcachePorts(dcache_ports), outstandingRequests(0), tickEvent(this) + MemTraceReader *data_trace) + : BaseCPU(name, 4, true), icacheInterface(icache_interface), + dcacheInterface(dcache_interface), + dataTrace(data_trace), outstandingRequests(0), tickEvent(this) { - if (instTrace) { - assert(icacheInterface); - nextInstCycle = instTrace->getNextReq(nextInstReq); - } - if (dataTrace) { - assert(dcacheInterface); - nextDataCycle = dataTrace->getNextReq(nextDataReq); - } + assert(dcacheInterface); + nextCycle = dataTrace->getNextReq(nextReq); tickEvent.schedule(0); } @@ -74,41 +64,46 @@ TraceCPU::tick() int instReqs = 0; int dataReqs = 0; - // Do data first to match tracing with FullCPU dumps - - while (nextDataReq && (dataReqs < dcachePorts) && - curTick >= nextDataCycle) { - assert(nextDataReq->thread_num < 4 && "Not enough threads"); - if (dcacheInterface->isBlocked()) - break; - - ++dataReqs; - nextDataReq->time = curTick; - nextDataReq->completionEvent = - new TraceCompleteEvent(nextDataReq, this); - dcacheInterface->access(nextDataReq); - nextDataCycle = dataTrace->getNextReq(nextDataReq); - } - - while (nextInstReq && (instReqs < icachePorts) && - curTick >= nextInstCycle) { - assert(nextInstReq->thread_num < 4 && "Not enough threads"); - if (icacheInterface->isBlocked()) - break; - - nextInstReq->time = curTick; - if (nextInstReq->cmd == Squash) { - icacheInterface->squash(nextInstReq->asid); + while (nextReq && curTick >= nextCycle) { + assert(nextReq->thread_num < 4 && "Not enough threads"); + if (nextReq->isInstRead() && icacheInterface) { + if (icacheInterface->isBlocked()) + break; + + nextReq->time = curTick; + if (nextReq->cmd == Squash) { + icacheInterface->squash(nextReq->asid); + } else { + ++instReqs; + if (icacheInterface->doEvents()) { + nextReq->completionEvent = + new TraceCompleteEvent(nextReq, this); + icacheInterface->access(nextReq); + } else { + icacheInterface->access(nextReq); + completeRequest(nextReq); + } + } } else { - ++instReqs; - nextInstReq->completionEvent = - new TraceCompleteEvent(nextInstReq, this); - icacheInterface->access(nextInstReq); + if (dcacheInterface->isBlocked()) + break; + + ++dataReqs; + nextReq->time = curTick; + if (dcacheInterface->doEvents()) { + nextReq->completionEvent = + new TraceCompleteEvent(nextReq, this); + dcacheInterface->access(nextReq); + } else { + dcacheInterface->access(nextReq); + completeRequest(nextReq); + } + } - nextInstCycle = instTrace->getNextReq(nextInstReq); + nextCycle = dataTrace->getNextReq(nextReq); } - if (!nextInstReq && !nextDataReq) { + if (!nextReq) { // No more requests to send. Finish trailing events and exit. if (mainEventQueue.empty()) { new SimExitEvent("Finshed Memory Trace"); @@ -116,8 +111,7 @@ TraceCPU::tick() tickEvent.schedule(mainEventQueue.nextEventTime() + 1); } } else { - tickEvent.schedule(max(curTick + 1, - min(nextInstCycle, nextDataCycle))); + tickEvent.schedule(max(curTick + 1, nextCycle)); } } @@ -161,10 +155,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) SimObjectParam<BaseMem *> icache; SimObjectParam<BaseMem *> dcache; - SimObjectParam<MemTraceReader *> inst_trace; SimObjectParam<MemTraceReader *> data_trace; - Param<int> inst_ports; - Param<int> data_ports; END_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) @@ -172,10 +163,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TraceCPU) INIT_PARAM_DFLT(icache, "instruction cache", NULL), INIT_PARAM_DFLT(dcache, "data cache", NULL), - INIT_PARAM_DFLT(inst_trace, "instruction trace", NULL), - INIT_PARAM_DFLT(data_trace, "data trace", NULL), - INIT_PARAM_DFLT(inst_ports, "instruction cache read ports", 4), - INIT_PARAM_DFLT(data_ports, "data cache read/write ports", 4) + INIT_PARAM_DFLT(data_trace, "data trace", NULL) END_INIT_SIM_OBJECT_PARAMS(TraceCPU) @@ -184,7 +172,7 @@ CREATE_SIM_OBJECT(TraceCPU) return new TraceCPU(getInstanceName(), (icache) ? icache->getInterface() : NULL, (dcache) ? dcache->getInterface() : NULL, - inst_trace, data_trace, inst_ports, data_ports); + data_trace); } REGISTER_SIM_OBJECT("TraceCPU", TraceCPU) diff --git a/cpu/trace/trace_cpu.hh b/cpu/trace/trace_cpu.hh index 6f3ef50a6..1711646a8 100644 --- a/cpu/trace/trace_cpu.hh +++ b/cpu/trace/trace_cpu.hh @@ -55,28 +55,17 @@ class TraceCPU : public BaseCPU /** Interface for data trace requests, if any. */ MemInterface *dcacheInterface; - /** Instruction reference trace. */ - MemTraceReader *instTrace; /** Data reference trace. */ MemTraceReader *dataTrace; - /** Number of Icache read ports. */ - int icachePorts; - /** Number of Dcache read/write ports. */ - int dcachePorts; - /** Number of outstanding requests. */ int outstandingRequests; - /** Cycle of the next instruction request, 0 if not available. */ - Tick nextInstCycle; - /** Cycle of the next data request, 0 if not available. */ - Tick nextDataCycle; + /** Cycle of the next request, 0 if not available. */ + Tick nextCycle; - /** Next instruction request. */ - MemReqPtr nextInstReq; - /** Next data request. */ - MemReqPtr nextDataReq; + /** Next request. */ + MemReqPtr nextReq; /** * Event to call the TraceCPU::tick @@ -113,10 +102,7 @@ class TraceCPU : public BaseCPU TraceCPU(const std::string &name, MemInterface *icache_interface, MemInterface *dcache_interface, - MemTraceReader *inst_trace, - MemTraceReader *data_trace, - int icache_ports, - int dcache_ports); + MemTraceReader *data_trace); /** * Perform all the accesses for one cycle. diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc index 680704b30..7deabe2fc 100644 --- a/dev/alpha_console.cc +++ b/dev/alpha_console.cc @@ -61,12 +61,12 @@ AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d, HierParams *hier, Bus *bus) : PioDevice(name), disk(d), console(cons), addr(a) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &AlphaConsole::cacheAccess); - pioInterface->addAddrRange(addr, addr + size); + pioInterface->addAddrRange(RangeSize(addr, size)); } alphaAccess = new AlphaAccess; @@ -98,7 +98,7 @@ AlphaConsole::read(MemReqPtr &req, uint8_t *data) { memset(data, 0, req->size); - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); switch (req->size) { @@ -198,7 +198,7 @@ AlphaConsole::write(MemReqPtr &req, const uint8_t *data) return Machine_Check_Fault; } - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); ExecContext *other_xc; switch (daddr) { diff --git a/dev/baddev.cc b/dev/baddev.cc index 7c563e80a..73b082d47 100644 --- a/dev/baddev.cc +++ b/dev/baddev.cc @@ -50,12 +50,12 @@ BadDevice::BadDevice(const string &name, Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, const string &devicename) : PioDevice(name), addr(a), devname(devicename) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &BadDevice::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); } } diff --git a/dev/etherdump.cc b/dev/etherdump.cc index 27817d456..485d5599c 100644 --- a/dev/etherdump.cc +++ b/dev/etherdump.cc @@ -42,11 +42,9 @@ using std::string; -EtherDump::EtherDump(const string &name, const string &file, int max) - : SimObject(name), maxlen(max) +EtherDump::EtherDump(const string &name, std::ostream *_stream, int max) + : SimObject(name), stream(_stream), maxlen(max) { - if (!file.empty()) - stream.open(file.c_str()); } #define DLT_EN10MB 1 // Ethernet (10Mb) @@ -74,9 +72,6 @@ struct pcap_pkthdr { void EtherDump::init() { - if (!stream.is_open()) - return; - curtime = time(NULL); s_freq = ticksPerSecond; us_freq = ticksPerSecond / ULL(1000000); @@ -91,7 +86,7 @@ EtherDump::init() hdr.sigfigs = 0; hdr.linktype = DLT_EN10MB; - stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); /* * output an empty packet with the current time so that we know @@ -103,9 +98,9 @@ EtherDump::init() pkthdr.microseconds = 0; pkthdr.caplen = 0; pkthdr.len = 0; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.flush(); + stream->flush(); } void @@ -116,9 +111,9 @@ EtherDump::dumpPacket(PacketPtr &packet) pkthdr.microseconds = (curTick / us_freq) % ULL(1000000); pkthdr.caplen = std::min(packet->length, maxlen); pkthdr.len = packet->length; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); - stream.flush(); + stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); + stream->flush(); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) @@ -130,28 +125,14 @@ END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) - INIT_PARAM(file, "file to dump packets to"), + INIT_PARAM_DFLT(file, "file to dump packets to", "etherdump"), INIT_PARAM_DFLT(maxlen, "max portion of packet data to dump", 96) END_INIT_SIM_OBJECT_PARAMS(EtherDump) CREATE_SIM_OBJECT(EtherDump) { - string filename; - if (file.isValid()) { - filename = file; - - if (filename[0] != '/' && !outputDirectory.empty()) - filename = outputDirectory + filename; - } else { - if (outputDirectory.empty()) { - filename = "etherdump"; - } else { - filename = outputDirectory + "etherdump"; - } - } - - return new EtherDump(getInstanceName(), filename, maxlen); + return new EtherDump(getInstanceName(), makeOutputStream(file), maxlen); } REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/dev/etherdump.hh b/dev/etherdump.hh index 62364359e..b127d05e2 100644 --- a/dev/etherdump.hh +++ b/dev/etherdump.hh @@ -43,7 +43,7 @@ class EtherDump : public SimObject { private: - std::ofstream stream; + std::ostream *stream; const int maxlen; void dumpPacket(PacketPtr &packet); void init(); @@ -53,9 +53,9 @@ class EtherDump : public SimObject Tick us_freq; public: - EtherDump(const std::string &name, const std::string &file, int max); + EtherDump(const std::string &name, std::ostream *_stream, int max); - inline void dump(PacketPtr &pkt) { if (stream.is_open()) dumpPacket(pkt); } + inline void dump(PacketPtr &pkt) { dumpPacket(pkt); } }; #endif // __ETHERDUMP_H__ diff --git a/dev/etherint.hh b/dev/etherint.hh index ddfe16d88..bcdf0ae06 100644 --- a/dev/etherint.hh +++ b/dev/etherint.hh @@ -31,8 +31,8 @@ * components. */ -#ifndef __ETHERINT_HH__ -#define __ETHERINT_HH__ +#ifndef __DEV_ETHERINT_HH__ +#define __DEV_ETHERINT_HH__ #include <string> @@ -54,13 +54,13 @@ class EtherInt : public SimObject virtual ~EtherInt() {} void setPeer(EtherInt *p); - virtual bool recvPacket(PacketPtr &packet) = 0; + void recvDone() { peer->sendDone(); } - bool sendPacket(PacketPtr &packet) - { - return peer ? peer->recvPacket(packet) : true; - } virtual void sendDone() = 0; + + bool sendPacket(PacketPtr packet) + { return peer ? peer->recvPacket(packet) : true; } + virtual bool recvPacket(PacketPtr packet) = 0; }; -#endif // __ETHERINT_HH__ +#endif // __DEV_ETHERINT_HH__ diff --git a/dev/etherlink.cc b/dev/etherlink.cc index 3cc4f75ea..d637e152a 100644 --- a/dev/etherlink.cc +++ b/dev/etherlink.cc @@ -41,8 +41,9 @@ #include "dev/etherlink.hh" #include "dev/etherpkt.hh" #include "sim/builder.hh" -#include "sim/universe.hh" +#include "sim/serialize.hh" #include "sim/system.hh" +#include "sim/universe.hh" using namespace std; @@ -104,7 +105,7 @@ EtherLink::unserialize(Checkpoint *cp, const string §ion) } void -EtherLink::Link::txComplete(PacketPtr &packet) +EtherLink::Link::txComplete(PacketPtr packet) { DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); DDUMP(EthernetData, packet->data, packet->length); @@ -121,7 +122,7 @@ class LinkDelayEvent : public Event LinkDelayEvent(EtherLink::Link *link); public: - LinkDelayEvent(EtherLink::Link *link, PacketPtr &pkt, Tick when); + LinkDelayEvent(EtherLink::Link *link, PacketPtr pkt, Tick when); void process(); @@ -152,7 +153,7 @@ EtherLink::Link::txDone() } bool -EtherLink::Link::transmit(PacketPtr &pkt) +EtherLink::Link::transmit(PacketPtr pkt) { if (busy()) { DPRINTF(Ethernet, "packet not sent, link busy\n"); @@ -184,10 +185,8 @@ EtherLink::Link::serialize(ostream &os) SERIALIZE_SCALAR(event_time); } - if (packet_exists) { - nameOut(os, csprintf("%s.packet", name())); - packet->serialize(os); - } + if (packet_exists) + packet->serialize("packet", os); } void @@ -196,8 +195,8 @@ EtherLink::Link::unserialize(Checkpoint *cp, const string §ion) bool packet_exists; UNSERIALIZE_SCALAR(packet_exists); if (packet_exists) { - packet = new EtherPacket; - packet->unserialize(cp, csprintf("%s.packet", section)); + packet = new PacketData(16384); + packet->unserialize("packet", cp, section); } bool event_scheduled; @@ -216,7 +215,7 @@ LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l) setFlags(AutoDelete); } -LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr &p, Tick when) +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr p, Tick when) : Event(&mainEventQueue), link(l), packet(p) { setFlags(AutoSerialize); @@ -237,8 +236,7 @@ LinkDelayEvent::serialize(ostream &os) Event::serialize(os); SERIALIZE_OBJPTR(link); - nameOut(os, csprintf("%s.packet", name())); - packet->serialize(os); + packet->serialize("packet", os); } @@ -246,8 +244,8 @@ void LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) { Event::unserialize(cp, section); - packet = new EtherPacket; - packet->unserialize(cp, csprintf("%s.packet", section)); + packet = new PacketData(16384); + packet->unserialize("packet", cp, section); } diff --git a/dev/etherlink.hh b/dev/etherlink.hh index 204348c6d..e998a006f 100644 --- a/dev/etherlink.hh +++ b/dev/etherlink.hh @@ -75,7 +75,7 @@ class EtherLink : public SimObject DoneEvent doneEvent; friend class LinkDelayEvent; - void txComplete(PacketPtr &packet); + void txComplete(PacketPtr packet); public: Link(const std::string &name, double rate, Tick delay, @@ -85,7 +85,7 @@ class EtherLink : public SimObject virtual const std::string name() const { return objName; } bool busy() const { return (bool)packet; } - bool transmit(PacketPtr &packet); + bool transmit(PacketPtr packet); void setTxInt(Interface *i) { assert(!txint); txint = i; } void setRxInt(Interface *i) { assert(!rxint); rxint = i; } @@ -104,7 +104,7 @@ class EtherLink : public SimObject public: Interface(const std::string &name, Link *txlink, Link *rxlink); - bool recvPacket(PacketPtr &packet) { return txlink->transmit(packet); } + bool recvPacket(PacketPtr packet) { return txlink->transmit(packet); } void sendDone() { peer->sendDone(); } }; diff --git a/dev/etherpkt.cc b/dev/etherpkt.cc index 9eda89e9d..bf60bc150 100644 --- a/dev/etherpkt.cc +++ b/dev/etherpkt.cc @@ -28,23 +28,23 @@ #include <iostream> +#include "base/misc.hh" #include "dev/etherpkt.hh" #include "sim/serialize.hh" using namespace std; void -EtherPacket::serialize(ostream &os) +PacketData::serialize(const string &base, ostream &os) { - SERIALIZE_SCALAR(length); - SERIALIZE_ARRAY(data, length); + paramOut(os, base + ".length", length); + arrayParamOut(os, base + ".data", data, length); } void -EtherPacket::unserialize(Checkpoint *cp, const string §ion) +PacketData::unserialize(const string &base, Checkpoint *cp, + const string §ion) { - UNSERIALIZE_SCALAR(length); - data = new uint8_t[length]; - UNSERIALIZE_ARRAY(data, length); + paramIn(cp, section, base + ".length", length); + arrayParamIn(cp, section, base + ".data", data, length); } - diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh index abdf30166..7a7809f0a 100644 --- a/dev/etherpkt.hh +++ b/dev/etherpkt.hh @@ -37,70 +37,32 @@ #include <memory> #include <assert.h> -#include "sim/host.hh" #include "base/refcnt.hh" -#include "base/inet_hdrs.hh" +#include "sim/host.hh" -class Checkpoint; /* * Reference counted class containing ethernet packet data */ -class EtherPacket : public RefCounted +class Checkpoint; +class PacketData : public RefCounted { public: uint8_t *data; int length; public: - EtherPacket() : data(NULL), length(0) {} - EtherPacket(std::auto_ptr<uint8_t> d, int l) - : data(d.release()), length(l) {} - ~EtherPacket() { if (data) delete [] data; } + PacketData() : data(NULL), length(0) { } + explicit PacketData(size_t size) : data(new uint8_t[size]), length(0) { } + PacketData(std::auto_ptr<uint8_t> d, int l) + : data(d.release()), length(l) { } + ~PacketData() { if (data) delete [] data; } public: - bool IsUnicast() { return data[0] == 0x00; } - bool IsMulticast() { return data[0] == 0x01; } - bool IsBroadcast() { return data[0] == 0xff; } - - bool isIpPkt() { - eth_header *eth = (eth_header *) data; - return (eth->type == 0x8); - } - bool isTcpPkt(ip_header *ip) { - return (ip->protocol == 0x6); - } - bool isTcpPkt() { - ip_header *ip = getIpHdr(); - return (ip->protocol == 0x6); - } - bool isUdpPkt(ip_header *ip) { - return (ip->protocol == 17); - } - bool isUdpPkt() { - ip_header *ip = getIpHdr(); - return (ip->protocol == 17); - } - - ip_header *getIpHdr() { - assert(isIpPkt()); - return (ip_header *) (data + sizeof(eth_header)); - } - - tcp_header *getTcpHdr(ip_header *ip) { - assert(isTcpPkt(ip)); - return (tcp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); - } - - udp_header *getUdpHdr(ip_header *ip) { - assert(isUdpPkt(ip)); - return (udp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); - } - typedef RefCountingPtr<EtherPacket> PacketPtr; - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); }; -typedef RefCountingPtr<EtherPacket> PacketPtr; +typedef RefCountingPtr<PacketData> PacketPtr; #endif // __ETHERPKT_HH__ diff --git a/dev/ethertap.cc b/dev/ethertap.cc index edc400760..1603a9bd3 100644 --- a/dev/ethertap.cc +++ b/dev/ethertap.cc @@ -169,7 +169,7 @@ EtherTap::detach() } bool -EtherTap::recvPacket(PacketPtr &packet) +EtherTap::recvPacket(PacketPtr packet) { if (dump) dump->dump(packet); @@ -219,8 +219,7 @@ EtherTap::process(int revent) while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { PacketPtr packet; - packet = new EtherPacket; - packet->data = new uint8_t[data_len]; + packet = new PacketData(data_len); packet->length = data_len; memcpy(packet->data, data, data_len); diff --git a/dev/ethertap.hh b/dev/ethertap.hh index 1fe368085..5f760ed34 100644 --- a/dev/ethertap.hh +++ b/dev/ethertap.hh @@ -70,7 +70,7 @@ class EtherTap : public EtherInt std::queue<PacketPtr> packetBuffer; void process(int revent); - void enqueue(EtherPacket *packet); + void enqueue(PacketData *packet); void retransmit(); /* @@ -94,7 +94,7 @@ class EtherTap : public EtherInt EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); virtual ~EtherTap(); - virtual bool recvPacket(PacketPtr &packet); + virtual bool recvPacket(PacketPtr packet); virtual void sendDone(); virtual void serialize(std::ostream &os); diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc index e40248461..109908ead 100644 --- a/dev/ide_ctrl.cc +++ b/dev/ide_ctrl.cc @@ -34,16 +34,15 @@ #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 "dev/ide_disk.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcireg.h" +#include "dev/platform.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/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" @@ -55,17 +54,9 @@ 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, Tick pio_latency, HierParams *hier) - : PciDev(name, mmu, cf, cd, bus_num, dev_num, func_num), tsunami(t) +IdeController::IdeController(Params *p) + : PciDev(p) { - // put back pointer into Tsunami - tsunami->disk_controller = this; - // initialize the PIO interface addresses pri_cmd_addr = 0; pri_cmd_size = BARSize[0]; @@ -99,23 +90,25 @@ IdeController::IdeController(const string &name, IntrControl *ic, 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, + if (params()->host_bus) { + pioInterface = newPioInterface(name(), params()->hier, + params()->host_bus, this, &IdeController::cacheAccess); - dmaInterface = new DMAInterface<Bus>(name + ".dma", host_bus, - host_bus, 1); - pioLatency = pio_latency * host_bus->clockRatio; + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + params()->host_bus, + params()->host_bus, 1); + pioLatency = params()->pio_latency * params()->host_bus->clockRatio; } // setup the disks attached to controller memset(disks, 0, sizeof(IdeDisk *) * 4); - if (new_disks.size() > 3) + if (params()->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]; + for (int i = 0; i < params()->disks.size(); i++) { + disks[i] = params()->disks[i]; disks[i]->setController(this, dmaInterface); } } @@ -239,22 +232,6 @@ IdeController::setDmaComplete(IdeDisk *disk) } //// -// 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 //// @@ -377,10 +354,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[0] != 0) { pri_cmd_addr = BARAddrs[0]; if (pioInterface) - pioInterface->addAddrRange(pri_cmd_addr, - pri_cmd_addr + pri_cmd_size - 1); + pioInterface->addAddrRange(RangeSize(pri_cmd_addr, + pri_cmd_size)); - pri_cmd_addr &= PA_UNCACHED_MASK; + pri_cmd_addr &= EV5::PAddrUncachedMask; } break; @@ -388,10 +365,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[1] != 0) { pri_ctrl_addr = BARAddrs[1]; if (pioInterface) - pioInterface->addAddrRange(pri_ctrl_addr, - pri_ctrl_addr + pri_ctrl_size - 1); + pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, + pri_ctrl_size)); - pri_ctrl_addr &= PA_UNCACHED_MASK; + pri_ctrl_addr &= EV5::PAddrUncachedMask; } break; @@ -399,10 +376,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[2] != 0) { sec_cmd_addr = BARAddrs[2]; if (pioInterface) - pioInterface->addAddrRange(sec_cmd_addr, - sec_cmd_addr + sec_cmd_size - 1); + pioInterface->addAddrRange(RangeSize(sec_cmd_addr, + sec_cmd_size)); - sec_cmd_addr &= PA_UNCACHED_MASK; + sec_cmd_addr &= EV5::PAddrUncachedMask; } break; @@ -410,10 +387,10 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[3] != 0) { sec_ctrl_addr = BARAddrs[3]; if (pioInterface) - pioInterface->addAddrRange(sec_ctrl_addr, - sec_ctrl_addr + sec_ctrl_size - 1); + pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, + sec_ctrl_size)); - sec_ctrl_addr &= PA_UNCACHED_MASK; + sec_ctrl_addr &= EV5::PAddrUncachedMask; } break; @@ -421,9 +398,9 @@ IdeController::WriteConfig(int offset, int size, uint32_t data) if (BARAddrs[4] != 0) { bmi_addr = BARAddrs[4]; if (pioInterface) - pioInterface->addAddrRange(bmi_addr, bmi_addr + bmi_size - 1); + pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - bmi_addr &= PA_UNCACHED_MASK; + bmi_addr &= EV5::PAddrUncachedMask; } break; } @@ -675,15 +652,11 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_ARRAY(cmd_in_progress, 4); if (pioInterface) { - pioInterface->addAddrRange(pri_cmd_addr, pri_cmd_addr + - pri_cmd_size - 1); - pioInterface->addAddrRange(pri_ctrl_addr, pri_ctrl_addr + - pri_ctrl_size - 1); - pioInterface->addAddrRange(sec_cmd_addr, sec_cmd_addr + - sec_cmd_size - 1); - pioInterface->addAddrRange(sec_ctrl_addr, sec_ctrl_addr + - sec_ctrl_size - 1); - pioInterface->addAddrRange(bmi_addr, bmi_addr + bmi_size - 1); + pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size)); + pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size)); + pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size)); + pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size)); + pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); } } @@ -691,12 +664,11 @@ IdeController::unserialize(Checkpoint *cp, const std::string §ion) 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; + SimObjectParam<Platform *> platform; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; Param<uint32_t> pci_func; @@ -708,12 +680,11 @@ 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(platform, "Platform pointer"), INIT_PARAM(pci_bus, "PCI bus ID"), INIT_PARAM(pci_dev, "PCI device number"), INIT_PARAM(pci_func, "PCI function code"), @@ -725,9 +696,21 @@ 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, io_bus, pio_latency, hier); + IdeController::Params *params = new IdeController::Params; + params->name = getInstanceName(); + params->mmu = mmu; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->disks = disks; + params->host_bus = io_bus; + params->pio_latency = pio_latency; + params->hier = hier; + return new IdeController(params); } REGISTER_SIM_OBJECT("IdeController", IdeController) diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh index b29e5ae9a..f1082d094 100644 --- a/dev/ide_ctrl.hh +++ b/dev/ide_ctrl.hh @@ -80,14 +80,14 @@ typedef enum RegType { BMI_BLOCK } RegType_t; +class BaseInterface; +class Bus; +class HierParams; class IdeDisk; class IntrControl; class PciConfigAll; -class Tsunami; class PhysicalMemory; -class BaseInterface; -class HierParams; -class Bus; +class Platform; /** * Device model for an Intel PIIX4 IDE controller @@ -95,6 +95,8 @@ class Bus; class IdeController : public PciDev { + friend class IdeDisk; + private: /** Primary command block registers */ Addr pri_cmd_addr; @@ -125,10 +127,6 @@ class IdeController : public PciDev bool bm_enabled; bool cmd_in_progress[4]; - public: - /** Pointer to the chipset */ - Tsunami *tsunami; - private: /** IDE disks connected to controller */ IdeDisk *disks[4]; @@ -149,37 +147,23 @@ class IdeController : public PciDev bool isDiskSelected(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, Tick pio_latency, HierParams *hier); + struct Params : public PciDev::Params + { + /** Array of disk objects */ + std::vector<IdeDisk *> disks; + Bus *host_bus; + Tick pio_latency; + HierParams *hier; + }; + const Params *params() const { return (const Params *)_params; } - /** - * Deletes the connected devices. - */ + public: + IdeController(Params *p); ~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); /** diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index 99724f077..073c10436 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -35,7 +35,6 @@ #include <deque> #include <string> -#include "arch/alpha/pmap.h" #include "base/cprintf.hh" // csprintf #include "base/trace.hh" #include "dev/disk_image.hh" @@ -51,6 +50,7 @@ #include "sim/builder.hh" #include "sim/sim_object.hh" #include "sim/universe.hh" +#include "targetarch/isa_traits.hh" using namespace std; @@ -177,7 +177,7 @@ Addr IdeDisk::pciToDma(Addr pciAddr) { if (ctrl) - return ctrl->tsunami->pchip->translatePciToDma(pciAddr); + return ctrl->plat->pciToDma(pciAddr); else panic("Access to unset controller!\n"); } @@ -188,14 +188,14 @@ 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; + if (bytesLeft > TheISA::PageBytes) + bytesInPage = TheISA::PageBytes; 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; + Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); @@ -510,7 +510,7 @@ IdeDisk::dmaWriteDone() // setup the initial page and DMA address curAddr = curPrd.getBaseAddr(); - pageAddr = alpha_trunc_page(curAddr); + pageAddr = TheISA::TruncPage(curAddr); dmaAddr = pciToDma(curAddr); // clear out the data buffer @@ -518,14 +518,14 @@ IdeDisk::dmaWriteDone() while (bytesRead < curPrd.getByteCount()) { // see if we have crossed into a new page - if (pageAddr != alpha_trunc_page(curAddr)) { + if (pageAddr != TheISA::TruncPage(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); + pageAddr = TheISA::TruncPage(curAddr); dmaAddr = pciToDma(curAddr); bytesInPage = 0; @@ -732,6 +732,7 @@ IdeDisk::startCommand() void IdeDisk::intrPost() { + DPRINTF(IdeDisk, "IDE Disk Posting Interrupt\n"); if (intrPending) panic("Attempt to post an interrupt with one pending\n"); @@ -745,6 +746,7 @@ IdeDisk::intrPost() void IdeDisk::intrClear() { + DPRINTF(IdeDisk, "IDE Disk Clearing Interrupt\n"); if (!intrPending) panic("Attempt to clear a non-pending interrupt\n"); diff --git a/dev/io_device.hh b/dev/io_device.hh index f49afc0a6..8c9dc4a35 100644 --- a/dev/io_device.hh +++ b/dev/io_device.hh @@ -34,7 +34,7 @@ class BaseInterface; class Bus; class HierParams; -template <class Bus> class DMAInterface; +template <class BusType> class DMAInterface; class PioDevice : public FunctionalMemory { diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index f7f56d39b..eee8fbbce 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -41,7 +41,6 @@ #include "dev/etherlink.hh" #include "dev/ns_gige.hh" #include "dev/pciconfigall.hh" -#include "dev/tsunami_cchip.hh" #include "mem/bus/bus.hh" #include "mem/bus/dma_interface.hh" #include "mem/bus/pio_interface.hh" @@ -51,7 +50,7 @@ #include "sim/builder.hh" #include "sim/debug.hh" #include "sim/host.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #include "targetarch/vtophys.hh" const char *NsRxStateStrings[] = @@ -86,82 +85,68 @@ const char *NsDmaState[] = }; using namespace std; - -// helper function declarations -// These functions reverse Endianness so we can evaluate network data -// correctly -uint16_t reverseEnd16(uint16_t); -uint32_t reverseEnd32(uint32_t); +using namespace Net; /////////////////////////////////////////////////////////////////////// // // 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], - uint32_t tx_fifo_size, uint32_t rx_fifo_size) - : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), - maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), +NSGigE::NSGigE(Params *p) + : PciDev(p), ioEnable(false), + txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), - CTDD(false), txFifoAvail(tx_fifo_size), + CTDD(false), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0), + rxEnable(false), CRDD(false), rxPktBytes(0), 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), + dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), + txDelay(p->tx_delay), rxDelay(p->rx_delay), + rxKickTick(0), txKickTick(0), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), acceptPerfect(false), acceptArp(false), - physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), + physmem(p->pmem), intrTick(0), cpuPendingIntr(false), intrEvent(0), interface(0) { - tsunami->ethernet = this; - - if (header_bus) { - pioInterface = newPioInterface(name, hier, header_bus, this, + if (p->header_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->header_bus, this, &NSGigE::cacheAccess); - pioLatency = pio_latency * header_bus->clockRatio; + pioLatency = p->pio_latency * p->header_bus->clockRatio; - if (payload_bus) - dmaInterface = new DMAInterface<Bus>(name + ".dma", - header_bus, payload_bus, 1); + if (p->payload_bus) + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->header_bus, + p->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, + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->header_bus, + p->header_bus, 1); + } else if (p->payload_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->payload_bus, this, &NSGigE::cacheAccess); - pioLatency = pio_latency * payload_bus->clockRatio; + pioLatency = p->pio_latency * p->payload_bus->clockRatio; - dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, - payload_bus, 1); + dmaInterface = new DMAInterface<Bus>(name() + ".dma", + p->payload_bus, + p->payload_bus, 1); } - intrDelay = US2Ticks(intr_delay); - dmaReadDelay = dma_read_delay; - dmaWriteDelay = dma_write_delay; - dmaReadFactor = dma_read_factor; - dmaWriteFactor = dma_write_factor; + intrDelay = US2Ticks(p->intr_delay); + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; 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]; + memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); } NSGigE::~NSGigE() @@ -194,34 +179,48 @@ NSGigE::regStats() .prereq(rxBytes) ; - txIPChecksums - .name(name() + ".txIPChecksums") + txIpChecksums + .name(name() + ".txIpChecksums") .desc("Number of tx IP Checksums done by device") .precision(0) .prereq(txBytes) ; - rxIPChecksums - .name(name() + ".rxIPChecksums") + rxIpChecksums + .name(name() + ".rxIpChecksums") .desc("Number of rx IP Checksums done by device") .precision(0) .prereq(rxBytes) ; - txTCPChecksums - .name(name() + ".txTCPChecksums") + txTcpChecksums + .name(name() + ".txTcpChecksums") .desc("Number of tx TCP Checksums done by device") .precision(0) .prereq(txBytes) ; - rxTCPChecksums - .name(name() + ".rxTCPChecksums") + rxTcpChecksums + .name(name() + ".rxTcpChecksums") .desc("Number of rx TCP Checksums done by device") .precision(0) .prereq(rxBytes) ; + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + descDmaReads .name(name() + ".descDMAReads") .desc("Number of descriptors the device read w/ DMA") @@ -275,6 +274,180 @@ NSGigE::regStats() .prereq(rxBytes) ; + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("number of total Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("number of total RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("number of total RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("number of total RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("number of total TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("number of total TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("number of total TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("number of total RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + totalTxOk + + totalTxIdle + totalTxDesc + totalRxOrn) / postedInterrupts; + txBandwidth = txBytes * Stats::constant(8) / simSeconds; rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; txPacketRate = txPackets / simSeconds; @@ -335,19 +508,17 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data) case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[0], - BARAddrs[0] + BARSize[0] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - BARAddrs[0] &= PA_UNCACHED_MASK; + BARAddrs[0] &= EV5::PAddrUncachedMask; } break; case PCI0_BASE_ADDR1: if (BARAddrs[1] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[1], - BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - BARAddrs[1] &= PA_UNCACHED_MASK; + BARAddrs[1] &= EV5::PAddrUncachedMask; } break; } @@ -934,6 +1105,33 @@ NSGigE::devIntrPost(uint32_t interrupts) interrupts &= ~ISR_NOIMPL; regs.isr |= interrupts; + if (interrupts & regs.imr) { + if (interrupts & ISR_SWI) { + totalSwi++; + } + if (interrupts & ISR_RXIDLE) { + totalRxIdle++; + } + if (interrupts & ISR_RXOK) { + totalRxOk++; + } + if (interrupts & ISR_RXDESC) { + totalRxDesc++; + } + if (interrupts & ISR_TXOK) { + totalTxOk++; + } + if (interrupts & ISR_TXIDLE) { + totalTxIdle++; + } + if (interrupts & ISR_TXDESC) { + totalTxDesc++; + } + if (interrupts & ISR_RXORN) { + totalRxOrn++; + } + } + DPRINTF(EthernetIntr, "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", interrupts, regs.isr, regs.imr); @@ -946,12 +1144,46 @@ NSGigE::devIntrPost(uint32_t interrupts) } } +/* writing this interrupt counting stats inside this means that this function + is now limited to being used to clear all interrupts upon the kernel + reading isr and servicing. just telling you in case you were thinking + of expanding use. +*/ void NSGigE::devIntrClear(uint32_t interrupts) { if (interrupts & ISR_RESERVE) panic("Cannot clear a reserved interrupt"); + if (regs.isr & regs.imr & ISR_SWI) { + postedSwi++; + } + if (regs.isr & regs.imr & ISR_RXIDLE) { + postedRxIdle++; + } + if (regs.isr & regs.imr & ISR_RXOK) { + postedRxOk++; + } + if (regs.isr & regs.imr & ISR_RXDESC) { + postedRxDesc++; + } + if (regs.isr & regs.imr & ISR_TXOK) { + postedTxOk++; + } + if (regs.isr & regs.imr & ISR_TXIDLE) { + postedTxIdle++; + } + if (regs.isr & regs.imr & ISR_TXDESC) { + postedTxDesc++; + } + if (regs.isr & regs.imr & ISR_RXORN) { + postedRxOrn++; + } + + if (regs.isr & regs.imr & (ISR_SWI | ISR_RXIDLE | ISR_RXOK | ISR_RXDESC | + ISR_TXOK | ISR_TXIDLE | ISR_TXDESC | ISR_RXORN) ) + postedInterrupts++; + interrupts &= ~ISR_NOIMPL; regs.isr &= ~interrupts; @@ -987,61 +1219,50 @@ NSGigE::cpuIntrPost(Tick when) * @todo this warning should be removed and the intrTick code should * be fixed. */ - if (intrTick < curTick && intrTick != 0) { - warn("intrTick < curTick !!! intrTick=%d curTick=%d\n", - intrTick, curTick); - intrTick = 0; - } - assert((intrTick >= curTick) || (intrTick == 0)); - if (when > intrTick && intrTick != 0) + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); return; + } intrTick = when; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; } - if (when < curTick) { - cpuInterrupt(); - } else { - DPRINTF(EthernetIntr, - "going to schedule an interrupt for intrTick=%d\n", - intrTick); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); - } + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); } void NSGigE::cpuInterrupt() { - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - intrTick = 0; - return; - } - // Don't send an interrupt if it's supposed to be delayed - if (intrTick > curTick) { - DPRINTF(EthernetIntr, - "an interrupt is scheduled for %d, wait til then\n", - intrTick); - return; - } + assert(intrTick == curTick); // Whether or not there's a pending interrupt, we don't care about // it anymore intrEvent = 0; intrTick = 0; - // Send interrupt - cpuPendingIntr = true; + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; - DPRINTF(EthernetIntr, "posting cchip interrupt\n"); - tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } } void @@ -1050,10 +1271,17 @@ NSGigE::cpuIntrClear() if (!cpuPendingIntr) return; + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + cpuPendingIntr = false; - DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); - tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); } bool @@ -1067,7 +1295,6 @@ NSGigE::txReset() DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; - txFifoAvail = maxTxFifoSize; txEnable = false;; txFragPtr = 0; assert(txDescCnt == 0); @@ -1083,7 +1310,6 @@ NSGigE::rxReset() CRDD = false; assert(rxPktBytes == 0); - rxFifoCnt = 0; rxEnable = false; rxFragPtr = 0; assert(rxDescCnt == 0); @@ -1336,14 +1562,13 @@ NSGigE::rxKick() #if TRACING_ON if (DTRACE(Ethernet)) { - if (rxPacket->isIpPkt()) { - ip_header *ip = rxPacket->getIpHdr(); - DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); - if (rxPacket->isTcpPkt()) { - tcp_header *tcp = rxPacket->getTcpHdr(ip); + IpPtr ip(rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - reverseEnd16(tcp->src_port_num), - reverseEnd16(tcp->dest_port_num)); + tcp->sport(), tcp->dport()); } } } @@ -1351,12 +1576,7 @@ NSGigE::rxKick() // 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(); - rxFifoCnt -= rxPacket->length; + rxFifo.pop(); } @@ -1399,33 +1619,38 @@ NSGigE::rxKick() */ if (rxFilterEnable) { rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; - if (rxFifo.front()->IsUnicast()) + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) rxDescCache.cmdsts |= CMDSTS_DEST_SELF; - if (rxFifo.front()->IsMulticast()) + if (dst->multicast()) rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; - if (rxFifo.front()->IsBroadcast()) + if (dst->broadcast()) rxDescCache.cmdsts |= CMDSTS_DEST_MASK; } #endif - if (rxPacket->isIpPkt() && extstsEnable) { + IpPtr ip(rxPacket); + if (extstsEnable && ip) { rxDescCache.extsts |= EXTSTS_IPPKT; - rxIPChecksums++; - if (!ipChecksum(rxPacket, false)) { + rxIpChecksums++; + if (cksum(ip) != 0) { DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_IPERR; } - if (rxPacket->isTcpPkt()) { + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { rxDescCache.extsts |= EXTSTS_TCPPKT; - rxTCPChecksums++; - if (!tcpChecksum(rxPacket, false)) { + rxTcpChecksums++; + if (cksum(tcp) != 0) { DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_TCPERR; } - } else if (rxPacket->isUdpPkt()) { + } else if (udp) { rxDescCache.extsts |= EXTSTS_UDPPKT; - if (!udpChecksum(rxPacket, false)) { + rxUdpChecksums++; + if (cksum(udp) != 0) { DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_UDPERR; } @@ -1539,18 +1764,17 @@ NSGigE::transmit() } DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", - maxTxFifoSize - txFifoAvail); + txFifo.size()); if (interface->sendPacket(txFifo.front())) { #if TRACING_ON if (DTRACE(Ethernet)) { - if (txFifo.front()->isIpPkt()) { - ip_header *ip = txFifo.front()->getIpHdr(); - DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); - if (txFifo.front()->isTcpPkt()) { - tcp_header *tcp = txFifo.front()->getTcpHdr(ip); + IpPtr ip(txFifo.front()); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - reverseEnd16(tcp->src_port_num), - reverseEnd16(tcp->dest_port_num)); + tcp->sport(), tcp->dport()); } } } @@ -1560,12 +1784,9 @@ NSGigE::transmit() txBytes += txFifo.front()->length; txPackets++; - txFifoAvail += txFifo.front()->length; - DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", - txFifoAvail); - txFifo.front() = NULL; - txFifo.pop_front(); + txFifo.avail()); + txFifo.pop(); /* * normally do a writeback of the descriptor here, and ONLY @@ -1575,9 +1796,6 @@ NSGigE::transmit() * besides, it's functionally the same. */ devIntrPost(ISR_TXOK); - } else { - DPRINTF(Ethernet, - "May need to rethink always sending the descriptors back?\n"); } if (!txFifo.empty() && !txEvent.scheduled()) { @@ -1784,8 +2002,7 @@ NSGigE::txKick() case txFifoBlock: if (!txPacket) { DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); - txPacket = new EtherPacket; - txPacket->data = new uint8_t[16384]; + txPacket = new PacketData(16384); txPacketBufPtr = txPacket->data; } @@ -1810,15 +2027,22 @@ NSGigE::txKick() DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); /* deal with the the packet that just finished */ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { + IpPtr ip(txPacket); if (txDescCache.extsts & EXTSTS_UDPPKT) { - udpChecksum(txPacket, true); + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; } else if (txDescCache.extsts & EXTSTS_TCPPKT) { - tcpChecksum(txPacket, true); - txTCPChecksums++; + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; } if (txDescCache.extsts & EXTSTS_IPPKT) { - ipChecksum(txPacket, true); - txIPChecksums++; + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; } } @@ -1826,7 +2050,11 @@ NSGigE::txKick() // this is just because the receive can't handle a // packet bigger want to make sure assert(txPacket->length <= 1514); - txFifo.push_back(txPacket); +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); /* * this following section is not tqo spec, but @@ -1872,7 +2100,7 @@ NSGigE::txKick() } } else { DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); - if (txFifoAvail) { + if (!txFifo.full()) { txState = txFragRead; /* @@ -1881,7 +2109,7 @@ NSGigE::txKick() * is not enough room in the fifo, just whatever room * is left in the fifo */ - txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); + txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); txDmaAddr = txFragPtr & 0x3fffffff; txDmaData = txPacketBufPtr; @@ -1907,7 +2135,7 @@ NSGigE::txKick() txPacketBufPtr += txXferLen; txFragPtr += txXferLen; txDescCnt -= txXferLen; - txFifoAvail -= txXferLen; + txFifo.reserve(txXferLen); txState = txFifoBlock; break; @@ -1976,45 +2204,35 @@ NSGigE::transferDone() } bool -NSGigE::rxFilter(PacketPtr packet) +NSGigE::rxFilter(const PacketPtr &packet) { + EthPtr eth = packet; bool drop = true; string type; - if (packet->IsUnicast()) { - type = "unicast"; - + const EthAddr &dst = eth->dst(); + if (dst.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, EADDR_LEN) == 0) + if (acceptPerfect && dst == rom.perfectMatch) drop = false; - eth_header *eth = (eth_header *) packet->data; - if ((acceptArp) && (eth->type == 0x608)) + if (acceptArp && eth->type() == ETH_TYPE_ARP) drop = false; - } else if (packet->IsBroadcast()) { - type = "broadcast"; - + } else if (dst.broadcast()) { // if we're accepting broadcasts if (acceptBroadcast) drop = false; - } else if (packet->IsMulticast()) { - type = "multicast"; - + } else if (dst.multicast()) { // if we're accepting all multicasts if (acceptMulticast) drop = false; - } else { - type = "unknown"; - - // oh well, punt on this one } if (drop) { @@ -2032,7 +2250,7 @@ NSGigE::recvPacket(PacketPtr packet) rxPackets++; DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", - maxRxFifoSize - rxFifoCnt); + rxFifo.avail()); if (!rxEnable) { DPRINTF(Ethernet, "receive disabled...packet dropped\n"); @@ -2047,136 +2265,21 @@ NSGigE::recvPacket(PacketPtr packet) return true; } - if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { + if (rxFifo.avail() < packet->length) { DPRINTF(Ethernet, "packet will not fit in receive buffer...packet dropped\n"); + droppedPackets++; devIntrPost(ISR_RXORN); return false; } - rxFifo.push_back(packet); - rxFifoCnt += packet->length; + rxFifo.push(packet); 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) -{ - ip_header *ip = packet->getIpHdr(); - udp_header *hdr = packet->getUdpHdr(ip); - - 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) -{ - ip_header *ip = packet->getIpHdr(); - tcp_header *hdr = packet->getTcpHdr(ip); - - uint16_t cksum; - pseudo_header *pseudo = new pseudo_header; - if (!gen) { - pseudo->src_ip_addr = ip->src_ip_addr; - pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = reverseEnd16(ip->protocol); - pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - - (ip->vers_len & 0xf)*4); - - cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) reverseEnd16(pseudo->len)); - } else { - pseudo->src_ip_addr = 0; - pseudo->dest_ip_addr = 0; - pseudo->protocol = hdr->chksum; - pseudo->len = 0; - hdr->chksum = 0; - cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) (reverseEnd16(ip->dgram_len) - - (ip->vers_len & 0xf)*4)); - } - - 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)*4); - - if (gen) { - DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); - 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; -} - //===================================================================== // // @@ -2234,30 +2337,15 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(regs.taner); SERIALIZE_SCALAR(regs.tesr); - SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); SERIALIZE_SCALAR(ioEnable); /* * Serialize the data Fifos */ - int txNumPkts = txFifo.size(); - SERIALIZE_SCALAR(txNumPkts); - int i = 0; - pktiter_t end = txFifo.end(); - for (pktiter_t p = txFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.txFifo%d", name(), i++)); - (*p)->serialize(os); - } - - int rxNumPkts = rxFifo.size(); - SERIALIZE_SCALAR(rxNumPkts); - i = 0; - end = rxFifo.end(); - for (pktiter_t p = rxFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); - (*p)->serialize(os); - } + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); /* * Serialize the various helper variables @@ -2265,8 +2353,7 @@ NSGigE::serialize(ostream &os) bool txPacketExists = txPacket; SERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - nameOut(os, csprintf("%s.txPacket", name())); - txPacket->serialize(os); + txPacket->serialize("txPacket", os); uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); SERIALIZE_SCALAR(txPktBufPtr); } @@ -2274,8 +2361,7 @@ NSGigE::serialize(ostream &os) bool rxPacketExists = rxPacket; SERIALIZE_SCALAR(rxPacketExists); if (rxPacketExists) { - nameOut(os, csprintf("%s.rxPacket", name())); - rxPacket->serialize(os); + rxPacket->serialize("rxPacket", os); uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); SERIALIZE_SCALAR(rxPktBufPtr); } @@ -2302,7 +2388,6 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(txState); SERIALIZE_SCALAR(txEnable); SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFifoAvail); SERIALIZE_SCALAR(txFragPtr); SERIALIZE_SCALAR(txDescCnt); int txDmaState = this->txDmaState; @@ -2316,7 +2401,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxEnable); SERIALIZE_SCALAR(CRDD); SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFifoCnt); + SERIALIZE_SCALAR(rxFragPtr); SERIALIZE_SCALAR(rxDescCnt); int rxDmaState = this->rxDmaState; SERIALIZE_SCALAR(rxDmaState); @@ -2391,29 +2476,15 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(regs.taner); UNSERIALIZE_SCALAR(regs.tesr); - UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); UNSERIALIZE_SCALAR(ioEnable); /* * unserialize the data fifos */ - int txNumPkts; - UNSERIALIZE_SCALAR(txNumPkts); - int i; - for (i = 0; i < txNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - txFifo.push_back(p); - } - - int rxNumPkts; - UNSERIALIZE_SCALAR(rxNumPkts); - for (i = 0; i < rxNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - rxFifo.push_back(p); - } + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); /* * unserialize the various helper variables @@ -2421,8 +2492,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) bool txPacketExists; UNSERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - txPacket = new EtherPacket; - txPacket->unserialize(cp, csprintf("%s.txPacket", section)); + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); uint32_t txPktBufPtr; UNSERIALIZE_SCALAR(txPktBufPtr); txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; @@ -2433,8 +2504,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxPacketExists); rxPacket = 0; if (rxPacketExists) { - rxPacket = new EtherPacket; - rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); uint32_t rxPktBufPtr; UNSERIALIZE_SCALAR(rxPktBufPtr); rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; @@ -2464,7 +2535,6 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) this->txState = (TxState) txState; UNSERIALIZE_SCALAR(txEnable); UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFifoAvail); UNSERIALIZE_SCALAR(txFragPtr); UNSERIALIZE_SCALAR(txDescCnt); int txDmaState; @@ -2480,7 +2550,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxEnable); UNSERIALIZE_SCALAR(CRDD); UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFifoCnt); + UNSERIALIZE_SCALAR(rxFragPtr); UNSERIALIZE_SCALAR(rxDescCnt); int rxDmaState; UNSERIALIZE_SCALAR(rxDmaState); @@ -2522,8 +2592,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) * re-add addrRanges to bus bridges */ if (pioInterface) { - pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); - pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); } } @@ -2534,28 +2604,6 @@ NSGigE::cacheAccess(MemReqPtr &req) req->paddr, req->paddr - addr); return curTick + pioLatency; } -//===================================================================== - - -//********** helper functions****************************************** - -uint16_t reverseEnd16(uint16_t num) -{ - uint16_t reverse = (num & 0xff)<<8; - reverse += ((num & 0xff00) >> 8); - return reverse; -} - -uint32_t reverseEnd32(uint32_t num) -{ - uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; - reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); - return reverse; -} - - - -//===================================================================== BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) @@ -2591,7 +2639,6 @@ 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; @@ -2609,7 +2656,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) Param<Tick> dma_write_factor; SimObjectParam<PciConfigAll *> configspace; SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Tsunami *> tsunami; + SimObjectParam<Platform *> platform; Param<uint32_t> pci_bus; Param<uint32_t> pci_dev; Param<uint32_t> pci_func; @@ -2622,7 +2669,6 @@ 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"), @@ -2641,7 +2687,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 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(platform, "Platform"), INIT_PARAM(pci_bus, "PCI bus"), INIT_PARAM(pci_dev, "PCI device number"), INIT_PARAM(pci_func, "PCI function code"), @@ -2653,17 +2699,36 @@ 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, - tx_fifo_size, rx_fifo_size); + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + params->mmu = mmu; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->intr_delay = intr_delay; + params->pmem = physmem; + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->hier = hier; + params->header_bus = header_bus; + params->payload_bus = payload_bus; + params->pio_latency = pio_latency; + params->dma_desc_free = dma_desc_free; + params->dma_data_free = dma_data_free; + params->dma_read_delay = dma_read_delay; + params->dma_write_delay = dma_write_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_factor = dma_write_factor; + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_size = rx_fifo_size; + return new NSGigE(params); } REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh index 82f640db1..8d6016126 100644 --- a/dev/ns_gige.hh +++ b/dev/ns_gige.hh @@ -31,22 +31,20 @@ * DP83820 ethernet controller */ -#ifndef __NS_GIGE_HH__ -#define __NS_GIGE_HH__ +#ifndef __DEV_NS_GIGE_HH__ +#define __DEV_NS_GIGE_HH__ +#include "base/inet.hh" #include "base/statistics.hh" #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "dev/io_device.hh" #include "dev/ns_gige_reg.h" #include "dev/pcidev.hh" -#include "dev/tsunami.hh" +#include "dev/pktfifo.hh" #include "mem/bus/bus.hh" #include "sim/eventq.hh" -/** length of ethernet address in bytes */ -#define EADDR_LEN 6 - /** * Ethernet device registers */ @@ -90,7 +88,7 @@ struct dp_rom { * for perfect match memory. * the linux driver doesn't use any other ROM */ - uint8_t perfectMatch[EADDR_LEN]; + uint8_t perfectMatch[ETH_ADDR_LEN]; }; class IntrControl; @@ -141,10 +139,6 @@ class NSGigE : public PciDev }; private: - /** pointer to the chipset */ - Tsunami *tsunami; - - private: Addr addr; static const Addr size = sizeof(dp_regs); @@ -165,10 +159,8 @@ class NSGigE : public PciDev /*** BASIC STRUCTURES FOR TX/RX ***/ /* Data FIFOs */ - pktbuf_t txFifo; - uint32_t maxTxFifoSize; - pktbuf_t rxFifo; - uint32_t maxRxFifoSize; + PacketFifo txFifo; + PacketFifo rxFifo; /** various helper vars */ PacketPtr txPacket; @@ -190,8 +182,6 @@ class NSGigE : public PciDev /** Current Transmit Descriptor Done */ bool CTDD; - /** 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 */ @@ -208,8 +198,6 @@ class NSGigE : public PciDev 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 */ @@ -302,7 +290,7 @@ class NSGigE : public PciDev * receive address filter */ bool rxFilterEnable; - bool rxFilter(PacketPtr packet); + bool rxFilter(const PacketPtr &packet); bool acceptBroadcast; bool acceptMulticast; bool acceptUnicast; @@ -329,28 +317,34 @@ class NSGigE : public PciDev 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], - uint32_t tx_fifo_size, uint32_t rx_fifo_size); + struct Params : public PciDev::Params + { + PhysicalMemory *pmem; + HierParams *hier; + Bus *header_bus; + Bus *payload_bus; + Tick intr_delay; + Tick tx_delay; + Tick rx_delay; + 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; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t tx_fifo_size; + uint32_t rx_fifo_size; + }; + + NSGigE(Params *params); ~NSGigE(); + const Params *params() const { return (const Params *)_params; } virtual void WriteConfig(int offset, int size, uint32_t data); virtual void ReadConfig(int offset, int size, uint8_t *data); @@ -377,10 +371,12 @@ class NSGigE : public PciDev Stats::Scalar<> rxBytes; Stats::Scalar<> txPackets; Stats::Scalar<> rxPackets; - Stats::Scalar<> txIPChecksums; - Stats::Scalar<> rxIPChecksums; - Stats::Scalar<> txTCPChecksums; - Stats::Scalar<> rxTCPChecksums; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> txUdpChecksums; + Stats::Scalar<> rxUdpChecksums; Stats::Scalar<> descDmaReads; Stats::Scalar<> descDmaWrites; Stats::Scalar<> descDmaRdBytes; @@ -389,6 +385,33 @@ class NSGigE : public PciDev Stats::Formula rxBandwidth; Stats::Formula txPacketRate; Stats::Formula rxPacketRate; + Stats::Scalar<> postedSwi; + Stats::Formula coalescedSwi; + Stats::Scalar<> totalSwi; + Stats::Scalar<> postedRxIdle; + Stats::Formula coalescedRxIdle; + Stats::Scalar<> totalRxIdle; + Stats::Scalar<> postedRxOk; + Stats::Formula coalescedRxOk; + Stats::Scalar<> totalRxOk; + Stats::Scalar<> postedRxDesc; + Stats::Formula coalescedRxDesc; + Stats::Scalar<> totalRxDesc; + Stats::Scalar<> postedTxOk; + Stats::Formula coalescedTxOk; + Stats::Scalar<> totalTxOk; + Stats::Scalar<> postedTxIdle; + Stats::Formula coalescedTxIdle; + Stats::Scalar<> totalTxIdle; + Stats::Scalar<> postedTxDesc; + Stats::Formula coalescedTxDesc; + Stats::Scalar<> totalTxDesc; + Stats::Scalar<> postedRxOrn; + Stats::Formula coalescedRxOrn; + Stats::Scalar<> totalRxOrn; + Stats::Formula coalescedTotal; + Stats::Scalar<> postedInterrupts; + Stats::Scalar<> droppedPackets; public: Tick cacheAccess(MemReqPtr &req); @@ -406,8 +429,8 @@ class NSGigEInt : public EtherInt NSGigEInt(const std::string &name, NSGigE *d) : EtherInt(name), dev(d) { dev->setInterface(this); } - virtual bool recvPacket(PacketPtr &pkt) { return dev->recvPacket(pkt); } + virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } virtual void sendDone() { dev->transferDone(); } }; -#endif // __NS_GIGE_HH__ +#endif // __DEV_NS_GIGE_HH__ diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc index 740a9b4ac..609763e92 100644 --- a/dev/pciconfigall.cc +++ b/dev/pciconfigall.cc @@ -33,10 +33,12 @@ #include <deque> #include <string> #include <vector> +#include <bitset> #include "base/trace.hh" #include "dev/pciconfigall.hh" #include "dev/pcidev.hh" +#include "dev/pcireg.h" #include "mem/bus/bus.hh" #include "mem/bus/pio_interface.hh" #include "mem/bus/pio_interface_impl.hh" @@ -50,12 +52,12 @@ PciConfigAll::PciConfigAll(const string &name, Addr a, MemoryController *mmu, HierParams *hier, Bus *bus, Tick pio_latency) : PioDevice(name), addr(a) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &PciConfigAll::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -65,13 +67,40 @@ PciConfigAll::PciConfigAll(const string &name, Addr a, MemoryController *mmu, devices[x][y] = NULL; } +// If two interrupts share the same line largely bad things will happen. +// Since we don't track how many times an interrupt was set and correspondingly +// cleared two devices on the same interrupt line and assert and deassert each +// others interrupt "line". Interrupts will not work correctly. +void +PciConfigAll::startup() +{ + bitset<256> intLines; + PciDev *tempDev; + uint8_t intline; + + for (int x = 0; x < MAX_PCI_DEV; x++) { + for (int y = 0; y < MAX_PCI_FUNC; y++) { + if (devices[x][y] != NULL) { + tempDev = devices[x][y]; + intline = tempDev->interruptLine(); + if (intLines.test(intline)) + warn("Interrupt line %#X is used multiple times" + "(You probably want to fix this).\n", (uint32_t)intline); + else + intLines.set(intline); + } // devices != NULL + } // PCI_FUNC + } // PCI_DEV + +} + 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)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; @@ -115,7 +144,7 @@ PciConfigAll::read(MemReqPtr &req, uint8_t *data) Fault PciConfigAll::write(MemReqPtr &req, const uint8_t *data) { - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); int device = (daddr >> 11) & 0x1F; int func = (daddr >> 8) & 0x7; diff --git a/dev/pciconfigall.hh b/dev/pciconfigall.hh index d6b37b9b1..9cf2cf972 100644 --- a/dev/pciconfigall.hh +++ b/dev/pciconfigall.hh @@ -116,6 +116,12 @@ class PciConfigAll : public PioDevice virtual Fault write(MemReqPtr &req, const uint8_t *data); /** + * Start up function to check if more than one person is using an interrupt line + * and print a warning if such a case exists + */ + virtual void startup(); + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ @@ -134,6 +140,7 @@ class PciConfigAll : public PioDevice * @return Tick when the request is done */ Tick cacheAccess(MemReqPtr &req); + }; #endif // __PCICONFIGALL_HH__ diff --git a/dev/pcidev.cc b/dev/pcidev.cc index 7b13aac80..d156b6a02 100644 --- a/dev/pcidev.cc +++ b/dev/pcidev.cc @@ -50,36 +50,38 @@ 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) +PciDev::PciDev(Params *p) + : DmaDevice(p->name), _params(p), plat(p->plat), configData(p->configData) { // 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)); + if (configData) { + memcpy(config.data, configData->config.data, sizeof(config.data)); + memcpy(BARSize, configData->BARSize, sizeof(BARSize)); + memcpy(BARAddrs, configData->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); + if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) + panic("Two PCI devices occuping same dev: %#x func: %#x", + p->deviceNum, p->functionNum); else - cf->registerDevice(dev, func, this); + p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); } void PciDev::ReadConfig(int offset, int size, uint8_t *data) { + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + switch(size) { case sizeof(uint32_t): memcpy((uint8_t*)data, config.data + offset, sizeof(uint32_t)); *(uint32_t*)data = htoa(*(uint32_t*)data); DPRINTF(PCIDEV, "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - deviceNum, functionNum, offset, size, + params()->deviceNum, params()->functionNum, offset, size, *(uint32_t*)(config.data + offset)); break; @@ -88,7 +90,7 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) *(uint16_t*)data = htoa(*(uint16_t*)data); DPRINTF(PCIDEV, "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - deviceNum, functionNum, offset, size, + params()->deviceNum, params()->functionNum, offset, size, *(uint16_t*)(config.data + offset)); break; @@ -96,7 +98,7 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) 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, + params()->deviceNum, params()->functionNum, offset, size, (uint16_t)(*(uint8_t*)(config.data + offset))); break; @@ -108,6 +110,9 @@ PciDev::ReadConfig(int offset, int size, uint8_t *data) void PciDev::WriteConfig(int offset, int size, uint32_t data) { + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + uint32_t barnum; union { @@ -119,7 +124,8 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) DPRINTF(PCIDEV, "write device: %#x function: %#x reg: %#x size: %d data: %#x\n", - deviceNum, functionNum, offset, size, word_value); + params()->deviceNum, params()->functionNum, offset, size, + word_value); barnum = (offset - PCI0_BASE_ADDR0) >> 2; @@ -129,7 +135,7 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) case PCI0_INTERRUPT_LINE: case PCI_CACHE_LINE_SIZE: case PCI_LATENCY_TIMER: - *(uint8_t *)&config.data[offset] = byte_value; + *(uint8_t *)&config.data[offset] = htoa(byte_value); break; default: @@ -142,7 +148,7 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) case PCI_COMMAND: case PCI_STATUS: case PCI_CACHE_LINE_SIZE: - *(uint16_t *)&config.data[offset] = half_value; + *(uint16_t *)&config.data[offset] = htoa(half_value); break; default: @@ -166,67 +172,63 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) // 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] = + if (htoa(config.data[offset]) & 0x1) { + *(uint32_t *)&config.data[offset] = htoa( ~(BARSize[barnum] - 1) | - (config.data[offset] & 0x3); + (htoa(config.data[offset]) & 0x3)); } else { // This is memory space, bottom four bits are read only - *(uint32_t *)&config.data[offset] = + *(uint32_t *)&config.data[offset] = htoa( ~(BARSize[barnum] - 1) | - (config.data[offset] & 0xF); + (htoa(config.data[offset]) & 0xF)); } } else { + MemoryController *mmu = params()->mmu; + // 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(htoa(config.data[offset]) & 0x1) { + *(uint32_t *)&config.data[offset] = + htoa((word_value & ~0x3) | + (htoa(config.data[offset]) & 0x3)); if (word_value & ~0x1) { Addr base_addr = (word_value & ~0x1) + TSUNAMI_PCI0_IO; - Addr base_size = BARSize[barnum]-1; + Addr base_size = BARSize[barnum]; // It's never been set if (BARAddrs[barnum] == 0) mmu->add_child((FunctionalMemory *)this, - Range<Addr>(base_addr, - base_addr + base_size)); + RangeSize(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)); + RangeSize(BARAddrs[barnum], + base_size), + RangeSize(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); + *(uint32_t *)&config.data[offset] = + htoa((word_value & ~0xF) | + (htoa(config.data[offset]) & 0xF)); if (word_value & ~0x3) { Addr base_addr = (word_value & ~0x3) + TSUNAMI_PCI0_MEMORY; - Addr base_size = BARSize[barnum]-1; + Addr base_size = BARSize[barnum]; // It's never been set if (BARAddrs[barnum] == 0) mmu->add_child((FunctionalMemory *)this, - Range<Addr>(base_addr, - base_addr + base_size)); + RangeSize(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)); + RangeSize(BARAddrs[barnum], + base_size), + RangeSize(base_addr, base_size)); BARAddrs[barnum] = base_addr; } @@ -238,14 +240,14 @@ PciDev::WriteConfig(int offset, int size, uint32_t data) if (word_value == 0xfffffffe) *(uint32_t *)&config.data[offset] = 0xffffffff; else - *(uint32_t *)&config.data[offset] = word_value; + *(uint32_t *)&config.data[offset] = htoa(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; + *(uint16_t *)&config.data[offset] = htoa(half_value); break; default: @@ -273,10 +275,7 @@ PciDev::unserialize(Checkpoint *cp, const std::string §ion) // Add the MMU mappings for the BARs for (int i=0; i < 6; i++) { if (BARAddrs[i] != 0) - mmu->add_child((FunctionalMemory *)this, - Range<Addr>(BARAddrs[i], - BARAddrs[i] + - BARSize[i] - 1)); + params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i])); } } diff --git a/dev/pcidev.hh b/dev/pcidev.hh index c0fe47ac4..4b947b560 100644 --- a/dev/pcidev.hh +++ b/dev/pcidev.hh @@ -30,11 +30,12 @@ * Interface for devices using PCI configuration */ -#ifndef __PCI_DEV_HH__ -#define __PCI_DEV_HH__ +#ifndef __DEV_PCIDEV_HH__ +#define __DEV_PCIDEV_HH__ -#include "dev/pcireg.h" #include "dev/io_device.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" class PciConfigAll; class MemoryController; @@ -78,29 +79,43 @@ class PciConfigData : public SimObject 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; + struct Params; + Params *_params; - /** - * A pointer to the object that contains the first 64 bytes of - * config space - */ - PciConfigData *configData; + public: + struct Params + { + std::string name; + Platform *plat; + 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 bus number we are on */ + uint32_t busNum; - /** The device number we have */ - uint32_t deviceNum; + /** The device number we have */ + uint32_t deviceNum; - /** The function number */ - uint32_t functionNum; + /** The function number */ + uint32_t functionNum; + }; + const Params *params() const { return _params; } - /** The current config space. Unlike the PciConfigData this is updated - * during simulation while continues to refelect what was in the config file. + protected: + /** The current config space. Unlike the PciConfigData this is + * updated during simulation while continues to refelect what was + * in the config file. */ PCIConfig config; @@ -110,21 +125,33 @@ class PciDev : public DmaDevice /** The current address mapping of the BARs */ Addr BARAddrs[6]; + protected: + Platform *plat; + PciConfigData *configData; + + public: + Addr pciToDma(Addr pciAddr) const + { return plat->pciToDma(pciAddr); } + + void + intrPost() + { plat->postPciInt(configData->config.hdr.pci0.interruptLine); } + + void + intrClear() + { plat->clearPciInt(configData->config.hdr.pci0.interruptLine); } + + uint8_t + interruptLine() + { return configData->config.hdr.pci0.interruptLine; } + 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 + * Constructor for PCI Dev. This function copies data from the + * config file object PCIConfigData and registers the device with + * a PciConfigAll object. */ - PciDev(const std::string &name, MemoryController *mmu, PciConfigAll *cf, - PciConfigData *cd, uint32_t bus, uint32_t dev, uint32_t func); + PciDev(Params *params); virtual Fault read(MemReqPtr &req, uint8_t *data) { return No_Fault; @@ -168,4 +195,4 @@ class PciDev : public DmaDevice virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -#endif // __PCI_DEV_HH__ +#endif // __DEV_PCIDEV_HH__ diff --git a/dev/pktfifo.cc b/dev/pktfifo.cc new file mode 100644 index 000000000..ae82123cf --- /dev/null +++ b/dev/pktfifo.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2004 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 "base/misc.hh" +#include "dev/pktfifo.hh" + +using namespace std; + +void +PacketFifo::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".size", _size); + paramOut(os, base + ".maxsize", _maxsize); + paramOut(os, base + ".reserved", _reserved); + paramOut(os, base + ".packets", fifo.size()); + + int i = 0; + std::list<PacketPtr>::iterator p = fifo.begin(); + std::list<PacketPtr>::iterator end = fifo.end(); + while (p != end) { + (*p)->serialize(csprintf("%s.packet%d", base, i), os); + ++p; + ++i; + } +} + +void +PacketFifo::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".size", _size); + paramIn(cp, section, base + ".maxsize", _maxsize); + paramIn(cp, section, base + ".reserved", _reserved); + int fifosize; + paramIn(cp, section, base + ".packets", fifosize); + + fifo.clear(); + fifo.resize(fifosize); + + for (int i = 0; i < fifosize; ++i) { + PacketPtr p = new PacketData(16384); + p->unserialize(csprintf("%s.packet%d", base, i), cp, section); + fifo.push_back(p); + } +} diff --git a/dev/pktfifo.hh b/dev/pktfifo.hh new file mode 100644 index 000000000..0c237949c --- /dev/null +++ b/dev/pktfifo.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002-2004 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 __DEV_PKTFIFO_HH__ +#define __DEV_PKTFIFO_HH__ + +#include <iosfwd> +#include <list> +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +class Checkpoint; +class PacketFifo +{ + protected: + std::list<PacketPtr> fifo; + int _maxsize; + int _size; + int _reserved; + + public: + explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} + virtual ~PacketFifo() {} + + int packets() const { return fifo.size(); } + int maxsize() const { return _maxsize; } + int size() const { return _size; } + int reserved() const { return _reserved; } + int avail() const { return _maxsize - _size - _reserved; } + bool empty() const { return size() <= 0; } + bool full() const { return avail() <= 0; } + + int reserve(int len = 0) + { + _reserved += len; + assert(avail() >= 0); + return _reserved; + } + + bool push(PacketPtr ptr) + { + assert(_reserved <= ptr->length); + if (avail() < ptr->length - _reserved) + return false; + + _size += ptr->length; + fifo.push_back(ptr); + _reserved = 0; + return true; + } + + PacketPtr front() { return fifo.front(); } + + void pop() + { + if (empty()) + return; + + _size -= fifo.front()->length; + fifo.front() = NULL; + fifo.pop_front(); + } + + void clear() + { + fifo.clear(); + _size = 0; + _reserved = 0; + } + +/** + * Serialization stuff + */ + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, + Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_PKTFIFO_HH__ diff --git a/dev/platform.cc b/dev/platform.cc index 8515d543a..cf012352b 100644 --- a/dev/platform.cc +++ b/dev/platform.cc @@ -32,5 +32,23 @@ using namespace std; +void +Platform::postPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +void +Platform::clearPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +Addr +Platform::pciToDma(Addr pciAddr) const +{ + panic("No PCI dma support in platform."); +} + DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) diff --git a/dev/platform.hh b/dev/platform.hh index 7920480bc..717e49411 100644 --- a/dev/platform.hh +++ b/dev/platform.hh @@ -35,6 +35,7 @@ #define __PLATFORM_HH_ #include "sim/sim_object.hh" +#include "targetarch/isa_traits.hh" class PciConfigAll; class IntrControl; @@ -65,6 +66,9 @@ class Platform : public SimObject virtual void postConsoleInt() = 0; virtual void clearConsoleInt() = 0; virtual Tick intrFrequency() = 0; + virtual void postPciInt(int line); + virtual void clearPciInt(int line); + virtual Addr pciToDma(Addr pciAddr) const; }; #endif // __PLATFORM_HH_ diff --git a/dev/simconsole.cc b/dev/simconsole.cc index a15057402..d8d890e15 100644 --- a/dev/simconsole.cc +++ b/dev/simconsole.cc @@ -45,12 +45,11 @@ #include "base/misc.hh" #include "base/socket.hh" #include "base/trace.hh" +#include "dev/platform.hh" #include "dev/simconsole.hh" +#include "dev/uart.hh" #include "mem/functional_mem/memory_control.hh" #include "sim/builder.hh" -#include "targetarch/ev5.hh" -#include "dev/uart.hh" -#include "dev/platform.hh" using namespace std; @@ -72,27 +71,22 @@ SimConsole::Event::process(int revent) cons->detach(); } -SimConsole::SimConsole(const string &name, const string &file, int num) +SimConsole::SimConsole(const string &name, std::ostream *os, int num) : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL) + listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) #if TRACING_ON == 1 , linebuf(16384) #endif { - if (!file.empty()) - outfile = new ofstream(file.c_str()); - if (outfile) outfile->setf(ios::unitbuf); - } SimConsole::~SimConsole() { close(); - if (outfile) - delete outfile; + closeOutputStream(outfile); } void @@ -311,7 +305,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) INIT_PARAM(listener, "console listener"), INIT_PARAM(intr_control, "interrupt controller"), - INIT_PARAM_DFLT(output, "file to dump output to", ""), + INIT_PARAM(output, "file to dump output to"), INIT_PARAM_DFLT(append_name, "append name() to filename", true), INIT_PARAM_DFLT(number, "console number", 0) @@ -319,18 +313,18 @@ END_INIT_SIM_OBJECT_PARAMS(SimConsole) CREATE_SIM_OBJECT(SimConsole) { - string filename = output; - if (filename.empty()) { - if (!outputDirectory.empty()) - filename = outputDirectory + getInstanceName(); + string filename; + + if (!output.isValid()) { + filename = getInstanceName(); + } else if (append_name) { + filename = (string)output + "." + getInstanceName(); } else { - if (append_name) - filename += "." + getInstanceName(); - if (!outputDirectory.empty()) - filename = outputDirectory + filename; + filename = output; } - SimConsole *console = new SimConsole(getInstanceName(), filename, number); + SimConsole *console = new SimConsole(getInstanceName(), + makeOutputStream(filename), number); ((ConsoleListener *)listener)->add(console); return console; diff --git a/dev/simconsole.hh b/dev/simconsole.hh index 138e2e36a..c5a281834 100644 --- a/dev/simconsole.hh +++ b/dev/simconsole.hh @@ -70,7 +70,7 @@ class SimConsole : public SimObject ConsoleListener *listener; public: - SimConsole(const std::string &name, const std::string &file, int num); + SimConsole(const std::string &name, std::ostream *os, int num); ~SimConsole(); protected: diff --git a/dev/sinic.cc b/dev/sinic.cc new file mode 100644 index 000000000..56782b589 --- /dev/null +++ b/dev/sinic.cc @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 2004 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 <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/etherlink.hh" +#include "dev/sinic.hh" +#include "dev/pciconfigall.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/debug.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "targetarch/vtophys.hh" + +using namespace Net; + +namespace Sinic { + +const char *RxStateStrings[] = +{ + "rxIdle", + "rxFifoBlock", + "rxBeginCopy", + "rxCopy", + "rxCopyDone" +}; + +const char *TxStateStrings[] = +{ + "txIdle", + "txFifoBlock", + "txBeginCopy", + "txCopy", + "txCopyDone" +}; + + +/////////////////////////////////////////////////////////////////////// +// +// Sinic PCI Device +// +Base::Base(Params *p) + : PciDev(p), rxEnable(false), txEnable(false), + intrDelay(US2Ticks(p->intr_delay)), + intrTick(0), cpuIntrEnable(false), cpuPendingIntr(false), intrEvent(0), + interface(NULL) +{ +} + +Device::Device(Params *p) + : Base(p), plat(p->plat), physmem(p->physmem), + rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), + rxKickTick(0), txKickTick(0), + txEvent(this), rxDmaEvent(this), txDmaEvent(this), + dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), + dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) +{ + reset(); + + if (p->header_bus) { + pioInterface = newPioInterface(p->name, p->hier, p->header_bus, this, + &Device::cacheAccess); + + pioLatency = p->pio_latency * p->header_bus->clockRatio; + + if (p->payload_bus) + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", + p->header_bus, p->payload_bus, + 1); + else + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", + p->header_bus, p->header_bus, + 1); + } else if (p->payload_bus) { + pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this, + &Device::cacheAccess); + + pioLatency = p->pio_latency * p->payload_bus->clockRatio; + + dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus, + p->payload_bus, 1); + } +} + +Device::~Device() +{} + +void +Device::regStats() +{ + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxIpPackets + .name(name() + ".rxIpPackets") + .desc("Number of IP Packets Received") + .prereq(rxBytes) + ; + + rxTcpPackets + .name(name() + ".rxTcpPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxUdpPackets + .name(name() + ".rxUdpPackets") + .desc("Number of UDP Packets Received") + .prereq(rxBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + txIpPackets + .name(name() + ".txIpPackets") + .desc("Number of IP Packets Transmitted") + .prereq(txBytes) + ; + + txTcpPackets + .name(name() + ".txTcpPackets") + .desc("Number of TCP Packets Transmitted") + .prereq(txBytes) + ; + + txUdpPackets + .name(name() + ".txUdpPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + +/** + * This is to write to the PCI general configuration registers + */ +void +Device::WriteConfig(int offset, int size, uint32_t data) +{ + switch (offset) { + case PCI0_BASE_ADDR0: + // Need to catch writes to BARs to update the PIO interface + PciDev::WriteConfig(offset, size, data); + if (BARAddrs[0] != 0) { + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + + BARAddrs[0] &= EV5::PAddrUncachedMask; + } + break; + + default: + PciDev::WriteConfig(offset, size, data); + } +} + +/** + * This reads the device registers, which are detailed in the NS83820 + * spec sheet + */ +Fault +Device::read(MemReqPtr &req, uint8_t *data) +{ + assert(config.hdr.command & PCI_CMD_MSE); + + //The mask is to give you only the offset into the device register file + Addr daddr = req->paddr & 0xfff; + + if (Regs::regSize(daddr) == 0) + panic("invalid address: da=%#x pa=%#x va=%#x size=%d", + daddr, req->paddr, req->vaddr, req->size); + + if (req->size != Regs::regSize(daddr)) + panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + uint32_t ®32 = *(uint32_t *)data; + uint64_t ®64 = *(uint64_t *)data; + + switch (daddr) { + case Regs::Config: + reg32 = regs.Config; + break; + + case Regs::RxMaxCopy: + reg32 = regs.RxMaxCopy; + break; + + case Regs::TxMaxCopy: + reg32 = regs.TxMaxCopy; + break; + + case Regs::RxThreshold: + reg32 = regs.RxThreshold; + break; + + case Regs::TxThreshold: + reg32 = regs.TxThreshold; + break; + + case Regs::IntrStatus: + reg32 = regs.IntrStatus; + devIntrClear(); + break; + + case Regs::IntrMask: + reg32 = regs.IntrMask; + break; + + case Regs::RxData: + reg64 = regs.RxData; + break; + + case Regs::RxDone: + case Regs::RxWait: + reg64 = Regs::set_RxDone_FifoLen(regs.RxDone, + min(rxFifo.packets(), 255)); + break; + + case Regs::TxData: + reg64 = regs.TxData; + break; + + case Regs::TxDone: + case Regs::TxWait: + reg64 = Regs::set_TxDone_FifoLen(regs.TxDone, + min(txFifo.packets(), 255)); + break; + + case Regs::HwAddr: + reg64 = params()->eaddr; + break; + + default: + panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + } + + DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr), + Regs::regSize(daddr) == 4 ? reg32 : reg64); + + return No_Fault; +} + +Fault +Device::write(MemReqPtr &req, const uint8_t *data) +{ + assert(config.hdr.command & PCI_CMD_MSE); + Addr daddr = req->paddr & 0xfff; + + if (Regs::regSize(daddr) == 0) + panic("invalid address: da=%#x pa=%#x va=%#x size=%d", + daddr, req->paddr, req->vaddr, req->size); + + if (req->size != Regs::regSize(daddr)) + panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + + uint32_t reg32 = *(uint32_t *)data; + uint64_t reg64 = *(uint64_t *)data; + + DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n", + Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64, + daddr, req->paddr, req->vaddr, req->size); + + + switch (daddr) { + case Regs::Config: + changeConfig(reg32); + break; + + case Regs::RxThreshold: + regs.RxThreshold = reg32; + break; + + case Regs::TxThreshold: + regs.TxThreshold = reg32; + break; + + case Regs::IntrMask: + devIntrChangeMask(reg32); + break; + + case Regs::RxData: + if (rxState != rxIdle) + panic("receive machine busy with another request!"); + + regs.RxDone = 0; + regs.RxData = reg64; + if (rxEnable) { + rxState = rxFifoBlock; + rxKick(); + } + break; + + case Regs::TxData: + if (txState != txIdle) + panic("transmit machine busy with another request!"); + + regs.TxDone = 0; + regs.TxData = reg64; + if (txEnable) { + txState = txFifoBlock; + txKick(); + } + break; + + default: + panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d", + Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); + } + + return No_Fault; +} + +void +Device::devIntrPost(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot set a reserved interrupt"); + + regs.IntrStatus |= interrupts; + + DPRINTF(EthernetIntr, + "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if ((regs.IntrStatus & regs.IntrMask)) { + Tick when = curTick; + if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +void +Device::devIntrClear(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot clear a reserved interrupt"); + + regs.IntrStatus &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if (!(regs.IntrStatus & regs.IntrMask)) + cpuIntrClear(); +} + +void +Device::devIntrChangeMask(uint32_t newmask) +{ + if (regs.IntrMask == newmask) + return; + + regs.IntrMask = newmask; + + DPRINTF(EthernetIntr, + "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", + regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); + + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +Base::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (!cpuIntrEnable) { + DPRINTF(EthernetIntr, "interrupts not enabled.\n", + intrTick); + return; + } + + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +Base::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +Base::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); + intrClear(); +} + +bool +Base::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +Device::changeConfig(uint32_t newconf) +{ + uint32_t changed = regs.Config ^ newconf; + if (!changed) + return; + + regs.Config = newconf; + + if ((changed & Regs::Config_Reset)) { + assert(regs.Config & Regs::Config_Reset); + reset(); + regs.Config &= ~Regs::Config_Reset; + } + + if ((changed & Regs::Config_IntEn)) { + cpuIntrEnable = regs.Config & Regs::Config_IntEn; + if (cpuIntrEnable) { + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + } else { + cpuIntrClear(); + } + } + + if ((changed & Regs::Config_TxEn)) { + txEnable = regs.Config & Regs::Config_TxEn; + if (txEnable) + txKick(); + } + + if ((changed & Regs::Config_RxEn)) { + rxEnable = regs.Config & Regs::Config_RxEn; + if (rxEnable) + rxKick(); + } +} + +void +Device::reset() +{ + using namespace Regs; + memset(®s, 0, sizeof(regs)); + regs.RxMaxCopy = params()->rx_max_copy; + regs.TxMaxCopy = params()->tx_max_copy; + regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData; + + rxState = rxIdle; + txState = txIdle; + + rxFifo.clear(); + txFifo.clear(); +} + +void +Device::rxDmaCopy() +{ + assert(rxState == rxCopy); + rxState = rxCopyDone; + physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); + DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); +} + +void +Device::rxDmaDone() +{ + rxDmaCopy(); + rxKick(); +} + +void +Device::rxKick() +{ + DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n", + RxStateStrings[rxState], rxFifo.size()); + + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", + rxKickTick); + return; + } + + next: + switch (rxState) { + case rxIdle: + if (rxPioRequest) { + pioInterface->respond(rxPioRequest, curTick); + rxPioRequest = 0; + } + goto exit; + + case rxFifoBlock: + if (rxPacket) { + rxState = rxBeginCopy; + break; + } + + if (rxFifo.empty()) { + DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); + goto exit; + } + + // Grab a new packet from the fifo. + rxPacket = rxFifo.front(); + rxPacketBufPtr = rxPacket->data; + rxPktBytes = rxPacket->length; + assert(rxPktBytes); + + rxDoneData = 0; + /* scope for variables */ { + IpPtr ip(rxPacket); + if (ip) { + rxDoneData |= Regs::RxDone_IpPacket; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + rxDoneData |= Regs::RxDone_IpError; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + rxDoneData |= Regs::RxDone_TcpPacket; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + rxDoneData |= Regs::RxDone_TcpError; + } + } else if (udp) { + rxDoneData |= Regs::RxDone_UdpPacket; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + rxDoneData |= Regs::RxDone_UdpError; + } + } + } + } + rxState = rxBeginCopy; + break; + + case rxBeginCopy: + rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData)); + rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes); + rxDmaData = rxPacketBufPtr; + + if (dmaInterface) { + if (!dmaInterface->busy()) { + dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, + curTick, &rxDmaEvent, true); + rxState = rxCopy; + } + goto exit; + } + + rxState = rxCopy; + if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { + Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; + Tick start = curTick + dmaWriteDelay + factor; + rxDmaEvent.schedule(start); + goto exit; + } + + rxDmaCopy(); + break; + + case rxCopy: + DPRINTF(EthernetSM, "receive machine still copying\n"); + goto exit; + + case rxCopyDone: + regs.RxDone = rxDoneData | rxDmaLen; + + if (rxPktBytes == rxDmaLen) { + rxPacket = NULL; + rxFifo.pop(); + } else { + regs.RxDone |= Regs::RxDone_More; + rxPktBytes -= rxDmaLen; + rxPacketBufPtr += rxDmaLen; + } + + regs.RxDone |= Regs::RxDone_Complete; + devIntrPost(Regs::Intr_RxData); + rxState = rxIdle; + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + RxStateStrings[rxState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + RxStateStrings[rxState]); +} + +void +Device::txDmaCopy() +{ + assert(txState == txCopy); + txState = txCopyDone; + physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); +} + +void +Device::txDmaDone() +{ + txDmaCopy(); + txKick(); +} + +void +Device::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + PacketPtr packet = txFifo.front(); + if (!interface->sendPacket(packet)) { + DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", + txFifo.avail()); + goto reschedule; + } + + txFifo.pop(); + +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(packet); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", + tcp->sport(), tcp->dport()); + } + } + } +#endif + + DDUMP(Ethernet, packet->data, packet->length); + txBytes += packet->length; + txPackets++; + + DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", + txFifo.avail()); + + if (txFifo.size() <= params()->tx_fifo_threshold) + devIntrPost(Regs::Intr_TxFifo); + + devIntrPost(Regs::Intr_TxDone); + + reschedule: + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + 1000); + } +} + +void +Device::txKick() +{ + DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n", + TxStateStrings[txState], txFifo.size()); + + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + return; + } + + next: + switch (txState) { + case txIdle: + if (txPioRequest) { + pioInterface->respond(txPioRequest, curTick + pioLatency); + txPioRequest = 0; + } + goto exit; + + case txFifoBlock: + if (!txPacket) { + // Grab a new packet from the fifo. + txPacket = new PacketData(16384); + txPacketBufPtr = txPacket->data; + } + + if (txFifo.avail() - txPacket->length < + Regs::get_TxData_Len(regs.TxData)) { + DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); + goto exit; + } + + txState = txBeginCopy; + break; + + case txBeginCopy: + txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData)); + txDmaLen = Regs::get_TxData_Len(regs.TxData); + txDmaData = txPacketBufPtr; + + if (dmaInterface) { + if (!dmaInterface->busy()) { + dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, + curTick, &txDmaEvent, true); + txState = txCopy; + } + + goto exit; + } + + txState = txCopy; + if (dmaReadDelay != 0 || dmaReadFactor != 0) { + Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; + Tick start = curTick + dmaReadDelay + factor; + txDmaEvent.schedule(start); + goto exit; + } + + txDmaCopy(); + break; + + case txCopy: + DPRINTF(EthernetSM, "transmit machine still copying\n"); + goto exit; + + case txCopyDone: + txPacket->length += txDmaLen; + if ((regs.TxData & Regs::TxData_More)) { + txPacketBufPtr += txDmaLen; + } else { + assert(txPacket->length <= txFifo.avail()); + if ((regs.TxData & Regs::TxData_Checksum)) { + IpPtr ip(txPacket); + if (ip) { + TcpPtr tcp(ip); + if (tcp) { + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + + UdpPtr udp(ip); + if (udp) { + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } + + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + txFifo.push(txPacket); + txPacket = 0; + transmit(); + } + + regs.TxDone = txDmaLen | Regs::TxDone_Complete; + devIntrPost(Regs::Intr_TxData); + txState = txIdle; + break; + + default: + panic("Invalid txState!"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + TxStateStrings[txState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + TxStateStrings[txState]); +} + +void +Device::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + 1); + else + txEvent.schedule(curTick + 1); +} + +bool +Device::rxFilter(const PacketPtr &packet) +{ + if (!Regs::get_Config_Filter(regs.Config)) + return false; + + panic("receive filter not implemented\n"); + bool drop = true; + +#if 0 + string type; + + EthHdr *eth = packet->eth(); + if (eth->unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && params->eaddr == eth.dst()) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (eth->broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (eth->multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } +#endif + return drop; +} + +bool +Device::recvPacket(PacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + interface->recvDone(); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + interface->recvDone(); + return true; + } + + if (rxFifo.size() >= params()->rx_fifo_threshold) + devIntrPost(Regs::Intr_RxFifo); + + if (!rxFifo.push(packet)) { + DPRINTF(Ethernet, + "packet will not fit in receive buffer...packet dropped\n"); + return false; + } + + interface->recvDone(); + devIntrPost(Regs::Intr_RxDone); + rxKick(); + return true; +} + +//===================================================================== +// +// +void +Base::serialize(ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); +} + +void +Base::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(cpuIntrEnable); + + /* + * 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); + } +} + +void +Device::serialize(ostream &os) +{ + // Serialize the PciDev base class + Base::serialize(os); + + if (rxDmaEvent.scheduled()) + rxDmaCopy(); + + if (txDmaEvent.scheduled()) + txDmaCopy(); + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.Config); + SERIALIZE_SCALAR(regs.RxMaxCopy); + SERIALIZE_SCALAR(regs.TxMaxCopy); + SERIALIZE_SCALAR(regs.RxThreshold); + SERIALIZE_SCALAR(regs.TxThreshold); + SERIALIZE_SCALAR(regs.IntrStatus); + SERIALIZE_SCALAR(regs.IntrMask); + SERIALIZE_SCALAR(regs.RxData); + SERIALIZE_SCALAR(regs.RxDone); + SERIALIZE_SCALAR(regs.TxData); + SERIALIZE_SCALAR(regs.TxDone); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + rxFifo.serialize("rxFifo", os); + bool rxPacketExists = rxPacket; + SERIALIZE_SCALAR(rxPacketExists); + if (rxPacketExists) { + rxPacket->serialize("rxPacket", os); + uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); + SERIALIZE_SCALAR(rxPktBufPtr); + SERIALIZE_SCALAR(rxPktBytes); + } + SERIALIZE_SCALAR(rxDoneData); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + txFifo.serialize("txFifo", os); + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->serialize("txPacket", os); + uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); + SERIALIZE_SCALAR(txPktBufPtr); + SERIALIZE_SCALAR(txPktBytes); + } + + /* + * 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); +} + +void +Device::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + Base::unserialize(cp, section); + + /* + * Unserialize the device registers + */ + UNSERIALIZE_SCALAR(regs.Config); + UNSERIALIZE_SCALAR(regs.RxMaxCopy); + UNSERIALIZE_SCALAR(regs.TxMaxCopy); + UNSERIALIZE_SCALAR(regs.RxThreshold); + UNSERIALIZE_SCALAR(regs.TxThreshold); + UNSERIALIZE_SCALAR(regs.IntrStatus); + UNSERIALIZE_SCALAR(regs.IntrMask); + UNSERIALIZE_SCALAR(regs.RxData); + UNSERIALIZE_SCALAR(regs.RxDone); + UNSERIALIZE_SCALAR(regs.TxData); + UNSERIALIZE_SCALAR(regs.TxDone); + + /* + * Unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + this->rxState = (RxState) rxState; + rxFifo.unserialize("rxFifo", cp, section); + bool rxPacketExists; + UNSERIALIZE_SCALAR(rxPacketExists); + rxPacket = 0; + if (rxPacketExists) { + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); + uint32_t rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBufPtr); + this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBytes); + } + UNSERIALIZE_SCALAR(rxDoneData); + + /* + * Unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + this->txState = (TxState) txState; + txFifo.unserialize("txFifo", cp, section); + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + txPacket = 0; + if (txPacketExists) { + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); + uint32_t txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBufPtr); + this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBytes); + } + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + /* + * re-add addrRanges to bus bridges + */ + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); +} + +Tick +Device::cacheAccess(MemReqPtr &req) +{ + //The mask is to give you only the offset into the device register file + Addr daddr = req->paddr - addr; + + DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", + req->paddr, daddr); + + Tick when = curTick + pioLatency; + + switch (daddr) { + case Regs::RxDone: + if (rxState != rxIdle) { + rxPioRequest = req; + when = 0; + } + break; + + case Regs::TxDone: + if (txState != txIdle) { + txPioRequest = req; + when = 0; + } + break; + } + + return when; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<Device *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(Interface) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(Interface) + +CREATE_SIM_OBJECT(Interface) +{ + Interface *dev_int = new Interface(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("SinicInt", Interface) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) + + Param<Tick> tx_delay; + Param<Tick> rx_delay; + Param<Tick> intr_delay; + SimObjectParam<MemoryController *> mmu; + SimObjectParam<PhysicalMemory *> physmem; + Param<bool> rx_filter; + Param<string> hardware_address; + SimObjectParam<Bus*> header_bus; + SimObjectParam<Bus*> payload_bus; + SimObjectParam<HierParams *> hier; + Param<Tick> pio_latency; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + SimObjectParam<Platform *> platform; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<uint32_t> rx_max_copy; + Param<uint32_t> tx_max_copy; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + Param<uint32_t> rx_fifo_threshold; + Param<uint32_t> tx_fifo_threshold; + Param<Tick> dma_read_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_delay; + Param<Tick> dma_write_factor; + +END_DECLARE_SIM_OBJECT_PARAMS(Device) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Device) + + INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), + INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), + INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(physmem, "Physical Memory"), + 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 in bus cycles", 1), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(platform, "Platform"), + INIT_PARAM(pci_bus, "PCI bus"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024), + INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024), + INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024), + INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024), + INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024), + INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024), + INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), + INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), + INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), + INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0) + +END_INIT_SIM_OBJECT_PARAMS(Device) + + +CREATE_SIM_OBJECT(Device) +{ + Device::Params *params = new Device::Params; + params->name = getInstanceName(); + params->intr_delay = intr_delay; + params->physmem = physmem; + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->mmu = mmu; + params->hier = hier; + params->header_bus = header_bus; + params->payload_bus = payload_bus; + params->pio_latency = pio_latency; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_max_copy = rx_max_copy; + params->tx_max_copy = tx_max_copy; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_threshold = rx_fifo_threshold; + params->tx_fifo_threshold = tx_fifo_threshold; + params->dma_read_delay = dma_read_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_delay = dma_write_delay; + params->dma_write_factor = dma_write_factor; + return new Device(params); +} + +REGISTER_SIM_OBJECT("Sinic", Device) + +/* namespace Sinic */ } diff --git a/dev/sinic.hh b/dev/sinic.hh new file mode 100644 index 000000000..ef515ffad --- /dev/null +++ b/dev/sinic.hh @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2004 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 __DEV_SINIC_HH__ +#define __DEV_SINIC_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "dev/sinicreg.hh" +#include "mem/bus/bus.hh" +#include "sim/eventq.hh" + +namespace Sinic { + +class Interface; +class Base : public PciDev +{ + protected: + bool rxEnable; + bool txEnable; + + protected: + Tick intrDelay; + Tick intrTick; + bool cpuIntrEnable; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; + friend class IntrEvent; + IntrEvent *intrEvent; + Interface *interface; + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public PciDev::Params + { + Tick intr_delay; + }; + + Base(Params *p); +}; + +class Device : public Base +{ + protected: + Platform *plat; + PhysicalMemory *physmem; + + protected: + /** Receive State Machine States */ + enum RxState { + rxIdle, + rxFifoBlock, + rxBeginCopy, + rxCopy, + rxCopyDone + }; + + /** Transmit State Machine states */ + enum TxState { + txIdle, + txFifoBlock, + txBeginCopy, + txCopy, + txCopyDone + }; + + /** device register file */ + struct { + uint32_t Config; + uint32_t RxMaxCopy; + uint32_t TxMaxCopy; + uint32_t RxThreshold; + uint32_t TxThreshold; + uint32_t IntrStatus; + uint32_t IntrMask; + uint64_t RxData; + uint64_t RxDone; + uint64_t TxData; + uint64_t TxDone; + } regs; + + private: + Addr addr; + static const Addr size = Regs::Size; + + protected: + RxState rxState; + PacketFifo rxFifo; + PacketPtr rxPacket; + uint8_t *rxPacketBufPtr; + int rxPktBytes; + uint64_t rxDoneData; + Addr rxDmaAddr; + uint8_t *rxDmaData; + int rxDmaLen; + + TxState txState; + PacketFifo txFifo; + PacketPtr txPacket; + uint8_t *txPacketBufPtr; + int txPktBytes; + Addr txDmaAddr; + uint8_t *txDmaData; + int txDmaLen; + + protected: + void reset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; + friend class RxKickEvent; + + void txKick(); + Tick txKickTick; + typedef EventWrapper<Device, &Device::txKick> TxKickEvent; + friend class TxKickEvent; + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; + friend class TxEvent; + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilter(const PacketPtr &packet); + +/** + * device configuration + */ + void changeConfig(uint32_t newconfig); + +/** + * device ethernet interface + */ + public: + bool recvPacket(PacketPtr packet); + void transferDone(); + void setInterface(Interface *i) { assert(!interface); interface = i; } + +/** + * DMA parameters + */ + protected: + void rxDmaCopy(); + void rxDmaDone(); + friend class EventWrapper<Device, &Device::rxDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; + + void txDmaCopy(); + void txDmaDone(); + friend class EventWrapper<Device, &Device::txDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> txDmaEvent; + + Tick dmaReadDelay; + Tick dmaReadFactor; + Tick dmaWriteDelay; + Tick dmaWriteFactor; + +/** + * PIO parameters + */ + protected: + MemReqPtr rxPioRequest; + MemReqPtr txPioRequest; + +/** + * Interrupt management + */ + protected: + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts = Regs::Intr_All); + void devIntrChangeMask(uint32_t newmask); + +/** + * PCI Configuration interface + */ + public: + virtual void WriteConfig(int offset, int size, uint32_t data); + +/** + * Memory Interface + */ + public: + virtual Fault read(MemReqPtr &req, uint8_t *data); + virtual Fault write(MemReqPtr &req, const uint8_t *data); + Tick cacheAccess(MemReqPtr &req); + +/** + * Statistics + */ + private: + Stats::Scalar<> rxBytes; + Stats::Formula rxBandwidth; + Stats::Scalar<> rxPackets; + Stats::Formula rxPacketRate; + Stats::Scalar<> rxIpPackets; + Stats::Scalar<> rxTcpPackets; + Stats::Scalar<> rxUdpPackets; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> rxUdpChecksums; + + Stats::Scalar<> txBytes; + Stats::Formula txBandwidth; + Stats::Scalar<> txPackets; + Stats::Formula txPacketRate; + Stats::Scalar<> txIpPackets; + Stats::Scalar<> txTcpPackets; + Stats::Scalar<> txUdpPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> txUdpChecksums; + + public: + virtual void regStats(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public Base::Params + { + IntrControl *i; + PhysicalMemory *pmem; + Tick tx_delay; + Tick rx_delay; + HierParams *hier; + Bus *header_bus; + Bus *payload_bus; + Tick pio_latency; + PhysicalMemory *physmem; + IntrControl *intctrl; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t rx_max_copy; + uint32_t tx_max_copy; + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; + uint32_t rx_fifo_threshold; + uint32_t tx_fifo_threshold; + Tick dma_read_delay; + Tick dma_read_factor; + Tick dma_write_delay; + Tick dma_write_factor; + }; + + protected: + const Params *params() const { return (const Params *)_params; } + + public: + Device(Params *params); + ~Device(); +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class Interface : public EtherInt +{ + private: + Device *dev; + + public: + Interface(const std::string &name, Device *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +/* namespace Sinic */ } + +#endif // __DEV_SINIC_HH__ diff --git a/dev/sinicreg.hh b/dev/sinicreg.hh new file mode 100644 index 000000000..9f3412a31 --- /dev/null +++ b/dev/sinicreg.hh @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2004 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 __DEV_SINICREG_HH__ +#define __DEV_SINICREG_HH__ + +#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL) +#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL) + +#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \ + static const uint32_t NAME##_width = WIDTH; \ + static const uint32_t NAME##_offset = OFFSET; \ + static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \ + static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \ + static inline uint32_t get_##NAME(uint32_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \ + static const uint64_t NAME##_width = WIDTH; \ + static const uint64_t NAME##_offset = OFFSET; \ + static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \ + static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ + static inline uint64_t get_##NAME(uint64_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +namespace Sinic { +namespace Regs { + +// Registers +__SINIC_REG32(Config, 0x00); // 32: configuration register +__SINIC_REG32(RxMaxCopy, 0x04); // 32: max rx copy +__SINIC_REG32(TxMaxCopy, 0x08); // 32: max tx copy +__SINIC_REG32(RxThreshold, 0x0c); // 32: receive fifo threshold +__SINIC_REG32(TxThreshold, 0x10); // 32: transmit fifo threshold +__SINIC_REG32(IntrStatus, 0x14); // 32: interrupt status +__SINIC_REG32(IntrMask, 0x18); // 32: interrupt mask +__SINIC_REG32(RxData, 0x20); // 64: receive data +__SINIC_REG32(RxDone, 0x28); // 64: receive done +__SINIC_REG32(RxWait, 0x30); // 64: receive done (busy wait) +__SINIC_REG32(TxData, 0x38); // 64: transmit data +__SINIC_REG32(TxDone, 0x40); // 64: transmit done +__SINIC_REG32(TxWait, 0x48); // 64: transmit done (busy wait) +__SINIC_REG32(HwAddr, 0x50); // 64: mac address +__SINIC_REG32(Size, 0x58); + +// Config register bits +__SINIC_VAL32(Config_Reset, 31, 1); // reset chip +__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter +__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging +__SINIC_VAL32(Config_Virtual, 5, 1); // enable virtual addressing +__SINIC_VAL32(Config_Desc, 4, 1); // enable tx/rx descriptors +__SINIC_VAL32(Config_Poll, 3, 1); // enable polling +__SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts +__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit +__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive + +// Interrupt register bits +__SINIC_VAL32(Intr_TxFifo, 5, 1); // Fifo oflow/uflow/threshold +__SINIC_VAL32(Intr_TxData, 4, 1); // DMA Completed w/ interrupt +__SINIC_VAL32(Intr_TxDone, 3, 1); // Packet transmitted +__SINIC_VAL32(Intr_RxFifo, 2, 1); // Fifo oflow/uflow/threshold +__SINIC_VAL32(Intr_RxData, 1, 1); // DMA Completed w/ interrupt +__SINIC_VAL32(Intr_RxDone, 0, 1); // Packet received +__SINIC_REG32(Intr_All, 0x3f); +__SINIC_REG32(Intr_NoDelay, 0x24); +__SINIC_REG32(Intr_Res, ~0x3f); + +// RX Data Description +__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 1M +__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB + +// TX Data Description +__SINIC_VAL64(TxData_More, 63, 1); +__SINIC_VAL64(TxData_Checksum, 62, 1); +__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 1M +__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB + +// RX Done/Busy Information +__SINIC_VAL64(RxDone_Complete, 63, 1); +__SINIC_VAL64(RxDone_IpPacket, 45, 1); +__SINIC_VAL64(RxDone_TcpPacket, 44, 1); +__SINIC_VAL64(RxDone_UdpPacket, 43, 1); +__SINIC_VAL64(RxDone_IpError, 42, 1); +__SINIC_VAL64(RxDone_TcpError, 41, 1); +__SINIC_VAL64(RxDone_UdpError, 40, 1); +__SINIC_VAL64(RxDone_More, 32, 1); +__SINIC_VAL64(RxDone_FifoLen, 20, 8); // up to 255 packets +__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k + +// TX Done/Busy Information +__SINIC_VAL64(TxDone_Complete, 63, 1); +__SINIC_VAL64(TxDone_FifoLen, 20, 8); // up to 255 packets +__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k + +inline int +regSize(int offset) +{ + static const char sizes[] = { + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0, + 8, 0 + }; + + if (offset & 0x3) + return 0; + + if (offset >= Size) + return 0; + + return sizes[offset / 4]; +} + +inline const char * +regName(int offset) +{ + static const char *names[] = { + "Config", + "RxMaxCopy", + "TxMaxCopy", + "RxThreshold", + "TxThreshold", + "IntrStatus", + "IntrMask", + "invalid", + "RxData", "invalid", + "RxDone", "invalid", + "RxWait", "invalid", + "TxData", "invalid", + "TxDone", "invalid", + "TxWait", "invalid", + "HwAddr", "invalid" + }; + + if (offset & 0x3) + return "invalid"; + + if (offset >= Size) + return "invalid"; + + return names[offset / 4]; +} + +/* namespace Regs */ } +/* namespace Sinic */ } + +#endif // __DEV_SINICREG_HH__ diff --git a/dev/tsunami.cc b/dev/tsunami.cc index c44da69b7..f98254354 100644 --- a/dev/tsunami.cc +++ b/dev/tsunami.cc @@ -75,6 +75,24 @@ Tsunami::clearConsoleInt() } void +Tsunami::postPciInt(int line) +{ + cchip->postDRIR(line); +} + +void +Tsunami::clearPciInt(int line) +{ + cchip->clearDRIR(line); +} + +Addr +Tsunami::pciToDma(Addr pciAddr) const +{ + return pchip->translatePciToDma(pciAddr); +} + +void Tsunami::serialize(std::ostream &os) { SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); diff --git a/dev/tsunami.hh b/dev/tsunami.hh index db266d62d..d7c549e90 100644 --- a/dev/tsunami.hh +++ b/dev/tsunami.hh @@ -58,16 +58,13 @@ class Tsunami : public Platform public: /** Max number of CPUs in a Tsunami */ - static const int Max_CPUs = 4; + static const int Max_CPUs = 64; /** Pointer to the system */ System *system; + /** Pointer to the TsunamiIO device which has the RTC */ TsunamiIO *io; - /** Pointer to the 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 @@ -112,6 +109,18 @@ class Tsunami : public Platform virtual void clearConsoleInt(); /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + virtual Addr pciToDma(Addr pciAddr) const; + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc index 870924a2f..a1f900153 100644 --- a/dev/tsunami_cchip.cc +++ b/dev/tsunami_cchip.cc @@ -53,25 +53,24 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, Tick pio_latency) : PioDevice(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; - } + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiCChip::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } drir = 0; - misc = 0; + ipint = 0; + itint = 0; + + for (int x = 0; x < Tsunami::Max_CPUs; x++) + { + dim[x] = 0; + dir[x] = 0; + } //Put back pointer in tsunami tsunami->cchip = this; @@ -80,16 +79,29 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, Fault TsunamiCChip::read(MemReqPtr &req, uint8_t *data) { - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); + DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); + + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; ExecContext *xc = req->xc; switch (req->size) { case sizeof(uint64_t): - switch(daddr) { + if (daddr & TSDEV_CC_BDIMS) + { + *(uint64_t*)data = dim[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + if (daddr & TSDEV_CC_BDIRS) + { + *(uint64_t*)data = dir[(daddr >> 4) & 0x3F]; + return No_Fault; + } + + switch(regnum) { case TSDEV_CC_CSR: *(uint64_t*)data = 0x0; return No_Fault; @@ -97,7 +109,9 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) panic("TSDEV_CC_MTR not implemeted\n"); return No_Fault; case TSDEV_CC_MISC: - *(uint64_t*)data = misc | (xc->cpu_id & 0x3); + *(uint64_t*)data = (ipint << 8) & 0xF | + (itint << 4) & 0xF | + (xc->cpu_id & 0x3); return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: @@ -147,6 +161,12 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx not implemented\n"); return No_Fault; + case TSDEV_CC_IPIR: + *(uint64_t*)data = ipint; + return No_Fault; + case TSDEV_CC_ITIR: + *(uint64_t*)data = itint; + return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); } // uint64_t @@ -158,7 +178,7 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data) default: panic("invalid access size(?) for tsunami register!\n"); } - DPRINTFN("Tsunami CChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); + DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); return No_Fault; } @@ -169,73 +189,95 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", req->vaddr, *(uint64_t*)data, req->size); - Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); + Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 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: + if (daddr & TSDEV_CC_BDIMS) + { + int number = (daddr >> 4) & 0x3F; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = *(uint64_t*)data; + dir[number] = dim[number] & drir; + for(int x = 0; x < Tsunami::Max_CPUs; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in posting dir" + " interrupt to cpu %d\n", number); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", number); + + } + + + } + } + return No_Fault; + } + + switch(regnum) { + 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); - } - } + ipreq = (*(uint64_t*)data >> 12) & 0xF; + //If it is bit 12-15, this is an IPI post + if (ipreq) { + reqIPI(ipreq); supportedWrite = true; } - //If it is bits 8-11, then clearing IPI's + + //If it is bit 8-11, this is an IPI clear 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); - } - } + ipintr = (*(uint64_t*)data >> 8) & 0xF; + if (ipintr) { + clearIPI(ipintr); + supportedWrite = true; + } + + //If it is the 4-7th bit, clear the RTC interrupt + uint64_t itintr; + itintr = (*(uint64_t*)data >> 4) & 0xF; + if (itintr) { + clearITI(itintr); supportedWrite = true; } - // ignore NXMs - if (*(uint64_t*)data & 0x10000000) - supportedWrite = true; + // ignore NXMs + if (*(uint64_t*)data & 0x10000000) + supportedWrite = true; + + if(!supportedWrite) + panic("TSDEV_CC_MISC write not implemented\n"); - if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n"); return No_Fault; case TSDEV_CC_AAR0: case TSDEV_CC_AAR1: @@ -248,11 +290,11 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) case TSDEV_CC_DIM2: case TSDEV_CC_DIM3: int number; - if(daddr == TSDEV_CC_DIM0) + if(regnum == TSDEV_CC_DIM0) number = 0; - else if(daddr == TSDEV_CC_DIM1) + else if(regnum == TSDEV_CC_DIM1) number = 1; - else if(daddr == TSDEV_CC_DIM2) + else if(regnum == TSDEV_CC_DIM2) number = 2; else number = 3; @@ -267,7 +309,7 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) dir[number] = dim[number] & drir; for(int x = 0; x < 64; x++) { - bitvector = (uint64_t)1 << x; + bitvector = ULL(1) << x; // Figure out which bits have changed if ((dim[number] & bitvector) != (olddim & bitvector)) { @@ -284,7 +326,8 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) // 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"); + " dir interrupt to cpu %d\n", + x); } @@ -311,6 +354,15 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) case TSDEV_CC_MPR2: case TSDEV_CC_MPR3: panic("TSDEV_CC_MPRx write not implemented\n"); + case TSDEV_CC_IPIR: + clearIPI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_ITIR: + clearITI(*(uint64_t*)data); + return No_Fault; + case TSDEV_CC_IPIQ: + reqIPI(*(uint64_t*)data); + return No_Fault; default: panic("default in cchip read reached, accessing 0x%x\n"); } @@ -329,14 +381,88 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) } void +TsunamiCChip::clearIPI(uint64_t ipintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipintr) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipintr & cpumask) { + // Check if there is a pending ipi + if (ipint & cpumask) { + ipint &= ~cpumask; + tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); + } + else + warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); + } + } + } + else + panic("Big IPI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::clearITI(uint64_t itintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (itintr) { + for (int i=0; i < numcpus; i++) { + uint64_t cpumask = ULL(1) << i; + if (itintr & cpumask & itint) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); + itint &= ~cpumask; + DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); + } + } + } + else + panic("Big ITI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::reqIPI(uint64_t ipreq) +{ + int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipreq) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipreq & cpumask) { + // Check if there is already an ipi (bits 8:11) + if (!(ipint & cpumask)) { + ipint |= cpumask; + tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); + } + else + warn("post IPI for CPU=%d, but IPI already\n", cpunum); + } + } + } + else + panic("Big IPI Request, but not processors indicated\n"); +} + + +void TsunamiCChip::postRTC() { int size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); for (int i = 0; i < size; i++) { - if (!RTCInterrupting[i]) { - misc |= 16 << i; - RTCInterrupting[i] = true; + uint64_t cpumask = ULL(1) << i; + if (!(cpumask & itint)) { + itint |= cpumask; tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); } @@ -347,9 +473,11 @@ TsunamiCChip::postRTC() void TsunamiCChip::postDRIR(uint32_t interrupt) { - uint64_t bitvector = (uint64_t)0x1 << interrupt; - drir |= bitvector; + uint64_t bitvector = ULL(1) << interrupt; uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + drir |= bitvector; + for(int i=0; i < size; i++) { dir[i] = dim[i] & drir; if (dim[i] & bitvector) { @@ -363,8 +491,10 @@ TsunamiCChip::postDRIR(uint32_t interrupt) void TsunamiCChip::clearDRIR(uint32_t interrupt) { - uint64_t bitvector = (uint64_t)0x1 << interrupt; + uint64_t bitvector = ULL(1) << interrupt; uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); + assert(size <= Tsunami::Max_CPUs); + if (drir & bitvector) { drir &= ~bitvector; @@ -394,11 +524,9 @@ 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(ipint); + SERIALIZE_SCALAR(itint); SERIALIZE_SCALAR(drir); - SERIALIZE_SCALAR(misc); - SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs); } void @@ -406,11 +534,9 @@ TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) { 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(ipint); + UNSERIALIZE_SCALAR(itint); UNSERIALIZE_SCALAR(drir); - UNSERIALIZE_SCALAR(misc); - UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) diff --git a/dev/tsunami_cchip.hh b/dev/tsunami_cchip.hh index 3269cf53a..05fafa782 100644 --- a/dev/tsunami_cchip.hh +++ b/dev/tsunami_cchip.hh @@ -47,7 +47,7 @@ class TsunamiCChip : public PioDevice Addr addr; /** The size of mappad from the above address */ - static const Addr size = 0xfff; + static const Addr size = 0xfffffff; protected: /** @@ -68,7 +68,6 @@ class TsunamiCChip : public PioDevice * 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 @@ -76,17 +75,11 @@ class TsunamiCChip : public PioDevice */ 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; + /** Indicator of which CPUs have an IPI interrupt */ + uint64_t ipint; - /** 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]; + /** Indicator of which CPUs have an RTC interrupt */ + uint64_t itint; public: /** @@ -138,6 +131,25 @@ class TsunamiCChip : public PioDevice void clearDRIR(uint32_t interrupt); /** + * post an ipi interrupt to the CPU. + * @param ipintr the cpu number to clear(bitvector) + */ + void clearIPI(uint64_t ipintr); + + /** + * clear a timer interrupt previously posted to the CPU. + * @param interrupt the cpu number to clear(bitvector) + */ + void clearITI(uint64_t itintr); + + /** + * request an interrupt be posted to the CPU. + * @param ipreq the cpu number to interrupt(bitvector) + */ + void reqIPI(uint64_t ipreq); + + + /** * Serialize this object to the given output stream. * @param os The stream to serialize to. */ diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc index 105e3b5b7..51ff8b81c 100644 --- a/dev/tsunami_io.cc +++ b/dev/tsunami_io.cc @@ -164,12 +164,12 @@ TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, Tick pio_latency) : PioDevice(name), addr(a), tsunami(t), rtc(t) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiIO::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -196,7 +196,7 @@ 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)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); switch(req->size) { @@ -298,7 +298,7 @@ TsunamiIO::write(MemReqPtr &req, const uint8_t *data) 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)); + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); switch(req->size) { case sizeof(uint8_t): diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc index 89940fb5a..9af19d930 100644 --- a/dev/tsunami_pchip.cc +++ b/dev/tsunami_pchip.cc @@ -53,7 +53,7 @@ TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, Bus *bus, Tick pio_latency) : PioDevice(name), addr(a), tsunami(t) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); for (int i = 0; i < 4; i++) { wsba[i] = 0; @@ -64,7 +64,7 @@ TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &TsunamiPChip::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -82,7 +82,7 @@ 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; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; switch (req->size) { @@ -171,7 +171,7 @@ 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; + Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; switch (req->size) { diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h index 876c6bf18..3304082a5 100644 --- a/dev/tsunamireg.h +++ b/dev/tsunamireg.h @@ -60,6 +60,13 @@ #define TSDEV_CC_IIC2 0x1C #define TSDEV_CC_IIC3 0x1D +// BigTsunami Registers +#define TSDEV_CC_BDIMS 0x1000000 +#define TSDEV_CC_BDIRS 0x2000000 +#define TSDEV_CC_IPIQ 0x20 //0xf01a000800 +#define TSDEV_CC_IPIR 0x21 //0xf01a000840 +#define TSDEV_CC_ITIR 0x22 //0xf01a000880 + // PChip Registers #define TSDEV_PC_WSBA0 0x00 diff --git a/dev/uart.cc b/dev/uart.cc index fca856d5d..2ff94dda5 100644 --- a/dev/uart.cc +++ b/dev/uart.cc @@ -44,7 +44,6 @@ #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; @@ -92,13 +91,13 @@ Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, : PioDevice(name), addr(a), size(s), cons(c), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT), platform(p) { - mmu->add_child(this, Range<Addr>(addr, addr + size)); + mmu->add_child(this, RangeSize(addr, size)); if (bus) { pioInterface = newPioInterface(name, hier, bus, this, &Uart::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); + pioInterface->addAddrRange(RangeSize(addr, size)); pioLatency = pio_latency * bus->clockRatio; } @@ -118,7 +117,7 @@ Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, Fault Uart::read(MemReqPtr &req, uint8_t *data) { - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); DPRINTF(Uart, " read register %#x\n", daddr); @@ -246,7 +245,7 @@ Uart::read(MemReqPtr &req, uint8_t *data) Fault Uart::write(MemReqPtr &req, const uint8_t *data) { - Addr daddr = req->paddr - (addr & PA_IMPL_MASK); + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); @@ -287,7 +286,7 @@ Uart::write(MemReqPtr &req, const uint8_t *data) switch (daddr) { case 0x0: if (!(LCR & 0x80)) { // write byte - cons->out(*(uint64_t *)data); + cons->out(*(uint8_t *)data); platform->clearConsoleInt(); status &= ~TX_INT; if (UART_IER_THRI & IER) diff --git a/kern/kernel_stats.cc b/kern/kernel_stats.cc index e6bcb4d29..ed0b613ff 100644 --- a/kern/kernel_stats.cc +++ b/kern/kernel_stats.cc @@ -30,134 +30,84 @@ #include <stack> #include <string> -#include "base/statistics.hh" +#include "arch/alpha/osfpal.hh" #include "base/trace.hh" +#include "base/statistics.hh" +#include "base/stats/bin.hh" #include "cpu/exec_context.hh" +#include "cpu/pc_event.hh" +#include "cpu/static_inst.hh" #include "kern/kernel_stats.hh" -#include "sim/stats.hh" -#include "sim/sw_context.hh" -#include "targetarch/isa_traits.hh" -#include "targetarch/osfpal.hh" -#include "targetarch/syscalls.hh" +#include "kern/linux/linux_syscalls.hh" +#include "kern/tru64/tru64_syscalls.hh" using namespace std; using namespace Stats; -class KSData -{ - private: - string _name; - ExecContext *xc; - BaseCPU *cpu; - - public: - KSData(ExecContext *_xc, BaseCPU *_cpu) - : xc(_xc), cpu(_cpu), iplLast(0), iplLastTick(0), lastUser(false), - lastModeTick(0) - {} - - const string &name() { return _name; } - void regStats(const string &name); - - public: - Scalar<> _arm; - Scalar<> _quiesce; - Scalar<> _ivlb; - Scalar<> _ivle; - Scalar<> _hwrei; - - Vector<> _iplCount; - Vector<> _iplGood; - Vector<> _iplTicks; - Formula _iplUsed; - - Vector<> _callpal; - Vector<> _syscall; - Vector<> _faults; - - Vector<> _mode; - Vector<> _modeGood; - Formula _modeFraction; - Vector<> _modeTicks; - - Scalar<> _swap_context; - - private: - int iplLast; - Tick iplLastTick; - - bool lastUser; - Tick lastModeTick; - - public: - void swpipl(int ipl); - void mode(bool user); - void callpal(int code); -}; - -KernelStats::KernelStats(ExecContext *xc, BaseCPU *cpu) -{ data = new KSData(xc, cpu); } - -KernelStats::~KernelStats() -{ delete data; } +namespace Kernel { -void -KernelStats::regStats(const string &name) -{ data->regStats(name); } +const char *modestr[] = { "kernel", "user", "idle", "interrupt" }; + +Statistics::Statistics(ExecContext *context) + : xc(context), idleProcess((Addr)-1), themode(kernel), lastModeTick(0), + iplLast(0), iplLastTick(0) +{ + bin_int = xc->system->params->bin_int; +} void -KSData::regStats(const string &name) +Statistics::regStats(const string &_name) { - _name = name; + myname = _name; _arm - .name(name + ".inst.arm") + .name(name() + ".inst.arm") .desc("number of arm instructions executed") ; _quiesce - .name(name + ".inst.quiesce") + .name(name() + ".inst.quiesce") .desc("number of quiesce instructions executed") ; _ivlb - .name(name + ".inst.ivlb") + .name(name() + ".inst.ivlb") .desc("number of ivlb instructions executed") ; _ivle - .name(name + ".inst.ivle") + .name(name() + ".inst.ivle") .desc("number of ivle instructions executed") ; _hwrei - .name(name + ".inst.hwrei") + .name(name() + ".inst.hwrei") .desc("number of hwrei instructions executed") ; _iplCount .init(32) - .name(name + ".ipl_count") + .name(name() + ".ipl_count") .desc("number of times we switched to this ipl") .flags(total | pdf | nozero | nonan) ; _iplGood .init(32) - .name(name + ".ipl_good") + .name(name() + ".ipl_good") .desc("number of times we switched to this ipl from a different ipl") .flags(total | pdf | nozero | nonan) ; _iplTicks .init(32) - .name(name + ".ipl_ticks") + .name(name() + ".ipl_ticks") .desc("number of cycles we spent at this ipl") .flags(total | pdf | nozero | nonan) ; _iplUsed - .name(name + ".ipl_used") + .name(name() + ".ipl_used") .desc("fraction of swpipl calls that actually changed the ipl") .flags(total | nozero | nonan) ; @@ -166,7 +116,7 @@ KSData::regStats(const string &name) _callpal .init(256) - .name(name + ".callpal") + .name(name() + ".callpal") .desc("number of callpals executed") .flags(total | pdf | nozero | nonan) ; @@ -179,7 +129,7 @@ KSData::regStats(const string &name) _syscall .init(SystemCalls<Tru64>::Number) - .name(name + ".syscall") + .name(name() + ".syscall") .desc("number of syscalls executed") .flags(total | pdf | nozero | nonan) ; @@ -193,7 +143,7 @@ KSData::regStats(const string &name) _faults .init(Num_Faults) - .name(name + ".faults") + .name(name() + ".faults") .desc("number of faults") .flags(total | pdf | nozero | nonan) ; @@ -205,85 +155,79 @@ KSData::regStats(const string &name) } _mode - .init(2) - .name(name + ".mode_switch") - .subname(0, "kernel") - .subname(1, "user") + .init(cpu_mode_num) + .name(name() + ".mode_switch") .desc("number of protection mode switches") ; + for (int i = 0; i < cpu_mode_num; ++i) + _mode.subname(i, modestr[i]); + _modeGood - .init(2) - .name(name + ".mode_good") + .init(cpu_mode_num) + .name(name() + ".mode_good") ; + for (int i = 0; i < cpu_mode_num; ++i) + _modeGood.subname(i, modestr[i]); + _modeFraction - .name(name + ".mode_switch_good") - .subname(0, "kernel") - .subname(1, "user") + .name(name() + ".mode_switch_good") .desc("fraction of useful protection mode switches") .flags(total) ; + + for (int i = 0; i < cpu_mode_num; ++i) + _modeFraction.subname(i, modestr[i]); + _modeFraction = _modeGood / _mode; _modeTicks - .init(2) - .name(name + ".mode_ticks") - .subname(0, "kernel") - .subname(1, "user") + .init(cpu_mode_num) + .name(name() + ".mode_ticks") .desc("number of ticks spent at the given mode") .flags(pdf) ; + for (int i = 0; i < cpu_mode_num; ++i) + _modeTicks.subname(i, modestr[i]); _swap_context - .name(name + ".swap_context") + .name(name() + ".swap_context") .desc("number of times the context was actually changed") ; } void -KernelStats::arm() -{ data->_arm++; } - -void -KernelStats::quiesce() -{ data->_quiesce++; } - -void -KernelStats::ivlb() -{ data->_ivlb++; } - -void -KernelStats::ivle() -{ data->_ivle++; } - -void -KernelStats::hwrei() -{ data->_hwrei++; } +Statistics::setIdleProcess(Addr idlepcbb) +{ + assert(themode == kernel || themode == interrupt); + idleProcess = idlepcbb; + themode = idle; + changeMode(themode); +} void -KernelStats::fault(Fault fault) -{ data->_faults[fault]++; } +Statistics::changeMode(cpu_mode newmode) +{ + _mode[newmode]++; -void -KernelStats::swpipl(int ipl) -{ data->swpipl(ipl); } + if (newmode == themode) + return; -void -KernelStats::mode(bool user) -{ data->mode(user); } + DPRINTF(Context, "old mode=%-8s new mode=%-8s\n", + modestr[themode], modestr[newmode]); -void -KernelStats::context(Addr old_pcbb, Addr new_pcbb) -{ data->_swap_context++; } + _modeGood[newmode]++; + _modeTicks[themode] += curTick - lastModeTick; -void -KernelStats::callpal(int code) -{ data->callpal(code); } + xc->system->kernelBinning->changeMode(newmode); + lastModeTick = curTick; + themode = newmode; +} void -KSData::swpipl(int ipl) +Statistics::swpipl(int ipl) { assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); @@ -299,30 +243,31 @@ KSData::swpipl(int ipl) } void -KSData::mode(bool user) +Statistics::mode(cpu_mode newmode) { - _mode[user]++; - if (user == lastUser) - return; + Addr pcbb = xc->regs.ipr[AlphaISA::IPR_PALtemp23]; - _modeGood[user]++; - _modeTicks[lastUser] += curTick - lastModeTick; + if ((newmode == kernel || newmode == interrupt) && + pcbb == idleProcess) + newmode = idle; - lastModeTick = curTick; - lastUser = user; - - if (xc->system->bin) { - if (!xc->swCtx || xc->swCtx->callStack.empty()) { - if (user) - xc->system->User->activate(); - else - xc->system->Kernel->activate(); - } - } + if (bin_int == false && newmode == interrupt) + newmode = kernel; + + changeMode(newmode); } void -KSData::callpal(int code) +Statistics::context(Addr oldpcbb, Addr newpcbb) +{ + assert(themode != user); + + _swap_context++; + changeMode(newpcbb == idleProcess ? idle : kernel); +} + +void +Statistics::callpal(int code) { if (!PAL::name(code)) return; @@ -330,63 +275,42 @@ KSData::callpal(int code) _callpal[code]++; switch (code) { - case PAL::callsys: - { - int number = xc->regs.intRegFile[0]; - if (SystemCalls<Tru64>::validSyscallNumber(number)) { - int cvtnum = SystemCalls<Tru64>::convert(number); - _syscall[cvtnum]++; - } - } + case PAL::callsys: { + int number = xc->regs.intRegFile[0]; + if (SystemCalls<Tru64>::validSyscallNumber(number)) { + int cvtnum = SystemCalls<Tru64>::convert(number); + _syscall[cvtnum]++; + } + } break; + + case PAL::swpctx: + if (xc->system->kernelBinning) + xc->system->kernelBinning->palSwapContext(xc); break; } +} - if (code == PAL::swpctx) { - SWContext *out = xc->swCtx; - System *sys = xc->system; - if (!sys->bin) - return; - DPRINTF(TCPIP, "swpctx event\n"); - if (out) { - DPRINTF(TCPIP, "swapping context out with this stack!\n"); - xc->system->dumpState(xc); - Addr oldPCB = xc->regs.ipr[TheISA::IPR_PALtemp23]; - - if (out->callStack.empty()) { - DPRINTF(TCPIP, "but removing it, cuz empty!\n"); - SWContext *find = sys->findContext(oldPCB); - if (find) { - assert(sys->findContext(oldPCB) == out); - sys->remContext(oldPCB); - } - delete out; - } else { - DPRINTF(TCPIP, "switching out context with pcb %#x, top fn %s\n", - oldPCB, out->callStack.top()->name); - if (!sys->findContext(oldPCB)) { - if (!sys->addContext(oldPCB, out)) - panic("could not add context"); - } - } - } +void +Statistics::serialize(ostream &os) +{ + int exemode = themode; + SERIALIZE_SCALAR(exemode); + SERIALIZE_SCALAR(idleProcess); + SERIALIZE_SCALAR(iplLast); + SERIALIZE_SCALAR(iplLastTick); + SERIALIZE_SCALAR(lastModeTick); +} - Addr newPCB = xc->regs.intRegFile[16]; - SWContext *in = sys->findContext(newPCB); - xc->swCtx = in; - - if (in) { - assert(!in->callStack.empty() && - "should not be switching in empty context"); - DPRINTF(TCPIP, "swapping context in with this callstack!\n"); - xc->system->dumpState(xc); - sys->remContext(newPCB); - fnCall *top = in->callStack.top(); - DPRINTF(TCPIP, "switching in to pcb %#x, %s\n", newPCB, top->name); - assert(top->myBin && "should not switch to context with no Bin"); - top->myBin->activate(); - } else { - sys->Kernel->activate(); - } - DPRINTF(TCPIP, "end swpctx\n"); - } +void +Statistics::unserialize(Checkpoint *cp, const string §ion) +{ + int exemode; + UNSERIALIZE_SCALAR(exemode); + UNSERIALIZE_SCALAR(idleProcess); + UNSERIALIZE_SCALAR(iplLast); + UNSERIALIZE_SCALAR(iplLastTick); + UNSERIALIZE_SCALAR(lastModeTick); + themode = (cpu_mode)exemode; } + +/* end namespace Kernel */ } diff --git a/kern/kernel_stats.hh b/kern/kernel_stats.hh index 497403762..af93eb95c 100644 --- a/kern/kernel_stats.hh +++ b/kern/kernel_stats.hh @@ -29,35 +29,166 @@ #ifndef __KERNEL_STATS_HH__ #define __KERNEL_STATS_HH__ +#include <map> +#include <stack> #include <string> +#include <vector> + +#include "base/statistics.hh" +#include "sim/serialize.hh" +#include "targetarch/isa_traits.hh" -class KSData; -class ExecContext; class BaseCPU; +class ExecContext; +class FnEvent; enum Fault; -class KernelStats +namespace Kernel { + +enum cpu_mode { kernel, user, idle, interrupt, cpu_mode_num }; +extern const char *modestr[]; + +class Binning { private: - KSData *data; + std::string myname; + System *system; + + private: + // lisa's binning stuff + struct fnCall + { + Stats::MainBin *myBin; + std::string name; + }; + + struct SWContext + { + Counter calls; + std::stack<fnCall *> callStack; + }; + + std::map<const std::string, Stats::MainBin *> fnBins; + std::map<const Addr, SWContext *> swCtxMap; + + std::multimap<const std::string, std::string> callerMap; + void populateMap(std::string caller, std::string callee); + + std::vector<FnEvent *> fnEvents; + + Stats::Scalar<> fnCalls; + + Stats::MainBin *getBin(const std::string &name); + bool findCaller(std::string, std::string) const; + + SWContext *findContext(Addr pcb); + bool addContext(Addr pcb, SWContext *ctx) + { + return (swCtxMap.insert(std::make_pair(pcb, ctx))).second; + } + + void remContext(Addr pcb) + { + swCtxMap.erase(pcb); + } + + void dumpState() const; + + SWContext *swctx; + std::vector<std::string> binned_fns; + + private: + Stats::MainBin *modeBin[cpu_mode_num]; + + public: + const bool bin; + const bool fnbin; + + cpu_mode themode; + void palSwapContext(ExecContext *xc); + void execute(ExecContext *xc, const StaticInstBase *inst); + void call(ExecContext *xc, Stats::MainBin *myBin); + void changeMode(cpu_mode mode); public: - KernelStats(ExecContext *_xc, BaseCPU *_cpu); - ~KernelStats(); + Binning(System *sys); + virtual ~Binning(); + const std::string name() const { return myname; } void regStats(const std::string &name); - void arm(); - void quiesce(); - void ivlb(); - void ivle(); - void hwrei(); + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; - void fault(Fault fault); +class Statistics : public Serializable +{ + friend class Binning; + + private: + std::string myname; + ExecContext *xc; + + Addr idleProcess; + cpu_mode themode; + Tick lastModeTick; + bool bin_int; + + void changeMode(cpu_mode newmode); + + private: + Stats::Scalar<> _arm; + Stats::Scalar<> _quiesce; + Stats::Scalar<> _ivlb; + Stats::Scalar<> _ivle; + Stats::Scalar<> _hwrei; + + Stats::Vector<> _iplCount; + Stats::Vector<> _iplGood; + Stats::Vector<> _iplTicks; + Stats::Formula _iplUsed; + + Stats::Vector<> _callpal; + Stats::Vector<> _syscall; + Stats::Vector<> _faults; + + Stats::Vector<> _mode; + Stats::Vector<> _modeGood; + Stats::Formula _modeFraction; + Stats::Vector<> _modeTicks; + + Stats::Scalar<> _swap_context; + + private: + int iplLast; + Tick iplLastTick; + + public: + Statistics(ExecContext *context); + + const std::string name() const { return myname; } + void regStats(const std::string &name); + + public: + void arm() { _arm++; } + void quiesce() { _quiesce++; } + void ivlb() { _ivlb++; } + void ivle() { _ivle++; } + void hwrei() { _hwrei++; } + void fault(Fault fault) { _faults[fault]++; } void swpipl(int ipl); - void mode(bool user); - void context(Addr old_pcbb, Addr new_pcbb); + void mode(cpu_mode newmode); + void context(Addr oldpcbb, Addr newpcbb); void callpal(int code); + + void setIdleProcess(Addr idle); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); }; +/* end namespace Kernel */ } + #endif // __KERNEL_STATS_HH__ diff --git a/kern/linux/aligned.hh b/kern/linux/aligned.hh new file mode 100644 index 000000000..042f0ad2c --- /dev/null +++ b/kern/linux/aligned.hh @@ -0,0 +1,21 @@ +#ifndef __KERN_LINUX_ALIGNED_HH__ +#define __KERN_LINUX_ALIGNED_HH__ + +#include "sim/host.hh" +#include "targetarch/isa_traits.hh" + +/* GCC 3.3.X has a bug in which attributes+typedefs don't work. 3.2.X is fine + * as in 3.4.X, but the bug is marked will not fix in 3.3.X so here is + * the work around. + */ +#if __GNUC__ == 3 && __GNUC_MINOR__ != 3 +typedef uint64_t uint64_ta __attribute__ ((aligned (8))) ; +typedef int64_t int64_ta __attribute__ ((aligned (8))) ; +typedef Addr Addr_a __attribute__ ((aligned (8))) ; +#else +#define uint64_ta uint64_t __attribute__ ((aligned (8))) +#define int64_ta int64_t __attribute__ ((aligned (8))) +#define Addr_a Addr __attribute__ ((aligned (8))) +#endif /* __GNUC__ __GNUC_MINOR__ */ + +#endif /* __KERN_LINUX_ALIGNED_HH__ */ diff --git a/kern/linux/hwrpb.hh b/kern/linux/hwrpb.hh new file mode 100644 index 000000000..16544f196 --- /dev/null +++ b/kern/linux/hwrpb.hh @@ -0,0 +1,18 @@ +#ifndef __KERN_LINUX_HWRPB_HH__ +#define __KERN_LINUX_HWRPB_HH__ + +#include "kern/linux/aligned.hh" + +namespace Linux { + struct pcb_struct { + uint64_ta ksp; + uint64_ta usp; + uint64_ta ptbr; + uint32_t pcc; + uint32_t asn; + uint64_ta unique; + uint64_ta flags; + uint64_ta res1, res2; + }; +} +#endif // __KERN_LINUX_HWRPB_HH__ diff --git a/kern/linux/linux_syscalls.hh b/kern/linux/linux_syscalls.hh index a729431a0..dee7c5fcd 100644 --- a/kern/linux/linux_syscalls.hh +++ b/kern/linux/linux_syscalls.hh @@ -29,11 +29,14 @@ #ifndef __LINUX_SYSCALLS_HH__ #define __LINUX_SYSCALLS_HH__ -#include "targetarch/syscalls.hh" #include "kern/linux/linux.hh" -struct SystemCalls<Linux> +template <class OS> +class SystemCalls; + +class SystemCalls<Linux> { + public: enum { syscall = 0, llseek = 1, diff --git a/kern/linux/linux_system.cc b/kern/linux/linux_system.cc index bc2753908..4342463c3 100644 --- a/kern/linux/linux_system.cc +++ b/kern/linux/linux_system.cc @@ -35,11 +35,7 @@ * 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" @@ -54,90 +50,17 @@ #include "targetarch/vtophys.hh" #include "sim/debug.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) +LinuxSystem::LinuxSystem(Params *p) + : System(p) { - 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"); - - debugPrintkEvent = new DebugPrintkEvent(&pcEventQueue, "dprintk"); - 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. + * 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); @@ -150,19 +73,6 @@ LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, /** - * 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. */ @@ -170,32 +80,11 @@ LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, Addr paddr = vtophys(physmem, PARAM_ADDR); char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t)); if (commandline) - strcpy(commandline, boot_osflags.c_str()); + strcpy(commandline, params->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) { - // Tsunami - *(uint64_t*)(hwprb + 0x50) = htoa(ULL(34)); - - // Plain DP264 - *(uint64_t*)(hwprb + 0x58) = htoa(ULL(1) << 10); - } - 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"); - - /** * EV5 only supports 127 ASNs so we are going to tell the kernel that the * paritiuclar EV6 we have only supports 127 asns. * @todo At some point we should change ev5.hh and the palcode to support @@ -208,55 +97,95 @@ LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, if (dp264_mv) { *(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127); } else - panic("could not translate dp264_mv addr to set the MAX_ASN to 127\n"); + panic("could not translate dp264_mv addr\n"); } else - panic("could not find dp264_mv to set the MAX_ASN to 127\n"); - - + panic("could not find dp264_mv\n"); #ifdef DEBUG + kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic"); 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. + * 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. */ + skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, "ide_delay_50ms"); if (kernelSymtab->findAddress("ide_delay_50ms", addr)) skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst)); + skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue, + "calibrate_delay"); if (kernelSymtab->findAddress("calibrate_delay", addr)) skipDelayLoopEvent->schedule(addr+sizeof(MachInst)); + skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue, + "determine_cpu_caches"); if (kernelSymtab->findAddress("determine_cpu_caches", addr)) skipCacheProbeEvent->schedule(addr+sizeof(MachInst)); + debugPrintkEvent = new DebugPrintkEvent(&pcEventQueue, "dprintk"); if (kernelSymtab->findAddress("dprintk", addr)) - debugPrintkEvent->schedule(addr+sizeof(MachInst)*2); + debugPrintkEvent->schedule(addr+8); + + idleStartEvent = new IdleStartEvent(&pcEventQueue, "cpu_idle", this); + if (kernelSymtab->findAddress("cpu_idle", addr)) + idleStartEvent->schedule(addr); + + printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo"); + if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) + printThreadEvent->schedule(addr + sizeof(MachInst) * 6); + + intStartEvent = new InterruptStartEvent(&pcEventQueue, "intStartEvent"); + + if (params->bin_int) { + if (palSymtab->findAddress("sys_int_21", addr)) + intStartEvent->schedule(addr + sizeof(MachInst) * 2); + else + panic("could not find symbol: sys_int_21\n"); + + intEndEvent = new InterruptEndEvent(&pcEventQueue, "intEndEvent"); + if (palSymtab->findAddress("rti_to_kern", addr)) + intEndEvent->schedule(addr) ; + else + panic("could not find symbol: rti_to_kern\n"); + + intEndEvent2 = new InterruptEndEvent(&pcEventQueue, "intEndEvent2"); + if (palSymtab->findAddress("rti_to_user", addr)) + intEndEvent2->schedule(addr); + else + panic("could not find symbol: rti_to_user\n"); + + + intEndEvent3 = new InterruptEndEvent(&pcEventQueue, "intEndEvent3"); + if (kernelSymtab->findAddress("do_softirq", addr)) + intEndEvent3->schedule(addr + sizeof(MachInst) * 2); + else + panic("could not find symbol: do_softirq\n"); + } } LinuxSystem::~LinuxSystem() { - delete kernel; - delete console; - - delete kernelSymtab; - delete consoleSymtab; - +#ifdef DEBUG delete kernelPanicEvent; - delete consolePanicEvent; +#endif delete skipIdeDelay50msEvent; delete skipDelayLoopEvent; delete skipCacheProbeEvent; + delete debugPrintkEvent; + delete idleStartEvent; + delete printThreadEvent; + delete intStartEvent; + delete intEndEvent; + delete intEndEvent2; } @@ -277,92 +206,66 @@ LinuxSystem::setDelayLoop(ExecContext *xc) } } -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; + Param<string> boot_osflags; Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + + Param<bool> bin; + VectorParam<string> binned_fns; + Param<bool> bin_int; 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(kernel_code, "file that contains the kernel 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"), + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", "") - + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) 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); - - sys->readfile = readfile; - return sys; + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->memctrl = mem_ctl; + p->physmem = physmem; + p->kernel_path = kernel_code; + p->console_path = console_code; + p->palcode = pal_code; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new LinuxSystem(p); } REGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem) + diff --git a/kern/linux/linux_system.hh b/kern/linux/linux_system.hh index e7cdf140d..5e3cba9b3 100644 --- a/kern/linux/linux_system.hh +++ b/kern/linux/linux_system.hh @@ -26,32 +26,28 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __LINUX_SYSTEM_HH__ -#define __LINUX_SYSTEM_HH__ +#ifndef __KERN_LINUX_LINUX_SYSTEM_HH__ +#define __KERN_LINUX_LINUX_SYSTEM_HH__ -#include <vector> - -#include "sim/system.hh" #include "sim/host.hh" +#include "sim/system.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); +const Addr PARAM_ADDR = ULL(0xfffffc000030a000); class ExecContext; -class ElfObject; -class SymbolTable; + +class BreakPCEvent; class DebugPrintkEvent; class BreakPCEvent; class LinuxSkipDelayLoopEvent; class SkipFuncEvent; -class FnEvent; -class AlphaArguments; +class IdleStartEvent; +class PrintThreadInfo; /** * This class contains linux specific system code (Loading, Events, Binning). @@ -61,94 +57,58 @@ class AlphaArguments; 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; - +#ifdef DEBUG /** Event to halt the simulator if the kernel calls panic() */ BreakPCEvent *kernelPanicEvent; +#endif - /** 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 + /** + * 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; - /** PC based event to skip the dprink() call and emulate its functionality */ + /** + * PC based event to skip the dprink() call and emulate its + * functionality + */ DebugPrintkEvent *debugPrintkEvent; - /** Skip calculate_delay_loop() rather than waiting for this to be + /** + * 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 + * Event to print information about thread switches if the trace flag + * Thread is set */ - Addr getKernelStart() const { return kernelStart; } + PrintThreadInfo *printThreadEvent; /** - * Returns the addess the kernel ends at. - * @return address the kernel ends at + * Event to bin Interrupts seperately from kernel code */ - Addr getKernelEnd() const { return kernelEnd; } + InterruptStartEvent *intStartEvent; /** - * Returns the addess the entry point to the kernel code. - * @return entry point of the kernel code + * Event to bin Interrupts seperately from kernel code */ - Addr getKernelEntry() const { return kernelEntry; } + InterruptEndEvent *intEndEvent; + InterruptEndEvent *intEndEvent2; + InterruptEndEvent *intEndEvent3; + /** Grab the PCBB of the idle process when it starts */ + IdleStartEvent *idleStartEvent; - bool breakpoint(); + public: + LinuxSystem(Params *p); + ~LinuxSystem(); + + void setDelayLoop(ExecContext *xc); }; -#endif // __LINUX_SYSTEM_HH__ +#endif // __KERN_LINUX_LINUX_SYSTEM_HH__ diff --git a/kern/linux/linux_threadinfo.hh b/kern/linux/linux_threadinfo.hh new file mode 100644 index 000000000..99ce9965a --- /dev/null +++ b/kern/linux/linux_threadinfo.hh @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004 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_TREADNIFO_HH__ +#define __LINUX_TREADNIFO_HH__ + + +#include "targetarch/isa_traits.hh" +#include "targetarch/vptr.hh" +#include "cpu/exec_context.hh" +#include "kern/linux/thread_info.hh" +#include "kern/linux/sched.hh" + + +namespace Linux { + +class ThreadInfo +{ + private: + ExecContext *xc; + + public: + ThreadInfo(ExecContext *exec) : xc(exec) {} + ~ThreadInfo() {} + + inline VPtr<thread_info> + curThreadInfo() + { + Addr current; + + /* Each kernel stack is only 2 pages, the start of which is the + * thread_info struct. So we can get the address by masking off + * the lower 14 bits. + */ + current = xc->regs.intRegFile[StackPointerReg] & ~0x3fff; + return VPtr<thread_info>(xc, current); + } + + inline VPtr<task_struct> + curTaskInfo() + { + Addr task = curThreadInfo()->task; + return VPtr<task_struct>(xc, task); + } + + std::string + curTaskName() + { + return curTaskInfo()->comm; + } + + int32_t + curTaskPID() + { + return curTaskInfo()->pid; + } + + uint64_t + curTaskStart() + { + return curTaskInfo()->start_time; + } +}; +} + +#endif /* __LINUX_THREADINFO_HH__ */ diff --git a/kern/linux/sched.hh b/kern/linux/sched.hh new file mode 100644 index 000000000..287214b2b --- /dev/null +++ b/kern/linux/sched.hh @@ -0,0 +1,110 @@ +#ifndef __LINUX_SCHED_H__ +#define __LINUX_SCHED_H__ + +#include "targetarch/isa_traits.hh" +#include "kern/linux/atomic.hh" +#include "kern/linux/list.hh" +#include "kern/linux/wait.hh" +#include "kern/linux/timer.hh" +#include "kern/linux/pid.hh" +#include "kern/linux/aligned.hh" + +namespace Linux { + + struct rlimit { + uint64_ta rlim_cur; + uint64_ta rlim_max; + }; + + const uint32_t RLIM_NLIMITS = 11; + + struct task_struct { + int64_ta state; /* -1 unrunnable, 0 runnable, >0 stopped */ + Addr_a thread_info; + atomic_t usage; + + uint64_ta flags; /* per process flags, defined below */ + uint64_ta ptrace; + + int32_t lock_depth; /* Lock depth */ + + int32_t prio, static_prio; + + struct list_head run_list; + Addr_a array; + + uint64_ta sleep_avg; + int64_ta interactive_credit; + uint64_ta timestamp; + int32_t activated; + + uint64_ta policy; + uint64_ta cpus_allowed; + uint32_t time_slice, first_time_slice; + + struct list_head tasks; + struct list_head ptrace_children; + struct list_head ptrace_list; + + Addr_a mm, active_mm; + + /* task state */ + Addr_a binfmt; + int32_t exit_code, exit_signal; + int32_t pdeath_signal; /* The signal sent when the parent dies */ + /* ??? */ + uint64_ta personality; + int32_t did_exec:1; + int32_t pid; + int32_t __pgrp; /* Accessed via process_group() */ + int32_t tty_old_pgrp; + int32_t session; + int32_t tgid; + /* boolean value for session group leader */ + int32_t leader; + /* + * pointers to (original) parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->parent->pid) + */ + Addr_a real_parent; /* real parent process (when being debugged) */ + Addr_a parent; /* parent process */ + struct list_head children; /* list of my children */ + struct list_head sibling; /* linkage in my parent's children list */ + Addr_a group_leader; /* threadgroup leader */ + + /* PID/PID hash table linkage. */ + struct pid_link pids[PIDTYPE_MAX]; + + wait_queue_head_t wait_chldexit; /* for wait4() */ + Addr_a vfork_done; /* for vfork() */ + Addr_a set_child_tid; /* CLONE_CHILD_SETTID */ + Addr_a clear_child_tid; /* CLONE_CHILD_CLEARTID */ + + uint64_ta rt_priority; + uint64_ta it_real_value, it_prof_value, it_virt_value; + uint64_ta it_real_incr, it_prof_incr, it_virt_incr; + struct timer_list real_timer; + struct list_head posix_timers; /* POSIX.1b Interval Timers */ + uint64_ta utime, stime, cutime, cstime; + uint64_ta nvcsw, nivcsw, cnvcsw, cnivcsw; /* context switch counts */ + uint64_ta start_time; + /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ + uint64_ta min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; + /* process credentials */ + uint32_t uid,euid,suid,fsuid; + uint32_t gid,egid,sgid,fsgid; + Addr_a group_info; + uint32_t cap_effective, cap_inheritable, cap_permitted; + int32_t keep_capabilities:1; + Addr user; + /* limits */ + struct rlimit rlim[RLIM_NLIMITS]; + uint16_t used_math; + char comm[16]; + }; + + +} + +#endif diff --git a/kern/linux/thread_info.hh b/kern/linux/thread_info.hh new file mode 100644 index 000000000..1b4053a78 --- /dev/null +++ b/kern/linux/thread_info.hh @@ -0,0 +1,27 @@ +#ifndef __ALPHA_THREAD_INFO_H__ +#define __ALPHA_THREAD_INFO_H__ + +#include "kern/linux/hwrpb.hh" +#include "kern/linux/aligned.hh" + +namespace Linux { + struct thread_info { + struct pcb_struct pcb; /* palcode state */ + + Addr_a task; /* main task structure */ + uint32_t flags; /* low level flags */ + uint32_t ieee_state; /* see fpu.h */ + + Addr_a exec_domain; /* execution domain */ + uint64_ta addr_limit; /* thread address space */ + int64_ta cpu; /* current CPU */ + int32_t preempt_count; /* 0 => preemptable, <0 => BUG */ + + int32_t bpt_nsaved; + uint64_ta bpt_addr[2]; /* breakpoint handling */ + uint32_t bpt_insn[2]; + + /*restart_block;*/ + }; +} +#endif /* __ALPHA_THREAD_INFO_H__ */ diff --git a/kern/system_events.cc b/kern/system_events.cc index 351c3ddb2..9acf2f65a 100644 --- a/kern/system_events.cc +++ b/kern/system_events.cc @@ -30,9 +30,9 @@ #include "cpu/base_cpu.hh" #include "cpu/full_cpu/bpred.hh" #include "cpu/full_cpu/full_cpu.hh" +#include "kern/kernel_stats.hh" #include "kern/system_events.hh" #include "sim/system.hh" -#include "sim/sw_context.hh" void SkipFuncEvent::process(ExecContext *xc) @@ -52,11 +52,9 @@ SkipFuncEvent::process(ExecContext *xc) } -FnEvent::FnEvent(PCEventQueue *q, const std::string & desc, System *system) - : PCEvent(q, desc), _name(desc) +FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Stats::MainBin *bin) + : PCEvent(q, desc), _name(desc), mybin(bin) { - myBin = system->getBin(desc); - assert(myBin); } void @@ -64,46 +62,27 @@ FnEvent::process(ExecContext *xc) { if (xc->misspeculating()) return; - assert(xc->system->bin && "FnEvent must be in a binned system"); - SWContext *ctx = xc->swCtx; - DPRINTF(TCPIP, "%s: %s Event!!!\n", xc->system->name(), description); - if (ctx && !ctx->callStack.empty()) { - DPRINTF(TCPIP, "already a callstack!\n"); - fnCall *last = ctx->callStack.top(); - - if (last->name == "idle_thread") - ctx->calls++; + xc->system->kernelBinning->call(xc, mybin); +} - if (!xc->system->findCaller(myname(), "" ) && - !xc->system->findCaller(myname(), last->name)) { +void +IdleStartEvent::process(ExecContext *xc) +{ + xc->kernelStats->setIdleProcess(xc->regs.ipr[AlphaISA::IPR_PALtemp23]); + remove(); +} - DPRINTF(TCPIP, "but can't find parent %s\n", last->name); - return; - } - ctx->calls--; +void +InterruptStartEvent::process(ExecContext *xc) +{ + xc->kernelStats->mode(Kernel::interrupt); +} - //assert(!ctx->calls && "on a binned fn, calls should == 0 (but can happen in boot)"); - } else { - DPRINTF(TCPIP, "no callstack yet\n"); - if (!xc->system->findCaller(myname(), "")) { - DPRINTF(TCPIP, "not the right function, returning\n"); - return; - } - if (!ctx) { - DPRINTF(TCPIP, "creating new context for %s\n", myname()); - ctx = new SWContext; - xc->swCtx = ctx; - } - } - DPRINTF(TCPIP, "adding fn %s to context\n", myname()); - fnCall *call = new fnCall; - call->myBin = myBin; - call->name = myname(); - ctx->callStack.push(call); - myBin->activate(); - xc->system->fnCalls++; - DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, - xc->system->fnCalls.value()); - xc->system->dumpState(xc); +void +InterruptEndEvent::process(ExecContext *xc) +{ + // We go back to kernel, if we are user, inside the rti + // pal code we will get switched to user because of the ICM write + xc->kernelStats->mode(Kernel::kernel); } diff --git a/kern/system_events.hh b/kern/system_events.hh index 7f658bde9..8a8549d03 100644 --- a/kern/system_events.hh +++ b/kern/system_events.hh @@ -44,13 +44,44 @@ class SkipFuncEvent : public PCEvent class FnEvent : public PCEvent { public: - FnEvent(PCEventQueue *q, const std::string &desc, System *system); + FnEvent(PCEventQueue *q, const std::string &desc, Stats::MainBin *bin); virtual void process(ExecContext *xc); std::string myname() const { return _name; } private: std::string _name; - Stats::MainBin *myBin; + Stats::MainBin *mybin; }; +class IdleStartEvent : public PCEvent +{ + private: + System *system; + + public: + IdleStartEvent(PCEventQueue *q, const std::string &desc, System *sys) + : PCEvent(q, desc), system(sys) + {} + virtual void process(ExecContext *xc); +}; + +class InterruptStartEvent : public PCEvent +{ + public: + InterruptStartEvent(PCEventQueue *q, const std::string &desc) + : PCEvent(q, desc) + {} + virtual void process(ExecContext *xc); +}; + +class InterruptEndEvent : public PCEvent +{ + public: + InterruptEndEvent(PCEventQueue *q, const std::string &desc) + : PCEvent(q, desc) + {} + virtual void process(ExecContext *xc); +}; + + #endif // __SYSTEM_EVENTS_HH__ diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc index e96cc9c5d..f4300116e 100644 --- a/kern/tru64/tru64_events.cc +++ b/kern/tru64/tru64_events.cc @@ -32,8 +32,9 @@ #include "kern/tru64/tru64_events.hh" #include "kern/tru64/dump_mbuf.hh" #include "kern/tru64/printf.hh" -#include "targetarch/arguments.hh" #include "mem/functional_mem/memory_control.hh" +#include "targetarch/arguments.hh" +#include "targetarch/isa_traits.hh" //void SkipFuncEvent::process(ExecContext *xc); @@ -46,8 +47,8 @@ BadAddrEvent::process(ExecContext *xc) uint64_t a0 = xc->regs.intRegFile[ArgumentReg0]; - if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE || - xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) { + if (!TheISA::IsK0Seg(a0) || + xc->memctrl->badaddr(TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) { DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); xc->regs.intRegFile[ReturnValueReg] = 0x1; diff --git a/kern/tru64/tru64_syscalls.hh b/kern/tru64/tru64_syscalls.hh index f4853e3f8..7ddc699b1 100644 --- a/kern/tru64/tru64_syscalls.hh +++ b/kern/tru64/tru64_syscalls.hh @@ -29,11 +29,14 @@ #ifndef __TRU64_SYSCALLS_HH__ #define __TRU64_SYSCALLS_HH__ -#include "targetarch/syscalls.hh" #include "kern/tru64/tru64.hh" -struct SystemCalls<Tru64> +template <class OS> +class SystemCalls; + +class SystemCalls<Tru64> { + public: enum { syscall = 0, exit = 1, diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index 4395162e4..c6435cb18 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -26,11 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "base/loader/aout_object.hh" -#include "base/loader/ecoff_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 "kern/tru64/tru64_events.hh" @@ -42,75 +38,11 @@ #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, - 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) +Tru64System::Tru64System(Tru64System::Params *p) + : System(p) { - kernelSymtab = new SymbolTable; - consoleSymtab = new SymbolTable; - debugSymbolTable = kernelSymtab; - - ObjectFile *kernel = createObjectFile(kernel_path); - if (kernel == NULL) - fatal("Could not load kernel file %s", kernel_path); - - ObjectFile *console = createObjectFile(console_path); - if (console == NULL) - fatal("Could not load console file %s", console_path); - - if (!kernel->loadGlobalSymbols(kernelSymtab)) - panic("could not load kernel symbols\n"); - - if (!console->loadGlobalSymbols(consoleSymtab)) - panic("could not load console symbols\n"); - - // 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(); - - 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 - badaddrEvent = new BadAddrEvent(&pcEventQueue, "badaddr"); - skipPowerStateEvent = new SkipFuncEvent(&pcEventQueue, - "tl_v48_capture_power_state"); - skipScavengeBootEvent = new SkipFuncEvent(&pcEventQueue, - "pmap_scavenge_boot"); - printfEvent = new PrintfEvent(&pcEventQueue, "printf"); - debugPrintfEvent = new DebugPrintfEvent(&pcEventQueue, - "debug_printf", false); - debugPrintfrEvent = new DebugPrintfEvent(&pcEventQueue, - "debug_printfr", true); - dumpMbufEvent = new DumpMbufEvent(&pcEventQueue, "dump_mbuf"); - Addr addr = 0; if (kernelSymtab->findAddress("enable_async_printf", addr)) { Addr paddr = vtophys(physmem, addr); @@ -121,180 +53,125 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param, *(uint32_t *)enable_async_printf = 0; } - 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()); - } - - 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 + kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic"); 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 + badaddrEvent = new BadAddrEvent(&pcEventQueue, "badaddr"); if (kernelSymtab->findAddress("badaddr", addr)) badaddrEvent->schedule(addr); else panic("could not find kernel symbol \'badaddr\'"); + skipPowerStateEvent = new SkipFuncEvent(&pcEventQueue, + "tl_v48_capture_power_state"); if (kernelSymtab->findAddress("tl_v48_capture_power_state", addr)) skipPowerStateEvent->schedule(addr); + skipScavengeBootEvent = new SkipFuncEvent(&pcEventQueue, + "pmap_scavenge_boot"); if (kernelSymtab->findAddress("pmap_scavenge_boot", addr)) skipScavengeBootEvent->schedule(addr); #if TRACING_ON + printfEvent = new PrintfEvent(&pcEventQueue, "printf"); if (kernelSymtab->findAddress("printf", addr)) printfEvent->schedule(addr); + debugPrintfEvent = new DebugPrintfEvent(&pcEventQueue, "debug_printf", + false); if (kernelSymtab->findAddress("m5printf", addr)) debugPrintfEvent->schedule(addr); + debugPrintfrEvent = new DebugPrintfEvent(&pcEventQueue, "debug_printfr", + true); if (kernelSymtab->findAddress("m5printfr", addr)) debugPrintfrEvent->schedule(addr); + dumpMbufEvent = new DumpMbufEvent(&pcEventQueue, "dump_mbuf"); if (kernelSymtab->findAddress("m5_dump_mbuf", addr)) dumpMbufEvent->schedule(addr); #endif - - // BINNING STUFF - if (bin == true) { - int end = binned_fns.size(); - Addr address = 0; - - for (int i = 0; i < end; i +=2) { - if (kernelSymtab->findAddress(binned_fns[i], address)) - fnEvents[(i>>1)]->schedule(address); - else - panic("could not find kernel symbol %s\n", binned_fns[i]); - } - } - // } Tru64System::~Tru64System() { - delete kernel; - delete console; - - delete kernelSymtab; - delete consoleSymtab; - #ifdef DEBUG delete kernelPanicEvent; - delete consolePanicEvent; #endif delete badaddrEvent; delete skipPowerStateEvent; delete skipScavengeBootEvent; +#if TRACING_ON delete printfEvent; delete debugPrintfEvent; delete debugPrintfrEvent; delete dumpMbufEvent; -} - -int -Tru64System::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(); - - if (remoteGDB.size() <= xcIndex) { - remoteGDB.resize(xcIndex+1); - } - - remoteGDB[xcIndex] = rgdb; - - return xcIndex; -} - - -void -Tru64System::replaceExecContext(ExecContext *xc, int xcIndex) -{ - System::replaceExecContext(xcIndex, xc); - remoteGDB[xcIndex]->replaceExecContext(xc); -} - -bool -Tru64System::breakpoint() -{ - return remoteGDB[0]->trap(ALPHA_KENTRY_INT); +#endif } BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System) - Param<bool> bin; SimObjectParam<MemoryController *> mem_ctl; SimObjectParam<PhysicalMemory *> physmem; - Param<unsigned int> init_param; Param<string> kernel_code; Param<string> console_code; Param<string> pal_code; + Param<string> boot_osflags; - VectorParam<string> binned_fns; + Param<string> readfile; + Param<unsigned int> init_param; + Param<uint64_t> system_type; Param<uint64_t> system_rev; + Param<bool> bin; + VectorParam<string> binned_fns; + END_DECLARE_SIM_OBJECT_PARAMS(Tru64System) BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64System) - 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 kernel 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"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), 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) - + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned") END_INIT_SIM_OBJECT_PARAMS(Tru64System) 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, system_type, system_rev); - - return sys; + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->memctrl = mem_ctl; + p->physmem = physmem; + p->kernel_path = kernel_code; + p->console_path = console_code; + p->palcode = pal_code; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = false; + + return new Tru64System(p); } REGISTER_SIM_OBJECT("Tru64System", Tru64System) diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh index 8dd696b79..13d283fb3 100644 --- a/kern/tru64/tru64_system.hh +++ b/kern/tru64/tru64_system.hh @@ -26,18 +26,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __TRU64_SYSTEM_HH__ -#define __TRU64_SYSTEM_HH__ - -#include <map> -#include <vector> +#ifndef __KERN_TRU64_TRU64_SYSTEM_HH__ +#define __KERN_TRU64_TRU64_SYSTEM_HH__ #include "sim/system.hh" #include "targetarch/isa_traits.hh" class ExecContext; -class EcoffObject; -class SymbolTable; class BreakPCEvent; class BadAddrEvent; @@ -45,20 +40,16 @@ class SkipFuncEvent; class PrintfEvent; class DebugPrintfEvent; class DumpMbufEvent; -class FnEvent; class AlphaArguments; class Tru64System : public System { private: - EcoffObject *kernel; - EcoffObject *console; - - SymbolTable *kernelSymtab; - SymbolTable *consoleSymtab; - +#ifdef DEBUG + /** Event to halt the simulator if the kernel calls panic() */ BreakPCEvent *kernelPanicEvent; - BreakPCEvent *consolePanicEvent; +#endif + BadAddrEvent *badaddrEvent; SkipFuncEvent *skipPowerStateEvent; SkipFuncEvent *skipScavengeBootEvent; @@ -67,43 +58,12 @@ class Tru64System : public System DebugPrintfEvent *debugPrintfrEvent; DumpMbufEvent *dumpMbufEvent; - private: - - Addr kernelStart; - Addr kernelEnd; - Addr kernelEntry; - bool bin; - std::vector<string> binned_fns; - - public: - std::vector<RemoteGDB *> remoteGDB; - std::vector<GDBListener *> gdbListen; - public: - Tru64System(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<string> &binned_fns, - const uint64_t system_type, - const uint64_t system_rev); + Tru64System(Params *p); ~Tru64System(); - int registerExecContext(ExecContext *xc); - void replaceExecContext(ExecContext *xc, int xcIndex); - - Addr getKernelStart() const { return kernelStart; } - Addr getKernelEnd() const { return kernelEnd; } - Addr getKernelEntry() const { return kernelEntry; } - bool breakpoint(); - static void Printf(AlphaArguments args); static void DumpMbuf(AlphaArguments args); }; -#endif // __TRU64_SYSTEM_HH__ +#endif // __KERN_TRU64_TRU64_SYSTEM_HH__ diff --git a/sim/builder.cc b/sim/builder.cc index 53e5cf3d8..fa5c113a7 100644 --- a/sim/builder.cc +++ b/sim/builder.cc @@ -39,31 +39,11 @@ using namespace std; - -ostream & -builderStream() -{ - static ofstream file; - static ostream *stream = NULL; - - if (!stream) { - if (!outputDirectory.empty()) { - string filename = outputDirectory + "builder.txt"; - file.open(filename.c_str()); - stream = &file; - } else { - stream = outputStream; - } - } - - return *stream; -} - SimObjectBuilder::SimObjectBuilder(const string &_configClass, const string &_instanceName, ConfigNode *_configNode, const string &_simObjClassName) - : ParamContext(_configClass, true), + : ParamContext(_configClass, NoAutoInit), instanceName(_instanceName), configNode(_configNode), simObjClassName(_simObjClassName) @@ -187,10 +167,10 @@ SimObjectClass::createObject(IniFile &configDB, // echo object parameters to stats file (for documenting the // config used to generate the associated stats) - builderStream() << "[" << object->name() << "]" << endl; - builderStream() << "type=" << simObjClassName << endl; - objectBuilder->showParams(builderStream()); - builderStream() << endl; + *configStream << "[" << object->name() << "]" << endl; + *configStream << "type=" << simObjClassName << endl; + objectBuilder->showParams(*configStream); + *configStream << endl; // done with the SimObjectBuilder now delete objectBuilder; diff --git a/sim/builder.hh b/sim/builder.hh index a85c88b76..36e40c2a9 100644 --- a/sim/builder.hh +++ b/sim/builder.hh @@ -38,9 +38,6 @@ class SimObject; -std::ostream & -builderStream(); - // // A SimObjectBuilder serves as an evaluation context for a set of // parameters that describe a specific instance of a SimObject. This diff --git a/sim/debug.cc b/sim/debug.cc index 293edcbe2..3467d1669 100644 --- a/sim/debug.cc +++ b/sim/debug.cc @@ -40,13 +40,15 @@ using namespace std; -#ifdef DEBUG void debug_break() { +#ifndef NDEBUG kill(getpid(), SIGTRAP); -} +#else + cprintf("debug_break suppressed, compiled with NDEBUG\n"); #endif +} // // Debug event: place a breakpoint on the process function and diff --git a/sim/debug.hh b/sim/debug.hh index 3ccf1dbd4..5ee77cf28 100644 --- a/sim/debug.hh +++ b/sim/debug.hh @@ -29,10 +29,6 @@ #ifndef __DEBUG_HH__ #define __DEBUG_HH__ -#ifdef DEBUG void debug_break(); -#else -inline void debug_break() { } -#endif #endif // __DEBUG_HH__ diff --git a/sim/main.cc b/sim/main.cc index 2a0427303..e8ac58786 100644 --- a/sim/main.cc +++ b/sim/main.cc @@ -51,7 +51,6 @@ #include "sim/host.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" -#include "sim/sim_init.hh" #include "sim/sim_object.hh" #include "sim/stat_control.hh" #include "sim/stats.hh" @@ -111,12 +110,15 @@ static void showBriefHelp(ostream &out) { out << "Usage: " << myProgName - << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] " - << "[--<section>:<param>=<value>] [<config file> ...]" << endl - << " -h: print long help (including parameter listing)" << endl - << " -n: don't load default.ini" << endl - << " -u: don't quit on unreferenced parameters" << endl - << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl; + << " [-hnu] [-Dname[=def]] [-Uname] [-I[dir]] " + << "<config-spec> [<config-spec> ...]\n" + << "[] [<config file> ...]\n" + << " -h: print long help (including parameter listing)\n" + << " -u: don't quit on unreferenced parameters\n" + << " -D,-U,-I: passed to cpp for preprocessing .ini files\n" + << " <config-spec>: config file name (.ini or .py) or\n" + << " single param (--<section>:<param>=<value>)" + << endl; } /// Show verbose help message. Includes parameter listing from @@ -212,27 +214,6 @@ echoCommandLine(int argc, char **argv, ostream &out) /// static IniFile simConfigDB; -/// Check for a default.ini file and load it if necessary. -static void -handleDefaultIni(bool &loadIt, vector<char *> &cppArgs) -{ - struct stat sb; - - if (loadIt) { - if (stat("default.ini", &sb) == 0) { - if (!simConfigDB.loadCPP("default.ini", cppArgs)) { - cout << "Error processing file default.ini" << endl; - exit(1); - } - } - - // set this whether it actually was found or not, so we don't - // bother to check again next time - loadIt = false; - } -} - - /// M5 entry point. int main(int argc, char **argv) @@ -254,21 +235,13 @@ main(int argc, char **argv) vector<char *> cppArgs; - // Should we use default.ini if it exists? By default, yes. (Use - // -n to override.) - bool loadDefaultIni = true; - // Should we quit if there are unreferenced parameters? By // default, yes... it's a good way of catching typos in // section/parameter names (which otherwise go by silently). Use // -u to override. bool quitOnUnreferenced = true; - // Parse command-line options. The tricky part here is figuring - // out whether to look for & load default.ini, and if needed, - // doing so at the right time w.r.t. processing the other - // parameters. - // + // Parse command-line options. // Since most of the complex options are handled through the // config database, we don't mess with getopts, and just parse // manually. @@ -286,17 +259,6 @@ main(int argc, char **argv) showLongHelp(cerr); exit(1); - case 'n': - // -n: don't load default.ini - if (!loadDefaultIni) { - cerr << "Warning: -n option needs to precede any " - << "explicit configuration file name " << endl - << " or command-line configuration parameter." - << endl; - } - loadDefaultIni = false; - break; - case 'u': // -u: don't quit on unreferenced parameters quitOnUnreferenced = false; @@ -317,11 +279,6 @@ main(int argc, char **argv) case '-': // command-line configuration parameter: // '--<section>:<parameter>=<value>' - - // Load default.ini if necessary -- see comment in - // else clause below. - handleDefaultIni(loadDefaultIni, cppArgs); - if (!simConfigDB.add(arg_str + 2)) { // parse error ccprintf(cerr, @@ -350,13 +307,6 @@ main(int argc, char **argv) (ext_loc != string::npos) ? filename.substr(ext_loc) : ""; if (ext == ".ini") { - // If we haven't loaded default.ini yet, and we want to, - // now is the time. Can't do it sooner because we need to - // look for '-n', can't do it later since we want - // default.ini loaded first (so that any other settings - // override it). - handleDefaultIni(loadDefaultIni, cppArgs); - if (!simConfigDB.loadCPP(filename, cppArgs)) { cprintf("Error processing file %s\n", filename); exit(1); @@ -375,10 +325,6 @@ main(int argc, char **argv) } } - // Final check for default.ini, in case no config files or - // command-line config parameters were given. - handleDefaultIni(loadDefaultIni, cppArgs); - // The configuration database is now complete; start processing it. // Parse and check all non-config-hierarchy parameters. @@ -396,13 +342,16 @@ main(int argc, char **argv) // Echo command line and all parameter settings to stats file as well. echoCommandLine(argc, argv, *outputStream); - ParamContext::showAllContexts(builderStream()); + ParamContext::showAllContexts(*configStream); // Now process the configuration hierarchy and create the SimObjects. ConfigHierarchy configHierarchy(simConfigDB); configHierarchy.build(); configHierarchy.createSimObjects(); + // Do a second pass to finish initializing the sim objects + SimObject::initAll(); + // Restore checkpointed state, if any. configHierarchy.unserializeSimObjects(); @@ -435,9 +384,8 @@ main(int argc, char **argv) exit(1); } - SimInit(); warn("Entering event queue. Starting simulation...\n"); - + SimStartup(); while (!mainEventQueue.empty()) { assert(curTick <= mainEventQueue.nextTick() && "event scheduled in the past"); diff --git a/sim/param.cc b/sim/param.cc index 4f9d0a577..d20be8d33 100644 --- a/sim/param.cc +++ b/sim/param.cc @@ -211,6 +211,11 @@ template <class T> void VectorParam<T>::parse(const string &s) { + if (s.empty()) { + wasSet = true; + return; + } + vector<string> tokens; tokenize(tokens, s, ' '); @@ -555,15 +560,27 @@ SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) list<ParamContext *> *ParamContext::ctxList = NULL; -ParamContext::ParamContext(const string &_iniSection, bool noAutoParse) +ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) : iniFilePtr(NULL), // initialized on call to parseParams() - iniSection(_iniSection), paramList(NULL) + iniSection(_iniSection), paramList(NULL), + initPhase(_initPhase) { - if (!noAutoParse) { + // Put this context on global list for initialization + if (initPhase != NoAutoInit) { if (ctxList == NULL) ctxList = new list<ParamContext *>(); - (*ctxList).push_back(this); + // keep list sorted by ascending initPhase values + list<ParamContext *>::iterator i = ctxList->begin(); + list<ParamContext *>::iterator end = ctxList->end(); + for (; i != end; ++i) { + if (initPhase <= (*i)->initPhase) { + // found where we want to insert + break; + } + } + // (fall through case: insert at end) + ctxList->insert(i, this); } } diff --git a/sim/param.hh b/sim/param.hh index fe13edc48..ac57afa31 100644 --- a/sim/param.hh +++ b/sim/param.hh @@ -34,6 +34,7 @@ #include <vector> #include "sim/configfile.hh" +#include "sim/startup.hh" // forward decls class BaseParam; @@ -44,7 +45,7 @@ class SimObject; // SimObjectBuilder (which derives from ParamContext), but abstracted // here to support more global simulator control parameters as well. // -class ParamContext +class ParamContext : protected StartupCallback { private: @@ -74,11 +75,30 @@ class ParamContext public: - // Second arg, if set to true, says don't put on paramContextList - // (i.e. don't automatically parse params). Used by derived - // SimObjectBuilder class, where parsing is done in - // SimObject::create() - ParamContext(const std::string &_iniSection, bool noAutoParse = false); + /// Initialization phases for ParamContext objects. + enum InitPhase { + NoAutoInit = -1, ///< Don't initialize at all... params + /// will be parsed later (used by + /// SimObjectBuilder, which parses + /// params in SimObject::create(). + OutputInitPhase = 0, ///< Output stream initialization + TraceInitPhase = 1, ///< Trace context initialization: + /// depends on output streams, but + /// needs to come before others so we + /// can use tracing in other + /// ParamContext init code + StatsInitPhase = 2, ///< Stats output initialization + DefaultInitPhase = 3 ///< Everything else + }; + + /// Records the initialization phase for this ParamContext. + InitPhase initPhase; + + /// Constructor. + /// @param _iniSection Name of .ini section corresponding to this context. + /// @param _initPhase Initialization phase (see InitPhase). + ParamContext(const std::string &_iniSection, + InitPhase _initPhase = DefaultInitPhase); virtual ~ParamContext() {} diff --git a/sim/process.cc b/sim/process.cc index 7f93c1d9e..bd1a2d8fd 100644 --- a/sim/process.cc +++ b/sim/process.cc @@ -34,6 +34,7 @@ #include "base/intmath.hh" #include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" #include "base/statistics.hh" #include "cpu/exec_context.hh" #include "cpu/full_cpu/smt.hh" @@ -161,7 +162,7 @@ Process::registerExecContext(ExecContext *xc) void -Process::replaceExecContext(int xcIndex, ExecContext *xc) +Process::replaceExecContext(ExecContext *xc, int xcIndex) { if (xcIndex >= execContexts.size()) { panic("replaceExecContext: bad xcIndex, %d >= %d\n", @@ -263,6 +264,18 @@ LiveProcess::LiveProcess(const string &name, ObjectFile *objFile, // load object file into target memory objFile->loadSections(memory); + // load up symbols, if any... these may be used for debugging or + // profiling. + if (!debugSymbolTable) { + debugSymbolTable = new SymbolTable(); + if (!objFile->loadGlobalSymbols(debugSymbolTable) || + !objFile->loadLocalSymbols(debugSymbolTable)) { + // didn't load any symbols + delete debugSymbolTable; + debugSymbolTable = NULL; + } + } + // Set up stack. On Alpha, stack goes below text section. This // code should get moved to some architecture-specific spot. stack_base = text_base - (409600+4096); @@ -392,14 +405,10 @@ CREATE_SIM_OBJECT(LiveProcess) // dummy for default env vector<string> null_vec; - // We do this with "temp" because of the bogus compiler warning - // you get with g++ 2.95 -O if you just "return new LiveProcess(..." - LiveProcess *temp = LiveProcess::create(getInstanceName(), - stdin_fd, stdout_fd, stderr_fd, - cmd, - env.isValid() ? env : null_vec); - - return temp; + return LiveProcess::create(getInstanceName(), + stdin_fd, stdout_fd, stderr_fd, + cmd, + env.isValid() ? env : null_vec); } diff --git a/sim/process.hh b/sim/process.hh index bd6adc55c..bb4829875 100644 --- a/sim/process.hh +++ b/sim/process.hh @@ -130,7 +130,7 @@ class Process : public SimObject int registerExecContext(ExecContext *xc); - void replaceExecContext(int xcIndex, ExecContext *xc); + void replaceExecContext(ExecContext *xc, int xcIndex); // map simulator fd sim_fd to target fd tgt_fd void dup_fd(int sim_fd, int tgt_fd); diff --git a/sim/serialize.cc b/sim/serialize.cc index 91548f653..2a5e3d398 100644 --- a/sim/serialize.cc +++ b/sim/serialize.cc @@ -335,10 +335,7 @@ SerializeParamContext::checkParams() if (serialize_dir.isValid()) { checkpointDirBase = serialize_dir; } else { - if (outputDirectory.empty()) - checkpointDirBase = "m5.%012d"; - else - checkpointDirBase = outputDirectory + "cpt.%012d"; + checkpointDirBase = outputDirectory + "cpt.%012d"; } // guarantee that directory ends with a '/' diff --git a/sim/sim_events.cc b/sim/sim_events.cc index c454fdcf9..99c09f259 100644 --- a/sim/sim_events.cc +++ b/sim/sim_events.cc @@ -34,7 +34,7 @@ #include "sim/param.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" -#include "sim/sim_init.hh" +#include "sim/startup.hh" #include "sim/stats.hh" using namespace std; @@ -210,12 +210,11 @@ ProgressEvent::description() // Parameter space for execution address tracing options. Derive // from ParamContext so we can override checkParams() function. -class ProgressParamContext : public ParamContext +struct ProgressParamContext : public ParamContext { - public: ProgressParamContext(const string &_iniSection) : ParamContext(_iniSection) {} - void checkParams(); + void startup(); }; ProgressParamContext progessMessageParams("progress"); @@ -223,24 +222,9 @@ ProgressParamContext progessMessageParams("progress"); Param<Tick> progress_interval(&progessMessageParams, "cycle", "cycle interval for progress messages"); -namespace { - struct SetupProgress : public Callback - { - Tick interval; - SetupProgress(Tick tick) : interval(tick) {} - - virtual void process() - { - new ProgressEvent(&mainEventQueue, interval); - delete this; - } - }; -} - -/* check execute options */ void -ProgressParamContext::checkParams() +ProgressParamContext::startup() { if (progress_interval.isValid()) - registerInitCallback(new SetupProgress(progress_interval)); + new ProgressEvent(&mainEventQueue, progress_interval); } diff --git a/sim/sim_object.hh b/sim/sim_object.hh index dfd70f8ec..f4b316ebb 100644 --- a/sim/sim_object.hh +++ b/sim/sim_object.hh @@ -39,13 +39,14 @@ #include <iostream> #include "sim/serialize.hh" +#include "sim/startup.hh" /* * Abstract superclass for simulation objects. Represents things that * correspond to physical components and can be specified via the * config file (CPUs, caches, etc.). */ -class SimObject : public Serializable +class SimObject : public Serializable, protected StartupCallback { protected: std::string objName; @@ -65,7 +66,8 @@ class SimObject : public Serializable virtual const std::string name() const { return objName; } - // initialization pass of all objects. Gets invoked by SimInit() + // initialization pass of all objects. + // Gets invoked after construction, before unserialize. virtual void init(); static void initAll(); diff --git a/sim/startup.cc b/sim/startup.cc new file mode 100644 index 000000000..ebb4c0bc0 --- /dev/null +++ b/sim/startup.cc @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004 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 <list> + +#include "base/misc.hh" +#include "sim/startup.hh" +#include "sim/debug.hh" + +typedef std::list<StartupCallback *> startupq_t; +startupq_t &startupq() { static startupq_t queue; return queue; } +StartupCallback::StartupCallback() { startupq().push_back(this); } +StartupCallback::~StartupCallback() { startupq().remove(this); } +void StartupCallback::startup() { } + +void +SimStartup() +{ + startupq_t::iterator i = startupq().begin(); + startupq_t::iterator end = startupq().end(); + + while (i != end) { + (*i)->startup(); + ++i; + } +} diff --git a/sim/startup.hh b/sim/startup.hh new file mode 100644 index 000000000..e6c03a500 --- /dev/null +++ b/sim/startup.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 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 __SIM_STARTUP_HH__ +#define __SIM_STARTUP_HH__ + +struct StartupCallback +{ + StartupCallback(); + virtual ~StartupCallback(); + virtual void startup(); +}; + +void SimStartup(); + +#endif // __SIM_STARTUP_HH__ diff --git a/sim/system.cc b/sim/system.cc index b5a0e7a56..c6a65f9d9 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -26,7 +26,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/remote_gdb.hh" #include "cpu/exec_context.hh" +#include "kern/kernel_stats.hh" +#include "mem/functional_mem/memory_control.hh" +#include "mem/functional_mem/physical_memory.hh" #include "targetarch/vtophys.hh" #include "sim/param.hh" #include "sim/system.hh" @@ -38,237 +44,229 @@ vector<System *> System::systemList; int System::numSystemsRunning = 0; -System::System(const std::string _name, - const uint64_t _init_param, - MemoryController *_memCtrl, - PhysicalMemory *_physmem, - const bool _bin, - const std::vector<string> &binned_fns) - - : SimObject(_name), - init_param(_init_param), - memCtrl(_memCtrl), - physmem(_physmem), - bin(_bin), - binned_fns(binned_fns) +System::System(Params *p) + : SimObject(p->name), memctrl(p->memctrl), physmem(p->physmem), + init_param(p->init_param), params(p) { - // increment the number of running systems - numSystemsRunning++; - // add self to global system list systemList.push_back(this); - if (bin == true) { - Kernel = new Stats::MainBin("non TCPIP Kernel stats"); - Kernel->activate(); - User = new Stats::MainBin("User stats"); - int end = binned_fns.size(); - assert(!(end & 1)); + kernelSymtab = new SymbolTable; + consoleSymtab = new SymbolTable; + palSymtab = new SymbolTable; + debugSymbolTable = new SymbolTable; + + /** + * Load the kernel, pal, and console code into memory + */ + // Load kernel code + kernel = createObjectFile(params->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params->kernel_path); + + // Load Console Code + console = createObjectFile(params->console_path); + if (console == NULL) + fatal("Could not load console file %s", params->console_path); + + // Load pal file + pal = createObjectFile(params->palcode); + if (pal == NULL) + fatal("Could not load PALcode file %s", params->palcode); + + + // Load program sections into memory + pal->loadSections(physmem, true); + console->loadSections(physmem, true); + kernel->loadSections(physmem, true); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!console->loadGlobalSymbols(consoleSymtab)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + if (!console->loadGlobalSymbols(debugSymbolTable)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + - Stats::MainBin *Bin; + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); - fnEvents.resize(end>>1); + Addr addr = 0; +#ifdef DEBUG + consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic"); + if (consoleSymtab->findAddress("panic", addr)) + consolePanicEvent->schedule(addr); +#endif - for (int i = 0; i < end; i +=2) { - Bin = new Stats::MainBin(binned_fns[i]); - fnBins.insert(make_pair(binned_fns[i], Bin)); + /** + * Copy the osflags (kernel arguments) into the consoles + * memory. (Presently Linux does not use the console service + * routine to get these command line arguments, but Tru64 and + * others do.) + */ + if (consoleSymtab->findAddress("env_booted_osflags", addr)) { + Addr paddr = vtophys(physmem, addr); + char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t)); - fnEvents[(i>>1)] = new FnEvent(&pcEventQueue, binned_fns[i], this); + if (osflags) + strcpy(osflags, params->boot_osflags.c_str()); + } - if (binned_fns[i+1] == "null") - populateMap(binned_fns[i], ""); - else - populateMap(binned_fns[i], binned_fns[i+1]); - } + /** + * 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 *hwrpb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - fnCalls - .name(name() + ":fnCalls") - .desc("all fn calls being tracked") - ; + if (!hwrpb) + panic("could not translate hwrpb addr\n"); + *(uint64_t*)(hwrpb+0x50) = htoa(params->system_type); + *(uint64_t*)(hwrpb+0x58) = htoa(params->system_rev); } else - Kernel = NULL; -} + panic("could not find hwrpb\n"); + // increment the number of running systms + numSystemsRunning++; + + kernelBinning = new Kernel::Binning(this); +} System::~System() { - if (bin == true) { - int end = fnEvents.size(); - for (int i = 0; i < end; ++i) { - delete fnEvents[i]; - } - fnEvents.clear(); - } + delete kernelSymtab; + delete consoleSymtab; + delete kernel; + delete console; + delete pal; + + delete kernelBinning; + +#ifdef DEBUG + delete consolePanicEvent; +#endif } +bool +System::breakpoint() +{ + return remoteGDB[0]->trap(ALPHA_KENTRY_INT); +} int System::registerExecContext(ExecContext *xc) { - int myIndex = execContexts.size(); + int xcIndex = execContexts.size(); execContexts.push_back(xc); - return myIndex; -} - -void -System::replaceExecContext(int xcIndex, ExecContext *xc) -{ - if (xcIndex >= execContexts.size()) { - panic("replaceExecContext: bad xcIndex, %d >= %d\n", - xcIndex, execContexts.size()); + 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); } - execContexts[xcIndex] = xc; -} + remoteGDB[xcIndex] = rgdb; + return xcIndex; +} void -System::printSystems() +System::startup() { - vector<System *>::iterator i = systemList.begin(); - vector<System *>::iterator end = systemList.end(); - for (; i != end; ++i) { - System *sys = *i; - cerr << "System " << sys->name() << ": " << hex << sys << endl; + if (!execContexts.empty()) { + // activate with zero delay so that we start ticking right + // away on cycle 0 + execContexts[0]->activate(0); } } -extern "C" void -printSystems() +System::replaceExecContext(ExecContext *xc, int xcIndex) { - System::printSystems(); -} + if (xcIndex >= execContexts.size()) { + panic("replaceExecContext: bad xcIndex, %d >= %d\n", + xcIndex, execContexts.size()); + } -void -System::populateMap(std::string callee, std::string caller) -{ - multimap<const string, string>::const_iterator i; - i = callerMap.insert(make_pair(callee, caller)); - assert(i != callerMap.end() && "should not fail populating callerMap"); + execContexts[xcIndex] = xc; + remoteGDB[xcIndex]->replaceExecContext(xc); } -bool -System::findCaller(std::string callee, std::string caller) const +void +System::regStats() { - typedef multimap<const std::string, std::string>::const_iterator iter; - pair<iter, iter> range; - - range = callerMap.equal_range(callee); - for (iter i = range.first; i != range.second; ++i) { - if ((*i).second == caller) - return true; - } - return false; + kernelBinning->regStats(name() + ".kern"); } void -System::dumpState(ExecContext *xc) const +System::serialize(ostream &os) { - if (xc->swCtx) { - stack<fnCall *> copy(xc->swCtx->callStack); - if (copy.empty()) - return; - DPRINTF(TCPIP, "xc->swCtx, size: %d:\n", copy.size()); - fnCall *top; - DPRINTF(TCPIP, "|| call : %d\n",xc->swCtx->calls); - for (top = copy.top(); !copy.empty(); copy.pop() ) { - top = copy.top(); - DPRINTF(TCPIP, "|| %13s : %s \n", top->name, top->myBin->name()); - } - } + kernelBinning->serialize(os); } -Stats::MainBin * -System::getBin(const std::string &name) -{ - std::map<const std::string, Stats::MainBin *>::const_iterator i; - i = fnBins.find(name); - if (i == fnBins.end()) - panic("trying to getBin %s that is not on system map!", name); - return (*i).second; -} -SWContext * -System::findContext(Addr pcb) +void +System::unserialize(Checkpoint *cp, const string §ion) { - std::map<Addr, SWContext *>::const_iterator iter; - iter = swCtxMap.find(pcb); - if (iter != swCtxMap.end()) { - SWContext *ctx = (*iter).second; - assert(ctx != NULL && "should never have a null ctx in ctxMap"); - return ctx; - } else - return NULL; + kernelBinning->unserialize(cp, section); } void -System::serialize(std::ostream &os) +System::printSystems() { - if (bin == true) { - map<const Addr, SWContext *>::const_iterator iter, end; - iter = swCtxMap.begin(); - end = swCtxMap.end(); - - int numCtxs = swCtxMap.size(); - SERIALIZE_SCALAR(numCtxs); - SWContext *ctx; - for (int i = 0; iter != end; ++i, ++iter) { - paramOut(os, csprintf("Addr[%d]",i), (*iter).first); - ctx = (*iter).second; - paramOut(os, csprintf("calls[%d]",i), ctx->calls); - - stack<fnCall *> *stack = &(ctx->callStack); - fnCall *top; - int size = stack->size(); - paramOut(os, csprintf("stacksize[%d]",i), size); - for (int j=0; j<size; ++j) { - top = stack->top(); - paramOut(os, csprintf("ctx[%d].stackpos[%d]",i,j), - top->name); - delete top; - stack->pop(); - } - } + vector<System *>::iterator i = systemList.begin(); + vector<System *>::iterator end = systemList.end(); + for (; i != end; ++i) { + System *sys = *i; + cerr << "System " << sys->name() << ": " << hex << sys << endl; } } +extern "C" void -System::unserialize(Checkpoint *cp, const std::string §ion) +printSystems() { - if (bin == true) { - int numCtxs; - UNSERIALIZE_SCALAR(numCtxs); - - SWContext *ctx; - Addr addr; - int size; - for(int i = 0; i < numCtxs; ++i) { - ctx = new SWContext; - paramIn(cp, section, csprintf("Addr[%d]",i), addr); - paramIn(cp, section, csprintf("calls[%d]",i), ctx->calls); - - paramIn(cp, section, csprintf("stacksize[%d]",i), size); - - vector<fnCall *> calls; - fnCall *call; - for (int j = 0; j < size; ++j) { - call = new fnCall; - paramIn(cp, section, csprintf("ctx[%d].stackpos[%d]",i,j), - call->name); - call->myBin = getBin(call->name); - calls.push_back(call); - } - - for (int j=size-1; j>=0; --j) { - ctx->callStack.push(calls[j]); - } - - addContext(addr, ctx); - } - } + System::printSystems(); } DEFINE_SIM_OBJECT_CLASS_NAME("System", System) diff --git a/sim/system.hh b/sim/system.hh index da974cfdd..07881ff01 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -32,85 +32,123 @@ #include <string> #include <vector> -#include "base/loader/symtab.hh" #include "base/statistics.hh" #include "cpu/pc_event.hh" #include "kern/system_events.hh" #include "sim/sim_object.hh" -#include "sim/sw_context.hh" class MemoryController; class PhysicalMemory; class Platform; class RemoteGDB; class GDBListener; - +class SymbolTable; +class ObjectFile; class ExecContext; +namespace Kernel { class Binning; } class System : public SimObject { - // lisa's binning stuff - private: - std::map<const std::string, Stats::MainBin *> fnBins; - std::map<const Addr, SWContext *> swCtxMap; + public: + MemoryController *memctrl; + PhysicalMemory *physmem; + Platform *platform; + PCEventQueue pcEventQueue; + uint64_t init_param; - protected: - std::vector<FnEvent *> fnEvents; + std::vector<ExecContext *> execContexts; - public: - Stats::Scalar<> fnCalls; - Stats::MainBin *Kernel; - Stats::MainBin *User; + /** kernel Symbol table */ + SymbolTable *kernelSymtab; - Stats::MainBin * getBin(const std::string &name); - bool findCaller(std::string, std::string) const; + /** console symbol table */ + SymbolTable *consoleSymtab; - SWContext *findContext(Addr pcb); - bool addContext(Addr pcb, SWContext *ctx) { - return (swCtxMap.insert(make_pair(pcb, ctx))).second; - } - void remContext(Addr pcb) { - swCtxMap.erase(pcb); - return; - } - void dumpState(ExecContext *xc) const; + /** pal symbol table */ + SymbolTable *palSymtab; - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); + /** Object pointer for the kernel code */ + ObjectFile *kernel; + /** Object pointer for the console code */ + ObjectFile *console; - private: - std::multimap<const std::string, std::string> callerMap; - void populateMap(std::string caller, std::string callee); -// + /** Object pointer for the PAL code */ + ObjectFile *pal; - public: - const uint64_t init_param; - MemoryController *memCtrl; - PhysicalMemory *physmem; - Platform *platform; - bool bin; - std::vector<string> binned_fns; + /** Begining of kernel code */ + Addr kernelStart; - PCEventQueue pcEventQueue; + /** End of kernel code */ + Addr kernelEnd; - std::vector<ExecContext *> execContexts; + /** Entry point in the kernel to start at */ + Addr kernelEntry; - std::string readfile; + Kernel::Binning *kernelBinning; - virtual int registerExecContext(ExecContext *xc); - virtual void replaceExecContext(int xcIndex, ExecContext *xc); +#ifdef DEBUG + /** Event to halt the simulator if the console calls panic() */ + BreakPCEvent *consolePanicEvent; +#endif public: - System(const std::string _name, const uint64_t _init_param, - MemoryController *, PhysicalMemory *, const bool, - const std::vector<string> &binned_fns); + std::vector<RemoteGDB *> remoteGDB; + std::vector<GDBListener *> gdbListen; + bool breakpoint(); + + public: + struct Params + { + std::string name; + MemoryController *memctrl; + PhysicalMemory *physmem; + uint64_t init_param; + bool bin; + std::vector<std::string> binned_fns; + bool bin_int; + + std::string kernel_path; + std::string console_path; + std::string palcode; + std::string boot_osflags; + + std::string readfile; + uint64_t system_type; + uint64_t system_rev; + }; + Params *params; + + System(Params *p); ~System(); - virtual Addr getKernelStart() const = 0; - virtual Addr getKernelEnd() const = 0; - virtual Addr getKernelEntry() const = 0; - virtual bool breakpoint() = 0; + void startup(); + + public: + /** + * 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; } + + int registerExecContext(ExecContext *xc); + void replaceExecContext(ExecContext *xc, int xcIndex); + + void regStats(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); public: //////////////////////////////////////////// diff --git a/sim/universe.cc b/sim/universe.cc index 79e32098c..824b985fa 100644 --- a/sim/universe.cc +++ b/sim/universe.cc @@ -51,14 +51,13 @@ double __ticksPerPS; string outputDirectory; ostream *outputStream; +ostream *configStream; class UniverseParamContext : public ParamContext { - private: - ofstream outputFile; - public: - UniverseParamContext(const string &is) : ParamContext(is) {} + UniverseParamContext(const string &is) + : ParamContext(is, OutputInitPhase) {} void checkParams(); }; @@ -68,9 +67,14 @@ Param<Tick> universe_freq(&universe, "frequency", "tick frequency", 200000000); Param<string> universe_output_dir(&universe, "output_dir", - "directory to output data to"); + "directory to output data to", + "."); Param<string> universe_output_file(&universe, "output_file", - "file to dump simulator output to"); + "file to dump simulator output to", + "cout"); +Param<string> universe_config_output_file(&universe, "config_output_file", + "file to dump simulator config to", + "m5config.out"); void UniverseParamContext::checkParams() @@ -97,26 +101,49 @@ UniverseParamContext::checkParams() } } - string filename; - if (universe_output_file.isValid()) { - string f = universe_output_file; - if (f != "stdout" && f != "cout" && f != "stderr" && f != "cerr") - filename = outputDirectory + f; - else - filename = f; - } else { - if (outputDirectory.empty()) - filename = "stdout"; - else - filename = outputDirectory + "output.txt"; - } + outputStream = makeOutputStream(universe_output_file); + configStream = universe_config_output_file.isValid() + ? makeOutputStream(universe_config_output_file) + : outputStream; +} - if (filename == "stdout" || filename == "cout") - outputStream = &cout; - else if (filename == "stderr" || filename == "cerr") - outputStream = &cerr; - else { - outputFile.open(filename.c_str(), ios::trunc); - outputStream = &outputFile; - } + +std::ostream * +makeOutputStream(std::string &name) +{ + if (name == "cerr" || name == "stderr") + return &std::cerr; + + if (name == "cout" || name == "stdout") + return &std::cout; + + string path = (name[0] != '/') ? outputDirectory + name : name; + + // have to dynamically allocate a stream since we're going to + // return it... though the caller can't easily free it since it + // may be cerr or cout. need GC! + ofstream *s = new ofstream(path.c_str(), ios::trunc); + + if (!s->is_open()) + fatal("Cannot open file %s", path); + + return s; } + + +void +closeOutputStream(std::ostream *os) +{ + // can't close cerr or cout + if (os == &std::cerr || os == &std::cout) + return; + + // can only close ofstreams, not generic ostreams, so try to + // downcast and close only if the downcast succeeds + std::ofstream *ofs = dynamic_cast<std::ofstream *>(os); + if (ofs) + ofs->close(); +} + + + diff --git a/util/ccdrv/devtime.c b/util/ccdrv/devtime.c index e487f2fe7..62b0e2592 100644 --- a/util/ccdrv/devtime.c +++ b/util/ccdrv/devtime.c @@ -48,6 +48,9 @@ static char *dataAddr = NULL; static int count = 0; +#ifdef __alpha__ +static int memTest = 0; +#endif static inline uint32_t cycleCounter(uint32_t dep); @@ -63,6 +66,31 @@ static int __init devtime_start(void) printk("Devtime Driver Version %s Loaded...\n", DRIVER_VER); +#ifdef __alpha__ + if (memTest) { + addr = 0xfffffc0000000000; +// addr += 16*1024*1024; + + printk("Preparing memory test.\n"); + + t1 = cycleCounter(trash); + for (x = 0; x < count; x++) { + trash = readl(addr); + t2 = cycleCounter(trash); + times[num++] = t2 - t1; + t1 = t2; + addr += 4096; + } + + printk("Measurements:\n"); + for (x = 0; x < count; x++) { + printk("%d ", times[x]); + if (((x + 1) % 10) == 0) + printk("\n"); + } + printk("\nDone.\n"); + } else +#endif if (dataAddr != 0 && count != 0) { addr = simple_strtoull(dataAddr, NULL, 0); @@ -145,7 +173,7 @@ inline uint32_t cycleCounter(uint32_t dep) return res; } #else -#error Architecture NOT SUPPORTE +#error Architecture NOT SUPPORTED #endif static void __exit devtime_end(void) @@ -162,3 +190,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); module_param(dataAddr, charp, 0); module_param(count, int, 0); +#ifdef __alpha__ +module_param(memTest, int, 0); +#endif diff --git a/util/stats/info.py b/util/stats/info.py index a94563cf9..fa318a650 100644 --- a/util/stats/info.py +++ b/util/stats/info.py @@ -47,28 +47,21 @@ def wrapop(op, lv, rv): return op(lv, rv) -def same(lv, rv): - for lrun,rrun in zip(lv.keys(),rv.keys()): - if lrun != rrun: - print 'lrun != rrun' - print lrun, rrun - print lv.keys() - print rv.keys() +def same(lrun, rrun): + for lx,rx in zip(lrun.keys(),rrun.keys()): + if lx != rx: + print 'lx != rx' + print lx, rx + print lrun.keys() + print rrun.keys() return False - for lx,rx in zip(lv[lrun].keys(),rv[rrun].keys()): - if lx != rx: - print 'lx != rx' - print lx, rx - print lv[lrun].keys() - print rv[rrun].keys() + for ly,ry in zip(lrun[lx].keys(),rrun[rx].keys()): + if ly != ry: + print 'ly != ry' + print ly, ry + print lrun[lx].keys() + print rrun[rx].keys() return False - for ly,ry in zip(lv[lrun][lx].keys(),rv[rrun][rx].keys()): - if ly != ry: - print 'ly != ry' - print ly, ry - print lv[lrun][lx].keys() - print rv[rrun][rx].keys() - return False return True @@ -79,10 +72,15 @@ def binaryop(op, lf, rf): lv = lf.value rv = rf.value - if not same(lv, rv): - raise AttributeError, "run,x,y not identical" + theruns = [] + for r in lv.keys(): + if rv.has_key(r): + if same(lv[r], rv[r]): + theruns.append(r) + else: + raise AttributeError - for run in lv.keys(): + for run in theruns: result[run] = {} for x in lv[run].keys(): result[run][x] = {} @@ -152,9 +150,8 @@ class Statistic(object): def __setattr__(self, attr, value): if attr == 'bins' or attr == 'ticks': if attr == 'bins': - global db if value is not None: - value = db.getBin(value) + value = source.getBin(value) elif attr == 'samples' and type(value) is str: value = [ int(x) for x in value.split() ] diff --git a/util/stats/stats.py b/util/stats/stats.py index 1d521fd9d..68ba2b8ea 100755 --- a/util/stats/stats.py +++ b/util/stats/stats.py @@ -39,26 +39,51 @@ def unique(list): map(set.__setitem__, list, []) return set.keys() -def graphdata(runs, tag, label, value): +def graphdata(runs, options, tag, label, value): import info - configs = ['std', 'csa', 'ht1', 'ht4', 'htx', 'ocm', 'occ', 'ocp' ] - benchmarks = [ 'm', 's' ] - dmas = [ 'x', 'd', 'b' ] - caches = [ '1', '2', '3', '4', '5' ] - systems = [ 'M' ] - checkpoints = [ '1' ] + configs = ['ste', 'hte', 'htd', 'ocm', 'occ', 'ocp' ] + #benchmarks = [ 'm', 's', 'nb1', 'nb2', 'nt1', 'nt2', 'w1', 'w2', 'w3', 'w4', 'ns', 'nm', 'nw1', 'nw2', 'nw3' ] + #benchmarks = [ 'm', 's', 'nb1', 'nb2', 'nt1', 'w1', 'w2', 'w3', 'ns', 'nm', 'w1s' ] + benchmarks = [ 'm', 's', 'nb1', 'nb2', 'w1', 'w2', 'w3', 'w4', 'ns', 'nm', 'nw1', 'snt' ] + #dmas = [ 'x', 'd', 'b' ] + dmas = [ 'x' ] + caches = [ '2', '4' ] names = [] + + bench_system = { + 'm' : 'client', + 's' : 'client', + 'snt' : 'client', + 'nb1' : 'server', + 'nb2' : 'server', + 'nt1' : 'server', + 'nt2' : 'server', + 'w1' : 'server', + 'w2' : 'server', + 'w3' : 'server', + 'w4' : 'server', + 'w1s' : 'server', + 'w2s' : 'server', + 'w3s' : 'server', + 'ns' : 'natbox', + 'nm' : 'natbox', + 'nw1' : 'natbox', + 'nw2' : 'natbox', + 'nw3' : 'natbox' + } + for bench in benchmarks: + if bench_system[bench] != options.system: + continue + for dma in dmas: for cache in caches: - for sys in systems: - for cpt in checkpoints: - names.append([bench, dma, cache, sys, cpt]) + names.append([bench, dma, cache]) - for bench,dma,cache,sys,cpt in names: - base = '%s.%s.%s.%s.%s' % (bench, dma, cache, sys, cpt) - fname = '/n/ziff/z/binkertn/graph/data.ibm/%s.%s.dat' % (tag, base) + for bench,dma,cache in names: + base = '%s.%s.%s' % (bench, dma, cache) + fname = 'data/%s.%s.dat' % (tag, base) f = open(fname, 'w') print >>f, '#set TITLE = %s' % base print >>f, '#set xlbl = Configuration' @@ -68,8 +93,7 @@ def graphdata(runs, tag, label, value): for speed,freq in zip(['s', 'q'],['4GHz','10GHz']): print >>f, '"%s"' % freq, for conf in configs: - name = '%s.%s.%s.%s.%s.%s.%s' % (conf, bench, dma, speed, - cache, sys, cpt) + name = '%s.%s.%s.%s.%s' % (conf, bench, dma, cache, speed) run = info.source.allRunNames[name] info.display_run = run.run; val = float(value) @@ -134,8 +158,6 @@ def commands(options, command, args): info.source.connect() info.source.update_dict(globals()) - system = info.source.__dict__[options.system] - if type(options.get) is str: info.source.get = options.get @@ -177,13 +199,66 @@ def commands(options, command, args): stats = info.source.getStat(args[0]) for stat in stats: - if graph: - graphdata(runs, stat.name, stat.name, stat) + if options.graph: + graphdata(runs, options, stat.name, stat.name, stat) else: + if options.binned: + print 'kernel ticks' + stat.bins = 'kernel' + printdata(runs, stat) + + print 'idle ticks' + stat.bins = 'idle' + printdata(runs, stat) + + print 'user ticks' + stat.bins = 'user' + printdata(runs, stat) + + print 'interrupt ticks' + stat.bins = 'user' + printdata(runs, stat) + + print 'total ticks' + + stat.bins = None print stat.name printdata(runs, stat) return + if command == 'formula': + if len(args) != 1: + raise CommandException + + stats = eval(args[0]) + for stat in stats: + if options.graph: + graphdata(runs, options, stat.name, stat.name, stat) + else: + if options.binned: + print 'kernel ticks' + stat.bins = 'kernel' + printdata(runs, stat) + + print 'idle ticks' + stat.bins = 'idle' + printdata(runs, stat) + + print 'user ticks' + stat.bins = 'user' + printdata(runs, stat) + + print 'interrupt ticks' + stat.bins = 'user' + printdata(runs, stat) + + print 'total ticks' + + stat.bins = None + print args[0] + printdata(runs, stat) + return + if command == 'bins': if len(args) == 0: info.source.listBins() @@ -214,6 +289,8 @@ def commands(options, command, args): if len(args): raise CommandException + system = info.source.__dict__[options.system] + if command == 'usertime': import copy kernel = copy.copy(system.full_cpu.numCycles) @@ -222,15 +299,15 @@ def commands(options, command, args): user = copy.copy(system.full_cpu.numCycles) user.bins = 'user' - if graph: - graphdata(runs, 'usertime', 'User Fraction', + if options.graph: + graphdata(runs, options, 'usertime', 'User Fraction', user / system.full_cpu.numCycles) else: printdata(runs, user / system.full_cpu.numCycles) return if command == 'ticks': - if binned: + if options.binned: print 'kernel ticks' system.full_cpu.numCycles.bins = 'kernel' printdata(runs, system.full_cpu.numCycles) @@ -250,37 +327,37 @@ def commands(options, command, args): return if command == 'packets': - packets = system.tsunami.nsgige.rxPackets - if graph: - graphdata(runs, 'packets', 'Packets', packets) + packets = system.tsunami.etherdev.rxPackets + if options.graph: + graphdata(runs, options, 'packets', 'Packets', packets) else: printdata(runs, packets) return if command == 'ppt' or command == 'tpp': - ppt = system.tsunami.nsgige.rxPackets / sim_ticks + ppt = system.tsunami.etherdev.rxPackets / sim_ticks printdata(runs, ppt, command == 'tpp') return if command == 'pps': - pps = system.tsunami.nsgige.rxPackets / sim_seconds - if graph: - graphdata(runs, 'pps', 'Packets/s', pps) + pps = system.tsunami.etherdev.rxPackets / sim_seconds + if options.graph: + graphdata(runs, options, 'pps', 'Packets/s', pps) else: printdata(runs, pps) return if command == 'bpt' or command == 'tpb': - bytes = system.tsunami.nsgige.rxBytes + system.tsunami.nsgige.txBytes + bytes = system.tsunami.etherdev.rxBytes + system.tsunami.etherdev.txBytes bpt = bytes / sim_ticks * 8 - if graph: - graphdata(runs, 'bpt', 'bps / Hz', bpt) + if options.graph: + graphdata(runs, options, 'bpt', 'bps / Hz', bpt) else: printdata(runs, bpt, command == 'tpb') return if command == 'bptb' or command == 'tpbb': - bytes = system.tsunami.nsgige.rxBytes + system.tsunami.nsgige.txBytes + bytes = system.tsunami.etherdev.rxBytes + system.tsunami.etherdev.txBytes print 'kernel stats' bytes.bins = 'kernel' @@ -297,9 +374,9 @@ def commands(options, command, args): return if command == 'bytes': - stat = system.tsunami.nsgige.rxBytes + system.tsunami.nsgige.txBytes + stat = system.tsunami.etherdev.rxBytes + system.tsunami.etherdev.txBytes - if binned: + if options.binned: print '%s kernel stats' % stat.name stat.bins = 'kernel' printdata(runs, stat) @@ -319,34 +396,34 @@ def commands(options, command, args): return if command == 'rxbps': - gbps = system.tsunami.nsgige.rxBandwidth / 1e9 - if graph: - graphdata(runs, 'rxbps', 'Bandwidth (Gbps)', gbps) + gbps = system.tsunami.etherdev.rxBandwidth / 1e9 + if options.graph: + graphdata(runs, options, 'rxbps', 'Bandwidth (Gbps)', gbps) else: printdata(runs, gbps) return if command == 'txbps': - gbps = system.tsunami.nsgige.txBandwidth / 1e9 - if graph: - graphdata(runs, 'txbps', 'Bandwidth (Gbps)', gbps) + gbps = system.tsunami.etherdev.txBandwidth / 1e9 + if options.graph: + graphdata(runs, options, 'txbps', 'Bandwidth (Gbps)', gbps) else: printdata(runs, gbps) return if command == 'bps': - rxbps = system.tsunami.nsgige.rxBandwidth - txbps = system.tsunami.nsgige.txBandwidth + rxbps = system.tsunami.etherdev.rxBandwidth + txbps = system.tsunami.etherdev.txBandwidth gbps = (rxbps + txbps) / 1e9 - if graph: - graphdata(runs, 'bps', 'Bandwidth (Gbps)', gbps) + if options.graph: + graphdata(runs, options, 'bps', 'Bandwidth (Gbps)', gbps) else: printdata(runs, gbps) return if command == 'misses': - stat = system.L3.overall_mshr_misses - if binned: + stat = system.L2.overall_mshr_misses + if options.binned: print '%s kernel stats' % stat.name stat.bins = 'kernel' printdata(runs, stat) @@ -362,18 +439,18 @@ def commands(options, command, args): print '%s total stats' % stat.name stat.bins = None - if graph: - graphdata(runs, 'misses', 'Overall MSHR Misses', stat) + if options.graph: + graphdata(runs, options, 'misses', 'Overall MSHR Misses', stat) else: printdata(runs, stat) return if command == 'mpkb': - misses = system.L3.overall_mshr_misses - rxbytes = system.tsunami.nsgige.rxBytes - txbytes = system.tsunami.nsgige.txBytes + misses = system.L2.overall_mshr_misses + rxbytes = system.tsunami.etherdev.rxBytes + txbytes = system.tsunami.etherdev.txBytes - if binned: + if options.binned: print 'mpkb kernel stats' misses.bins = 'kernel' mpkb = misses / ((rxbytes + txbytes) / 1024) @@ -393,12 +470,43 @@ def commands(options, command, args): mpkb = misses / ((rxbytes + txbytes) / 1024) misses.bins = None - if graph: - graphdata(runs, 'mpkb', 'Misses / KB', mpkb) + if options.graph: + graphdata(runs, options, 'mpkb', 'Misses / KB', mpkb) else: printdata(runs, mpkb) return + if command == 'ipkb': + interrupts = system.full_cpu.kern.faults[4] + rxbytes = system.tsunami.etherdev.rxBytes + txbytes = system.tsunami.etherdev.txBytes + + if options.binned: + print 'ipkb kernel stats' + interrupts.bins = 'kernel' + ipkb = interrupts / ((rxbytes + txbytes) / 1024) + printdata(runs, ipkb) + + print 'ipkb idle stats' + interrupts.bins = 'idle' + ipkb = interrupts / ((rxbytes + txbytes) / 1024) + printdata(runs, ipkb) + + print 'ipkb user stats' + interrupts.bins = 'user' + ipkb = interrupts / ((rxbytes + txbytes) / 1024) + printdata(runs, ipkb) + + print 'ipkb total stats' + + ipkb = interrupts / ((rxbytes + txbytes) / 1024) + interrupts.bins = None + if options.graph: + graphdata(runs, options, 'ipkb', 'Interrupts / KB', ipkb) + else: + printdata(runs, ipkb) + return + if command == 'execute': printdata(runs, system.full_cpu.ISSUE__count) return @@ -411,21 +519,49 @@ def commands(options, command, args): printdata(runs, system.full_cpu.FETCH__count) return + if command == 'bpp': + ed = system.tsunami.etherdev + bpp = (ed.rxBytes + ed.txBytes) / (ed.rxPackets + ed.txPackets) + if options.graph: + graphdata(runs, options, 'bpp', 'Bytes / Packet', bpp) + else: + printdata(runs, bpp) + return + if command == 'rxbpp': - bpp = system.tsunami.nsgige.rxBytes / system.tsunami.nsgige.rxPackets - printdata(run, 8 * bpp) + bpp = system.tsunami.etherdev.rxBytes / system.tsunami.etherdev.rxPackets + if options.graph: + graphdata(runs, options, 'rxbpp', 'Receive Bytes / Packet', bpp) + else: + printdata(runs, bpp) return if command == 'txbpp': - bpp = system.tsunami.nsgige.txBytes / system.tsunami.nsgige.txPackets - printdata(run, 8 * bpp) + bpp = system.tsunami.etherdev.txBytes / system.tsunami.etherdev.txPackets + if options.graph: + graphdata(runs, options, 'txbpp', 'Transmit Bytes / Packet', bpp) + else: + printdata(runs, bpp) return - raise CommandException + if command == 'rtp': + rtp = system.tsunami.etherdev.rxPackets / system.tsunami.etherdev.txPackets + if options.graph: + graphdata(runs, options, 'rtp', 'rxPackets / txPackets', rtp) + else: + printdata(runs, rtp) + return + if command == 'rtb': + rtb = system.tsunami.etherdev.rxBytes / system.tsunami.etherdev.txBytes + if options.graph: + graphdata(runs, options, 'rtb', 'rxBytes / txBytes', rtb) + else: + printdata(runs, rtb) + return + + raise CommandException -graph = False -binned = False class Options: pass @@ -440,6 +576,8 @@ if __name__ == '__main__': options.runs = None options.system = 'client' options.get = None + options.binned = False + options.graph = False opts, args = getopts(sys.argv[1:], '-BEFGd:g:h:pr:s:u:') for o,a in opts: diff --git a/util/tracediff b/util/tracediff index ed35d5dd7..a95ce8b82 100755 --- a/util/tracediff +++ b/util/tracediff @@ -27,10 +27,20 @@ # # Authors: Steve Reinhardt -# Script to simplify using rundiff on trace outputs from two invocations of m5. +# Script to simplify using rundiff on trace outputs from two +# invocations of m5. +# +# Note that you need to enable some trace flags in the args in order +# to do anything useful! +# +# If you want to pass different arguments to the two instances of m5, +# you can embed them in the simulator arguments like this: +# +# % tracediff "m5.opt --foo:bar=1" "m5.opt --foo:bar=2" [common args] +# if (@ARGV < 2) { - die "Usage: tracediff sim1 sim2 [args...]\n"; + die "Usage: tracediff sim1 sim2 [--trace:flags=X args...]\n"; } # First two args are the two simulator binaries to compare @@ -41,6 +51,10 @@ $sim2 = shift; # be given to both invocations $simargs = '"' . join('" "', @ARGV) . '"'; +# Redirect config output to cout so that gets diffed too (in case +# that's the source of the problem). +$simargs += " --Universe:config_output_file=cout"; + $cmd1 = "$sim1 $simargs --stats:text_file=tracediff-$$-1.stats 2>&1 |"; $cmd2 = "$sim2 $simargs --stats:text_file=tracediff-$$-2.stats 2>&1 |"; |