base/stats/text.cc
cpu/base.cc
- cpu/exec_context.cc
- cpu/base_dyn_inst.cc
+ cpu/cpu_exec_context.cc
cpu/exetrace.cc
+ cpu/op_class.cc
cpu/pc_event.cc
cpu/static_inst.cc
cpu/sampler/sampler.cc
encumbered/cpu/full/iq/standard/iq_standard.cc
''')
- o3_cpu_sources = Split('''
- arch/alpha/alpha_o3_exec.cc
- cpu/o3/2bit_local_pred.cc
- cpu/o3/alpha_dyn_inst.cc
- cpu/o3/alpha_cpu.cc
- cpu/o3/alpha_cpu_builder.cc
- cpu/o3/bpred_unit.cc
- cpu/o3/btb.cc
- cpu/o3/commit.cc
- cpu/o3/decode.cc
- cpu/o3/fetch.cc
- cpu/o3/free_list.cc
- cpu/o3/cpu.cc
- cpu/o3/iew.cc
- cpu/o3/inst_queue.cc
- cpu/o3/ldstq.cc
- cpu/o3/mem_dep_unit.cc
- cpu/o3/ras.cc
- cpu/o3/rename.cc
- cpu/o3/rename_map.cc
- cpu/o3/rob.cc
- cpu/o3/sat_counter.cc
- cpu/o3/store_set.cc
- cpu/o3/tournament_pred.cc
++trace_reader_sources = Split('''
++ cpu/trace/reader/mem_trace_reader.cc
++ cpu/trace/reader/ibm_reader.cc
++ cpu/trace/reader/itx_reader.cc
++ cpu/trace/reader/m5_reader.cc
++ cpu/trace/opt_cpu.cc
++ cpu/trace/trace_cpu.cc
+ ''')
+
++
++
# MySql sources
mysql_sources = Split('''
base/mysql.cc
kern/tru64/printf.cc
kern/tru64/tru64_events.cc
kern/tru64/tru64_syscalls.cc
- kern/tru64/tru64_system.cc
mem/functional/memory_control.cc
- mem/functional/physical.cc
-
- sim/system.cc
+ sim/pseudo_inst.cc
''')
# turbolaser encumbered sources
# Syscall emulation (non-full-system) sources
syscall_emulation_sources = Split('''
- arch/alpha/alpha_common_syscall_emul.cc
- arch/alpha/alpha_linux_process.cc
- arch/alpha/alpha_tru64_process.cc
- cpu/memtest/memtest.cc
- encumbered/eio/eio.cc
+
encumbered/eio/exolex.cc
encumbered/eio/libexo.cc
+ kern/linux/linux.cc
+ kern/tru64/tru64.cc
sim/process.cc
sim/syscall_emul.cc
''')
- targetarch_files = Split('''
- alpha_common_syscall_emul.hh
- alpha_linux_process.hh
- alpha_memory.hh
- alpha_tru64_process.hh
- aout_machdep.h
- arguments.hh
- byte_swap.hh
- ecoff_machdep.h
- ev5.hh
- faults.hh
- isa_fullsys_traits.hh
- isa_traits.hh
- osfpal.hh
- pseudo_inst.hh
- stacktrace.hh
- vptr.hh
- vtophys.hh
- ''')
+eio_sources = Split('''
+ encumbered/eio/eio.cc
+ ''')
+
+memtest_sources = Split('''
+ cpu/memtest/memtest.cc
+ ''')
+
+ # Add a flag defining what THE_ISA should be for all compilation
+ env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
- for f in targetarch_files:
- env.Command('targetarch/' + f, 'arch/alpha/' + f,
- '''echo '#include "arch/alpha/%s"' > $TARGET''' % f)
+ arch_sources = SConscript('arch/SConscript',
+ exports = 'env', duplicate = False)
+ cpu_sources = SConscript('cpu/SConscript',
+ exports = 'env', duplicate = False)
+
+ # This is outside of cpu/SConscript since the source directory isn't
+ # underneath 'cpu'.
+ if 'FullCPU' in env['CPU_MODELS']:
+ cpu_sources += full_cpu_sources
# Set up complete list of sources based on configuration.
- sources = base_sources + simple_cpu_sources
+ sources = base_sources + arch_sources + cpu_sources
if env['FULL_SYSTEM']:
sources += full_system_sources
--- /dev/null
-#include "mem/mem_req.hh" // some constructors use MemReq flags
+ // -*- mode:c++ -*-
+
+ // Copyright (c) 2003-2005 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.
+
+ output header {{
+ #include <sstream>
+ #include <iostream>
+ #include <iomanip>
+
+ #include "config/ss_compatible_fp.hh"
+ #include "cpu/static_inst.hh"
+ #include "arch/alpha/faults.hh"
++#include "mem/request.hh" // some constructors use MemReq flags
+ }};
+
+ output decoder {{
+ #include "base/cprintf.hh"
+ #include "base/fenv.hh"
+ #include "base/loader/symtab.hh"
+ #include "config/ss_compatible_fp.hh"
+ #include "cpu/exec_context.hh" // for Jump::branchTarget()
+
+ #include <math.h>
+
+ using namespace AlphaISA;
+ }};
+
+ output exec {{
+ #include <math.h>
+
+ #if FULL_SYSTEM
+ #include "sim/pseudo_inst.hh"
+ #endif
+ #include "base/fenv.hh"
+ #include "config/ss_compatible_fp.hh"
+ #include "cpu/base.hh"
+ #include "cpu/exetrace.hh"
+ #include "sim/sim_exit.hh"
+
+ using namespace AlphaISA;
+ }};
+
+ ////////////////////////////////////////////////////////////////////
+ //
+ // Namespace statement. Everything below this line will be in the
+ // AlphaISAInst namespace.
+ //
+
+
+ namespace AlphaISA;
+
+ ////////////////////////////////////////////////////////////////////
+ //
+ // Bitfield definitions.
+ //
+
+ // Universal (format-independent) fields
+ def bitfield PALMODE <32:32>;
+ def bitfield OPCODE <31:26>;
+ def bitfield RA <25:21>;
+ def bitfield RB <20:16>;
+
+ // Memory format
+ def signed bitfield MEMDISP <15: 0>; // displacement
+ def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned)
+
+ // Memory-format jumps
+ def bitfield JMPFUNC <15:14>; // function code (disp<15:14>)
+ def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>)
+
+ // Branch format
+ def signed bitfield BRDISP <20: 0>; // displacement
+
+ // Integer operate format(s>;
+ def bitfield INTIMM <20:13>; // integer immediate (literal)
+ def bitfield IMM <12:12>; // immediate flag
+ def bitfield INTFUNC <11: 5>; // function code
+ def bitfield RC < 4: 0>; // dest reg
+
+ // Floating-point operate format
+ def bitfield FA <25:21>;
+ def bitfield FB <20:16>;
+ def bitfield FP_FULLFUNC <15: 5>; // complete function code
+ def bitfield FP_TRAPMODE <15:13>; // trapping mode
+ def bitfield FP_ROUNDMODE <12:11>; // rounding mode
+ def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding
+ def bitfield FP_SRCTYPE <10: 9>; // source reg type
+ def bitfield FP_SHORTFUNC < 8: 5>; // short function code
+ def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code
+ def bitfield FC < 4: 0>; // dest reg
+
+ // PALcode format
+ def bitfield PALFUNC <25: 0>; // function code
+
+ // EV5 PAL instructions:
+ // HW_LD/HW_ST
+ def bitfield HW_LDST_PHYS <15>; // address is physical
+ def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR
+ def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc
+ def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b
+ def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch
+ def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked
+ def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional
+ def signed bitfield HW_LDST_DISP <9:0>; // signed displacement
+
+ // HW_REI
+ def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk
+ def bitfield HW_REI_MBZ <13: 0>; // must be zero
+
+ // HW_MTPR/MW_MFPR
+ def bitfield HW_IPR_IDX <15:0>; // IPR index
+
+ // M5 instructions
+ def bitfield M5FUNC <7:0>;
+
+ def operand_types {{
+ 'sb' : ('signed int', 8),
+ 'ub' : ('unsigned int', 8),
+ 'sw' : ('signed int', 16),
+ 'uw' : ('unsigned int', 16),
+ 'sl' : ('signed int', 32),
+ 'ul' : ('unsigned int', 32),
+ 'sq' : ('signed int', 64),
+ 'uq' : ('unsigned int', 64),
+ 'sf' : ('float', 32),
+ 'df' : ('float', 64)
+ }};
+
+ def operands {{
+ # Int regs default to unsigned, but code should not count on this.
+ # For clarity, descriptions that depend on unsigned behavior should
+ # explicitly specify '.uq'.
+ 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA',
+ 'IsInteger', 1),
+ 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB',
+ 'IsInteger', 2),
+ 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC',
+ 'IsInteger', 3),
+ 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1),
+ 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2),
+ 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3),
+ 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+ 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4),
+ 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1),
+ 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1),
+ # The next two are hacks for non-full-system call-pal emulation
+ 'R0': ('IntReg', 'uq', '0', None, 1),
+ 'R16': ('IntReg', 'uq', '16', None, 1),
+ 'R17': ('IntReg', 'uq', '17', None, 1),
+ 'R18': ('IntReg', 'uq', '18', None, 1)
+ }};
+
+ ////////////////////////////////////////////////////////////////////
+ //
+ // Basic instruction classes/templates/formats etc.
+ //
+
+ output header {{
+ // uncomment the following to get SimpleScalar-compatible disassembly
+ // (useful for diffing output traces).
+ // #define SS_COMPATIBLE_DISASSEMBLY
+
+ /**
+ * Base class for all Alpha static instructions.
+ */
+ class AlphaStaticInst : public StaticInst
+ {
+ protected:
+
+ /// Make AlphaISA register dependence tags directly visible in
+ /// this class and derived classes. Maybe these should really
+ /// live here and not in the AlphaISA namespace.
+ enum DependenceTags {
+ FP_Base_DepTag = AlphaISA::FP_Base_DepTag,
+ Fpcr_DepTag = AlphaISA::Fpcr_DepTag,
+ Uniq_DepTag = AlphaISA::Uniq_DepTag,
+ Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag,
+ Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag,
+ IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag
+ };
+
+ /// Constructor.
+ AlphaStaticInst(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass)
+ : StaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ /// Print a register name for disassembly given the unique
+ /// dependence tag number (FP or int).
+ void printReg(std::ostream &os, int reg) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+ }};
+
+ output decoder {{
+ void
+ AlphaStaticInst::printReg(std::ostream &os, int reg) const
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string
+ AlphaStaticInst::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+ if (_numSrcRegs > 1) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if (_numDestRegs > 0) {
+ if (_numSrcRegs > 0)
+ ss << ",";
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+ }};
+
+ // Declarations for execute() methods.
+ def template BasicExecDeclare {{
+ Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+ }};
+
+ // Basic instruction class declaration template.
+ def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)s(ExtMachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+ }};
+
+ // Basic instruction class constructor template.
+ def template BasicConstructor {{
+ inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+ }};
+
+ // Basic instruction class execute method template.
+ def template BasicExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+ }};
+
+ // Basic decode template.
+ def template BasicDecode {{
+ return new %(class_name)s(machInst);
+ }};
+
+ // Basic decode template, passing mnemonic in as string arg to constructor.
+ def template BasicDecodeWithMnemonic {{
+ return new %(class_name)s("%(mnemonic)s", machInst);
+ }};
+
+ // The most basic instruction format... used only for a few misc. insts
+ def format BasicOperate(code, *flags) {{
+ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+ }};
+
+
+
+ ////////////////////////////////////////////////////////////////////
+ //
+ // Nop
+ //
+
+ output header {{
+ /**
+ * Static instruction class for no-ops. This is a leaf class.
+ */
+ class Nop : public AlphaStaticInst
+ {
+ /// Disassembly of original instruction.
+ const std::string originalDisassembly;
+
+ public:
+ /// Constructor
+ Nop(const std::string _originalDisassembly, ExtMachInst _machInst)
+ : AlphaStaticInst("nop", _machInst, No_OpClass),
+ originalDisassembly(_originalDisassembly)
+ {
+ flags[IsNop] = true;
+ }
+
+ ~Nop() { }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ %(BasicExecDeclare)s
+ };
+
+ /// Helper function for decoding nops. Substitute Nop object
+ /// for original inst passed in as arg (and delete latter).
+ static inline
+ AlphaStaticInst *
+ makeNop(AlphaStaticInst *inst)
+ {
+ AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ delete inst;
+ return nop;
+ }
+ }};
+
+ output decoder {{
+ std::string Nop::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ #ifdef SS_COMPATIBLE_DISASSEMBLY
+ return originalDisassembly;
+ #else
+ return csprintf("%-10s (%s)", "nop", originalDisassembly);
+ #endif
+ }
+ }};
+
+ output exec {{
+ Fault
+ Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
+ {
+ return NoFault;
+ }
+ }};
+
+ // integer & FP operate instructions use Rc as dest, so check for
+ // Rc == 31 to detect nops
+ def template OperateNopCheckDecode {{
+ {
+ AlphaStaticInst *i = new %(class_name)s(machInst);
+ if (RC == 31) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+ }};
+
+ // Like BasicOperate format, but generates NOP if RC/FC == 31
+ def format BasicOperateWithNopCheck(code, *opt_args) {{
+ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code),
+ opt_args)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = OperateNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+ }};
+
+ // Integer instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/int.isa"
+
+ // Floating-point instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/fp.isa"
+
+ // Memory instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/mem.isa"
+
+ // Branch/jump instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/branch.isa"
+
+ // PAL instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/pal.isa"
+
+ // Opcdec fault instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/opcdec.isa"
+
+ // Unimplemented instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/unimp.isa"
+
+ // Unknown instruction templates, formats, etc.
+ ##include "m5/arch/alpha/isa/unknown.isa"
+
+ // Execution utility functions
+ ##include "m5/arch/alpha/isa/util.isa"
+
+ // The actual decoder
+ ##include "m5/arch/alpha/isa/decoder.isa"
--- /dev/null
+ /*
+ * 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.
+ */
+
+ #ifndef __ALPHA_LINUX_PROCESS_HH__
+ #define __ALPHA_LINUX_PROCESS_HH__
+
+ #include "sim/process.hh"
+
+
+ /// A process with emulated Alpha/Linux syscalls.
+ class AlphaLinuxProcess : public LiveProcess
+ {
+ public:
+ /// Constructor.
+ AlphaLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
++ System *system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual SyscallDesc* getDesc(int callnum);
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ const int Num_Syscall_Descs;
+ };
+
+
+ #endif // __ALPHA_LINUX_PROCESS_HH__
--- /dev/null
+ /*
+ * 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.
+ */
+
+ #ifndef __ALPHA_TRU64_PROCESS_HH__
+ #define __ALPHA_TRU64_PROCESS_HH__
+
+ #include "sim/process.hh"
+
+ /// A process with emulated Alpha Tru64 syscalls.
+ class AlphaTru64Process : public LiveProcess
+ {
+ public:
+ /// Constructor.
+ AlphaTru64Process(const std::string &name,
+ ObjectFile *objFile,
++ System *system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ /// Array of mach syscall descriptors, indexed by call number.
+ static SyscallDesc machSyscallDescs[];
+
+ const int Num_Syscall_Descs;
+ const int Num_Mach_Syscall_Descs;
+
+ virtual SyscallDesc* getDesc(int callnum);
+ };
+
+
+ #endif // __ALPHA_TRU64_PROCESS_HH__
#ifndef __OBJECT_FILE_HH__
#define __OBJECT_FILE_HH__
- #include "targetarch/isa_traits.hh" // for Addr
+ #include <string>
+
+ #include "sim/host.hh" // for Addr
-class FunctionalMemory;
+class TranslatingPort;
class SymbolTable;
class ObjectFile
#include "cpu/sampler/sampler.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
- #include "targetarch/isa_traits.hh"
+ #include "arch/isa_traits.hh"
-#if FULL_SYSTEM
class System;
-#endif
-
+ namespace Kernel { class Statistics; }
class BranchPred;
class ExecContext;
+class Port;
class BaseCPU : public SimObject
{
--- /dev/null
- FunctionalMemory *_mem)
+ /*
+ * Copyright (c) 2001-2006 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 <string>
+
+ #include "cpu/base.hh"
+ #include "cpu/cpu_exec_context.hh"
+ #include "cpu/exec_context.hh"
+
+ #if FULL_SYSTEM
+ #include "base/callback.hh"
+ #include "base/cprintf.hh"
+ #include "base/output.hh"
+ #include "base/trace.hh"
+ #include "cpu/profile.hh"
+ #include "kern/kernel_stats.hh"
+ #include "sim/serialize.hh"
+ #include "sim/sim_exit.hh"
+ #include "sim/system.hh"
+ #include "arch/stacktrace.hh"
+ #else
+ #include "sim/process.hh"
++#include "mem/translating_port.hh"
+ #endif
+
+ using namespace std;
+
+ // constructor
+ #if FULL_SYSTEM
+ CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaITB *_itb, AlphaDTB *_dtb,
- Process *_process, int _asid)
++ Memory *_mem)
+ : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
+ cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb),
+ dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem),
+ profile(NULL), quiesceEvent(this), func_exe_inst(0), storeCondFailures(0)
+ {
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+
+ memset(®s, 0, sizeof(RegFile));
+
+ if (cpu->params->profile) {
+ profile = new FunctionProfile(system->kernelSymtab);
+ Callback *cb =
+ new MakeCallback<CPUExecContext,
+ &CPUExecContext::dumpFuncProfile>(this);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ profileNode = &dummyNode;
+ profilePC = 3;
+ }
+ #else
+ CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
- lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid),
- func_exe_inst(0), storeCondFailures(0)
-{
- memset(®s, 0, sizeof(RegFile));
- proxy = new ProxyExecContext<CPUExecContext>(this);
-}
-
-CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
- FunctionalMemory *_mem, int _asid)
- : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid),
++ Process *_process, int _asid, Port *mem_port)
+ : _status(ExecContext::Unallocated),
+ cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0),
- assert(mem == oldContext->getMemPtr());
++ lastSuspend(0), process(_process), asid(_asid),
+ func_exe_inst(0), storeCondFailures(0)
+ {
++ port = new TranslatingPort(mem_port, process->pTable);
+ memset(®s, 0, sizeof(RegFile));
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+ }
+
+ CPUExecContext::CPUExecContext(RegFile *regFile)
+ : cpu(NULL), thread_num(-1), process(NULL), mem(NULL), asid(-1),
+ func_exe_inst(0), storeCondFailures(0)
+ {
+ regs = *regFile;
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+ }
+
+ #endif
+
+ CPUExecContext::~CPUExecContext()
+ {
+ delete proxy;
+ }
+
+ #if FULL_SYSTEM
+ void
+ CPUExecContext::dumpFuncProfile()
+ {
+ std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
+ profile->dump(proxy, *os);
+ }
+
+ CPUExecContext::EndQuiesceEvent::EndQuiesceEvent(CPUExecContext *_cpuXC)
+ : Event(&mainEventQueue), cpuXC(_cpuXC)
+ {
+ }
+
+ void
+ CPUExecContext::EndQuiesceEvent::process()
+ {
+ cpuXC->activate();
+ }
+
+ const char*
+ CPUExecContext::EndQuiesceEvent::description()
+ {
+ return "End Quiesce Event.";
+ }
+
+ void
+ CPUExecContext::profileClear()
+ {
+ if (profile)
+ profile->clear();
+ }
+
+ void
+ CPUExecContext::profileSample()
+ {
+ if (profile)
+ profile->sample(profileNode, profilePC);
+ }
+
+ #endif
+
+ void
+ CPUExecContext::takeOverFrom(ExecContext *oldContext)
+ {
+ // some things should already be set up
+ #if FULL_SYSTEM
+ assert(system == oldContext->getSystemPtr());
+ #else
+ assert(process == oldContext->getProcessPtr());
+ #endif
+
+ // copy over functional state
+ _status = oldContext->status();
+ copyArchRegs(oldContext);
+ cpu_id = oldContext->readCpuId();
+ #if !FULL_SYSTEM
+ func_exe_inst = oldContext->readFuncExeInst();
+ #endif
+
+ storeCondFailures = 0;
+
+ oldContext->setStatus(ExecContext::Unallocated);
+ }
+
+ void
+ CPUExecContext::serialize(ostream &os)
+ {
+ SERIALIZE_ENUM(_status);
+ regs.serialize(os);
+ // thread_num and cpu_id are deterministic from the config
+ SERIALIZE_SCALAR(func_exe_inst);
+ SERIALIZE_SCALAR(inst);
+
+ #if FULL_SYSTEM
+ Tick quiesceEndTick = 0;
+ if (quiesceEvent.scheduled())
+ quiesceEndTick = quiesceEvent.when();
+ SERIALIZE_SCALAR(quiesceEndTick);
+
+ #endif
+ }
+
+
+ void
+ CPUExecContext::unserialize(Checkpoint *cp, const std::string §ion)
+ {
+ UNSERIALIZE_ENUM(_status);
+ regs.unserialize(cp, section);
+ // thread_num and cpu_id are deterministic from the config
+ UNSERIALIZE_SCALAR(func_exe_inst);
+ UNSERIALIZE_SCALAR(inst);
+
+ #if FULL_SYSTEM
+ Tick quiesceEndTick;
+ UNSERIALIZE_SCALAR(quiesceEndTick);
+ if (quiesceEndTick)
+ quiesceEvent.schedule(quiesceEndTick);
+ #endif
+ }
+
+
+ void
+ CPUExecContext::activate(int delay)
+ {
+ if (status() == ExecContext::Active)
+ return;
+
+ lastActivate = curTick;
+
+ _status = ExecContext::Active;
+ cpu->activateContext(thread_num, delay);
+ }
+
+ void
+ CPUExecContext::suspend()
+ {
+ if (status() == ExecContext::Suspended)
+ return;
+
+ lastActivate = curTick;
+ lastSuspend = curTick;
+ /*
+ #if FULL_SYSTEM
+ // Don't change the status from active if there are pending interrupts
+ if (cpu->check_interrupts()) {
+ assert(status() == ExecContext::Active);
+ return;
+ }
+ #endif
+ */
+ _status = ExecContext::Suspended;
+ cpu->suspendContext(thread_num);
+ }
+
+ void
+ CPUExecContext::deallocate()
+ {
+ if (status() == ExecContext::Unallocated)
+ return;
+
+ _status = ExecContext::Unallocated;
+ cpu->deallocateContext(thread_num);
+ }
+
+ void
+ CPUExecContext::halt()
+ {
+ if (status() == ExecContext::Halted)
+ return;
+
+ _status = ExecContext::Halted;
+ cpu->haltContext(thread_num);
+ }
+
+
+ void
+ CPUExecContext::regStats(const string &name)
+ {
+ }
+
+ void
+ CPUExecContext::copyArchRegs(ExecContext *xc)
+ {
+ // First loop through the integer registers.
+ for (int i = 0; i < AlphaISA::NumIntRegs; ++i) {
+ setIntReg(i, xc->readIntReg(i));
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) {
+ setFloatRegDouble(i, xc->readFloatRegDouble(i));
+ setFloatRegInt(i, xc->readFloatRegInt(i));
+ }
+
+ // Copy misc. registers
+ regs.miscRegs.copyMiscRegs(xc);
+
+ // Lastly copy PC/NPC
+ setPC(xc->readPC());
+ setNextPC(xc->readNextPC());
+ }
+
--- /dev/null
-#include "mem/functional/functional.hh"
-#include "mem/mem_req.hh"
+ /*
+ * Copyright (c) 2001-2006 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 __CPU_CPU_EXEC_CONTEXT_HH__
+ #define __CPU_CPU_EXEC_CONTEXT_HH__
+
+ #include "arch/isa_traits.hh"
+ #include "config/full_system.hh"
+ #include "cpu/exec_context.hh"
-// forward declaration: see functional_memory.hh
-class FunctionalMemory;
-class PhysicalMemory;
++#include "mem/physical.hh"
++#include "mem/request.hh"
+ #include "sim/byteswap.hh"
+ #include "sim/eventq.hh"
+ #include "sim/host.hh"
+ #include "sim/serialize.hh"
+
- FunctionalMemory *mem;
+ class BaseCPU;
+
+ #if FULL_SYSTEM
+
+ #include "sim/system.hh"
+ #include "arch/tlb.hh"
+
+ class FunctionProfile;
+ class ProfileNode;
+ class MemoryController;
+
+ #else // !FULL_SYSTEM
+
+ #include "sim/process.hh"
++class TranslatingPort;
+
+ #endif // FULL_SYSTEM
+
+ //
+ // The CPUExecContext object represents a functional context for
+ // instruction execution. It incorporates everything required for
+ // architecture-level functional simulation of a single thread.
+ //
+
+ class CPUExecContext
+ {
+ protected:
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::MiscRegFile MiscRegFile;
+ typedef TheISA::MiscReg MiscReg;
+ public:
+ typedef ExecContext::Status Status;
+
+ private:
+ Status _status;
+
+ public:
+ Status status() const { return _status; }
+
+ void setStatus(Status newStatus) { _status = newStatus; }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1);
+
+ /// Set the status to Suspended.
+ void suspend();
+
+ /// Set the status to Unallocated.
+ void deallocate();
+
+ /// Set the status to Halted.
+ void halt();
+
+ protected:
+ RegFile regs; // correct-path register context
+
+ public:
+ // pointer to CPU associated with this context
+ BaseCPU *cpu;
+
+ ProxyExecContext<CPUExecContext> *proxy;
+
+ // Current instruction
+ MachInst inst;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int thread_num;
+
+ // ID of this context w.r.t. the System or Process object to which
+ // it belongs. For full-system mode, this is the system CPU ID.
+ int cpu_id;
+
+ Tick lastActivate;
+ Tick lastSuspend;
+
++ System *system;
++
++ /// Port that syscalls can use to access memory (provides translation step).
++ TranslatingPort *port;
++// Memory *mem;
++
+ #if FULL_SYSTEM
- System *system;
+ AlphaITB *itb;
+ AlphaDTB *dtb;
- PhysicalMemory *physmem;
+
+ // the following two fields are redundant, since we can always
+ // look them up through the system pointer, but we'll leave them
+ // here for now for convenience
+ MemoryController *memctrl;
- FunctionalMemory *mem; // functional storage for process address space
-
++// PhysicalMemory *physmem;
+
+ FunctionProfile *profile;
+ ProfileNode *profileNode;
+ Addr profilePC;
+ void dumpFuncProfile();
+
+ /** Event for timing out quiesce instruction */
+ struct EndQuiesceEvent : public Event
+ {
+ /** A pointer to the execution context that is quiesced */
+ CPUExecContext *cpuXC;
+
+ EndQuiesceEvent(CPUExecContext *_cpuXC);
+
+ /** Event process to occur at interrupt*/
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description();
+ };
+ EndQuiesceEvent quiesceEvent;
+
+ Event *getQuiesceEvent() { return &quiesceEvent; }
+
+ Tick readLastActivate() { return lastActivate; }
+
+ Tick readLastSuspend() { return lastSuspend; }
+
+ void profileClear();
+
+ void profileSample();
+
+ #else
+ Process *process;
+
- CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
- CPUExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
- int _asid);
+ // Address space ID. Note that this is used for TIMING cache
+ // simulation only; all functional memory accesses should use
+ // one of the FunctionalMemory pointers above.
+ short asid;
+
+ #endif
+
+ /**
+ * Temporary storage to pass the source address from copy_load to
+ * copy_store.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcAddr;
+ /**
+ * Temp storage for the physical source address of a copy.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcPhysAddr;
+
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter func_exe_inst;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+
+ // constructor: initialize context from given process structure
+ #if FULL_SYSTEM
+ CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem);
+ #else
- Fault translateInstReq(MemReqPtr &req)
++ CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid, Port *mem_port);
+ // Constructor to use XC to pass reg file around. Not used for anything
+ // else.
+ CPUExecContext(RegFile *regFile);
+ #endif
+ virtual ~CPUExecContext();
+
+ virtual void takeOverFrom(ExecContext *oldContext);
+
+ void regStats(const std::string &name);
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string §ion);
+
+ BaseCPU *getCpuPtr() { return cpu; }
+
+ ExecContext *getProxy() { return proxy; }
+
+ int getThreadNum() { return thread_num; }
+
+ #if FULL_SYSTEM
+ System *getSystemPtr() { return system; }
+
+ PhysicalMemory *getPhysMemPtr() { return physmem; }
+
+ AlphaITB *getITBPtr() { return itb; }
+
+ AlphaDTB *getDTBPtr() { return dtb; }
+
+ bool validInstAddr(Addr addr) { return true; }
+ bool validDataAddr(Addr addr) { return true; }
+ int getInstAsid() { return regs.instAsid(); }
+ int getDataAsid() { return regs.dataAsid(); }
+
- Fault translateDataReadReq(MemReqPtr &req)
++ Fault translateInstReq(CpuRequestPtr &req)
+ {
+ return itb->translate(req);
+ }
+
- Fault translateDataWriteReq(MemReqPtr &req)
++ Fault translateDataReadReq(CpuRequestPtr &req)
+ {
+ return dtb->translate(req, false);
+ }
+
- Fault dummyTranslation(MemReqPtr &req)
++ Fault translateDataWriteReq(CpuRequestPtr &req)
+ {
+ return dtb->translate(req, true);
+ }
+
+ #else
+ Process *getProcessPtr() { return process; }
+
+ bool validInstAddr(Addr addr)
+ { return process->validInstAddr(addr); }
+
+ bool validDataAddr(Addr addr)
+ { return process->validDataAddr(addr); }
+
+ int getInstAsid() { return asid; }
+ int getDataAsid() { return asid; }
+
-#if 0
- assert((req->vaddr >> 48 & 0xffff) == 0);
-#endif
-
- // put the asid in the upper 16 bits of the paddr
- req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
- req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
- return NoFault;
++ Fault translateInstReq(CpuRequestPtr &req)
+ {
- Fault translateInstReq(MemReqPtr &req)
- {
- return dummyTranslation(req);
- }
- Fault translateDataReadReq(MemReqPtr &req)
++ return process->pTable->translate(req);
+ }
- return dummyTranslation(req);
++
++ Fault translateDataReadReq(CpuRequestPtr &req)
+ {
- Fault translateDataWriteReq(MemReqPtr &req)
++ return process->pTable->translate(req);
+ }
- return dummyTranslation(req);
++
++ Fault translateDataWriteReq(CpuRequestPtr &req)
+ {
- Fault read(MemReqPtr &req, T &data)
++ return process->pTable->translate(req);
+ }
+
+ #endif
+
++/*
+ template <class T>
- error = mem->read(req, data);
++ Fault read(CpuRequestPtr &req, T &data)
+ {
+ #if FULL_SYSTEM && defined(TARGET_ALPHA)
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+ #endif
+
+ Fault error;
- Fault write(MemReqPtr &req, T &data)
++ error = mem->prot_read(req->paddr, data, req->size);
+ data = LittleEndianGuest::gtoh(data);
+ return error;
+ }
+
+ template <class T>
- return mem->write(req, (T)LittleEndianGuest::htog(data));
++ Fault write(CpuRequestPtr &req, T &data)
+ {
+ #if FULL_SYSTEM && defined(TARGET_ALPHA)
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < system->execContexts.size(); i++){
+ xc = system->execContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
+
+ #endif
-
++ return mem->prot_write(req->paddr, (T)htog(data), req->size);
+ }
- Fault instRead(MemReqPtr &req)
++*/
+ virtual bool misspeculating();
+
+
+ MachInst getInst() { return inst; }
+
+ void setInst(MachInst new_inst)
+ {
+ inst = new_inst;
+ }
+
- return mem->read(req, inst);
++ Fault instRead(CpuRequestPtr &req)
+ {
++ panic("instRead not implemented");
++ // return funcPhysMem->read(req, inst);
++ return No_Fault;
+ }
+
+ void setCpuId(int id) { cpu_id = id; }
+
+ int readCpuId() { return cpu_id; }
+
+ FunctionalMemory *getMemPtr() { return mem; }
+
+ void copyArchRegs(ExecContext *xc);
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ {
+ return regs.intRegFile[reg_idx];
+ }
+
+ float readFloatRegSingle(int reg_idx)
+ {
+ return (float)regs.floatRegFile.d[reg_idx];
+ }
+
+ double readFloatRegDouble(int reg_idx)
+ {
+ return regs.floatRegFile.d[reg_idx];
+ }
+
+ uint64_t readFloatRegInt(int reg_idx)
+ {
+ return regs.floatRegFile.q[reg_idx];
+ }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ regs.intRegFile[reg_idx] = val;
+ }
+
+ void setFloatRegSingle(int reg_idx, float val)
+ {
+ regs.floatRegFile.d[reg_idx] = (double)val;
+ }
+
+ void setFloatRegDouble(int reg_idx, double val)
+ {
+ regs.floatRegFile.d[reg_idx] = val;
+ }
+
+ void setFloatRegInt(int reg_idx, uint64_t val)
+ {
+ regs.floatRegFile.q[reg_idx] = val;
+ }
+
+ uint64_t readPC()
+ {
+ return regs.pc;
+ }
+
+ void setPC(uint64_t val)
+ {
+ regs.pc = val;
+ }
+
+ uint64_t readNextPC()
+ {
+ return regs.npc;
+ }
+
+ void setNextPC(uint64_t val)
+ {
+ regs.npc = val;
+ }
+
+ uint64_t readNextNPC()
+ {
+ return regs.nnpc;
+ }
+
+ void setNextNPC(uint64_t val)
+ {
+ regs.nnpc = val;
+ }
+
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return regs.miscRegs.readReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return regs.miscRegs.readRegWithEffect(misc_reg, fault, proxy);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ return regs.miscRegs.setReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ return regs.miscRegs.setRegWithEffect(misc_reg, val, proxy);
+ }
+
+ unsigned readStCondFailures() { return storeCondFailures; }
+
+ void setStCondFailures(unsigned sc_failures)
+ { storeCondFailures = sc_failures; }
+
+ void clearArchRegs() { memset(®s, 0, sizeof(regs)); }
+
+ #if FULL_SYSTEM
+ int readIntrFlag() { return regs.intrflag; }
+ void setIntrFlag(int val) { regs.intrflag = val; }
+ Fault hwrei();
+ bool inPalMode() { return AlphaISA::PcPAL(regs.pc); }
+ bool simPalCheck(int palFunc);
+ #endif
+
+ #if !FULL_SYSTEM
+ TheISA::IntReg getSyscallArg(int i)
+ {
+ return regs.intRegFile[TheISA::ArgumentReg0 + i];
+ }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, TheISA::IntReg val)
+ {
+ regs.intRegFile[TheISA::ArgumentReg0 + i] = val;
+ }
+
+ void setSyscallReturn(SyscallReturn return_value)
+ {
+ TheISA::setSyscallReturn(return_value, ®s);
+ }
+
+ void syscall()
+ {
+ process->syscall(proxy);
+ }
+
+ Counter readFuncExeInst() { return func_exe_inst; }
+
+ void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; }
+ #endif
+ };
+
+
+ // for non-speculative execution context, spec_mode is always false
+ inline bool
+ CPUExecContext::misspeculating()
+ {
+ return false;
+ }
+
+ #endif // __CPU_CPU_EXEC_CONTEXT_HH__
#include <iomanip>
#include "sim/param.hh"
-#include "encumbered/cpu/full/dyn_inst.hh"
-#include "encumbered/cpu/full/spec_state.hh"
-#include "encumbered/cpu/full/issue.hh"
#include "cpu/exetrace.hh"
- #include "cpu/exec_context.hh"
#include "base/loader/symtab.hh"
#include "cpu/base.hh"
#include "cpu/static_inst.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
#include "kern/kernel_stats.hh"
-#include "mem/base_mem.hh"
-#include "mem/mem_interface.hh"
+ #include "sim/byteswap.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "mem/functional/memory_control.hh"
#include "mem/functional/physical.hh"
#include "sim/system.hh"
- #include "targetarch/alpha_memory.hh"
- #include "targetarch/stacktrace.hh"
- #include "targetarch/vtophys.hh"
+ #include "arch/tlb.hh"
+ #include "arch/stacktrace.hh"
+ #include "arch/vtophys.hh"
#else // !FULL_SYSTEM
-#include "mem/functional/functional.hh"
+#include "mem/memory.hh"
#endif // FULL_SYSTEM
using namespace std;
}
SimpleCPU::SimpleCPU(Params *p)
- : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL),
- cacheCompletionEvent(this)
+ : BaseCPU(p), icachePort(this),
- dcachePort(this), tickEvent(this, p->width), xc(NULL)
++ dcachePort(this), tickEvent(this, p->width), cpuXC(NULL)
{
_status = Idle;
+
+ //Create Memory Ports (conect them up)
+ p->mem->addPort("DCACHE");
+ dcachePort.setPeer(p->mem->getPort("DCACHE"));
+ (p->mem->getPort("DCACHE"))->setPeer(&dcachePort);
+
+ p->mem->addPort("ICACHE");
+ icachePort.setPeer(p->mem->getPort("ICACHE"));
+ (p->mem->getPort("ICACHE"))->setPeer(&icachePort);
+
#if FULL_SYSTEM
- xc = new ExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
-
- // initialize CPU, including PC
- TheISA::initCPU(&xc->regs);
+ cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem);
-
#else
- xc = new ExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
- cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process,
- /* asid */ 0);
++ cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, /* asid */ 0,
+ &dcachePort);
#endif // !FULL_SYSTEM
- xcProxy = cpuXC->getProxy();
- icacheInterface = p->icache_interface;
- dcacheInterface = p->dcache_interface;
++ xcProxy = cpuXC->getProxy();
+
- memReq = new MemReq();
- memReq->xc = xcProxy;
- memReq->asid = 0;
- memReq->data = new uint8_t[64];
+#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE
+ ifetch_req = new CpuRequest;
+ ifetch_req->asid = 0;
+ ifetch_req->size = sizeof(MachInst);
+ ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->data = (uint8_t *)&inst;
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+
+ data_read_req = new CpuRequest;
+ data_read_req->asid = 0;
+ data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->data = new uint8_t[8];
+ data_read_pkt->req = data_read_req;
+
+ data_write_req = new CpuRequest;
+ data_write_req->asid = 0;
+ data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+#endif
numInst = 0;
startNumInst = 0;
BaseCPU::unserialize(cp, section);
UNSERIALIZE_ENUM(_status);
UNSERIALIZE_SCALAR(inst);
- xc->unserialize(cp, csprintf("%s.xc", section));
+ cpuXC->unserialize(cp, csprintf("%s.xc", section));
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
- cacheCompletionEvent
- .unserialize(cp, csprintf("%s.cacheCompletionEvent", section));
}
void
memReq->reset(src & ~(blk_size - 1), blk_size);
-- // translate to physical address
- Fault fault = xc->translateDataReadReq(req);
-
- assert(fault != Alignment_Fault);
- Fault fault = cpuXC->translateDataReadReq(memReq);
++ // translate to physical address Fault fault = cpuXC->translateDataReadReq(req);
- if (fault == No_Fault) {
- xc->copySrcAddr = src;
- xc->copySrcPhysAddr = memReq->paddr + offset;
+ if (fault == NoFault) {
+ cpuXC->copySrcAddr = src;
+ cpuXC->copySrcPhysAddr = memReq->paddr + offset;
} else {
- xc->copySrcAddr = 0;
- xc->copySrcPhysAddr = 0;
+ assert(!fault->isAlignmentFault());
+
+ cpuXC->copySrcAddr = 0;
+ cpuXC->copySrcPhysAddr = 0;
}
return fault;
+#else
+ return No_Fault;
+#endif
}
Fault
memReq->reset(dest & ~(blk_size -1), blk_size);
// translate to physical address
- Fault fault = xc->translateDataWriteReq(req);
-
- assert(fault != Alignment_Fault);
- Fault fault = cpuXC->translateDataWriteReq(memReq);
++ Fault fault = cpuXC->translateDataWriteReq(req);
- if (fault == No_Fault) {
+ if (fault == NoFault) {
Addr dest_addr = memReq->paddr + offset;
// Need to read straight from memory since we have more than 8 bytes.
- memReq->paddr = xc->copySrcPhysAddr;
- xc->mem->read(memReq, data);
+ memReq->paddr = cpuXC->copySrcPhysAddr;
+ cpuXC->mem->read(memReq, data);
memReq->paddr = dest_addr;
- xc->mem->write(memReq, data);
+ cpuXC->mem->write(memReq, data);
if (dcacheInterface) {
memReq->cmd = Copy;
memReq->completionEvent = NULL;
dcacheInterface->access(memReq);
}
}
+ else
+ assert(!fault->isAlignmentFault());
+
return fault;
+#else
+ panic("copy not implemented");
+ return No_Fault;
+#endif
}
// precise architected memory state accessor macros
if (traceData) {
traceData->setAddr(addr);
}
- return fault;
+
+ // @todo: Figure out a way to create a Fault from the packet result.
+ return No_Fault;
}
- memReq->reset(addr, sizeof(T), flags);
+// memReq->reset(addr, sizeof(T), flags);
+
+#if SIMPLE_CPU_MEM_TIMING
+ CpuRequest *data_read_req = new CpuRequest;
+#endif
+
+ data_read_req->vaddr = addr;
+ data_read_req->size = sizeof(T);
+ data_read_req->flags = flags;
+ data_read_req->time = curTick;
// translate to physical address
- Fault fault = xc->translateDataReadReq(data_read_req);
- Fault fault = cpuXC->translateDataReadReq(memReq);
++ Fault fault = cpuXC->translateDataReadReq(data_read_req);
+
+ // Now do the access.
+ if (fault == No_Fault) {
+#if SIMPLE_CPU_MEM_TIMING
+ data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->req = data_read_req;
+ data_read_pkt->data = new uint8_t[8];
+#endif
+ data_read_pkt->addr = data_read_req->paddr;
+ data_read_pkt->size = sizeof(T);
- // if we have a cache, do cache access too
- if (fault == NoFault && dcacheInterface) {
+ sendDcacheRequest(data_read_pkt);
+
+#if SIMPLE_CPU_MEM_IMMEDIATE
+ // Need to find a way to not duplicate code above.
+
+ if (data_read_pkt->result == Success) {
+ memcpy(&data, data_read_pkt->data, sizeof(T));
+ }
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+
+ // @todo: Figure out a way to create a Fault from the packet result.
+ return No_Fault;
+#endif
+ }
+/*
memReq->cmd = Read;
memReq->completionEvent = NULL;
memReq->time = curTick;
_status = DcacheMissStall;
} else {
// do functional access
- fault = xc->read(memReq, data);
+ fault = cpuXC->read(memReq, data);
}
-
- } else if(fault == No_Fault) {
+ } else if(fault == NoFault) {
// do functional access
- fault = xc->read(memReq, data);
+ fault = cpuXC->read(memReq, data);
}
-
- if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+*/
+ // This will need a new way to tell if it has a dcache attached.
+ if (data_read_req->flags & UNCACHEABLE)
recordEvent("Uncached Read");
return fault;
Fault
SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- memReq->reset(addr, sizeof(T), flags);
+ data_write_req->vaddr = addr;
+ data_write_req->time = curTick;
+ data_write_req->size = sizeof(T);
+ data_write_req->flags = flags;
// translate to physical address
- Fault fault = xc->translateDataWriteReq(data_write_req);
-
- Fault fault = cpuXC->translateDataWriteReq(memReq);
++ Fault fault = cpuXC->translateDataWriteReq(data_write_req);
+ // Now do the access.
+ if (fault == No_Fault) {
+#if SIMPLE_CPU_MEM_TIMING
+ data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+ data_write_pkt->data = new uint8_t[64];
+ memcpy(data_write_pkt->data, &data, sizeof(T));
+#else
+ data_write_pkt->data = (uint8_t *)&data;
+#endif
+ data_write_pkt->addr = data_write_req->paddr;
+ data_write_pkt->size = sizeof(T);
+
+ sendDcacheRequest(data_write_pkt);
+ }
+/*
// do functional access
- if (fault == No_Fault)
- fault = xc->write(memReq, data);
+ if (fault == NoFault)
+ fault = cpuXC->write(memReq, data);
- if (fault == No_Fault && dcacheInterface) {
+ if (fault == NoFault && dcacheInterface) {
memReq->cmd = Write;
memcpy(memReq->data,(uint8_t *)&data,memReq->size);
memReq->completionEvent = NULL;
_status = DcacheMissStall;
}
}
-
+*/
- if (res && (fault == No_Fault))
+ if (res && (fault == NoFault))
- *res = memReq->result;
+ *res = data_write_pkt->result;
- if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (data_write_req->flags & UNCACHEABLE)
recordEvent("Uncached Write");
+ // If the write needs to have a fault on the access, consider calling
+ // changeStatus() and changing it to "bad addr write" or something.
return fault;
}
#endif
// maintain $r0 semantics
- xc->regs.intRegFile[ZeroReg] = 0;
+ cpuXC->setIntReg(ZeroReg, 0);
#ifdef TARGET_ALPHA
- xc->regs.floatRegFile.d[ZeroReg] = 0.0;
+ cpuXC->setFloatRegDouble(ZeroReg, 0.0);
#endif // TARGET_ALPHA
- if (status() == IcacheMissComplete) {
+ if (status() == IcacheAccessComplete) {
// We've already fetched an instruction and were stalled on an
// I-cache miss. No need to fetch it again.
#define IFETCH_FLAGS(pc) 0
#endif
- memReq->cmd = Read;
- memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t),
- IFETCH_FLAGS(cpuXC->readPC()));
+#if SIMPLE_CPU_MEM_TIMING
+ CpuRequest *ifetch_req = new CpuRequest();
+ ifetch_req->size = sizeof(MachInst);
+#endif
- ifetch_req->vaddr = xc->regs.pc & ~3;
- fault = cpuXC->translateInstReq(memReq);
++ ifetch_req->vaddr = cpuXC->readPC() & ~3;
+ ifetch_req->time = curTick;
- if (fault == NoFault)
- fault = cpuXC->mem->read(memReq, inst);
+/* memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
+ IFETCH_FLAGS(xc->regs.pc));
+*/
+
+ fault = xc->translateInstReq(ifetch_req);
+
- if (fault == No_Fault) {
++ if (fault == NoFault) {
+#if SIMPLE_CPU_MEM_TIMING
+ Packet *ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->data = (uint8_t *)&inst;
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+#endif
+ ifetch_pkt->addr = ifetch_req->paddr;
- if (icacheInterface && fault == No_Fault) {
+ sendIcacheRequest(ifetch_pkt);
+#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC
+ return;
+#endif
+/*
+ if (icacheInterface && fault == NoFault) {
memReq->completionEvent = NULL;
memReq->time = curTick;
class InstRecord;
}
+
+// Set exactly one of these symbols to 1 to set the memory access
+// model. Probably should make these template parameters, or even
+// just fork the CPU models.
+//
+#define SIMPLE_CPU_MEM_TIMING 0
+#define SIMPLE_CPU_MEM_ATOMIC 0
+#define SIMPLE_CPU_MEM_IMMEDIATE 1
+
+
class SimpleCPU : public BaseCPU
{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::MiscReg MiscReg;
+ class CpuPort : public Port
+ {
+
+ SimpleCPU *cpu;
+
+ public:
+
+ CpuPort(SimpleCPU *_cpu)
+ : cpu(_cpu)
+ { }
+
+ protected:
+
+ virtual bool recvTiming(Packet &pkt);
+
+ virtual Tick recvAtomic(Packet &pkt);
+
+ virtual void recvFunctional(Packet &pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual Packet *recvRetry();
+ };
+
+ CpuPort icachePort;
+ CpuPort dcachePort;
+
public:
// main simulation loop (one cycle)
void tick();
// the next switchover
Sampler *sampler;
- StaticInstPtr<TheISA> curStaticInst;
+ StaticInstPtr curStaticInst;
- class CacheCompletionEvent : public Event
- {
- private:
- SimpleCPU *cpu;
-
- public:
- CacheCompletionEvent(SimpleCPU *_cpu);
-
- virtual void process();
- virtual const char *description();
- };
-
- CacheCompletionEvent cacheCompletionEvent;
-
Status status() const { return _status; }
virtual void activateContext(int thread_num, int delay);
#include "base/hashmap.hh"
#include "base/refcnt.hh"
-#include "encumbered/cpu/full/op_class.hh"
+#include "cpu/op_class.hh"
#include "sim/host.hh"
- #include "targetarch/isa_traits.hh"
+ #include "arch/isa_traits.hh"
// forward declarations
struct AlphaSimpleImpl;
#include "sim/fake_syscall.hh"
#include "sim/process.hh"
#include "sim/stats.hh"
+ #include "sim/syscall_emul.hh"
+#include "sim/system.hh"
- #ifdef TARGET_ALPHA
- #include "arch/alpha/alpha_tru64_process.hh"
- #include "arch/alpha/alpha_linux_process.hh"
- #endif
+ #include "arch/process.hh"
using namespace std;
+ using namespace TheISA;
//
// The purpose of this code is to fake the loader & syscall mechanism
static void
copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
- FunctionalMemory *memory)
+ TranslatingPort* memPort)
{
+ Addr data_ptr_swap;
for (int i = 0; i < strings.size(); ++i) {
- memPort->writeBlobFunctional(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr));
+ data_ptr_swap = htog(data_ptr);
- memory->access(Write, array_ptr, &data_ptr_swap, sizeof(Addr));
- memory->writeString(data_ptr, strings[i].c_str());
++ memPort->writeBlobFunctional(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr));
+ memPort->writeStringFunctional(data_ptr, strings[i].c_str());
array_ptr += sizeof(Addr);
data_ptr += strings[i].size() + 1;
}
// write contents to stack
uint64_t argc = argv.size();
- memory->access(Write, stack_min, &argc, sizeof(uint64_t));
+ argc = htog(argc);
+ initVirtMem->writeBlobFunctional(stack_min, (uint8_t*)&argc, sizeof(uint64_t));
- copyStringArray(argv, argv_array_base, arg_data_base, memory);
- copyStringArray(envp, envp_array_base, env_data_base, memory);
+ copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
+ copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
- RegFile *init_regs = &(execContexts[0]->regs);
-
-- init_regs->intRegFile[ArgumentReg0] = argc;
-- init_regs->intRegFile[ArgumentReg1] = argv_array_base;
-- init_regs->intRegFile[StackPointerReg] = stack_min;
-- init_regs->intRegFile[GlobalPointerReg] = objFile->globalPointer();
-- init_regs->pc = prog_entry;
-- init_regs->npc = prog_entry + sizeof(MachInst);
++ execContexts[0]->setIntReg(ArgumentReg0, argc);
++ execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
++ execContexts[0]->setIntReg(StackPointerReg, stack_min);
++ execContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer());
++ execContexts[0]->setPC(prog_entry);
++ execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+
+ num_processes++;
}
+ void
+ LiveProcess::syscall(ExecContext *xc)
+ {
+ num_syscalls++;
+
+ int64_t callnum = xc->readIntReg(SyscallNumReg);
+
+ SyscallDesc *desc = getDesc(callnum);
+ if (desc == NULL)
+ fatal("Syscall %d out of range", callnum);
+
+ desc->doSyscall(callnum, this, xc);
+ }
LiveProcess *
-LiveProcess::create(const string &nm,
+LiveProcess::create(const string &nm, System *system,
int stdin_fd, int stdout_fd, int stderr_fd,
string executable,
vector<string> &argv, vector<string> &envp)
fatal("Can't load object file %s", executable);
}
- // check object type & set up syscall emulation pointer
- if (objFile->getArch() == ObjectFile::Alpha) {
-
- switch (objFile->getOpSys()) {
- case ObjectFile::Tru64:
- process = new AlphaTru64Process(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
-
- break;
-
- case ObjectFile::Linux:
- process = new AlphaLinuxProcess(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
-
- break;
-
- default:
- fatal("Unknown/unsupported operating system.");
- }
- } else {
- fatal("Unknown object file architecture.");
- }
+ // set up syscall emulation pointer for the current ISA
- process = createProcess(nm, objFile,
++ process = createProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
- delete objFile;
-
if (process == NULL)
fatal("Unknown error creating process object.");
#include <vector>
-#include "sim/sim_object.hh"
-#include "sim/stats.hh"
+ #include "arch/isa_traits.hh"
#include "base/statistics.hh"
#include "base/trace.hh"
+#include "mem/memory.hh"
+//#include "mem/mem_interface.hh"
+#include "mem/page_table.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+#include "targetarch/isa_traits.hh"
+ class CPUExecContext;
class ExecContext;
-class FunctionalMemory;
+ class SyscallDesc;
+class TranslatingPort;
+class System;
+
class Process : public SimObject
{
+ protected:
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MachInst MachInst;
public:
+ /// Pointer to object representing the system this process is
+ /// running on.
+ System *system;
+
// have we initialized an execution context from this process? If
// yes, subsequent contexts are assumed to be for dynamically
// created threads and are not initialized.
{
string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
return (TheISA::IntReg)-EFAULT;
int result = unlink(path.c_str());
{
string old_name;
- if (xc->port->readStringFunctional(old_name, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(old_name, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(old_name, xc->getSyscallArg(0)) != NoFault)
return -EFAULT;
string new_name;
- if (xc->port->readStringFunctional(new_name, xc->getSyscallArg(1)) != No_Fault)
- if (xc->getMemPtr()->readString(new_name, xc->getSyscallArg(1)) != NoFault)
++ if (xc->port->readStringFunctional(new_name, xc->getSyscallArg(1)) != NoFault)
return -EFAULT;
int64_t result = rename(old_name.c_str(), new_name.c_str());
{
string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
return -EFAULT;
off_t length = xc->getSyscallArg(1);
{
string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
return -EFAULT;
/* XXX endianess */
#include <sys/uio.h>
#include "base/intmath.hh" // for RoundUp
-#include "mem/functional/functional.hh"
+#include "mem/translating_port.hh"
- #include "targetarch/isa_traits.hh" // for Addr
+ #include "arch/isa_traits.hh" // for Addr
#include "base/trace.hh"
#include "cpu/exec_context.hh"
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
return -EFAULT;
if (path == "/dev/sysdev0") {
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
return -EFAULT;
uint32_t mode = xc->getSyscallArg(1);
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
- return -EFAULT;
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
+ return -EFAULT;
struct stat hostBuf;
int result = stat(path.c_str(), &hostBuf);
if (result < 0)
- return errno;
+ return -errno;
- OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatBuf(xc->port, xc->getSyscallArg(1), &hostBuf);
return 0;
}
return -EBADF;
}
- struct stat64 hostBuf;
+ #if BSD_HOST
+ struct stat hostBuf;
+ int result = fstat(process->sim_fd(fd), &hostBuf);
+ #else
+ struct stat64 hostBuf;
int result = fstat64(process->sim_fd(fd), &hostBuf);
+ #endif
if (result < 0)
- return errno;
+ return -errno;
- OS::copyOutStat64Buf(xc->port, xc->getSyscallArg(1), &hostBuf);
- OS::copyOutStat64Buf(xc->getMemPtr(), fd, xc->getSyscallArg(1), &hostBuf);
++ OS::copyOutStat64Buf(xc->port, fd, xc->getSyscallArg(1), &hostBuf);
return 0;
}
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
- return -EFAULT;
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
+ return -EFAULT;
struct stat hostBuf;
int result = lstat(path.c_str(), &hostBuf);
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
- return -EFAULT;
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
+ return -EFAULT;
+ #if BSD_HOST
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+ #else
struct stat64 hostBuf;
int result = lstat64(path.c_str(), &hostBuf);
+ #endif
if (result < 0)
return -errno;
- OS::copyOutStat64Buf(xc->port, xc->getSyscallArg(1), &hostBuf);
- OS::copyOutStat64Buf(xc->getMemPtr(), -1, xc->getSyscallArg(1), &hostBuf);
++ OS::copyOutStat64Buf(xc->port, -1, xc->getSyscallArg(1), &hostBuf);
return 0;
}
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
- return -EFAULT;
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
+ return -EFAULT;
struct statfs hostBuf;
int result = statfs(path.c_str(), &hostBuf);
if (result < 0)
- return errno;
+ return -errno;
- OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf);
return 0;
}
int result = fstatfs(fd, &hostBuf);
if (result < 0)
- return errno;
+ return -errno;
- OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatfsBuf(xc->port, xc->getSyscallArg(1), &hostBuf);
return 0;
}
for (int i = 0; i < count; ++i)
{
typename OS::tgt_iovec tiov;
- xc->getMemPtr()->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec),
+ xc->port->readBlobFunctional(tiov_base + i*sizeof(typename OS::tgt_iovec),(uint8_t*)
&tiov, sizeof(typename OS::tgt_iovec));
- hiov[i].iov_len = tiov.iov_len;
+ hiov[i].iov_len = gtoh(tiov.iov_len);
hiov[i].iov_base = new char [hiov[i].iov_len];
- xc->port->readBlobFunctional(tiov.iov_base,
- xc->getMemPtr()->access(Read, gtoh(tiov.iov_base),
- hiov[i].iov_base, hiov[i].iov_len);
++ xc->port->readBlobFunctional(gtoh(tiov.iov_base),
+ (uint8_t *)hiov[i].iov_base, hiov[i].iov_len);
}
int result = writev(process->sim_fd(fd), hiov, count);
TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
switch (resource) {
- case OS::RLIMIT_STACK:
- // max stack size in bytes: make up a number (2MB for now)
- rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
- break;
-
- default:
- std::cerr << "getrlimitFunc: unimplemented resource " << resource
- << std::endl;
- abort();
- break;
+ case OS::TGT_RLIMIT_STACK:
+ // max stack size in bytes: make up a number (2MB for now)
+ rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+ rlp->rlim_cur = htog(rlp->rlim_cur);
+ rlp->rlim_max = htog(rlp->rlim_max);
+ break;
+
+ default:
+ std::cerr << "getrlimitFunc: unimplemented resource " << resource
+ << std::endl;
+ abort();
+ break;
}
- rlp.copyOut(xc->getMemPtr());
+ rlp.copyOut(xc->port);
return 0;
}
getElapsedTime(tp->tv_sec, tp->tv_usec);
tp->tv_sec += seconds_since_epoch;
+ tp->tv_sec = htog(tp->tv_sec);
+ tp->tv_usec = htog(tp->tv_usec);
- tp.copyOut(xc->getMemPtr());
+ tp.copyOut(xc->port);
return 0;
}
{
std::string path;
- if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != No_Fault)
- if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault)
- return -EFAULT;
++ if (xc->port->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault)
+ return -EFAULT;
TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
- tp.copyIn(xc->getMemPtr());
+ tp.copyIn(xc->port);
struct timeval hostTimeval[2];
for (int i = 0; i < 2; ++i)
- /*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
-#include "base/remote_gdb.hh"
#include "cpu/exec_context.hh"
-#include "kern/kernel_stats.hh"
-#include "mem/functional/memory_control.hh"
-#include "mem/functional/physical.hh"
+ #include "arch/vtophys.hh"
+#include "mem/memory.hh"
#include "sim/builder.hh"
+ #include "arch/isa_traits.hh"
+ #include "sim/byteswap.hh"
#include "sim/system.hh"
#include "base/trace.hh"
+#if FULL_SYSTEM
+#include "base/remote_gdb.hh"
+#include "kern/kernel_stats.hh"
+#include "mem/functional/memory_control.hh"
+#include "targetarch/vtophys.hh"
+#endif
using namespace std;
+ using namespace TheISA;
vector<System *> System::systemList;
int System::numSystemsRunning = 0;
System::System(Params *p)
- : SimObject(p->name), memctrl(p->memctrl), physmem(p->physmem),
- init_param(p->init_param), numcpus(0), _params(p)
+ : SimObject(p->name), physmem(p->physmem), numcpus(0),
+#if FULL_SYSTEM
+ memctrl(p->memctrl), init_param(p->init_param),
+#else
+ page_ptr(0),
+#endif
- params(p)
++ _params(p)
{
// add self to global system list
systemList.push_back(this);
+#if FULL_SYSTEM
kernelSymtab = new SymbolTable;
- consoleSymtab = new SymbolTable;
- palSymtab = new SymbolTable;
debugSymbolTable = new SymbolTable;
/**
DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
DPRINTF(Loader, "Kernel loaded...\n");
- Addr addr = 0;
- #ifdef DEBUG
- consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic");
- #endif
-
- /**
- * Copy the osflags (kernel arguments) into the consoles
- * memory. (Presently Linux does not use the console service
- * routine to get these command line arguments, but Tru64 and
- * others do.)
- */
- if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
- Addr paddr = vtophys(physmem, addr);
- char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t));
-
- if (osflags)
- strcpy(osflags, params->boot_osflags.c_str());
- }
-
- /**
- * Set the hardware reset parameter block system type and revision
- * information to Tsunami.
- */
- if (consoleSymtab->findAddress("m5_rpb", addr)) {
- Addr paddr = vtophys(physmem, addr);
- char *hwrpb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
-
- if (!hwrpb)
- panic("could not translate hwrpb addr\n");
-
- *(uint64_t*)(hwrpb+0x50) = htog(params->system_type);
- *(uint64_t*)(hwrpb+0x58) = htog(params->system_rev);
- } else
- panic("could not find hwrpb\n");
-
++#if FULL_SYSTEM
+ kernelBinning = new Kernel::Binning(this);
-
+#endif // FULL_SYSTEM
+
// increment the number of running systms
numSystemsRunning++;
-
- kernelBinning = new Kernel::Binning(this);
}
System::~System()
{
+#if FULL_SYSTEM
delete kernelSymtab;
- delete consoleSymtab;
delete kernel;
- delete console;
- delete pal;
delete kernelBinning;
-
- #ifdef DEBUG
- delete consolePanicEvent;
- #endif
-
- #endif // FULL_SYSTEM
- }
-
-
- /**
- * This function fixes up addresses that are used to match PCs for
- * hooking simulator events on to target function executions.
- *
- * Alpha binaries may have multiple global offset table (GOT)
- * sections. A function that uses the GOT starts with a
- * two-instruction prolog which sets the global pointer (gp == r29) to
- * the appropriate GOT section. The proper gp value is calculated
- * based on the function address, which must be passed by the caller
- * in the procedure value register (pv aka t12 == r27). This sequence
- * looks like the following:
- *
- * opcode Ra Rb offset
- * ldah gp,X(pv) 09 29 27 X
- * lda gp,Y(gp) 08 29 29 Y
- *
- * for some constant offsets X and Y. The catch is that the linker
- * (or maybe even the compiler, I'm not sure) may recognize that the
- * caller and callee are using the same GOT section, making this
- * prolog redundant, and modify the call target to skip these
- * instructions. If we check for execution of the first instruction
- * of a function (the one the symbol points to) to detect when to skip
- * it, we'll miss all these modified calls. It might work to
- * unconditionally check for the third instruction, but not all
- * functions have this prolog, and there's some chance that those
- * first two instructions could have undesired consequences. So we do
- * the Right Thing and pattern-match the first two instructions of the
- * function to decide where to patch.
- *
- * Eventually this code should be moved into an ISA-specific file.
- */
- Addr
- System::fixFuncEventAddr(Addr addr)
- {
- #if FULL_SYSTEM
- // mask for just the opcode, Ra, and Rb fields (not the offset)
- const uint32_t inst_mask = 0xffff0000;
- // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27
- const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16);
- // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29
- const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16);
- // instruction size
- const int sz = sizeof(uint32_t);
-
- Addr paddr = vtophys(physmem, addr);
- uint32_t i1 = *(uint32_t *)physmem->dma_addr(paddr, sz);
- uint32_t i2 = *(uint32_t *)physmem->dma_addr(paddr+sz, sz);
-
- if ((i1 & inst_mask) == gp_ldah_pattern &&
- (i2 & inst_mask) == gp_lda_pattern) {
- Addr new_addr = addr + 2*sz;
- DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr);
- return new_addr;
- } else {
- return addr;
- }
+#else
+ panic("System::fixFuncEventAddr needs to be rewritten "
+ "to work with syscall emulation");
+#endif // FULL_SYSTEM}
}
-
+#if FULL_SYSTEM
- void
- System::setAlphaAccess(Addr access)
- {
- Addr addr = 0;
- if (consoleSymtab->findAddress("m5AlphaAccess", addr)) {
- Addr paddr = vtophys(physmem, addr);
- uint64_t *m5AlphaAccess =
- (uint64_t *)physmem->dma_addr(paddr, sizeof(uint64_t));
-
- if (!m5AlphaAccess)
- panic("could not translate m5AlphaAccess addr\n");
-
- *m5AlphaAccess = htog(EV5::Phys2K0Seg(access));
- } else
- panic("could not find m5AlphaAccess\n");
- }
-
- bool
- System::breakpoint()
- {
- return remoteGDB[0]->trap(ALPHA_KENTRY_INT);
- }
int rgdb_wait = -1;
kernelBinning->serialize(os);
kernelSymtab->serialize("kernel_symtab", os);
- consoleSymtab->serialize("console_symtab", os);
- palSymtab->serialize("pal_symtab", os);
+#endif // FULL_SYSTEM
}
kernelBinning->unserialize(cp, section);
kernelSymtab->unserialize("kernel_symtab", cp, section);
- consoleSymtab->unserialize("console_symtab", cp, section);
- palSymtab->unserialize("pal_symtab", cp, section);
+#endif // FULL_SYSTEM
}
void
Kernel::Binning *kernelBinning;
- #ifdef DEBUG
- /** Event to halt the simulator if the console calls panic() */
- BreakPCEvent *consolePanicEvent;
- #endif
-
+#else
+
+ int page_ptr;
+
+
+#endif // FULL_SYSTEM
+
protected:
/**
return addFuncEvent<T>(kernelSymtab, lbl);
}
- /** Add a function-based event to PALcode. */
- template <class T>
- T *System::addPalFuncEvent(const char *lbl)
- {
- return addFuncEvent<T>(palSymtab, lbl);
- }
-
- /** Add a function-based event to the console code. */
- template <class T>
- T *System::addConsoleFuncEvent(const char *lbl)
- {
- return addFuncEvent<T>(consoleSymtab, lbl);
- }
+#endif
-
public:
+#if FULL_SYSTEM
std::vector<RemoteGDB *> remoteGDB;
std::vector<GDBListener *> gdbListen;
- bool breakpoint();
+ virtual bool breakpoint() = 0;
+#endif // FULL_SYSTEM
public:
struct Params
bool bin_int;
std::string kernel_path;
- std::string console_path;
- std::string palcode;
- std::string boot_osflags;
-
std::string readfile;
- uint64_t system_type;
- uint64_t system_rev;
+#endif
};
- Params *params;
+ protected:
+ Params *_params;
+
+ public:
System(Params *p);
~System();
void startup();
+ const Params *params() const { return (const Params *)_params; }
+
public:
- /**
- * Set the m5AlphaAccess pointer in the console
- */
- void setAlphaAccess(Addr access);
-
+
+#if FULL_SYSTEM
/**
* Returns the addess the kernel starts at.
* @return address the kernel starts at