diff options
-rw-r--r-- | arch/alpha/alpha_memory.cc | 47 | ||||
-rw-r--r-- | arch/alpha/alpha_memory.hh | 2 | ||||
-rw-r--r-- | arch/alpha/ev5.cc | 5 | ||||
-rw-r--r-- | arch/alpha/isa_desc | 11 | ||||
-rw-r--r-- | arch/alpha/isa_traits.hh | 1 | ||||
-rw-r--r-- | base/misc.cc | 5 | ||||
-rw-r--r-- | base/traceflags.py | 1 | ||||
-rw-r--r-- | cpu/simple_cpu/simple_cpu.hh | 2 | ||||
-rw-r--r-- | cpu/static_inst.hh | 3 | ||||
-rw-r--r-- | cpu/trace/reader/ibm_reader.cc | 120 | ||||
-rw-r--r-- | cpu/trace/reader/ibm_reader.hh | 73 | ||||
-rw-r--r-- | cpu/trace/reader/itx_reader.cc | 198 | ||||
-rw-r--r-- | cpu/trace/reader/itx_reader.hh | 82 | ||||
-rw-r--r-- | cpu/trace/reader/m5_reader.cc | 95 | ||||
-rw-r--r-- | cpu/trace/reader/m5_reader.hh | 67 | ||||
-rw-r--r-- | cpu/trace/reader/mem_trace_reader.cc | 37 | ||||
-rw-r--r-- | cpu/trace/reader/mem_trace_reader.hh | 57 | ||||
-rw-r--r-- | cpu/trace/trace_cpu.cc | 191 | ||||
-rw-r--r-- | cpu/trace/trace_cpu.hh | 151 | ||||
-rw-r--r-- | kern/kernel_stats.cc | 391 | ||||
-rw-r--r-- | kern/kernel_stats.hh | 63 | ||||
-rw-r--r-- | sim/main.cc | 13 | ||||
-rw-r--r-- | util/config/m5configbase.py (renamed from util/config/m5config.py) | 253 |
23 files changed, 1643 insertions, 225 deletions
diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc index d7004b461..f8be89cbe 100644 --- a/arch/alpha/alpha_memory.cc +++ b/arch/alpha/alpha_memory.cc @@ -430,12 +430,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 +454,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,10 +478,8 @@ 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; @@ -489,9 +491,7 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const // 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; } @@ -516,9 +516,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 +527,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/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/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..e26fcd1fe 100644 --- a/base/traceflags.py +++ b/base/traceflags.py @@ -67,6 +67,7 @@ baseFlags = [ 'AlphaConsole', 'Flow', 'Interrupt', + 'Fault', 'Cycle', 'Loader', 'MMU', 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/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: |