diff options
author | Ali Saidi <saidi@eecs.umich.edu> | 2004-06-23 17:55:54 -0400 |
---|---|---|
committer | Ali Saidi <saidi@eecs.umich.edu> | 2004-06-23 17:55:54 -0400 |
commit | 17bfb1540e938406548202f3f1c941857f514c33 (patch) | |
tree | 6b39561099e011efbc9f59be4048b1cca4fa96a8 | |
parent | 231fac0a2b4ed7c882c6d83c279bf2a4d2083726 (diff) | |
parent | 06d8f0af5def68e395b58636d5e7d6ca69daa51f (diff) | |
download | gem5-17bfb1540e938406548202f3f1c941857f514c33.tar.xz |
Merge zizzer:/bk/linux into zeep.eecs.umich.edu:/z/saidi/work/m5-endian
--HG--
extra : convert_revision : d4938c6011173d3017f47fd592c4b5e4c8d543a3
32 files changed, 1945 insertions, 367 deletions
diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc index d7004b461..a40ad7a5c 100644 --- a/arch/alpha/alpha_memory.cc +++ b/arch/alpha/alpha_memory.cc @@ -101,18 +101,34 @@ AlphaTLB::checkCacheability(MemReqPtr &req) * to catch a weird case where both are used, which shouldn't happen. */ + +#ifdef ALPHA_TLASER + if (req->paddr & PA_UNCACHED_BIT_39) { +#else if (req->paddr & PA_UNCACHED_BIT_43) { +#endif // IPR memory space not implemented - if (PA_IPR_SPACE(req->paddr)) - if (!req->xc->misspeculating()) - panic("IPR memory space not implemented! PA=%x\n", - req->paddr); - - // mark request as uncacheable - req->flags |= UNCACHEABLE; + if (PA_IPR_SPACE(req->paddr)) { + if (!req->xc->misspeculating()) { + switch (req->paddr) { + case ULL(0xFFFFF00188): + req->data = 0; + break; + + default: + panic("IPR memory space not implemented! PA=%x\n", + req->paddr); + } + } + } else { + // mark request as uncacheable + req->flags |= UNCACHEABLE; - // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) - req->paddr &= PA_UNCACHED_MASK; +#ifndef ALPHA_TLASER + // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) + req->paddr &= PA_UNCACHED_MASK; +#endif + } } } @@ -301,7 +317,13 @@ AlphaITB::translate(MemReqPtr &req) const // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 +#ifdef ALPHA_TLASER + if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && + VA_SPACE_EV5(req->vaddr) == 2) { +#else if (VA_SPACE_EV6(req->vaddr) == 0x7e) { +#endif + // only valid in kernel mode if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) { @@ -312,11 +334,13 @@ AlphaITB::translate(MemReqPtr &req) const req->paddr = req->vaddr & PA_IMPL_MASK; +#ifndef ALPHA_TLASER // sign extend the physical address properly if (req->paddr & PA_UNCACHED_BIT_40) req->paddr |= ULL(0xf0000000000); else req->paddr &= ULL(0xffffffffff); +#endif } else { // not a physical address: need to look up pte @@ -430,12 +454,19 @@ AlphaDTB::regStats() } void -AlphaDTB::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const +AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const { + ExecContext *xc = req->xc; + Addr vaddr = req->vaddr; uint64_t *ipr = xc->regs.ipr; - // set fault address and flags - if (!xc->misspeculating() && !xc->regs.intrlock) { + // Set fault address and flags. Even though we're modeling an + // EV5, we use the EV6 technique of not latching fault registers + // on VPTE loads (instead of locking the registers until IPR_VA is + // read, like the EV5). The EV6 approach is cleaner and seems to + // work with EV5 PAL code, but not the other way around. + if (!xc->misspeculating() + && !(req->flags & VPTE) && !(req->flags & NO_FAULT)) { // set VA register with faulting address ipr[AlphaISA::IPR_VA] = vaddr; @@ -447,9 +478,6 @@ AlphaDTB::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const // set VA_FORM register with faulting formatted address ipr[AlphaISA::IPR_VA_FORM] = ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3); - - // lock these registers until the VA register is read - xc->regs.intrlock = true; } } @@ -474,35 +502,38 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const } else { // verify that this is a good virtual address if (!validVirtualAddress(req->vaddr)) { - fault(req->vaddr, - ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK | - MM_STAT_ACV_MASK), - req->xc); + 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; } // Check for "superpage" mapping +#ifdef ALPHA_TLASER + if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && + VA_SPACE_EV5(req->vaddr) == 2) { +#else if (VA_SPACE_EV6(req->vaddr) == 0x7e) { +#endif // only valid in kernel mode if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) { - fault(req->vaddr, - ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK), - req->xc); + 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; +#ifndef ALPHA_TLASER // sign extend the physical address properly if (req->paddr & PA_UNCACHED_BIT_40) req->paddr |= ULL(0xf0000000000); else req->paddr &= ULL(0xffffffffff); +#endif } else { if (write) @@ -516,9 +547,8 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const if (!pte) { // page fault - fault(req->vaddr, - ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK), - req->xc); + 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; } @@ -528,29 +558,25 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const if (write) { if (!(pte->xwe & MODE2MASK(mode))) { // declare the instruction access fault - fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK | - (pte->fonw ? MM_STAT_FONW_MASK : 0), - req->xc); + 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->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK, - req->xc); + fault(req, MM_STAT_WR_MASK | MM_STAT_FONW_MASK); write_acv++; return DTB_Fault_Fault; } } else { if (!(pte->xre & MODE2MASK(mode))) { - fault(req->vaddr, - MM_STAT_ACV_MASK | - (pte->fonr ? MM_STAT_FONR_MASK : 0), - req->xc); + fault(req, (MM_STAT_ACV_MASK | + (pte->fonr ? MM_STAT_FONR_MASK : 0))); read_acv++; return DTB_Acv_Fault; } if (pte->fonr) { - fault(req->vaddr, MM_STAT_FONR_MASK, req->xc); + fault(req, MM_STAT_FONR_MASK); read_acv++; return DTB_Fault_Fault; } diff --git a/arch/alpha/alpha_memory.hh b/arch/alpha/alpha_memory.hh index 04dd0dcf1..42bc03ddd 100644 --- a/arch/alpha/alpha_memory.hh +++ b/arch/alpha/alpha_memory.hh @@ -112,7 +112,7 @@ class AlphaDTB : public AlphaTLB Stats::Formula accesses; protected: - void fault(Addr pc, uint64_t flags, ExecContext *xc) const; + void fault(MemReqPtr &req, uint64_t flags) const; public: AlphaDTB(const std::string &name, int size); diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index ecf66f4f5..d2ca71b3a 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -162,6 +162,7 @@ AlphaISA::zeroRegisters(XC *xc) void ExecContext::ev5_trap(Fault fault) { + DPRINTF(Fault, "Fault %s\n", FaultName(fault)); Stats::recordEvent(csprintf("Fault %s", FaultName(fault))); assert(!misspeculating()); @@ -302,11 +303,7 @@ ExecContext::readIpr(int idx, Fault &fault) break; case AlphaISA::IPR_VA: - // SFX: unlocks interrupt status registers retval = ipr[idx]; - - if (!misspeculating()) - regs.intrlock = false; break; case AlphaISA::IPR_VA_FORM: diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh index 517e1111f..5b27dd3dc 100644 --- a/arch/alpha/ev5.hh +++ b/arch/alpha/ev5.hh @@ -32,8 +32,15 @@ #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) @@ -41,9 +48,16 @@ #define DTB_PTE_GH(X) (((X) >> 5) & 0x3) #define DTB_PTE_ASMA(X) (((X) >> 4) & 0x1) -#define ICM_CM(X) (((X) >> 3) & 0x3) +#define ICM_CM(X) (((X) >> 3) & 0x3) + +#ifdef ALPHA_TLASER +#define ITB_ASN_ASN(X) (((X) >> 4) & 0x7f) +#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff) +#else #define ITB_ASN_ASN(X) (((X) >> 4) & 0xff) #define ITB_PTE_PPN(X) (((X) >> 32) & 0x07fffffff) +#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) @@ -52,18 +66,23 @@ #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_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 VA_SPACE_EV6(X) (((X) >> 41) & 0x7f) +#define VA_POFS(X) ((X) & 0x1fff) -#define PA_IMPL_MASK ULL(0xfffffffffff) // for Tsunami #define PA_UNCACHED_BIT_39 ULL(0x8000000000) #define PA_UNCACHED_BIT_40 ULL(0x10000000000) #define PA_UNCACHED_BIT_43 ULL(0x80000000000) #define PA_UNCACHED_MASK ULL(0x807ffffffff) // Clear PA<42:35> +#ifdef ALPHA_TLASER +#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFF00000)) +#define PA_IMPL_MASK ULL(0xffffffffff) +#else #define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFFF00000)) +#define PA_IMPL_MASK ULL(0xfffffffffff) // for Tsunami +#endif #define PA_PFN2PA(X) ((X) << 13) diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 080699ddb..94f5d9bc3 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -1023,7 +1023,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', # and memory access flags (handled here). # Would be nice to autogenerate this list, but oh well. - valid_mem_flags = ['LOCKED', 'EVICT_NEXT', 'PF_EXCLUSIVE'] + valid_mem_flags = ['LOCKED', 'NO_FAULT', 'EVICT_NEXT', 'PF_EXCLUSIVE'] inst_flags = [] mem_flags = [] for f in flags: @@ -1072,7 +1072,7 @@ def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{ # Declare the prefetch instruction object. # convert flags from tuple to list to make them mutable - pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'MemReadOp'] + pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'MemReadOp', 'NO_FAULT'] (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ LoadStoreBase(name, Name + 'Prefetch', ea_code, '', @@ -2391,9 +2391,10 @@ decode OPCODE default Unknown::unknown() { } format MiscPrefetch { - 0xf800: wh64({{ EA = Rb; }}, - {{ xc->writeHint(EA, 64); }}, - IsMemRef, IsStore, MemWriteOp); + 0xf800: wh64({{ EA = Rb & ~ULL(63); }}, + {{ xc->writeHint(EA, 64, memAccessFlags); }}, + IsMemRef, IsDataPrefetch, IsStore, MemWriteOp, + NO_FAULT); } format BasicOperate { diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh index 179e9897f..6559368e4 100644 --- a/arch/alpha/isa_traits.hh +++ b/arch/alpha/isa_traits.hh @@ -153,7 +153,6 @@ class AlphaISA #ifdef FULL_SYSTEM IntReg palregs[NumIntRegs]; // PAL shadow registers InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs - int intrlock; // interrupt register lock flag int intrflag; // interrupt flag bool pal_shadow; // using pal_shadow registers #endif // FULL_SYSTEM diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc index cf2ebbf80..7a38b296b 100644 --- a/arch/alpha/vtophys.cc +++ b/arch/alpha/vtophys.cc @@ -96,20 +96,23 @@ vtophys(ExecContext *xc, Addr vaddr) { Addr ptbr = xc->regs.ipr[AlphaISA::IPR_PALtemp20]; Addr paddr = 0; -// if (PC_PAL(vaddr)) { -// paddr = vaddr & ~ULL(1); -// } else { + //@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)) { + paddr = vaddr & ~ULL(1); + } else if (!ptbr) { + paddr = vaddr; + } else { if (vaddr >= ALPHA_K0SEG_BASE && vaddr <= ALPHA_K0SEG_END) { paddr = ALPHA_K0SEG_TO_PHYS(vaddr); - } else if (!ptbr) { - paddr = vaddr; } else { Addr pte = kernel_pte_lookup(xc->physmem, ptbr, vaddr); uint64_t entry = xc->physmem->phys_read_qword(pte); if (pte && entry_valid(entry)) paddr = PMAP_PTE_PA(entry) | (vaddr & PGOFSET); } -// } + } + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); diff --git a/base/misc.cc b/base/misc.cc index 075ed2af8..0c459352f 100644 --- a/base/misc.cc +++ b/base/misc.cc @@ -61,11 +61,6 @@ __panic(const string &format, cp::ArgList &args, const char *func, delete &args; -#if TRACING_ON - // dump trace buffer, if there is one - Trace::theLog.dump(cerr); -#endif - abort(); } diff --git a/base/traceflags.py b/base/traceflags.py index 3d7623965..14e28219a 100644 --- a/base/traceflags.py +++ b/base/traceflags.py @@ -67,6 +67,7 @@ baseFlags = [ 'AlphaConsole', 'Flow', 'Interrupt', + 'Fault', 'Cycle', 'Loader', 'MMU', @@ -74,6 +75,10 @@ baseFlags = [ 'EthernetPIO', 'EthernetDMA', 'EthernetData', + 'EthernetDesc', + 'EthernetIntr', + 'EthernetSM', + 'EthernetCksum', 'GDBMisc', 'GDBAcc', 'GDBRead', @@ -124,7 +129,7 @@ compoundFlagMap = { 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], - 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' ], + 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ] } diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 6639dbc1a..3692ab511 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -253,7 +253,7 @@ class SimpleCPU : public BaseCPU // need to do this... } - void writeHint(Addr addr, int size) + void writeHint(Addr addr, int size, unsigned flags) { // need to do this... } diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index 9a0425c8f..0315ab7a9 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -72,8 +72,7 @@ class StaticInstBase : public RefCounted /// unconditional branches, memory barriers) or both (e.g., an /// FP/int conversion). /// - If IsMemRef is set, then exactly one of IsLoad or IsStore - /// will be set. Prefetches are marked as IsLoad, even if they - /// prefetch exclusive copies. + /// will be set. /// - If IsControl is set, then exactly one of IsDirectControl or /// IsIndirect Control will be set, and exactly one of /// IsCondControl or IsUncondControl will be set. diff --git a/cpu/trace/reader/ibm_reader.cc b/cpu/trace/reader/ibm_reader.cc new file mode 100644 index 000000000..439931dba --- /dev/null +++ b/cpu/trace/reader/ibm_reader.cc @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2003-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 IBM memory trace format reader. + */ +#include <sstream> + +#include "cpu/trace/reader/ibm_reader.hh" +#include "sim/builder.hh" +#include "base/misc.hh" // for fatal + +using namespace std; + +IBMReader::IBMReader(const string &name, const string &filename) + : MemTraceReader(name) +{ + if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { + // Compressed file, need to use a pipe to gzip. + stringstream buf; + buf << "gzip -d -c " << filename << endl; + trace = popen(buf.str().c_str(), "r"); + } else { + trace = fopen(filename.c_str(), "rb"); + } + if (!trace) { + fatal("Can't open file %s", filename); + } +} + +Tick +IBMReader::getNextReq(MemReqPtr &req) +{ + MemReqPtr tmp_req; + + int c = getc(trace); + if (c != EOF) { + tmp_req = new MemReq(); + //int cpu_id = (c & 0xf0) >> 4; + int type = c & 0x0f; + // We have L1 miss traces, so all accesses are 128 bytes + tmp_req->size = 128; + + tmp_req->paddr = 0; + for (int i = 2; i >= 0; --i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of file"); + } + tmp_req->paddr |= ((c & 0xff) << (8 * i)); + } + tmp_req->paddr = tmp_req->paddr << 7; + + switch(type) { + case IBM_COND_EXCLUSIVE_FETCH: + case IBM_READ_ONLY_FETCH: + tmp_req->cmd = Read; + break; + case IBM_EXCLUSIVE_FETCH: + case IBM_FETCH_NO_DATA: + tmp_req->cmd = Write; + break; + case IBM_INST_FETCH: + tmp_req->cmd = Read; + break; + default: + fatal("Unknown trace entry type."); + } + + } + req = tmp_req; + return 0; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IBMReader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(IBMReader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(IBMReader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(IBMReader) + + +CREATE_SIM_OBJECT(IBMReader) +{ + return new IBMReader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("IBMReader", IBMReader) diff --git a/cpu/trace/reader/ibm_reader.hh b/cpu/trace/reader/ibm_reader.hh new file mode 100644 index 000000000..0f14da24d --- /dev/null +++ b/cpu/trace/reader/ibm_reader.hh @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003-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 IBM memory trace format reader. + */ + +#ifndef __IBM_READER_HH__ +#define __IBM_READER_HH__ + +#include <stdio.h> +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/mem_req.hh" + +/** + * A memory trace reader for the IBM memory trace format. + */ +class IBMReader : public MemTraceReader +{ + /** IBM trace file. */ + FILE* trace; + + enum IBMType { + IBM_INST_FETCH, + IBM_READ_ONLY_FETCH, + IBM_COND_EXCLUSIVE_FETCH, + IBM_EXCLUSIVE_FETCH, + IBM_FETCH_NO_DATA + }; + + public: + /** + * Construct an IBMReader. + */ + IBMReader(const std::string &name, const std::string &filename); + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return IBM traces don't store timing information, return 0 + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif //__IBM_READER_HH__ + diff --git a/cpu/trace/reader/itx_reader.cc b/cpu/trace/reader/itx_reader.cc new file mode 100644 index 000000000..54bbbc4ea --- /dev/null +++ b/cpu/trace/reader/itx_reader.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2003-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 Intel ITX memory trace format reader. + */ +#include <sstream> + +#include "cpu/trace/reader/itx_reader.hh" +#include "sim/builder.hh" +#include "base/misc.hh" // for fatal + +using namespace std; + +ITXReader::ITXReader(const string &name, const string &filename) + : MemTraceReader(name) +{ + if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { + // Compressed file, need to use a pipe to gzip. + stringstream buf; + buf << "gzip -d -c " << filename << endl; + trace = popen(buf.str().c_str(), "r"); + } else { + trace = fopen(filename.c_str(), "rb"); + } + if (!trace) { + fatal("Can't open file %s", filename); + } + traceFormat = 0; + int c; + for (int i = 0; i < 4; ++i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + traceFormat |= (c & 0xff) << (8 * i); + } + if (traceFormat > 2) + fatal("Invalid trace format."); +} + +Tick +ITXReader::getNextReq(MemReqPtr &req) +{ + MemReqPtr tmp_req = new MemReq(); + bool phys_val; + do { + int c = getc(trace); + if (c != EOF) { + // Decode first byte + // phys_val<1> | type <2:0> | size <3:0> + phys_val = c & 0x80; + tmp_req->size = (c & 0x0f) + 1; + int type = (c & 0x70) >> 4; + + // Could be a compressed instruction entry, expand if necessary + if (type == ITXCodeComp) { + if (traceFormat != 2) { + fatal("Compressed code entry in non CompCode trace."); + } + if (!codeVirtValid) { + fatal("Corrupt CodeComp entry."); + } + + tmp_req->vaddr = codeVirtAddr; + codeVirtAddr += tmp_req->size; + if (phys_val) { + if (!codePhysValid) { + fatal("Corrupt CodeComp entry."); + } + tmp_req->paddr = codePhysAddr; + if (((tmp_req->paddr & 0xfff) + tmp_req->size) & ~0xfff) { + // Crossed page boundary, next physical address is + // invalid + codePhysValid = false; + } else { + codePhysAddr += tmp_req->size; + } + } else { + codePhysValid = false; + } + type = ITXCode; + tmp_req->cmd = Read; + } else { + // Normal entry + tmp_req->vaddr = 0; + for (int i = 0; i < 4; ++i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + tmp_req->vaddr |= (c & 0xff) << (8 * i); + } + if (type == ITXCode) { + codeVirtAddr = tmp_req->vaddr + tmp_req->size; + codeVirtValid = true; + } + tmp_req->paddr = 0; + if (phys_val) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + // Get the page offset from the virtual address. + tmp_req->paddr = tmp_req->vaddr & 0xfff; + tmp_req->paddr |= (c & 0xf0) << 8; + 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); + } + if (type == ITXCode) { + if (((tmp_req->paddr & 0xfff) + tmp_req->size) + & ~0xfff) { + // Crossing the page boundary, next physical + // address isn't valid + codePhysValid = false; + } else { + codePhysAddr = tmp_req->paddr + tmp_req->size; + codePhysValid = true; + } + } + } else if (type == ITXCode) { + codePhysValid = false; + } + switch(type) { + case ITXRead: + tmp_req->cmd = Read; + break; + case ITXWrite: + tmp_req->cmd = Write; + break; + case ITXCode: + tmp_req->cmd = Read; + break; + default: + fatal("Unknown ITX type"); + } + } + } else { + // EOF need to return a null request + MemReqPtr null_req; + req = null_req; + return 0; + } + } while (!phys_val); + req = tmp_req; + return 0; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITXReader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(ITXReader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(ITXReader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(ITXReader) + + +CREATE_SIM_OBJECT(ITXReader) +{ + return new ITXReader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("ITXReader", ITXReader) diff --git a/cpu/trace/reader/itx_reader.hh b/cpu/trace/reader/itx_reader.hh new file mode 100644 index 000000000..ff74062ea --- /dev/null +++ b/cpu/trace/reader/itx_reader.hh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003-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 Intel ITX memory trace format reader. + */ + +#ifndef __ITX_READER_HH__ +#define __ITX_READER_HH__ + +#include <stdio.h> + +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/mem_req.hh" + + +/** + * A memory trace reader for the Intel ITX memory trace format. + */ +class ITXReader : public MemTraceReader +{ + /** Trace file. */ + FILE *trace; + + bool codeVirtValid; + Addr codeVirtAddr; + bool codePhysValid; + Addr codePhysAddr; + + int traceFormat; + + enum ITXType { + ITXRead, + ITXWrite, + ITXWriteback, + ITXCode, + ITXCodeComp + }; + + public: + /** + * Construct an ITXReader. + */ + ITXReader(const std::string &name, const std::string &filename); + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return ITX traces don't store timing information, return 0 + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif //__ITX_READER_HH__ + diff --git a/cpu/trace/reader/m5_reader.cc b/cpu/trace/reader/m5_reader.cc new file mode 100644 index 000000000..a1ada38a2 --- /dev/null +++ b/cpu/trace/reader/m5_reader.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2003-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 reader for a M5 memory trace. + */ + +#include "cpu/trace/reader/m5_reader.hh" +#include "mem/trace/m5_format.hh" +#include "mem/mem_cmd.hh" +#include "sim/builder.hh" + +using namespace std; + +M5Reader::M5Reader(const string &name, const string &filename) + : MemTraceReader(name) +{ + traceFile.open(filename.c_str(), ios::binary); +} + +Tick +M5Reader::getNextReq(MemReqPtr &req) +{ + M5Format ref; + + MemReqPtr tmp_req; + // Need to read EOF char before eof() will return true. + traceFile.read((char*) &ref, sizeof(ref)); + if (!traceFile.eof()) { + //traceFile.read((char*) &ref, sizeof(ref)); + int gcount = traceFile.gcount(); + assert(gcount != 0 || traceFile.eof()); + assert(gcount == sizeof(ref)); + assert(ref.cmd < 12); + tmp_req = new MemReq(); + tmp_req->paddr = ref.paddr; + tmp_req->asid = ref.asid; + // Assume asid == thread_num + tmp_req->thread_num = ref.asid; + tmp_req->cmd = (MemCmdEnum)ref.cmd; + tmp_req->size = ref.size; + tmp_req->dest = ref.dest; + } else { + ref.cycle = 0; + } + req = tmp_req; + return ref.cycle; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(M5Reader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(M5Reader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(M5Reader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(M5Reader) + + +CREATE_SIM_OBJECT(M5Reader) +{ + return new M5Reader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("M5Reader", M5Reader) diff --git a/cpu/trace/reader/m5_reader.hh b/cpu/trace/reader/m5_reader.hh new file mode 100644 index 000000000..d78787461 --- /dev/null +++ b/cpu/trace/reader/m5_reader.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003-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 reader for a M5 memory trace. + */ + +#ifndef __M5_READER_HH__ +#define __M5_READER_HH__ + +#include <fstream> + +#include "cpu/trace/reader/mem_trace_reader.hh" + +/** + * A memory trace reader for an M5 memory trace. @sa M5Writer. + */ +class M5Reader : public MemTraceReader +{ + /** The traceFile. */ + std::ifstream traceFile; + + std::string fn; + + public: + /** + * Construct an M5 memory trace reader. + */ + M5Reader(const std::string &name, const std::string &filename); + + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return The cycle the reference was started. + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif // __M5_READER_HH__ diff --git a/cpu/trace/reader/mem_trace_reader.cc b/cpu/trace/reader/mem_trace_reader.cc new file mode 100644 index 000000000..c6fc53f51 --- /dev/null +++ b/cpu/trace/reader/mem_trace_reader.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003-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 + * SimObject Declaration of pure virtual MemTraceReader class. + */ + +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "sim/param.hh" + +DEFINE_SIM_OBJECT_CLASS_NAME("MemTraceReader", MemTraceReader); diff --git a/cpu/trace/reader/mem_trace_reader.hh b/cpu/trace/reader/mem_trace_reader.hh new file mode 100644 index 000000000..5da99a498 --- /dev/null +++ b/cpu/trace/reader/mem_trace_reader.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003-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. + */ + +/** + * Definitions for a pure virtual interface to a memory trace reader. + */ + +#ifndef __MEM_TRACE_READER_HH__ +#define __MEM_TRACE_READER_HH__ + +#include "sim/sim_object.hh" +#include "mem/mem_req.hh" // For MemReqPtr + +/** + * Pure virtual base class for memory trace readers. + */ +class MemTraceReader : public SimObject +{ + public: + /** Construct this MemoryTrace reader. */ + MemTraceReader(const std::string &name) : SimObject(name) {} + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return The cycle of the request, 0 if none in trace. + */ + virtual Tick getNextReq(MemReqPtr &req) = 0; +}; + +#endif //__MEM_TRACE_READER_HH__ diff --git a/cpu/trace/trace_cpu.cc b/cpu/trace/trace_cpu.cc new file mode 100644 index 000000000..6122fc786 --- /dev/null +++ b/cpu/trace/trace_cpu.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of a memory trace CPU object. Uses a memory trace to drive the + * provided memory hierarchy. + */ + +#include <algorithm> // For min + +#include "cpu/trace/trace_cpu.hh" +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/base_mem.hh" // For PARAM constructor +#include "mem/mem_interface.hh" +#include "sim/builder.hh" +#include "sim/sim_events.hh" + +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) +{ + if (instTrace) { + assert(icacheInterface); + nextInstCycle = instTrace->getNextReq(nextInstReq); + } + if (dataTrace) { + assert(dcacheInterface); + nextDataCycle = dataTrace->getNextReq(nextDataReq); + } + tickEvent.schedule(0); +} + +void +TraceCPU::tick() +{ + assert(outstandingRequests >= 0); + assert(outstandingRequests < 1000); + 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); + } else { + ++instReqs; + nextInstReq->completionEvent = + new TraceCompleteEvent(nextInstReq, this); + icacheInterface->access(nextInstReq); + } + nextInstCycle = instTrace->getNextReq(nextInstReq); + } + + if (!nextInstReq && !nextDataReq) { + // No more requests to send. Finish trailing events and exit. + if (mainEventQueue.empty()) { + new SimExitEvent("Finshed Memory Trace"); + } else { + tickEvent.schedule(mainEventQueue.nextEventTime() + 1); + } + } else { + tickEvent.schedule(max(curTick + 1, + min(nextInstCycle, nextDataCycle))); + } +} + +void +TraceCPU::completeRequest(MemReqPtr& req) +{ +} + +void +TraceCompleteEvent::process() +{ + tester->completeRequest(req); +} + +const char * +TraceCompleteEvent::description() +{ + return "trace access complete"; +} + +TraceCPU::TickEvent::TickEvent(TraceCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +void +TraceCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +TraceCPU::TickEvent::description() +{ + return "TraceCPU tick event"; +} + + + +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) + +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) + +END_INIT_SIM_OBJECT_PARAMS(TraceCPU) + +CREATE_SIM_OBJECT(TraceCPU) +{ + return new TraceCPU(getInstanceName(), + (icache) ? icache->getInterface() : NULL, + (dcache) ? dcache->getInterface() : NULL, + inst_trace, data_trace, inst_ports, data_ports); +} + +REGISTER_SIM_OBJECT("TraceCPU", TraceCPU) + diff --git a/cpu/trace/trace_cpu.hh b/cpu/trace/trace_cpu.hh new file mode 100644 index 000000000..13a204f4e --- /dev/null +++ b/cpu/trace/trace_cpu.hh @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Declaration of a memory trace CPU object. Uses a memory trace to drive the + * provided memory hierarchy. + */ + +#ifndef __TRACE_CPU_HH__ +#define __TRACE_CPU_HH__ + +#include <string> + +#include "cpu/base_cpu.hh" +#include "mem/mem_req.hh" // for MemReqPtr +#include "sim/eventq.hh" // for Event + +// Forward declaration. +class MemInterface; +class MemTraceReader; + +/** + * A cpu object for running memory traces through a memory hierarchy. + */ +class TraceCPU : public BaseCPU +{ + /** Interface for instruction trace requests, if any. */ + MemInterface *icacheInterface; + /** 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; + + /** Next instruction request. */ + MemReqPtr nextInstReq; + /** Next data request. */ + MemReqPtr nextDataReq; + + /** + * Event to call the TraceCPU::tick + */ + class TickEvent : public Event + { + private: + /** The associated CPU */ + TraceCPU *cpu; + + public: + /** + * Construct this event; + */ + TickEvent(TraceCPU *c); + + /** + * Call the tick function. + */ + void process(); + + /** + * Return a string description of this event. + */ + const char *description(); + }; + + TickEvent tickEvent; + + public: + /** + * Construct a TraceCPU object. + */ + TraceCPU(const std::string &name, + MemInterface *icache_interface, + MemInterface *dcache_interface, + MemTraceReader *inst_trace, + MemTraceReader *data_trace, + int icache_ports, + int dcache_ports); + + /** + * Perform all the accesses for one cycle. + */ + void tick(); + + /** + * Handle a completed memory request. + */ + void completeRequest(MemReqPtr &req); +}; + +class TraceCompleteEvent : public Event +{ + MemReqPtr req; + TraceCPU *tester; + + public: + + TraceCompleteEvent(MemReqPtr &_req, TraceCPU *_tester) + : Event(&mainEventQueue), req(_req), tester(_tester) + { + setFlags(AutoDelete); + } + + void process(); + + virtual const char *description(); +}; + +#endif //__TRACE_CPU_HH__ + diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh index 76b4a9156..abdf30166 100644 --- a/dev/etherpkt.hh +++ b/dev/etherpkt.hh @@ -64,11 +64,17 @@ class EtherPacket : public RefCounted bool isIpPkt() { eth_header *eth = (eth_header *) data; - return (eth->type == 0x800); + return (eth->type == 0x8); + } + bool isTcpPkt(ip_header *ip) { + return (ip->protocol == 0x6); } bool isTcpPkt() { ip_header *ip = getIpHdr(); - return (ip->protocol == 6); + return (ip->protocol == 0x6); + } + bool isUdpPkt(ip_header *ip) { + return (ip->protocol == 17); } bool isUdpPkt() { ip_header *ip = getIpHdr(); @@ -81,11 +87,13 @@ class EtherPacket : public RefCounted } tcp_header *getTcpHdr(ip_header *ip) { - return (tcp_header *) (ip + (ip->vers_len & 0xf)); + assert(isTcpPkt(ip)); + return (tcp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); } udp_header *getUdpHdr(ip_header *ip) { - return (udp_header *) (ip + (ip->vers_len & 0xf)); + assert(isUdpPkt(ip)); + return (udp_header *) ((uint8_t *) ip + (ip->vers_len & 0xf)*4); } typedef RefCountingPtr<EtherPacket> PacketPtr; diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc index 46a0e8179..4805570d2 100644 --- a/dev/ide_ctrl.cc +++ b/dev/ide_ctrl.cc @@ -192,6 +192,22 @@ IdeController::getDisk(IdeDisk *diskPtr) return -1; } +bool +IdeController::isDiskSelected(IdeDisk *diskPtr) +{ + for (int i = 0; i < 4; i++) { + if ((long)diskPtr == (long)disks[i]) { + // is disk is on primary or secondary channel + int channel = i/2; + // is disk the master or slave + int devID = i%2; + + return (dev[channel] == devID); + } + } + panic("Unable to find disk by pointer!!\n"); +} + //// // Command completion //// diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh index 679c7422b..39c64eb30 100644 --- a/dev/ide_ctrl.hh +++ b/dev/ide_ctrl.hh @@ -145,6 +145,10 @@ class IdeController : public PciDev int getDisk(IdeDisk *diskPtr); public: + /** See if a disk is selected based on its pointer */ + bool isDiskSelected(IdeDisk *diskPtr); + + public: /** * Constructs and initializes this controller. * @param name The name of this controller. diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index 0f5c02660..ee21feaea 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -167,6 +167,12 @@ IdeDisk::reset(int id) // Utility functions //// +bool +IdeDisk::isDEVSelect() +{ + return ctrl->isDiskSelected(this); +} + Addr IdeDisk::pciToDma(Addr pciAddr) { diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index 409aaef9a..9c6eea623 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -320,7 +320,7 @@ class IdeDisk : public SimObject // Utility functions bool isBSYSet() { return (status & STATUS_BSY_BIT); } bool isIENSet() { return nIENBit; } - bool isDEVSelect() { return ((cmdReg.drive & SELECT_DEV_BIT) == devID); } + bool isDEVSelect(); void setComplete() { diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index 28181ba64..f3f2f10b3 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -86,6 +86,11 @@ 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); + /////////////////////////////////////////////////////////////////////// // // NSGigE PCI Device @@ -98,10 +103,10 @@ NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_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]) - : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), io_enable(false), + : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false), - txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), + txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), + txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), @@ -112,8 +117,8 @@ NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), acceptPerfect(false), acceptArp(false), - physmem(pmem), intctrl(i), intrTick(0), - cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency) + physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), + intrEvent(0), interface(0), pioLatency(pio_latency) { tsunami->ethernet = this; @@ -143,7 +148,6 @@ NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, dmaReadFactor = dma_read_factor; dmaWriteFactor = dma_write_factor; - memset(®s, 0, sizeof(regs)); regsReset(); rom.perfectMatch[0] = eaddr[0]; rom.perfectMatch[1] = eaddr[1]; @@ -242,27 +246,31 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data) // Need to catch writes to BARs to update the PIO interface switch (offset) { - //seems to work fine without all these, but i ut in the IO to - //double check, an assertion will fail if we need to properly - // imlpement it + //seems to work fine without all these PCI settings, but i put in the IO + //to double check, an assertion will fail if we need to properly + // implement it case PCI_COMMAND: if (config.data[offset] & PCI_CMD_IOSE) - io_enable = true; + ioEnable = true; else - io_enable = false; + ioEnable = false; + #if 0 - if (config.data[offset] & PCI_CMD_BME) - bm_enabled = true; - else - bm_enabled = false; - break; + if (config.data[offset] & PCI_CMD_BME) { + bmEnabled = true; + } + else { + bmEnabled = false; + } - if (config.data[offset] & PCI_CMD_MSE) - mem_enable = true; - else - mem_enable = false; - break; + if (config.data[offset] & PCI_CMD_MSE) { + memEnable = true; + } + else { + memEnable = false; + } #endif + break; case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) { @@ -294,7 +302,7 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data) Fault NSGigE::read(MemReqPtr &req, uint8_t *data) { - assert(io_enable); + assert(ioEnable); //The mask is to give you only the offset into the device register file Addr daddr = req->paddr & 0xfff; @@ -498,7 +506,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) Fault NSGigE::write(MemReqPtr &req, const uint8_t *data) { - assert(io_enable); + assert(ioEnable); Addr daddr = req->paddr & 0xfff; DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", @@ -680,7 +688,11 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) /* we handle our own DMA, ignore the kernel's exhortations */ - if (reg & TXCFG_MXDMA) ; + //if (reg & TXCFG_MXDMA) ; + + //also, we currently don't care about fill/drain thresholds + //though this may change in the future with more realistic + //networks or a driver which changes it according to feedback break; @@ -709,9 +721,12 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) #endif /* we handle our own DMA, ignore what kernel says about it */ - if (reg & RXCFG_MXDMA) ; + //if (reg & RXCFG_MXDMA) ; #if 0 + //also, we currently don't care about fill/drain thresholds + //though this may change in the future with more realistic + //networks or a driver which changes it according to feedback if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; #endif break; @@ -735,15 +750,10 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) regs.rfcr = reg; rxFilterEnable = (reg & RFCR_RFEN) ? true : false; - acceptBroadcast = (reg & RFCR_AAB) ? true : false; - acceptMulticast = (reg & RFCR_AAM) ? true : false; - acceptUnicast = (reg & RFCR_AAU) ? true : false; - acceptPerfect = (reg & RFCR_APM) ? true : false; - acceptArp = (reg & RFCR_AARP) ? true : false; if (reg & RFCR_APAT) ; @@ -905,7 +915,7 @@ NSGigE::devIntrPost(uint32_t interrupts) cpuIntrPost(when); } - DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n", + DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", interrupts, regs.isr, regs.imr); } @@ -967,14 +977,14 @@ NSGigE::devIntrClear(uint32_t interrupts) if (!(regs.isr & regs.imr)) cpuIntrClear(); - DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n", + DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", interrupts, regs.isr, regs.imr); } void NSGigE::devIntrChangeMask() { - DPRINTF(Ethernet, "interrupt mask changed\n"); + DPRINTF(EthernetIntr, "interrupt mask changed\n"); if (regs.isr & regs.imr) cpuIntrPost(curTick); @@ -985,6 +995,12 @@ NSGigE::devIntrChangeMask() void NSGigE::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) + assert((intrTick >= curTick) || (intrTick == 0)); if (when > intrTick && intrTick != 0) return; @@ -998,6 +1014,8 @@ NSGigE::cpuIntrPost(Tick when) 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); } @@ -1007,12 +1025,18 @@ void NSGigE::cpuInterrupt() { // Don't send an interrupt if there's already one - if (cpuPendingIntr) + 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) + if (intrTick > curTick) { + DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n", + intrTick); return; + } // Whether or not there's a pending interrupt, we don't care about // it anymore @@ -1023,6 +1047,7 @@ NSGigE::cpuInterrupt() cpuPendingIntr = true; /** @todo rework the intctrl to be tsunami ok */ //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); + DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); } @@ -1033,6 +1058,7 @@ NSGigE::cpuIntrClear() cpuPendingIntr = false; /** @todo rework the intctrl to be tsunami ok */ //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); + DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); } } @@ -1048,7 +1074,6 @@ NSGigE::txReset() DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; - txFifoCnt = 0; txFifoAvail = MAX_TX_FIFO_SIZE; txHalt = false; txFragPtr = 0; @@ -1088,6 +1113,13 @@ void NSGigE::regsReset() regs.mibc = 0x2; regs.vdr = 0x81; regs.tesr = 0xc000; + + extstsEnable = false; + acceptBroadcast = false; + acceptMulticast = false; + acceptUnicast = false; + acceptPerfect = false; + acceptArp = false; } void @@ -1197,11 +1229,11 @@ NSGigE::rxDmaWriteDone() void NSGigE::rxKick() { - DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n", + DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", NsRxStateStrings[rxState], rxFifo.size()); if (rxKickTick > curTick) { - DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", rxKickTick); return; } @@ -1229,7 +1261,7 @@ NSGigE::rxKick() switch (rxState) { case rxIdle: if (!regs.command & CR_RXE) { - DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n"); + DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); goto exit; } @@ -1267,8 +1299,8 @@ NSGigE::rxKick() if (rxDmaState != dmaIdle) goto exit; - DPRINTF(Ethernet, - "rxDescCache:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n" + DPRINTF(EthernetDesc, + "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, rxDescCache.extsts); @@ -1291,11 +1323,26 @@ NSGigE::rxKick() if (rxFifo.empty()) goto exit; + DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); + // If we don't have a packet, grab a new one from the fifo. rxPacket = rxFifo.front(); rxPktBytes = rxPacket->length; rxPacketBufPtr = rxPacket->data; + 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); + DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", + reverseEnd16(tcp->src_port_num), + reverseEnd16(tcp->dest_port_num)); + } + } + } + // sanity check - i think the driver behaves like this assert(rxDescCnt >= rxPktBytes); @@ -1303,6 +1350,7 @@ NSGigE::rxKick() // reference count rxFifo.front() = NULL; rxFifo.pop_front(); + rxFifoCnt -= rxPacket->length; } @@ -1325,6 +1373,7 @@ NSGigE::rxKick() //if (rxPktBytes == 0) { /* packet is done */ assert(rxPktBytes == 0); + DPRINTF(EthernetSM, "done with receiving packet\n"); rxDescCache.cmdsts |= CMDSTS_OWN; rxDescCache.cmdsts &= ~CMDSTS_MORE; @@ -1349,22 +1398,26 @@ NSGigE::rxKick() } #endif - if (rxPacket->isIpPkt() && extstsEnable) { rxDescCache.extsts |= EXTSTS_IPPKT; - if (!ipChecksum(rxPacket, false)) + if (rxPacket->isIpPkt() && extstsEnable) { + rxDescCache.extsts |= EXTSTS_IPPKT; + if (!ipChecksum(rxPacket, false)) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_IPERR; - + } if (rxPacket->isTcpPkt()) { rxDescCache.extsts |= EXTSTS_TCPPKT; - if (!tcpChecksum(rxPacket, false)) + if (!tcpChecksum(rxPacket, false)) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_TCPERR; + } } else if (rxPacket->isUdpPkt()) { rxDescCache.extsts |= EXTSTS_UDPPKT; - if (!udpChecksum(rxPacket, false)) + if (!udpChecksum(rxPacket, false)) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_UDPERR; + } } } - - rxFifoCnt -= rxPacket->length; rxPacket = 0; /* the driver seems to always receive into desc buffers @@ -1373,7 +1426,7 @@ NSGigE::rxKick() i don't implement that case, hence the assert above. */ - DPRINTF(Ethernet, "rxDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n", + DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", rxDescCache.cmdsts, rxDescCache.extsts); rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; @@ -1410,6 +1463,7 @@ NSGigE::rxKick() devIntrPost(ISR_RXDESC); if (rxHalt) { + DPRINTF(EthernetSM, "Halting the RX state machine\n"); rxState = rxIdle; rxHalt = false; } else @@ -1440,7 +1494,7 @@ NSGigE::rxKick() } - DPRINTF(Ethernet, "entering next rx state = %s\n", + DPRINTF(EthernetSM, "entering next rx state = %s\n", NsRxStateStrings[rxState]); if (rxState == rxIdle) { @@ -1455,7 +1509,7 @@ NSGigE::rxKick() /** * @todo do we want to schedule a future kick? */ - DPRINTF(Ethernet, "rx state machine exited state=%s\n", + DPRINTF(EthernetSM, "rx state machine exited state=%s\n", NsRxStateStrings[rxState]); } @@ -1467,14 +1521,29 @@ NSGigE::transmit() return; } - if (interface->sendPacket(txFifo.front())) { - DPRINTF(Ethernet, "transmit packet\n"); + DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n", + MAX_TX_FIFO_SIZE - txFifoAvail); + if (interface->sendPacket(txFifo.front())) { + 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); + DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", + reverseEnd16(tcp->src_port_num), + reverseEnd16(tcp->dest_port_num)); + } + } + } + DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); txBytes += txFifo.front()->length; txPackets++; - txFifoCnt -= (txFifo.front()->length - txPktXmitted); - txPktXmitted = 0; + txFifoAvail += txFifo.front()->length; + + DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail); txFifo.front() = NULL; txFifo.pop_front(); @@ -1484,7 +1553,8 @@ NSGigE::transmit() nice format. 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()) { DPRINTF(Ethernet, "reschedule transmit\n"); @@ -1599,11 +1669,11 @@ NSGigE::txDmaWriteDone() void NSGigE::txKick() { - DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]); + DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]); - if (rxKickTick > curTick) { - DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", - rxKickTick); + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); return; } @@ -1625,7 +1695,7 @@ NSGigE::txKick() switch (txState) { case txIdle: if (!regs.command & CR_TXE) { - DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n"); + DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); goto exit; } @@ -1664,8 +1734,8 @@ NSGigE::txKick() if (txDmaState != dmaIdle) goto exit; - DPRINTF(Ethernet, - "txDescCache data:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n" + DPRINTF(EthernetDesc, + "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, txDescCache.extsts); @@ -1680,16 +1750,16 @@ NSGigE::txKick() case txFifoBlock: if (!txPacket) { - DPRINTF(Ethernet, "starting the tx of a new packet\n"); + DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n"); txPacket = new EtherPacket; txPacket->data = new uint8_t[16384]; txPacketBufPtr = txPacket->data; } if (txDescCnt == 0) { - DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n"); + DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); if (txDescCache.cmdsts & CMDSTS_MORE) { - DPRINTF(Ethernet, "there are more descriptors to come\n"); + DPRINTF(EthernetSM, "there are more descriptors to come\n"); txState = txDescWrite; txDescCache.cmdsts &= ~CMDSTS_OWN; @@ -1703,7 +1773,7 @@ NSGigE::txKick() goto exit; } else { /* this packet is totally done */ - DPRINTF(Ethernet, "This packet is done, let's wrap it up\n"); + 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) { if (txDescCache.extsts & EXTSTS_UDPPKT) { @@ -1721,7 +1791,6 @@ NSGigE::txKick() assert(txPacket->length <= 1514); txFifo.push_back(txPacket); - /* this following section is not to spec, but functionally shouldn't be any different. normally, the chip will wait til the transmit has occurred before writing back the descriptor because it has to wait @@ -1730,11 +1799,12 @@ NSGigE::txKick() successfully transmitted, and writing it exactly to spec would complicate the code, we just do it here */ + txDescCache.cmdsts &= ~CMDSTS_OWN; txDescCache.cmdsts |= CMDSTS_OK; - DPRINTF(Ethernet, - "txDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n", + DPRINTF(EthernetDesc, + "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", txDescCache.cmdsts, txDescCache.extsts); txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; @@ -1745,25 +1815,19 @@ NSGigE::txKick() if (doTxDmaWrite()) goto exit; - txPacket = 0; transmit(); + txPacket = 0; + if (txHalt) { + DPRINTF(EthernetSM, "halting TX state machine\n"); txState = txIdle; txHalt = false; } else txState = txAdvance; } } else { - DPRINTF(Ethernet, "this descriptor isn't done yet\n"); - /* the fill thresh is in units of 32 bytes, shift right by 8 to get the - value, shift left by 5 to get the real number of bytes */ - if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) { - DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n", - txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK); - goto exit; - } - + DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); txState = txFragRead; /* The number of bytes transferred is either whatever is left @@ -1788,8 +1852,8 @@ NSGigE::txKick() txPacketBufPtr += txXferLen; txFragPtr += txXferLen; - txFifoCnt += txXferLen; txDescCnt -= txXferLen; + txFifoAvail -= txXferLen; txState = txFifoBlock; break; @@ -1798,16 +1862,6 @@ NSGigE::txKick() if (txDmaState != dmaIdle) goto exit; - if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) { - if (txFifo.empty()) { - uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted); - txFifoCnt -= xmitted; - txPktXmitted += xmitted; - } else { - transmit(); - } - } - if (txDescCache.cmdsts & CMDSTS_INTR) { devIntrPost(ISR_TXDESC); } @@ -1837,7 +1891,7 @@ NSGigE::txKick() panic("invalid state"); } - DPRINTF(Ethernet, "entering next tx state=%s\n", + DPRINTF(EthernetSM, "entering next tx state=%s\n", NsTxStateStrings[txState]); if (txState == txIdle) { @@ -1852,7 +1906,7 @@ NSGigE::txKick() /** * @todo do we want to schedule a future kick? */ - DPRINTF(Ethernet, "tx state machine exited state=%s\n", + DPRINTF(EthernetSM, "tx state machine exited state=%s\n", NsTxStateStrings[txState]); } @@ -1862,8 +1916,6 @@ NSGigE::transferDone() if (txFifo.empty()) return; - DPRINTF(Ethernet, "schedule transmit\n"); - if (txEvent.scheduled()) txEvent.reschedule(curTick + 1); else @@ -1889,7 +1941,7 @@ NSGigE::rxFilter(PacketPtr packet) drop = false; eth_header *eth = (eth_header *) packet->data; - if ((acceptArp) && (eth->type == 0x806)) + if ((acceptArp) && (eth->type == 0x608)) drop = false; } else if (packet->IsBroadcast()) { @@ -1926,6 +1978,8 @@ NSGigE::recvPacket(PacketPtr packet) rxBytes += packet->length; rxPackets++; + DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt); + if (rxState == rxIdle) { DPRINTF(Ethernet, "receive disabled...packet dropped\n"); interface->recvDone(); @@ -1938,7 +1992,7 @@ NSGigE::recvPacket(PacketPtr packet) return true; } - if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) { + if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) { DPRINTF(Ethernet, "packet will not fit in receive buffer...packet dropped\n"); devIntrPost(ISR_RXORN); @@ -1993,11 +2047,11 @@ NSGigE::tcpChecksum(PacketPtr packet, bool gen) pseudo->src_ip_addr = ip->src_ip_addr; pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = ip->protocol; - pseudo->len = ip->dgram_len - (ip->vers_len & 0xf); + pseudo->protocol = reverseEnd16(ip->protocol); + pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4); uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) pseudo->len); + (uint32_t) reverseEnd16(pseudo->len)); delete pseudo; if (gen) @@ -2014,10 +2068,12 @@ NSGigE::ipChecksum(PacketPtr packet, bool gen) { ip_header *hdr = packet->getIpHdr(); - uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)); + uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4); - if (gen) + if (gen) { + DPRINTF(Ethernet, "generated checksum: %#x\n", cksum); hdr->hdr_chksum = cksum; + } else if (cksum != 0) return false; @@ -2111,7 +2167,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); - SERIALIZE_SCALAR(io_enable); + SERIALIZE_SCALAR(ioEnable); /* * Serialize the data Fifos @@ -2157,7 +2213,6 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(txXferLen); SERIALIZE_SCALAR(rxXferLen); - SERIALIZE_SCALAR(txPktXmitted); /* * Serialize DescCaches @@ -2177,7 +2232,6 @@ NSGigE::serialize(ostream &os) int txState = this->txState; SERIALIZE_SCALAR(txState); SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFifoCnt); SERIALIZE_SCALAR(txFifoAvail); SERIALIZE_SCALAR(txHalt); SERIALIZE_SCALAR(txFragPtr); @@ -2270,7 +2324,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); - UNSERIALIZE_SCALAR(io_enable); + UNSERIALIZE_SCALAR(ioEnable); /* * unserialize the data fifos @@ -2320,7 +2374,6 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(txXferLen); UNSERIALIZE_SCALAR(rxXferLen); - UNSERIALIZE_SCALAR(txPktXmitted); /* * Unserialize DescCaches @@ -2341,7 +2394,6 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(txState); this->txState = (TxState) txState; UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFifoCnt); UNSERIALIZE_SCALAR(txFifoAvail); UNSERIALIZE_SCALAR(txHalt); UNSERIALIZE_SCALAR(txFragPtr); @@ -2416,6 +2468,26 @@ NSGigE::cacheAccess(MemReqPtr &req) //===================================================================== +//********** 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) SimObjectParam<EtherInt *> peer; diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh index 25a7781e5..191c867ce 100644 --- a/dev/ns_gige.hh +++ b/dev/ns_gige.hh @@ -159,10 +159,10 @@ class NSGigE : public PciDev dp_rom rom; /** pci settings */ - bool io_enable; + bool ioEnable; #if 0 - bool mem_enable; - bool bm_enable; + bool memEnable; + bool bmEnable; #endif /*** BASIC STRUCTURES FOR TX/RX ***/ @@ -177,7 +177,6 @@ class NSGigE : public PciDev uint8_t *rxPacketBufPtr; uint32_t txXferLen; uint32_t rxXferLen; - uint32_t txPktXmitted; bool rxDmaFree; bool txDmaFree; @@ -189,8 +188,6 @@ class NSGigE : public PciDev TxState txState; /** Current Transmit Descriptor Done */ bool CTDD; - /** amt of data in the txDataFifo in bytes (logical) */ - uint32_t txFifoCnt; /** current amt of free space in txDataFifo in bytes */ uint32_t txFifoAvail; /** halt the tx state machine after next packet */ diff --git a/kern/kernel_stats.cc b/kern/kernel_stats.cc new file mode 100644 index 000000000..de944329a --- /dev/null +++ b/kern/kernel_stats.cc @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <map> +#include <stack> +#include <string> + +#include "base/statistics.hh" +#include "base/trace.hh" +#include "cpu/exec_context.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" + +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; } + +void +KernelStats::regStats(const string &name) +{ data->regStats(name); } + +void +KSData::regStats(const string &name) +{ + _name = name; + + _arm + .name(name + ".inst.arm") + .desc("number of arm instructions executed") + ; + + _quiesce + .name(name + ".inst.quiesce") + .desc("number of quiesce instructions executed") + ; + + _ivlb + .name(name + ".inst.ivlb") + .desc("number of ivlb instructions executed") + ; + + _ivle + .name(name + ".inst.ivle") + .desc("number of ivle instructions executed") + ; + + _hwrei + .name(name + ".inst.hwrei") + .desc("number of hwrei instructions executed") + ; + + _iplCount + .init(32) + .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") + .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") + .desc("number of cycles we spent at this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplUsed + .name(name + ".ipl_used") + .desc("fraction of swpipl calls that actually changed the ipl") + .flags(total | nozero | nonan) + ; + + _iplUsed = _iplGood / _iplCount; + + _callpal + .init(256) + .name(name + ".callpal") + .desc("number of callpals executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < PAL::NumCodes; ++i) { + const char *str = PAL::name(i); + if (str) + _callpal.subname(i, str); + } + + _syscall + .init(SystemCalls<Tru64>::Number) + .name(name + ".syscall") + .desc("number of syscalls executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) { + const char *str = SystemCalls<Tru64>::name(i); + if (str) { + _syscall.subname(i, str); + } + } + + _faults + .init(Num_Faults) + .name(name + ".faults") + .desc("number of faults") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 1; i < Num_Faults; ++i) { + const char *str = FaultName(i); + if (str) + _faults.subname(i, str); + } + + _mode + .init(2) + .name(name + ".mode_switch") + .subname(0, "kernel") + .subname(1, "user") + .desc("number of protection mode switches") + ; + + _modeGood + .init(2) + ; + + _modeFraction + .name(name + ".mode_switch_good") + .subname(0, "kernel") + .subname(1, "user") + .desc("fraction of useful protection mode switches") + .flags(total) + ; + _modeFraction = _modeGood / _mode; + + _modeTicks + .init(2) + .name(name + ".mode_ticks") + .subname(0, "kernel") + .subname(1, "user") + .desc("number of ticks spent at the given mode") + .flags(pdf) + ; + + _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++; } + +void +KernelStats::fault(Fault fault) +{ data->_faults[fault]++; } + +void +KernelStats::swpipl(int ipl) +{ data->swpipl(ipl); } + +void +KernelStats::mode(bool user) +{ data->mode(user); } + +void +KernelStats::context(Addr old_pcbb, Addr new_pcbb) +{ data->_swap_context++; } + +void +KernelStats::callpal(int code) +{ data->callpal(code); } + + +void +KSData::swpipl(int ipl) +{ + assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); + + _iplCount[ipl]++; + + if (ipl == iplLast) + return; + + _iplGood[ipl]++; + _iplTicks[iplLast] += curTick - iplLastTick; + iplLastTick = curTick; + iplLast = ipl; +} + +void +KSData::mode(bool user) +{ + _mode[user]++; + if (user == lastUser) + return; + + _modeGood[user]++; + _modeTicks[lastUser] += curTick - lastModeTick; + + 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(); + } + } +} + +void +KSData::callpal(int code) +{ + if (!PAL::name(code)) + return; + + _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]++; + } + } + 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"); + } + } + } + + 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"); + } +} diff --git a/kern/kernel_stats.hh b/kern/kernel_stats.hh new file mode 100644 index 000000000..497403762 --- /dev/null +++ b/kern/kernel_stats.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __KERNEL_STATS_HH__ +#define __KERNEL_STATS_HH__ + +#include <string> + +class KSData; +class ExecContext; +class BaseCPU; +enum Fault; + +class KernelStats +{ + private: + KSData *data; + + public: + KernelStats(ExecContext *_xc, BaseCPU *_cpu); + ~KernelStats(); + + void regStats(const std::string &name); + + void arm(); + void quiesce(); + void ivlb(); + void ivle(); + void hwrei(); + + void fault(Fault fault); + void swpipl(int ipl); + void mode(bool user); + void context(Addr old_pcbb, Addr new_pcbb); + void callpal(int code); +}; + +#endif // __KERNEL_STATS_HH__ diff --git a/sim/main.cc b/sim/main.cc index f0d10a67c..54c74fd1a 100644 --- a/sim/main.cc +++ b/sim/main.cc @@ -90,6 +90,18 @@ exitNowHandler(int sigtype) async_exit = true; } +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + cerr << "Program aborted at cycle " << curTick << endl; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif +} + /// Simulator executable name const char *myProgName = ""; @@ -232,6 +244,7 @@ main(int argc, char **argv) signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats signal(SIGINT, exitNowHandler); // dump final stats and exit + signal(SIGABRT, abortHandler); sayHello(cerr); diff --git a/util/config/m5config.py b/util/config/m5configbase.py index 9aa3e0387..2daf5d94d 100644 --- a/util/config/m5config.py +++ b/util/config/m5configbase.py @@ -157,6 +157,21 @@ class MetaConfigNode(type): print "Error setting '%s' default on class '%s'\n" \ % (pname, cls.__name__), exc + # Set the class's parameter dictionary given a code string of + # parameter initializers (as from an object description file). + # Note that the caller must pass in the namespace in which to + # execute the code (usually the caller's globals()), since if we + # call globals() from inside this function all we get is this + # module's internal scope. + def init_params(cls, init_code, ctx): + dict = {} + try: + exec fixPythonIndentation(init_code) in ctx, dict + except Exception, exc: + print "Error in %s.init_params:" % cls.__name__, exc + raise + cls.set_param_dict(dict) + # Lookup a parameter description by name in the given class. Use # the _param_bases list defined in __init__ to go up the # inheritance hierarchy if necessary. @@ -220,14 +235,13 @@ class ConfigNode(object): % (self.__class__.__name__, _name, type(_name)) self._name = _name self._parent = _parent - self._children = {} if (_parent): - _parent.__addChild(self) - # Set up absolute path from root. - if (_parent and _parent._path != 'Universe'): - self._path = _parent._path + '.' + self._name - else: - self._path = self._name + _parent._add_child(self) + self._children = {} + # keep a list of children in addition to the dictionary keys + # so we can remember the order they were added and print them + # out in that order. + self._child_list = [] # When printing (e.g. to .ini file), just give the name. def __str__(self): @@ -248,7 +262,7 @@ class ConfigNode(object): # Set attribute. All attribute assignments go through here. Must # be private attribute (starts with '_') or valid parameter entry. # Basically identical to MetaConfigClass.__setattr__(), except - # this handles instances rather than class attributes. + # this sets attributes on specific instances rather than on classes. def __setattr__(self, attr_name, value): if attr_name.startswith('_'): object.__setattr__(self, attr_name, value) @@ -261,11 +275,30 @@ class ConfigNode(object): % (self.__class__.__name__, attr_name) # It's ok: set attribute by delegating to 'object' class. # Note the use of param.make_value() to verify/canonicalize - # the assigned value - object.__setattr__(self, attr_name, param.make_value(value)) + # the assigned value. + v = param.make_value(value) + object.__setattr__(self, attr_name, v) + + # A little convenient magic: if the parameter is a ConfigNode + # (or vector of ConfigNodes, or anything else with a + # '_set_parent_if_none' function attribute) that does not have + # a parent (and so is not part of the configuration + # hierarchy), then make this node its parent. + if hasattr(v, '_set_parent_if_none'): + v._set_parent_if_none(self) + + def _path(self): + # Return absolute path from root. + if not self._parent and self._name != 'Universe': + print >> sys.stderr, "Warning:", self._name, "has no parent" + parent_path = self._parent and self._parent._path() + if parent_path and parent_path != 'Universe': + return parent_path + '.' + self._name + else: + return self._name # Add a child to this node. - def __addChild(self, new_child): + def _add_child(self, new_child): # set child's parent before calling this function assert new_child._parent == self if not isinstance(new_child, ConfigNode): @@ -276,6 +309,7 @@ class ConfigNode(object): "Node '%s' already has a child '%s'" \ % (self._name, new_child._name) self._children[new_child._name] = new_child + self._child_list += [new_child] # operator overload for '+='. You can say "node += child" to add # a child that was created with parent=None. An early attempt @@ -285,27 +319,28 @@ class ConfigNode(object): raise AttributeError, \ "Node '%s' already has a parent" % new_child._name new_child._parent = self - self.__addChild(new_child) + self._add_child(new_child) return self + # Set this instance's parent to 'parent' if it doesn't already + # have one. See ConfigNode.__setattr__(). + def _set_parent_if_none(self, parent): + if self._parent == None: + parent += self + # Print instance info to .ini file. def _instantiate(self): - print '[' + self._path + ']' # .ini section header - if self._children: - # instantiate children in sorted order for backward - # compatibility (else we can end up with cpu1 before cpu0). - child_names = self._children.keys() - child_names.sort() - print 'children =', - for child_name in child_names: - print child_name, - print + print '[' + self._path() + ']' # .ini section header + if self._child_list: + # instantiate children in same order they were added for + # backward compatibility (else we can end up with cpu1 + # before cpu0). + print 'children =', ' '.join([c._name for c in self._child_list]) self._instantiateParams() print # recursively dump out children - if self._children: - for child_name in child_names: - self._children[child_name]._instantiate() + for c in self._child_list: + c._instantiate() # ConfigNodes have no parameters. Overridden by SimObject. def _instantiateParams(self): @@ -373,9 +408,6 @@ class SimObject(ConfigNode): def isNullPointer(value): return isinstance(value, NullSimObject) -def isSimObjectType(ptype): - return issubclass(ptype, SimObject) - # Regular parameter. class Param(object): # Constructor. E.g., Param(Int, "number of widgets", 5) @@ -391,7 +423,7 @@ class Param(object): # nothing to do if None or already correct type. Also allow NULL # pointer to be assigned where a SimObject is expected. if value == None or isinstance(value, self.ptype) or \ - isNullPointer(value) and isSimObjectType(self.ptype): + isNullPointer(value) and issubclass(self.ptype, ConfigNode): return value # this type conversion will raise an exception if it's illegal return self.ptype(value) @@ -414,12 +446,21 @@ class Param(object): # storing these instead of a raw Python list is that we can override # the __str__() method to not print out '[' and ']' in the .ini file. class _VectorParamValue(object): - def __init__(self, list): - self.value = list + def __init__(self, value): + assert isinstance(value, list) or value == None + self.value = value def __str__(self): return ' '.join(map(str, self.value)) + # Set member instance's parents to 'parent' if they don't already + # have one. Extends "magic" parenting of ConfigNodes to vectors + # of ConfigNodes as well. See ConfigNode.__setattr__(). + def _set_parent_if_none(self, parent): + if self.value and hasattr(self.value[0], '_set_parent_if_none'): + for v in self.value: + v._set_parent_if_none(parent) + # Vector-valued parameter description. Just like Param, except that # the value is a vector (list) of the specified type instead of a # single value. @@ -623,7 +664,7 @@ false = False true = True # Some memory range specifications use this as a default upper bound. -MAX_ADDR = 2 ** 63 +MAX_ADDR = 2**64 - 1 # For power-of-two sizing, e.g. 64*K gives an integer value 65536. K = 1024 @@ -631,109 +672,6 @@ M = K*K G = K*M ##################################################################### -# -# Object description loading. -# -# The final step is to define the classes corresponding to M5 objects -# and their parameters. These classes are described in .odesc files -# in the source tree. This code walks the tree to find those files -# and loads up the descriptions (by evaluating them in pieces as -# Python code). -# -# -# Because SimObject classes inherit from other SimObject classes, and -# can use arbitrary other SimObject classes as parameter types, we -# have to do this in three steps: -# -# 1. Walk the tree to find all the .odesc files. Note that the base -# of the filename *must* match the class name. This step builds a -# mapping from class names to file paths. -# -# 2. Start generating empty class definitions (via def_class()) using -# the OBJECT field of the .odesc files to determine inheritance. -# def_class() recurses on demand to define needed base classes before -# derived classes. -# -# 3. Now that all of the classes are defined, go through the .odesc -# files one more time loading the parameter descriptions. -# -##################################################################### - -# dictionary: maps object names to file paths -odesc_file = {} - -# dictionary: maps object names to boolean flag indicating whether -# class definition was loaded yet. Since SimObject is defined in -# m5.config.py, count it as loaded. -odesc_loaded = { 'SimObject': True } - -# Find odesc files in namelist and initialize odesc_file and -# odesc_loaded dictionaries. Called via os.path.walk() (see below). -def find_odescs(process, dirpath, namelist): - # Prune out SCCS directories so we don't process s.*.odesc files. - i = 0 - while i < len(namelist): - if namelist[i] == "SCCS": - del namelist[i] - else: - i = i + 1 - # Find .odesc files and record them. - for name in namelist: - if name.endswith('.odesc'): - objname = name[:name.rindex('.odesc')] - path = os.path.join(dirpath, name) - if odesc_file.has_key(objname): - print "Warning: duplicate object names:", \ - odesc_file[objname], path - odesc_file[objname] = path - odesc_loaded[objname] = False - - -# Regular expression string for parsing .odesc files. -file_re_string = r''' -^OBJECT: \s* (\w+) \s* \( \s* (\w+) \s* \) -\s* -^PARAMS: \s*\n ( (\s+.*\n)* ) -''' - -# Compiled regular expression object. -file_re = re.compile(file_re_string, re.MULTILINE | re.VERBOSE) - -# .odesc file parsing function. Takes a filename and returns tuple of -# object name, object base, and parameter description section. -def parse_file(path): - f = open(path, 'r').read() - m = file_re.search(f) - if not m: - print "Can't parse", path - sys.exit(1) - return (m.group(1), m.group(2), m.group(3)) - -# Define SimObject class based on description in specified filename. -# Class itself is empty except for _name attribute; parameter -# descriptions will be loaded later. Will recurse to define base -# classes as needed before defining specified class. -def def_class(path): - # load & parse file - (obj, parent, params) = parse_file(path) - # check to see if base class is defined yet; define it if not - if not odesc_loaded.has_key(parent): - print "No .odesc file found for", parent - sys.exit(1) - if not odesc_loaded[parent]: - def_class(odesc_file[parent]) - # define the class. The _name attribute of the class lets us - # track the actual SimObject class name even when we derive new - # subclasses in scripts (to provide new parameter value settings). - s = "class %s(%s): _name = '%s'" % (obj, parent, obj) - try: - # execute in global namespace, so new class will be globally - # visible - exec s in globals() - except Exception, exc: - print "Object error in %s:" % path, exc - # mark this file as loaded - odesc_loaded[obj] = True # Munge an arbitrary Python code string to get it to execute (mostly # dealing with indentation). Stolen from isa_parser.py... see @@ -745,51 +683,6 @@ def fixPythonIndentation(s): s = 'if 1:\n' + s return s -# Load parameter descriptions from .odesc file. Object class must -# already be defined. -def def_params(path): - # load & parse file - (obj_name, parent_name, param_code) = parse_file(path) - # initialize param dict - param_dict = {} - # execute parameter descriptions. - try: - # "in globals(), param_dict" makes exec use the current - # globals as the global namespace (so all of the Param - # etc. objects are visible) and param_dict as the local - # namespace (so the newly defined parameter variables will be - # entered into param_dict). - exec fixPythonIndentation(param_code) in globals(), param_dict - except Exception, exc: - print "Param error in %s:" % path, exc - return - # Convert object name string to Python class object - obj = eval(obj_name) - # Set the object's parameter description dictionary (see MetaConfigNode). - obj.set_param_dict(param_dict) - - -# Walk directory tree to find .odesc files. -# Someday we'll have to make the root path an argument instead of -# hard-coding it. For now the assumption is you're running this in -# util/config. -root = '../..' -os.path.walk(root, find_odescs, None) - -# Iterate through file dictionary and define classes. -for objname, path in odesc_file.iteritems(): - if not odesc_loaded[objname]: - def_class(path) - -sim_object_list = odesc_loaded.keys() -sim_object_list.sort() - -# Iterate through files again and load parameters. -for path in odesc_file.itervalues(): - def_params(path) - -##################################################################### - # Hook to generate C++ parameter code. def gen_sim_code(file): for objname in sim_object_list: |