Merge zizzer:/bk/linux into zeep.eecs.umich.edu:/z/saidi/work/m5-endian

--HG--
extra : convert_revision : d4938c6011173d3017f47fd592c4b5e4c8d543a3
This commit is contained in:
Ali Saidi
2004-06-23 17:55:54 -04:00
32 changed files with 1945 additions and 367 deletions

View File

@@ -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);
if (PA_IPR_SPACE(req->paddr)) {
if (!req->xc->misspeculating()) {
switch (req->paddr) {
case ULL(0xFFFFF00188):
req->data = 0;
break;
// mark request as uncacheable
req->flags |= UNCACHEABLE;
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;
}

View File

@@ -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);

View File

@@ -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:

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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' ]
}

View File

@@ -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...
}

View File

@@ -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.

View File

@@ -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)

View File

@@ -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__

View File

@@ -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)

View File

@@ -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__

View File

@@ -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)

View File

@@ -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__

View File

@@ -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);

View File

@@ -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__

191
cpu/trace/trace_cpu.cc Normal file
View File

@@ -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)

151
cpu/trace/trace_cpu.hh Normal file
View File

@@ -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__

View File

@@ -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;

View File

@@ -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
////

View File

@@ -144,6 +144,10 @@ class IdeController : public PciDev
/** Select the disk based on a pointer */
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.

View File

@@ -167,6 +167,12 @@ IdeDisk::reset(int id)
// Utility functions
////
bool
IdeDisk::isDEVSelect()
{
return ctrl->isDiskSelected(this);
}
Addr
IdeDisk::pciToDma(Addr pciAddr)
{

View File

@@ -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()
{

View File

@@ -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(&regs, 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;
#if 0
if (config.data[offset] & PCI_CMD_BME)
bm_enabled = true;
else
bm_enabled = false;
break;
ioEnable = false;
if (config.data[offset] & PCI_CMD_MSE)
mem_enable = true;
else
mem_enable = false;
break;
#if 0
if (config.data[offset] & PCI_CMD_BME) {
bmEnabled = true;
}
else {
bmEnabled = false;
}
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 &section)
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 &section)
UNSERIALIZE_SCALAR(txXferLen);
UNSERIALIZE_SCALAR(rxXferLen);
UNSERIALIZE_SCALAR(txPktXmitted);
/*
* Unserialize DescCaches
@@ -2341,7 +2394,6 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
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;

View File

@@ -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 */

391
kern/kernel_stats.cc Normal file
View File

@@ -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");
}
}

63
kern/kernel_stats.hh Normal file
View File

@@ -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__

View File

@@ -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);

View File

@@ -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: