diff options
68 files changed, 2947 insertions, 1551 deletions
diff --git a/SConscript b/SConscript index a2d5de279..4cc232bfd 100644 --- a/SConscript +++ b/SConscript @@ -207,7 +207,6 @@ full_system_sources = Split(''' dev/platform.cc dev/simconsole.cc dev/simple_disk.cc - dev/sinic.cc dev/tsunami.cc dev/tsunami_cchip.cc dev/tsunami_io.cc @@ -228,6 +227,7 @@ full_system_sources = Split(''' sim/pseudo_inst.cc ''') +# dev/sinic.cc if env['TARGET_ISA'] == 'alpha': diff --git a/arch/alpha/faults.cc b/arch/alpha/faults.cc index c8cb9124e..0083aa9f3 100644 --- a/arch/alpha/faults.cc +++ b/arch/alpha/faults.cc @@ -105,10 +105,6 @@ FaultName IntegerOverflowFault::_name = "intover"; FaultVect IntegerOverflowFault::_vect = 0x0501; FaultStat IntegerOverflowFault::_count; -FaultName UnimpFault::_name = "Unimplemented Simulator feature"; -FaultVect UnimpFault::_vect = 0x0001; -FaultStat UnimpFault::_count; - #if FULL_SYSTEM void AlphaFault::invoke(ExecContext * xc) @@ -174,12 +170,6 @@ void ItbFault::invoke(ExecContext * xc) AlphaFault::invoke(xc); } -void UnimpFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - panic("Unimpfault: %s\n", panicStr.c_str()); -} - #endif } // namespace AlphaISA diff --git a/arch/alpha/faults.hh b/arch/alpha/faults.hh index 5024c124b..e8ccc6b79 100644 --- a/arch/alpha/faults.hh +++ b/arch/alpha/faults.hh @@ -347,26 +347,6 @@ class IntegerOverflowFault : public AlphaFault FaultStat & countStat() {return _count;} }; -class UnimpFault : public AlphaFault -{ - private: - std::string panicStr; - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - UnimpFault(std::string _str) - : panicStr(_str) - { } - - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif -}; - } // AlphaISA namespace #endif // __FAULTS_HH__ diff --git a/arch/alpha/isa/main.isa b/arch/alpha/isa/main.isa index 746fe776d..03a8e1ff5 100644 --- a/arch/alpha/isa/main.isa +++ b/arch/alpha/isa/main.isa @@ -60,6 +60,7 @@ output exec {{ #include "cpu/base.hh" #include "cpu/exetrace.hh" #include "sim/sim_exit.hh" +#include "mem/packet_impl.hh" using namespace AlphaISA; }}; diff --git a/arch/alpha/isa/mem.isa b/arch/alpha/isa/mem.isa index 8742d308f..98c7ba979 100644 --- a/arch/alpha/isa/mem.isa +++ b/arch/alpha/isa/mem.isa @@ -178,7 +178,8 @@ def template InitiateAccDeclare {{ def template CompleteAccDeclare {{ - Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; + Fault completeAcc(Packet *, %(CPU_exec_context)s *, + Trace::InstRecord *) const; }}; @@ -304,7 +305,7 @@ def template LoadInitiateAcc {{ def template LoadCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, + Fault %(class_name)s::completeAcc(Packet *pkt, %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { @@ -313,7 +314,7 @@ def template LoadCompleteAcc {{ %(fp_enable_check)s; %(op_decl)s; - memcpy(&Mem, data, sizeof(Mem)); + Mem = pkt->get<typeof(Mem)>(); if (fault == NoFault) { %(memacc_code)s; @@ -406,7 +407,6 @@ def template StoreInitiateAcc {{ { Addr EA; Fault fault = NoFault; - uint64_t write_result = 0; %(fp_enable_check)s; %(op_decl)s; @@ -419,7 +419,7 @@ def template StoreInitiateAcc {{ if (fault == NoFault) { fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); + memAccessFlags, NULL); if (traceData) { traceData->setData(Mem); } } @@ -429,17 +429,39 @@ def template StoreInitiateAcc {{ def template StoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, + Fault %(class_name)s::completeAcc(Packet *pkt, %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { Fault fault = NoFault; - uint64_t write_result = 0; %(fp_enable_check)s; %(op_dest_decl)s; - memcpy(&write_result, data, sizeof(write_result)); + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreCondCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + uint64_t write_result = pkt->req->getScResult(); if (fault == NoFault) { %(postacc_code)s; @@ -505,7 +527,7 @@ def template MiscInitiateAcc {{ def template MiscCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, + Fault %(class_name)s::completeAcc(Packet *pkt, %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { @@ -577,7 +599,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, if (exec_template_base == 'Load'): initiateacc_cblk = CodeBlock(ea_code + memacc_code) completeacc_cblk = CodeBlock(memacc_code + postacc_code) - elif (exec_template_base == 'Store'): + elif (exec_template_base.startswith('Store')): initiateacc_cblk = CodeBlock(ea_code + memacc_code) completeacc_cblk = CodeBlock(postacc_code) else: @@ -595,7 +617,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, initiateacc_iop.memacc_code = memacc_cblk.code completeacc_iop.memacc_code = memacc_cblk.code completeacc_iop.postacc_code = postacc_cblk.code - elif (exec_template_base == 'Store'): + elif (exec_template_base.startswith('Store')): initiateacc_iop.ea_code = ea_cblk.code initiateacc_iop.memacc_code = memacc_cblk.code completeacc_iop.postacc_code = postacc_cblk.code @@ -616,6 +638,13 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, memacc_iop.constructor += s # select templates + + # define aliases... most StoreCond templates are the same as the + # corresponding Store templates (only CompleteAcc is different). + StoreCondMemAccExecute = StoreMemAccExecute + StoreCondExecute = StoreExecute + StoreCondInitiateAcc = StoreInitiateAcc + memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') fullExecTemplate = eval(exec_template_base + 'Execute') initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') @@ -685,7 +714,7 @@ def format StoreCond(memacc_code, postacc_code, mem_flags = [], inst_flags = []) {{ (header_output, decoder_output, decode_block, exec_output) = \ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code, exec_template_base = 'Store') + postacc_code, exec_template_base = 'StoreCond') }}; diff --git a/arch/alpha/tlb.cc b/arch/alpha/tlb.cc index 877822c31..05b02d74b 100644 --- a/arch/alpha/tlb.cc +++ b/arch/alpha/tlb.cc @@ -26,7 +26,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <sstream> #include <string> #include <vector> diff --git a/arch/mips/faults.cc b/arch/mips/faults.cc index a31856f07..1b31dfa69 100644 --- a/arch/mips/faults.cc +++ b/arch/mips/faults.cc @@ -98,10 +98,6 @@ FaultName IntegerOverflowFault::_name = "intover"; FaultVect IntegerOverflowFault::_vect = 0x0501; FaultStat IntegerOverflowFault::_count; -FaultName UnimpFault::_name = "Unimplemented Simulator feature"; -FaultVect UnimpFault::_vect = 0x0001; -FaultStat UnimpFault::_count; - #if FULL_SYSTEM void MipsFault::invoke(ExecContext * xc) @@ -129,12 +125,6 @@ void ArithmeticFault::invoke(ExecContext * xc) panic("Arithmetic traps are unimplemented!"); } -void UnimpFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - panic("Unimpfault: %s\n", panicStr.c_str()); -} - #endif } // namespace MipsISA diff --git a/arch/mips/faults.hh b/arch/mips/faults.hh index b0d228090..0bdabe29e 100644 --- a/arch/mips/faults.hh +++ b/arch/mips/faults.hh @@ -264,26 +264,6 @@ class IntegerOverflowFault : public MipsFault FaultStat & countStat() {return _count;} }; -class UnimpFault : public MipsFault -{ - private: - std::string panicStr; - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - UnimpFault(std::string _str) - : panicStr(_str) - { } - - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif -}; - } // MipsISA namespace #endif // __FAULTS_HH__ diff --git a/arch/mips/linux/linux.hh b/arch/mips/linux/linux.hh index fd08e8c87..8bcc3f309 100644 --- a/arch/mips/linux/linux.hh +++ b/arch/mips/linux/linux.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MIPS_MIPS_LINUX_HH -#define __MIPS_MIPS_LINUX_HH +#ifndef __ARCH_MIPS_LINUX_LINUX_HH__ +#define __ARCH_MIPS_LINUX_LINUX_HH__ #include "kern/linux/linux.hh" diff --git a/arch/sparc/SConscript b/arch/sparc/SConscript index fd0df9349..7362c9275 100644 --- a/arch/sparc/SConscript +++ b/arch/sparc/SConscript @@ -59,6 +59,8 @@ full_system_sources = Split(''' syscall_emulation_sources = Split(''' linux/linux.cc linux/process.cc + solaris/solaris.cc + solaris/process.cc process.cc ''') diff --git a/arch/sparc/faults.cc b/arch/sparc/faults.cc index e83bba800..67a89ab0e 100644 --- a/arch/sparc/faults.cc +++ b/arch/sparc/faults.cc @@ -215,11 +215,6 @@ TrapType TrapInstruction::_baseTrapType = 0x100; FaultPriority TrapInstruction::_priority = 16; FaultStat TrapInstruction::_count; -FaultName UnimpFault::_name = "Unimplemented Simulator feature"; -TrapType UnimpFault::_trapType = 0x000; -FaultPriority UnimpFault::_priority = 0; -FaultStat UnimpFault::_count; - #if FULL_SYSTEM void SparcFault::invoke(ExecContext * xc) @@ -245,12 +240,15 @@ void SparcFault::invoke(ExecContext * xc) xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/ } -void UnimpFault::invoke(ExecContext * xc) +#endif + +#if !FULL_SYSTEM + +void TrapInstruction::invoke(ExecContext * xc) { - panic("Unimpfault: %s\n", panicStr.c_str()); + xc->syscall(syscall_num); } - #endif } // namespace SparcISA diff --git a/arch/sparc/faults.hh b/arch/sparc/faults.hh index 87de8daaa..e8fb8dfc5 100644 --- a/arch/sparc/faults.hh +++ b/arch/sparc/faults.hh @@ -573,37 +573,19 @@ class TrapInstruction : public EnumeratedFault static TrapType _baseTrapType; static FaultPriority _priority; static FaultStat _count; + uint64_t syscall_num; TrapType baseTrapType() {return _baseTrapType;} public: - TrapInstruction(uint32_t n) : EnumeratedFault(n) {;} + TrapInstruction(uint32_t n, uint64_t syscall) : + EnumeratedFault(n), syscall_num(syscall) {;} FaultName name() {return _name;} FaultPriority priority() {return _priority;} FaultStat & countStat() {return _count;} -}; - -class UnimpFault : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - std::string panicStr; - public: - UnimpFault(std::string _str) - : panicStr(_str) - { } - - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -#if FULL_SYSTEM +#if !FULL_SYSTEM void invoke(ExecContext * xc); #endif }; - } // SparcISA namespace #endif // __FAULTS_HH__ diff --git a/arch/sparc/isa/base.isa b/arch/sparc/isa/base.isa index cb370a3e7..8ea11b40e 100644 --- a/arch/sparc/isa/base.isa +++ b/arch/sparc/isa/base.isa @@ -99,14 +99,16 @@ def template ROrImmDecode {{ let {{ def splitOutImm(code): - matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)') + matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?') rOrImmMatch = matcher.search(code) if (rOrImmMatch == None): return (False, code, '', '', '') rString = rOrImmMatch.group("rNum") + if (rOrImmMatch.group("typeQual") != None): + rString += rOrImmMatch.group("typeQual") iString = rOrImmMatch.group("iNum") orig_code = code - code = matcher.sub('Rs' + rOrImmMatch.group("rNum"), orig_code) + code = matcher.sub('Rs' + rString, orig_code) imm_code = matcher.sub('imm', orig_code) return (True, code, imm_code, rString, iString) }}; diff --git a/arch/sparc/isa/decoder.isa b/arch/sparc/isa/decoder.isa index b9e83afd6..52ca5d7cd 100644 --- a/arch/sparc/isa/decoder.isa +++ b/arch/sparc/isa/decoder.isa @@ -119,11 +119,11 @@ decode OP default Unknown::unknown() } }}); 0x0F: sdiv({{ - if(Rs2_or_imm13 == 0) + if(Rs2_or_imm13.sdw == 0) fault = new DivisionByZero; else { - Rd.udw = ((YValue << 32) | Rs1.sdw<31:0>) / Rs2_or_imm13; + Rd.udw = ((int64_t)((YValue << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw; if(Rd.udw<63:31> != 0) Rd.udw = 0x7FFFFFFF; else if(Rd.udw<63:> && Rd.udw<62:31> != 0xFFFFFFFF) @@ -166,13 +166,13 @@ decode OP default Unknown::unknown() {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} ); 0x1A: umulcc({{ - uint64_t resTemp, val2 = Rs2_or_imm13; - Rd = resTemp = Rs1.udw<31:0> * val2<31:0>; + uint64_t resTemp; + Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>; YValue = resTemp<63:32>;}}, {{0}},{{0}},{{0}},{{0}}); 0x1B: smulcc({{ - int64_t resTemp, val2 = Rs2_or_imm13; - Rd = resTemp = Rs1.sdw<31:0> * val2<31:0>; + int64_t resTemp; + Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>; YValue = resTemp<63:32>;}}, {{0}},{{0}},{{0}},{{0}}); 0x1C: subccc({{ @@ -185,11 +185,11 @@ decode OP default Unknown::unknown() {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} ); 0x1D: udivxcc({{ - if(Rs2_or_imm13 == 0) fault = new DivisionByZero; - else Rd = Rs1.udw / Rs2_or_imm13;}} + if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero; + else Rd = Rs1.udw / Rs2_or_imm13.udw;}} ,{{0}},{{0}},{{0}},{{0}}); 0x1E: udivcc({{ - uint32_t resTemp, val2 = Rs2_or_imm13; + uint32_t resTemp, val2 = Rs2_or_imm13.udw; int32_t overflow; if(val2 == 0) fault = new DivisionByZero; else @@ -205,7 +205,7 @@ decode OP default Unknown::unknown() {{0}} ); 0x1F: sdivcc({{ - int32_t resTemp, val2 = Rs2_or_imm13; + int32_t resTemp, val2 = Rs2_or_imm13.sdw; int32_t overflow, underflow; if(val2 == 0) fault = new DivisionByZero; else @@ -363,8 +363,8 @@ decode OP default Unknown::unknown() } } 0x2D: sdivx({{ - if(Rs2_or_imm13 == 0) fault = new DivisionByZero; - else Rd.sdw = Rs1.sdw / Rs2_or_imm13; + if(Rs2_or_imm13.sdw == 0) fault = new DivisionByZero; + else Rd.sdw = Rs1.sdw / Rs2_or_imm13.sdw; }}); 0x2E: decode RS1 { 0x0: IntOp::popc({{ @@ -382,12 +382,12 @@ decode OP default Unknown::unknown() } 0x2F: decode RCOND3 { - 0x1: movreq({{Rd = (Rs1 == 0) ? Rs2_or_imm10 : Rd;}}); - 0x2: movrle({{Rd = (Rs1 <= 0) ? Rs2_or_imm10 : Rd;}}); - 0x3: movrl({{Rd = (Rs1 < 0) ? Rs2_or_imm10 : Rd;}}); - 0x5: movrne({{Rd = (Rs1 != 0) ? Rs2_or_imm10 : Rd;}}); - 0x6: movrg({{Rd = (Rs1 > 0) ? Rs2_or_imm10 : Rd;}}); - 0x7: movrge({{Rd = (Rs1 >= 0) ? Rs2_or_imm10 : Rd;}}); + 0x1: movreq({{Rd = (Rs1.sdw == 0) ? Rs2_or_imm10 : Rd;}}); + 0x2: movrle({{Rd = (Rs1.sdw <= 0) ? Rs2_or_imm10 : Rd;}}); + 0x3: movrl({{Rd = (Rs1.sdw < 0) ? Rs2_or_imm10 : Rd;}}); + 0x5: movrne({{Rd = (Rs1.sdw != 0) ? Rs2_or_imm10 : Rd;}}); + 0x6: movrg({{Rd = (Rs1.sdw > 0) ? Rs2_or_imm10 : Rd;}}); + 0x7: movrge({{Rd = (Rs1.sdw >= 0) ? Rs2_or_imm10 : Rd;}}); } 0x30: decode RD { 0x0: wry({{Y = Rs1 ^ Rs2_or_imm13;}}); @@ -492,10 +492,6 @@ decode OP default Unknown::unknown() xc->syscall(R1); #endif } - else - { - DPRINTF(Sparc, "Didn't fire on %s\n", CondTestAbbrev[machInst<25:28>]); - } }}); 0x2: Trap::tccx({{ if(passesCondition(CcrXcc, COND2)) diff --git a/arch/sparc/linux/linux.hh b/arch/sparc/linux/linux.hh index 1b31f67b0..9cde5bb9c 100644 --- a/arch/sparc/linux/linux.hh +++ b/arch/sparc/linux/linux.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MIPS_MIPS_LINUX_HH -#define __MIPS_MIPS_LINUX_HH +#ifndef __ARCH_SPARC_LINUX_LINUX_HH__ +#define __ARCH_SPARC_LINUX_LINUX_HH__ #include "kern/linux/linux.hh" diff --git a/arch/sparc/process.cc b/arch/sparc/process.cc index 7f2b0d40a..250c1bec4 100644 --- a/arch/sparc/process.cc +++ b/arch/sparc/process.cc @@ -29,6 +29,7 @@ #include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" #include "arch/sparc/linux/process.hh" +#include "arch/sparc/solaris/process.hh" #include "base/loader/object_file.hh" #include "base/misc.hh" #include "cpu/exec_context.hh" @@ -54,7 +55,8 @@ SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd, if (objFile->getArch() != ObjectFile::SPARC) - fatal("Object file with arch %x does not match architecture %x.", objFile->getArch(), ObjectFile::SPARC); + fatal("Object file with arch %x does not match architecture %x.", + objFile->getArch(), ObjectFile::SPARC); switch (objFile->getOpSys()) { case ObjectFile::Linux: process = new SparcLinuxProcess(nm, objFile, system, @@ -62,7 +64,12 @@ SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd, argv, envp); break; + case ObjectFile::Solaris: + process = new SparcSolarisProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; default: fatal("Unknown/unsupported operating system."); } diff --git a/arch/sparc/solaris/process.cc b/arch/sparc/solaris/process.cc new file mode 100644 index 000000000..95cdb0bd5 --- /dev/null +++ b/arch/sparc/solaris/process.cc @@ -0,0 +1,347 @@ +/* + * 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. + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/solaris/process.hh" +#include "arch/sparc/regfile.hh" + +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/solaris/solaris.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace SparcISA; + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<Solaris::utsname> name(xc->getSyscallArg(0)); + + strcpy(name->sysname, "SunOS"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "5.9"); //?? do we want this or something newer? + strcpy(name->version, "Generic_118558-21"); + strcpy(name->machine, "sun4u"); + + name.copyOut(xc->getMemPort()); + + return 0; +} + + +SyscallDesc SparcSolarisProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<SparcSolaris>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("exec", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>), + /* 16 */ SyscallDesc("chown", chownFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("stat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("pcsample", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("fstat", fstatFunc<SparcSolaris>), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("statfs", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 39 */ SyscallDesc("pgrpsys", unimplementedFunc), + /* 40 */ SyscallDesc("xenix", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("profil", unimplementedFunc), + /* 45 */ SyscallDesc("plock", unimplementedFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("msgsys", unimplementedFunc), + /* 50 */ SyscallDesc("syssun", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("shmsys", unimplementedFunc), + /* 53 */ SyscallDesc("semsys", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("uadmin", unimplementedFunc), + /* 56 */ SyscallDesc("RESERVED", unimplementedFunc), + /* 57 */ SyscallDesc("utssys", unimplementedFunc), + /* 58 */ SyscallDesc("fdsync", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("fcntl", unimplementedFunc), + /* 63 */ SyscallDesc("ulimit", unimplementedFunc), + /* 64 */ SyscallDesc("reserved_64", unimplementedFunc), + /* 65 */ SyscallDesc("reserved_65", unimplementedFunc), + /* 66 */ SyscallDesc("reserved_66", unimplementedFunc), + /* 67 */ SyscallDesc("reserved_67", unimplementedFunc), + /* 68 */ SyscallDesc("reserved_68", unimplementedFunc), + /* 69 */ SyscallDesc("reserved_69", unimplementedFunc), + /* 70 */ SyscallDesc("tasksys", unimplementedFunc), + /* 71 */ SyscallDesc("acctctl", unimplementedFunc), + /* 72 */ SyscallDesc("reserved_72", unimplementedFunc), + /* 73 */ SyscallDesc("getpagesizes", unimplementedFunc), + /* 74 */ SyscallDesc("rctlsys", unimplementedFunc), + /* 75 */ SyscallDesc("issetugid", unimplementedFunc), + /* 76 */ SyscallDesc("fsat", unimplementedFunc), + /* 77 */ SyscallDesc("lwp_park", unimplementedFunc), + /* 78 */ SyscallDesc("sendfilev", unimplementedFunc), + /* 79 */ SyscallDesc("rmdir", unimplementedFunc), + /* 80 */ SyscallDesc("mkdir", unimplementedFunc), + /* 81 */ SyscallDesc("getdents", unimplementedFunc), + /* 82 */ SyscallDesc("reserved_82", unimplementedFunc), + /* 83 */ SyscallDesc("reserved_83", unimplementedFunc), + /* 84 */ SyscallDesc("sysfs", unimplementedFunc), + /* 85 */ SyscallDesc("getmsg", unimplementedFunc), + /* 86 */ SyscallDesc("putmsg", unimplementedFunc), + /* 87 */ SyscallDesc("poll", unimplementedFunc), + /* 88 */ SyscallDesc("lstat", unimplementedFunc), + /* 89 */ SyscallDesc("symlink", unimplementedFunc), + /* 90 */ SyscallDesc("readlink", unimplementedFunc), + /* 91 */ SyscallDesc("setgroups", unimplementedFunc), + /* 92 */ SyscallDesc("getgroups", unimplementedFunc), + /* 93 */ SyscallDesc("fchmod", unimplementedFunc), + /* 94 */ SyscallDesc("fchown", unimplementedFunc), + /* 95 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 96 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 97 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 98 */ SyscallDesc("sigaction", unimplementedFunc), + /* 99 */ SyscallDesc("sigpending", unimplementedFunc), + /* 100 */ SyscallDesc("context", unimplementedFunc), + /* 101 */ SyscallDesc("evsys", unimplementedFunc), + /* 102 */ SyscallDesc("evtrapret", unimplementedFunc), + /* 103 */ SyscallDesc("statvfs", unimplementedFunc), + /* 104 */ SyscallDesc("fstatvfs", unimplementedFunc), + /* 105 */ SyscallDesc("getloadavg", unimplementedFunc), + /* 106 */ SyscallDesc("nfssys", unimplementedFunc), + /* 107 */ SyscallDesc("waitsys", unimplementedFunc), + /* 108 */ SyscallDesc("sigsendsys", unimplementedFunc), + /* 109 */ SyscallDesc("hrtsys", unimplementedFunc), + /* 110 */ SyscallDesc("acancel", unimplementedFunc), + /* 111 */ SyscallDesc("async", unimplementedFunc), + /* 112 */ SyscallDesc("priocntlsys", unimplementedFunc), + /* 113 */ SyscallDesc("pathconf", unimplementedFunc), + /* 114 */ SyscallDesc("mincore", unimplementedFunc), + /* 115 */ SyscallDesc("mmap", mmapFunc<SparcSolaris>), + /* 116 */ SyscallDesc("mprotect", unimplementedFunc), + /* 117 */ SyscallDesc("munmap", munmapFunc), + /* 118 */ SyscallDesc("fpathconf", unimplementedFunc), + /* 119 */ SyscallDesc("vfork", unimplementedFunc), + /* 120 */ SyscallDesc("fchdir", unimplementedFunc), + /* 121 */ SyscallDesc("readv", unimplementedFunc), + /* 122 */ SyscallDesc("writev", unimplementedFunc), + /* 123 */ SyscallDesc("xstat", unimplementedFunc), + /* 124 */ SyscallDesc("lxstat", unimplementedFunc), + /* 125 */ SyscallDesc("fxstat", unimplementedFunc), + /* 126 */ SyscallDesc("xmknod", unimplementedFunc), + /* 127 */ SyscallDesc("clocal", unimplementedFunc), + /* 128 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 129 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 130 */ SyscallDesc("lchown", unimplementedFunc), + /* 131 */ SyscallDesc("memcntl", unimplementedFunc), + /* 132 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 133 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 134 */ SyscallDesc("rename", unimplementedFunc), + /* 135 */ SyscallDesc("uname", unameFunc), + /* 136 */ SyscallDesc("setegid", unimplementedFunc), + /* 137 */ SyscallDesc("sysconfig", unimplementedFunc), + /* 138 */ SyscallDesc("adjtime", unimplementedFunc), + /* 139 */ SyscallDesc("systeminfo", unimplementedFunc), + /* 140 */ SyscallDesc("reserved_140", unimplementedFunc), + /* 141 */ SyscallDesc("seteuid", unimplementedFunc), + /* 142 */ SyscallDesc("vtrace", unimplementedFunc), + /* 143 */ SyscallDesc("fork1", unimplementedFunc), + /* 144 */ SyscallDesc("sigtimedwait", unimplementedFunc), + /* 145 */ SyscallDesc("lwp_info", unimplementedFunc), + /* 146 */ SyscallDesc("yield", unimplementedFunc), + /* 147 */ SyscallDesc("lwp_sema_wait", unimplementedFunc), + /* 148 */ SyscallDesc("lwp_sema_post", unimplementedFunc), + /* 149 */ SyscallDesc("lwp_sema_trywait", unimplementedFunc), + /* 150 */ SyscallDesc("lwp_detach", unimplementedFunc), + /* 151 */ SyscallDesc("corectl", unimplementedFunc), + /* 152 */ SyscallDesc("modctl", unimplementedFunc), + /* 153 */ SyscallDesc("fchroot", unimplementedFunc), + /* 154 */ SyscallDesc("utimes", unimplementedFunc), + /* 155 */ SyscallDesc("vhangup", unimplementedFunc), + /* 156 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 157 */ SyscallDesc("getitimer", unimplementedFunc), + /* 158 */ SyscallDesc("setitimer", unimplementedFunc), + /* 159 */ SyscallDesc("lwp_create", unimplementedFunc), + /* 160 */ SyscallDesc("lwp_exit", unimplementedFunc), + /* 161 */ SyscallDesc("lwp_suspend", unimplementedFunc), + /* 162 */ SyscallDesc("lwp_continue", unimplementedFunc), + /* 163 */ SyscallDesc("lwp_kill", unimplementedFunc), + /* 164 */ SyscallDesc("lwp_self", unimplementedFunc), + /* 165 */ SyscallDesc("lwp_setprivate", unimplementedFunc), + /* 166 */ SyscallDesc("lwp_getprivate", unimplementedFunc), + /* 167 */ SyscallDesc("lwp_wait", unimplementedFunc), + /* 168 */ SyscallDesc("lwp_mutex_wakeup", unimplementedFunc), + /* 169 */ SyscallDesc("lwp_mutex_lock", unimplementedFunc), + /* 170 */ SyscallDesc("lwp_cond_wait", unimplementedFunc), + /* 171 */ SyscallDesc("lwp_cond_signal", unimplementedFunc), + /* 172 */ SyscallDesc("lwp_cond_broadcast", unimplementedFunc), + /* 173 */ SyscallDesc("pread", unimplementedFunc), + /* 174 */ SyscallDesc("pwrite", unimplementedFunc), + /* 175 */ SyscallDesc("llseek", unimplementedFunc), + /* 176 */ SyscallDesc("inst_sync", unimplementedFunc), + /* 177 */ SyscallDesc("srmlimitsys", unimplementedFunc), + /* 178 */ SyscallDesc("kaio", unimplementedFunc), + /* 179 */ SyscallDesc("cpc", unimplementedFunc), + /* 180 */ SyscallDesc("lgrpsys_meminfosys", unimplementedFunc), + /* 181 */ SyscallDesc("rusagesys", unimplementedFunc), + /* 182 */ SyscallDesc("reserved_182", unimplementedFunc), + /* 183 */ SyscallDesc("reserved_183", unimplementedFunc), + /* 184 */ SyscallDesc("tsolsys", unimplementedFunc), + /* 185 */ SyscallDesc("acl", unimplementedFunc), + /* 186 */ SyscallDesc("auditsys", unimplementedFunc), + /* 187 */ SyscallDesc("processor_bind", unimplementedFunc), + /* 188 */ SyscallDesc("processor_info", unimplementedFunc), + /* 189 */ SyscallDesc("p_online", unimplementedFunc), + /* 190 */ SyscallDesc("sigqueue", unimplementedFunc), + /* 191 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 192 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 193 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 194 */ SyscallDesc("timer_create", unimplementedFunc), + /* 195 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 196 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 197 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 198 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 199 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 200 */ SyscallDesc("facl", unimplementedFunc), + /* 201 */ SyscallDesc("door", unimplementedFunc), + /* 202 */ SyscallDesc("setreuid", unimplementedFunc), + /* 203 */ SyscallDesc("setregid", unimplementedFunc), + /* 204 */ SyscallDesc("install_utrap", unimplementedFunc), + /* 205 */ SyscallDesc("signotify", unimplementedFunc), + /* 206 */ SyscallDesc("schedctl", unimplementedFunc), + /* 207 */ SyscallDesc("pset", unimplementedFunc), + /* 208 */ SyscallDesc("sparc_utrap_install", unimplementedFunc), + /* 209 */ SyscallDesc("resolvepath", unimplementedFunc), + /* 210 */ SyscallDesc("signotifywait", unimplementedFunc), + /* 211 */ SyscallDesc("lwp_sigredirect", unimplementedFunc), + /* 212 */ SyscallDesc("lwp_alarm", unimplementedFunc), + /* 213 */ SyscallDesc("getdents64", unimplementedFunc), + /* 214 */ SyscallDesc("mmap64", unimplementedFunc), + /* 215 */ SyscallDesc("stat64", unimplementedFunc), + /* 216 */ SyscallDesc("lstat64", unimplementedFunc), + /* 217 */ SyscallDesc("fstat64", unimplementedFunc), + /* 218 */ SyscallDesc("statvfs64", unimplementedFunc), + /* 219 */ SyscallDesc("fstatvfs64", unimplementedFunc), + /* 220 */ SyscallDesc("setrlimit64", unimplementedFunc), + /* 221 */ SyscallDesc("getrlimit64", unimplementedFunc), + /* 222 */ SyscallDesc("pread64", unimplementedFunc), + /* 223 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 224 */ SyscallDesc("creat64", unimplementedFunc), + /* 225 */ SyscallDesc("open64", unimplementedFunc), + /* 226 */ SyscallDesc("rpcsys", unimplementedFunc), + /* 227 */ SyscallDesc("reserved_227", unimplementedFunc), + /* 228 */ SyscallDesc("reserved_228", unimplementedFunc), + /* 229 */ SyscallDesc("reserved_229", unimplementedFunc), + /* 230 */ SyscallDesc("so_socket", unimplementedFunc), + /* 231 */ SyscallDesc("so_socketpair", unimplementedFunc), + /* 232 */ SyscallDesc("bind", unimplementedFunc), + /* 233 */ SyscallDesc("listen", unimplementedFunc), + /* 234 */ SyscallDesc("accept", unimplementedFunc), + /* 235 */ SyscallDesc("connect", unimplementedFunc), + /* 236 */ SyscallDesc("shutdown", unimplementedFunc), + /* 237 */ SyscallDesc("recv", unimplementedFunc), + /* 238 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 239 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 240 */ SyscallDesc("send", unimplementedFunc), + /* 241 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 242 */ SyscallDesc("sendto", unimplementedFunc), + /* 243 */ SyscallDesc("getpeername", unimplementedFunc), + /* 244 */ SyscallDesc("getsockname", unimplementedFunc), + /* 245 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 246 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 247 */ SyscallDesc("sockconfig", unimplementedFunc), + /* 248 */ SyscallDesc("ntp_gettime", unimplementedFunc), + /* 249 */ SyscallDesc("ntp_adjtime", unimplementedFunc), + /* 250 */ SyscallDesc("lwp_mutex_unlock", unimplementedFunc), + /* 251 */ SyscallDesc("lwp_mutex_trylock", unimplementedFunc), + /* 252 */ SyscallDesc("lwp_mutex_init", unimplementedFunc), + /* 253 */ SyscallDesc("cladm", unimplementedFunc), + /* 254 */ SyscallDesc("lwp_sigtimedwait", unimplementedFunc), + /* 255 */ SyscallDesc("umount2", unimplementedFunc) +}; + +SparcSolarisProcess::SparcSolarisProcess(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) + : SparcLiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + + + +SyscallDesc* +SparcSolarisProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/arch/sparc/solaris/process.hh b/arch/sparc/solaris/process.hh new file mode 100644 index 000000000..24dffdaf0 --- /dev/null +++ b/arch/sparc/solaris/process.hh @@ -0,0 +1,63 @@ +/* + * 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 __SPARC_SOLARIS_PROCESS_HH__ +#define __SPARC_SOLARIS_PROCESS_HH__ + +#include "arch/sparc/solaris/solaris.hh" +#include "arch/sparc/process.hh" +#include "sim/process.hh" + +namespace SparcISA { + +/// A process with emulated SPARC/Solaris syscalls. +class SparcSolarisProcess : public SparcLiveProcess +{ + public: + /// Constructor. + SparcSolarisProcess(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; +}; + + +} // namespace SparcISA +#endif // __ALPHA_SOLARIS_PROCESS_HH__ diff --git a/arch/sparc/solaris/solaris.cc b/arch/sparc/solaris/solaris.cc new file mode 100644 index 000000000..a56f10740 --- /dev/null +++ b/arch/sparc/solaris/solaris.cc @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include "arch/sparc/solaris/solaris.hh" + +// open(2) flags translation table +OpenFlagTransTable SparcSolaris::openFlagTable[] = { +#ifdef _MSC_VER + { SparcSolaris::TGT_O_RDONLY, _O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, _O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, _O_RDWR }, + { SparcSolaris::TGT_O_APPEND, _O_APPEND }, + { SparcSolaris::TGT_O_CREAT, _O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, _O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { SparcSolaris::TGT_O_SYNC, _O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, _O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { SparcSolaris::TGT_O_RDONLY, O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, O_RDWR }, + { SparcSolaris::TGT_O_APPEND, O_APPEND }, + { SparcSolaris::TGT_O_CREAT, O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, O_EXCL }, + { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK }, + { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { SparcSolaris::TGT_O_SYNC, O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int SparcSolaris::NUM_OPEN_FLAGS = + (sizeof(SparcSolaris::openFlagTable)/sizeof(SparcSolaris::openFlagTable[0])); + diff --git a/arch/sparc/solaris/solaris.hh b/arch/sparc/solaris/solaris.hh new file mode 100644 index 000000000..6833a2d6a --- /dev/null +++ b/arch/sparc/solaris/solaris.hh @@ -0,0 +1,62 @@ +/* + * 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. + */ + +#ifndef __ARCH_SPARC_SOLARIS_SOLARIS_HH__ +#define __ARCH_SPARC_SOLARIS_SOLARIS_HH__ + +#include "kern/solaris/solaris.hh" + +class SparcSolaris : public Solaris +{ + public: + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DSYNC = 0x00000040; //!< O_SYNC + static const int TGT_O_RSYNC = 0x00008000; //!< O_SYNC + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_PRIV = 0x00001000; //?? + static const int TGT_O_LARGEFILE = 0x00002000; //?? + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_XATTR = 0x00004000; //?? + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x100; +}; + +#endif diff --git a/base/cprintf.hh b/base/cprintf.hh index dcb292434..c468c375f 100644 --- a/base/cprintf.hh +++ b/base/cprintf.hh @@ -31,13 +31,12 @@ #include <iostream> #include <list> -#include <sstream> #include <string> -namespace cp { - #include "base/cprintf_formats.hh" +namespace cp { + class ArgList { private: diff --git a/base/cprintf_formats.hh b/base/cprintf_formats.hh index 11b0238ed..05a8723a4 100644 --- a/base/cprintf_formats.hh +++ b/base/cprintf_formats.hh @@ -29,6 +29,11 @@ #ifndef __CPRINTF_FORMATS_HH__ #define __CPRINTF_FORMATS_HH__ +#include <sstream> +#include <ostream> + +namespace cp { + struct Format { bool alternate_form; @@ -343,4 +348,6 @@ inline void format_string(std::ostream &out, const std::stringstream &data, Format &fmt) { _format_string(out, data.str(), fmt); } +} // namespace cp + #endif // __CPRINTF_FORMATS_HH__ diff --git a/base/crc.cc b/base/crc.cc index 87963ef14..08f039577 100644 --- a/base/crc.cc +++ b/base/crc.cc @@ -31,7 +31,6 @@ * SUCH DAMAGE. */ -#include <sstream> #include <string> #include "sim/host.hh" diff --git a/base/hostinfo.cc b/base/hostinfo.cc index d15e3ddc1..d42c96732 100644 --- a/base/hostinfo.cc +++ b/base/hostinfo.cc @@ -31,7 +31,6 @@ #include <math.h> #include <unistd.h> -#include <cstdio> #include <cstdlib> #include <cstring> #include <string> diff --git a/base/inet.cc b/base/inet.cc index 2e1c4c84b..f2665bd2b 100644 --- a/base/inet.cc +++ b/base/inet.cc @@ -26,7 +26,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <cstdio> #include <sstream> #include <string> diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc index a104719af..165501e1c 100644 --- a/base/loader/elf_object.cc +++ b/base/loader/elf_object.cc @@ -90,6 +90,7 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { arch = ObjectFile::Alpha; } else { + warn("Unknown architecture: %d\n", ehdr.e_machine); arch = ObjectFile::UnknownArch; } @@ -112,8 +113,7 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) //take a look at the .note.ABI section //It can let us know what's what. - if (opSys == ObjectFile::UnknownOpSys) - { + if (opSys == ObjectFile::UnknownOpSys) { Elf_Scn *section; GElf_Shdr shdr; Elf_Data *data; @@ -124,7 +124,7 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) section = elf_getscn(elf, secIdx); // While there are no more sections - while (section != NULL) { + while (section != NULL && opSys == ObjectFile::UnknownOpSys) { gelf_getshdr(section, &shdr); if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { @@ -147,6 +147,11 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) break; } } // if section found + if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + section = elf_getscn(elf, ++secIdx); } // while sections } diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc index 6b85bc680..41d0c1471 100644 --- a/base/remote_gdb.cc +++ b/base/remote_gdb.cc @@ -116,7 +116,6 @@ #include <sys/signal.h> -#include <cstdio> #include <string> #include <unistd.h> diff --git a/base/statistics.cc b/base/statistics.cc index c97564641..20de46347 100644 --- a/base/statistics.cc +++ b/base/statistics.cc @@ -31,7 +31,6 @@ #include <list> #include <map> #include <string> -#include <sstream> #include "base/callback.hh" #include "base/cprintf.hh" diff --git a/base/statistics.hh b/base/statistics.hh index c46744cac..dd507c091 100644 --- a/base/statistics.hh +++ b/base/statistics.hh @@ -50,7 +50,6 @@ #include <cmath> #include <functional> #include <iosfwd> -#include <sstream> #include <string> #include <vector> diff --git a/base/stats/text.cc b/base/stats/text.cc index 3d77ff87d..300737c60 100644 --- a/base/stats/text.cc +++ b/base/stats/text.cc @@ -31,6 +31,7 @@ #endif #include <iostream> +#include <sstream> #include <fstream> #include <string> diff --git a/build/SConstruct b/build/SConstruct index 28940fc5a..54307e945 100644 --- a/build/SConstruct +++ b/build/SConstruct @@ -222,7 +222,8 @@ env = conf.Finish() env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] # Define the universe of supported CPU models -env['ALL_CPU_LIST'] = ['SimpleCPU', 'FastCPU', 'FullCPU', 'AlphaFullCPU'] +env['ALL_CPU_LIST'] = ['AtomicSimpleCPU', 'TimingSimpleCPU', + 'FastCPU', 'FullCPU', 'AlphaFullCPU'] # Sticky options get saved in the options file so they persist from # one invocation to the next (unless overridden, in which case the new diff --git a/configs/test/SysPaths.py b/configs/test/SysPaths.py index 7f231916c..c7c7db4e7 100644 --- a/configs/test/SysPaths.py +++ b/configs/test/SysPaths.py @@ -22,11 +22,11 @@ BINDIR = SYSTEMDIR + '/binaries' DISKDIR = SYSTEMDIR + '/disks' def disk(file): - return '%s/%s' % (DISKDIR, file) + return os.path.join(DISKDIR, file) def binary(file): - return '%s/%s' % (BINDIR, file) + return os.path.join(BINDIR, file) def script(file): - return '%s/%s' % ('/z/saidi/work/m5.newmem/configs/boot', file) + return os.path.join(SYSTEMDIR, 'boot', file) diff --git a/configs/test/fs.py b/configs/test/fs.py index ce121bd76..fdbf86abe 100644 --- a/configs/test/fs.py +++ b/configs/test/fs.py @@ -181,9 +181,9 @@ class LinuxAlphaSystem(LinuxAlphaSystem): read_only=True) simple_disk = SimpleDisk(disk=Parent.raw_image) intrctrl = IntrControl() - cpu = SimpleCPU(mem=Parent.magicbus2) + cpu = AtomicSimpleCPU(mem=Parent.magicbus2) sim_console = SimConsole(listener=ConsoleListener(port=3456)) - kernel = '/z/saidi/work/m5.newmem/build/vmlinux' + kernel = binary('vmlinux') pal = binary('ts_osfpal') console = binary('console') boot_osflags = 'root=/dev/hda1 console=ttyS0' diff --git a/configs/test/test.py b/configs/test/test.py index 695d84b73..75e832f5e 100644 --- a/configs/test/test.py +++ b/configs/test/test.py @@ -6,7 +6,7 @@ class HelloWorld(AlphaLiveProcess): magicbus = Bus() mem = PhysicalMemory() -cpu = SimpleCPU(workload=HelloWorld(), mem=magicbus) +cpu = AtomicSimpleCPU(workload=HelloWorld(), mem=magicbus) system = System(physmem=mem, cpu=cpu) system.c1 = Connector(side_a=mem, side_b=magicbus) root = Root(system=system) diff --git a/cpu/SConscript b/cpu/SConscript index af6bab4eb..34fb6df78 100644 --- a/cpu/SConscript +++ b/cpu/SConscript @@ -51,6 +51,11 @@ execfile(models_db.srcnode().abspath) # Template for execute() signature. exec_sig_template = ''' virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +{ panic("initiateAcc not defined!"); }; +virtual Fault completeAcc(Packet *pkt, %s *xc, + Trace::InstRecord *traceData) const +{ panic("completeAcc not defined!"); }; ''' # Generate header. @@ -62,7 +67,7 @@ def gen_cpu_exec_signatures(target, source, env): ''' for cpu in env['CPU_MODELS']: xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % xc_type + print >> f, exec_sig_template % (xc_type, xc_type, xc_type) print >> f, ''' #endif // __CPU_STATIC_INST_EXEC_SIGS_HH__ ''' @@ -86,8 +91,17 @@ env.Command('static_inst_exec_sigs.hh', models_db, sources = [] -if 'SimpleCPU' in env['CPU_MODELS']: - sources += Split('simple/cpu.cc') +need_simple_base = False +if 'AtomicSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/atomic.cc') + +if 'TimingSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/timing.cc') + +if need_simple_base: + sources += Split('simple/base.cc') if 'FastCPU' in env['CPU_MODELS']: sources += Split('fast/cpu.cc') diff --git a/cpu/cpu_models.py b/cpu/cpu_models.py index 675204e5b..30cbabde1 100644 --- a/cpu/cpu_models.py +++ b/cpu/cpu_models.py @@ -56,9 +56,12 @@ class CpuModel: # - substitution strings for ISA description templates # -CpuModel('SimpleCPU', 'simple_cpu_exec.cc', - '#include "cpu/simple/cpu.hh"', - { 'CPU_exec_context': 'SimpleCPU' }) +CpuModel('AtomicSimpleCPU', 'atomic_simple_cpu_exec.cc', + '#include "cpu/simple/atomic.hh"', + { 'CPU_exec_context': 'AtomicSimpleCPU' }) +CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc', + '#include "cpu/simple/timing.hh"', + { 'CPU_exec_context': 'TimingSimpleCPU' }) CpuModel('FastCPU', 'fast_cpu_exec.cc', '#include "cpu/fast/cpu.hh"', { 'CPU_exec_context': 'FastCPU' }) diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc index 94b66b70b..54def1012 100644 --- a/cpu/memtest/memtest.cc +++ b/cpu/memtest/memtest.cc @@ -30,7 +30,6 @@ #include <iomanip> #include <set> -#include <sstream> #include <string> #include <vector> diff --git a/cpu/simple/atomic.cc b/cpu/simple/atomic.cc new file mode 100644 index 000000000..35a69cd4a --- /dev/null +++ b/cpu/simple/atomic.cc @@ -0,0 +1,564 @@ +/* + * 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 "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/atomic.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + +AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + + +void +AtomicSimpleCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +AtomicSimpleCPU::TickEvent::description() +{ + return "AtomicSimpleCPU tick event"; +} + + +void +AtomicSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(xc, xc->readCpuId()); + } +#endif +} + +bool +AtomicSimpleCPU::CpuPort::recvTiming(Packet &pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return true; +} + +Tick +AtomicSimpleCPU::CpuPort::recvAtomic(Packet &pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +AtomicSimpleCPU::CpuPort::recvFunctional(Packet &pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +AtomicSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); +} + +Packet * +AtomicSimpleCPU::CpuPort::recvRetry() +{ + panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); + return NULL; +} + + +AtomicSimpleCPU::AtomicSimpleCPU(Params *p) + : BaseSimpleCPU(p), tickEvent(this), + width(p->width), simulate_stalls(p->simulate_stalls), + icachePort(this), dcachePort(this) +{ + _status = Idle; + + ifetch_req = new Request(true); + ifetch_req->setAsid(0); + // @todo fix me and get the real cpu iD!!! + ifetch_req->setCpuNum(0); + ifetch_req->setSize(sizeof(MachInst)); + ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->dataStatic(&inst); + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); + ifetch_pkt->dest = Packet::Broadcast; + + data_read_req = new Request(true); + // @todo fix me and get the real cpu iD!!! + data_read_req->setCpuNum(0); + data_read_req->setAsid(0); + data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->dataStatic(&dataReg); + data_read_pkt->req = data_read_req; + data_read_pkt->dest = Packet::Broadcast; + + data_write_req = new Request(true); + // @todo fix me and get the real cpu iD!!! + data_write_req->setCpuNum(0); + data_write_req->setAsid(0); + data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; + data_write_pkt->dest = Packet::Broadcast; +} + + +AtomicSimpleCPU::~AtomicSimpleCPU() +{ +} + +void +AtomicSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); + nameOut(os, csprintf("%s.tickEvent", name())); + tickEvent.serialize(os); +} + +void +AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); + tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); +} + +void +AtomicSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + + tickEvent.squash(); + } + sampler->signalSwitched(); +} + + +void +AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + break; + } + } +} + + +void +AtomicSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Idle); + assert(!tickEvent.scheduled()); + + notIdleFraction++; + tickEvent.schedule(curTick + cycles(delay)); + _status = Running; +} + + +void +AtomicSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Running); + + // tick event may not be scheduled if this gets called from inside + // an instruction's execution, e.g. "quiesce" + if (tickEvent.scheduled()) + tickEvent.deschedule(); + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + data_read_req->setVaddr(addr); + data_read_req->setSize(sizeof(T)); + data_read_req->setFlags(flags); + data_read_req->setTime(curTick); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + data_read_pkt->reset(); + data_read_pkt->addr = data_read_req->getPaddr(); + data_read_pkt->size = sizeof(T); + + dcache_complete = dcachePort.sendAtomic(*data_read_pkt); + dcache_access = true; + + assert(data_read_pkt->result == Success); + data = data_read_pkt->get<T>(); + + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + data_write_req->setVaddr(addr); + data_write_req->setTime(curTick); + data_write_req->setSize(sizeof(T)); + data_write_req->setFlags(flags); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + + // Now do the access. + if (fault == NoFault) { + data_write_pkt->reset(); + data = htog(data); + data_write_pkt->dataStatic(&data); + data_write_pkt->addr = data_write_req->getPaddr(); + data_write_pkt->size = sizeof(T); + + dcache_complete = dcachePort.sendAtomic(*data_write_pkt); + dcache_access = true; + + assert(data_write_pkt->result == Success); + } + + if (res && (fault == NoFault)) + *res = data_write_pkt->result; + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Write"); + + // @todo this is a hack and only works on uniprocessor systems + // some one else can implement LL/SC. + if (data_write_req->getFlags() & LOCKED) + *res = 1; + + // 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; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +AtomicSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +AtomicSimpleCPU::tick() +{ + Tick latency = cycles(1); // instruction takes one cycle by default + + for (int i = 0; i < width; ++i) { + numCycles++; + + checkForInterrupts(); + + ifetch_req->resetMin(); + ifetch_pkt->reset(); + Fault fault = setupFetchPacket(ifetch_pkt); + + if (fault == NoFault) { + Tick icache_complete = icachePort.sendAtomic(*ifetch_pkt); + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + + dcache_access = false; // assume no dcache access + preExecute(); + fault = curStaticInst->execute(this, traceData); + postExecute(); + + if (traceData) { + traceData->finalize(); + } + + if (simulate_stalls) { + // This calculation assumes that the icache and dcache + // access latencies are always a multiple of the CPU's + // cycle time. If not, the next tick event may get + // scheduled at a non-integer multiple of the CPU + // cycle time. + Tick icache_stall = icache_complete - curTick - cycles(1); + Tick dcache_stall = + dcache_access ? dcache_complete - curTick - cycles(1) : 0; + latency += icache_stall + dcache_stall; + } + + } + + advancePC(fault); + } + + if (_status != Idle) + tickEvent.schedule(curTick + latency); +} + + +//////////////////////////////////////////////////////////////////////// +// +// AtomicSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + +CREATE_SIM_OBJECT(AtomicSimpleCPU) +{ + AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->width = width; + params->simulate_stalls = simulate_stalls; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU) + diff --git a/cpu/simple/atomic.hh b/cpu/simple/atomic.hh new file mode 100644 index 000000000..348308c46 --- /dev/null +++ b/cpu/simple/atomic.hh @@ -0,0 +1,139 @@ +/* + * 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. + */ + +#ifndef __CPU_SIMPLE_ATOMIC_HH__ +#define __CPU_SIMPLE_ATOMIC_HH__ + +#include "cpu/simple/base.hh" + +class AtomicSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + int width; + bool simulate_stalls; + }; + + AtomicSimpleCPU(Params *params); + virtual ~AtomicSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Running, + Idle, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + struct TickEvent : public Event + { + AtomicSimpleCPU *cpu; + + TickEvent(AtomicSimpleCPU *c); + void process(); + const char *description(); + }; + + TickEvent tickEvent; + + const int width; + const bool simulate_stalls; + + // main simulation loop (one cycle) + void tick(); + + class CpuPort : public Port + { + + AtomicSimpleCPU *cpu; + + public: + + CpuPort(AtomicSimpleCPU *_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(); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + CpuPort icachePort; + CpuPort dcachePort; + + Request *ifetch_req; + Packet *ifetch_pkt; + Request *data_read_req; + Packet *data_read_pkt; + Request *data_write_req; + Packet *data_write_pkt; + + bool dcache_access; + Tick dcache_complete; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); +}; + +#endif // __CPU_SIMPLE_ATOMIC_HH__ diff --git a/cpu/simple/base.cc b/cpu/simple/base.cc new file mode 100644 index 000000000..30c002ed5 --- /dev/null +++ b/cpu/simple/base.cc @@ -0,0 +1,478 @@ +/* + * 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 "arch/utility.hh" +#include "base/cprintf.hh" +#include "base/inifile.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/range.hh" +#include "base/stats/events.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/cpu_exec_context.hh" +#include "cpu/exec_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/simple/base.hh" +#include "cpu/smt.hh" +#include "cpu/static_inst.hh" +#include "kern/kernel_stats.hh" +#include "mem/packet_impl.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#if FULL_SYSTEM +#include "base/remote_gdb.hh" +#include "sim/system.hh" +#include "arch/tlb.hh" +#include "arch/stacktrace.hh" +#include "arch/vtophys.hh" +#else // !FULL_SYSTEM +#include "mem/mem_object.hh" +#endif // FULL_SYSTEM + +using namespace std; +using namespace TheISA; + +BaseSimpleCPU::BaseSimpleCPU(Params *p) + : BaseCPU(p), mem(p->mem), cpuXC(NULL) +{ +#if FULL_SYSTEM + cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb); +#else + cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, + /* asid */ 0, mem); +#endif // !FULL_SYSTEM + + xcProxy = cpuXC->getProxy(); + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + lastIcacheStall = 0; + lastDcacheStall = 0; + + execContexts.push_back(xcProxy); +} + +BaseSimpleCPU::~BaseSimpleCPU() +{ +} + +void +BaseSimpleCPU::deallocateContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::haltContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::regStats() +{ + using namespace Stats; + + BaseCPU::regStats(); + + numInsts + .name(name() + ".num_insts") + .desc("Number of instructions executed") + ; + + numMemRefs + .name(name() + ".num_refs") + .desc("Number of memory references") + ; + + notIdleFraction + .name(name() + ".not_idle_fraction") + .desc("Percentage of non-idle cycles") + ; + + idleFraction + .name(name() + ".idle_fraction") + .desc("Percentage of idle cycles") + ; + + icacheStallCycles + .name(name() + ".icache_stall_cycles") + .desc("ICache total stall cycles") + .prereq(icacheStallCycles) + ; + + dcacheStallCycles + .name(name() + ".dcache_stall_cycles") + .desc("DCache total stall cycles") + .prereq(dcacheStallCycles) + ; + + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + + idleFraction = constant(1.0) - notIdleFraction; +} + +void +BaseSimpleCPU::resetStats() +{ + startNumInst = numInst; + // notIdleFraction = (_status != Idle); +} + +void +BaseSimpleCPU::serialize(ostream &os) +{ + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + cpuXC->serialize(os); +} + +void +BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + cpuXC->unserialize(cp, csprintf("%s.xc", section)); +} + +void +change_thread_state(int thread_number, int activate, int priority) +{ +} + +Fault +BaseSimpleCPU::copySrcTranslate(Addr src) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & PageMask) != ((src + blk_size) & PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(req); + + if (fault == NoFault) { + cpuXC->copySrcAddr = src; + cpuXC->copySrcPhysAddr = memReq->paddr + offset; + } else { + assert(!fault->isAlignmentFault()); + + cpuXC->copySrcAddr = 0; + cpuXC->copySrcPhysAddr = 0; + } + return fault; +#else + return NoFault; +#endif +} + +Fault +BaseSimpleCPU::copy(Addr dest) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(cpuXC->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & PageMask) != ((dest + blk_size) & PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(req); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = cpuXC->copySrcPhysAddr; + cpuXC->mem->read(memReq, data); + memReq->paddr = dest_addr; + cpuXC->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = cpuXC->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + dcacheInterface->access(memReq); + } + } + else + assert(!fault->isAlignmentFault()); + + return fault; +#else + panic("copy not implemented"); + return NoFault; +#endif +} + +#if FULL_SYSTEM +Addr +BaseSimpleCPU::dbg_vtophys(Addr addr) +{ + return vtophys(xcProxy, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +void +BaseSimpleCPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (cpuXC->status() == ExecContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + cpuXC->activate(); + } +} +#endif // FULL_SYSTEM + +void +BaseSimpleCPU::checkForInterrupts() +{ +#if FULL_SYSTEM + if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) { + int ipl = 0; + int summary = 0; + checkInterrupts = false; + + if (cpuXC->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = cpuXC->cpu->intr_status(); + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + + if (cpuXC->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { + cpuXC->setMiscReg(IPR_ISR, summary); + cpuXC->setMiscReg(IPR_INTID, ipl); + + Fault(new InterruptFault)->invoke(xcProxy); + + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + cpuXC->readMiscReg(IPR_IPLR), ipl, summary); + } + } +#endif +} + + +Fault +BaseSimpleCPU::setupFetchPacket(Packet *ifetch_pkt) +{ + // Try to fetch an instruction + + // set up memory request for instruction fetch + + DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(), + cpuXC->readNextPC(),cpuXC->readNextNPC()); + + Request *ifetch_req = ifetch_pkt->req; + ifetch_req->setVaddr(cpuXC->readPC() & ~3); + ifetch_req->setTime(curTick); +#if FULL_SYSTEM + ifetch_req->setFlags((cpuXC->readPC() & 1) ? PHYSICAL : 0); +#else + ifetch_req->setFlags(0); +#endif + + Fault fault = cpuXC->translateInstReq(ifetch_req); + + if (fault == NoFault) { + ifetch_pkt->addr = ifetch_req->getPaddr(); + } + + return fault; +} + + +void +BaseSimpleCPU::preExecute() +{ + // maintain $r0 semantics + cpuXC->setIntReg(ZeroReg, 0); +#if THE_ISA == ALPHA_ISA + cpuXC->setFloatReg(ZeroReg, 0.0); +#endif // ALPHA_ISA + + // keep an instruction count + numInst++; + numInsts++; + + cpuXC->func_exe_inst++; + + // check for instruction-count-based events + comInstEventQueue[0]->serviceEvents(numInst); + + // decode the instruction + inst = gtoh(inst); + curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); + + traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, + cpuXC->readPC()); + + DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", + curStaticInst->getName(), curStaticInst->getOpcode(), + curStaticInst->machInst); + +#if FULL_SYSTEM + cpuXC->setInst(inst); +#endif // FULL_SYSTEM +} + +void +BaseSimpleCPU::postExecute() +{ +#if FULL_SYSTEM + if (system->kernelBinning->fnbin) { + assert(kernelStats); + system->kernelBinning->execute(xcProxy, inst); + } + + if (cpuXC->profile) { + bool usermode = + (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); + ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); + if (node) + cpuXC->profileNode = node; + } +#endif + + if (curStaticInst->isMemRef()) { + numMemRefs++; + } + + if (curStaticInst->isLoad()) { + ++numLoad; + comLoadEventQueue[0]->serviceEvents(numLoad); + } + + traceFunctions(cpuXC->readPC()); +} + + +void +BaseSimpleCPU::advancePC(Fault fault) +{ + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(xcProxy); +#else // !FULL_SYSTEM + fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC()); +#endif // FULL_SYSTEM + } + else { + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); +#if THE_ISA == ALPHA_ISA + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); +#else + cpuXC->setNextPC(cpuXC->readNextNPC()); + cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + Addr oldpc; + do { + oldpc = cpuXC->readPC(); + system->pcEventQueue.service(xcProxy); + } while (oldpc != cpuXC->readPC()); +#endif +} + diff --git a/cpu/simple/cpu.hh b/cpu/simple/base.hh index 945de20af..4c0e6f3c7 100644 --- a/cpu/simple/cpu.hh +++ b/cpu/simple/base.hh @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ -#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ +#ifndef __CPU_SIMPLE_BASE_HH__ +#define __CPU_SIMPLE_BASE_HH__ #include "base/statistics.hh" #include "config/full_system.hh" @@ -65,109 +65,20 @@ namespace Trace { } -// 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 +class BaseSimpleCPU : public BaseCPU { protected: typedef TheISA::MachInst MachInst; typedef TheISA::MiscReg MiscReg; typedef TheISA::FloatReg FloatReg; typedef TheISA::FloatRegBits FloatRegBits; - 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(); - - virtual void getDeviceAddressRanges(AddrRangeList &resp, - AddrRangeList &snoop) - { resp.clear(); snoop.clear(); } - }; MemObject *mem; - CpuPort icachePort; - CpuPort dcachePort; - - public: - // main simulation loop (one cycle) - void tick(); - virtual void init(); - - private: - struct TickEvent : public Event - { - SimpleCPU *cpu; - int width; - - TickEvent(SimpleCPU *c, int w); - void process(); - const char *description(); - }; - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int numCycles) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(numCycles)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(numCycles)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: + protected: Trace::InstRecord *traceData; public: - // - enum Status { - Running, - Idle, - IcacheRetry, - IcacheWaitResponse, - IcacheAccessComplete, - DcacheRetry, - DcacheWaitResponse, - DcacheWaitSwitch, - SwitchedOut - }; - - private: - Status _status; - - public: void post_interrupt(int int_num, int index); void zero_fill_64(Addr addr) { @@ -181,7 +92,6 @@ class SimpleCPU : public BaseCPU public: struct Params : public BaseCPU::Params { - int width; MemObject *mem; #if FULL_SYSTEM AlphaITB *itb; @@ -190,8 +100,8 @@ class SimpleCPU : public BaseCPU Process *process; #endif }; - SimpleCPU(Params *params); - virtual ~SimpleCPU(); + BaseSimpleCPU(Params *params); + virtual ~BaseSimpleCPU(); public: // execution context @@ -199,9 +109,6 @@ class SimpleCPU : public BaseCPU ExecContext *xcProxy; - void switchOut(Sampler *s); - void takeOverFrom(BaseCPU *oldCPU); - #if FULL_SYSTEM Addr dbg_vtophys(Addr addr); @@ -214,17 +121,6 @@ class SimpleCPU : public BaseCPU // Static data storage TheISA::IntReg dataReg; -#if SIMPLE_CPU_MEM_TIMING - Packet *retry_pkt; -#elif SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE - Request *ifetch_req; - Packet *ifetch_pkt; - Request *data_read_req; - Packet *data_read_pkt; - Request *data_write_req; - Packet *data_write_pkt; -#endif - // Pointer to the sampler that is telling us to switchover. // Used to signal the completion of the pipe drain and schedule // the next switchover @@ -232,10 +128,12 @@ class SimpleCPU : public BaseCPU StaticInstPtr curStaticInst; - Status status() const { return _status; } + void checkForInterrupts(); + Fault setupFetchPacket(Packet *ifetch_pkt); + void preExecute(); + void postExecute(); + void advancePC(Fault fault); - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); virtual void deallocateContext(int thread_num); virtual void haltContext(int thread_num); @@ -280,26 +178,13 @@ class SimpleCPU : public BaseCPU Stats::Scalar<> dcacheRetryCycles; Counter lastDcacheRetry; - void sendIcacheRequest(Packet *pkt); - void sendDcacheRequest(Packet *pkt); - void processResponse(Packet &response); - - Packet * processRetry(); - void recvStatusChange(Port::Status status) {} - virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - // These functions are only used in CPU models that split // effective address computation from the actual memory access. - void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); } - Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); } + void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); } void prefetch(Addr addr, unsigned flags) { @@ -428,4 +313,4 @@ class SimpleCPU : public BaseCPU ExecContext *xcBase() { return xcProxy; } }; -#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ +#endif // __CPU_SIMPLE_BASE_HH__ diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc deleted file mode 100644 index 33fe63c26..000000000 --- a/cpu/simple/cpu.cc +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * 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 <cmath> -#include <cstdio> -#include <cstdlib> -#include <iostream> -#include <iomanip> -#include <list> -#include <sstream> -#include <string> - -#include "arch/utility.hh" -#include "base/cprintf.hh" -#include "base/inifile.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/range.hh" -#include "base/stats/events.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/simple/cpu.hh" -#include "cpu/smt.hh" -#include "cpu/static_inst.hh" -#include "kern/kernel_stats.hh" -#include "mem/packet_impl.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "base/remote_gdb.hh" -//#include "mem/functional/memory_control.hh" -//#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/tlb.hh" -#include "arch/stacktrace.hh" -#include "arch/vtophys.hh" -#else // !FULL_SYSTEM -#include "mem/mem_object.hh" -#endif // FULL_SYSTEM - -using namespace std; -using namespace TheISA; - -SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - - -void -SimpleCPU::init() -{ - //Create Memory Ports (conect them up) - Port *mem_dport = mem->getPort(""); - dcachePort.setPeer(mem_dport); - mem_dport->setPeer(&dcachePort); - - Port *mem_iport = mem->getPort(""); - icachePort.setPeer(mem_iport); - mem_iport->setPeer(&icachePort); - - BaseCPU::init(); -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif -} - -void -SimpleCPU::TickEvent::process() -{ - int count = width; - do { - cpu->tick(); - } while (--count > 0 && cpu->status() == Running); -} - -const char * -SimpleCPU::TickEvent::description() -{ - return "SimpleCPU tick event"; -} - - -bool -SimpleCPU::CpuPort::recvTiming(Packet &pkt) -{ - cpu->processResponse(pkt); - return true; -} - -Tick -SimpleCPU::CpuPort::recvAtomic(Packet &pkt) -{ - panic("CPU doesn't expect callback!"); - return curTick; -} - -void -SimpleCPU::CpuPort::recvFunctional(Packet &pkt) -{ - panic("CPU doesn't expect callback!"); -} - -void -SimpleCPU::CpuPort::recvStatusChange(Status status) -{ - cpu->recvStatusChange(status); -} - -Packet * -SimpleCPU::CpuPort::recvRetry() -{ - return cpu->processRetry(); -} - -SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), mem(p->mem), icachePort(this), - dcachePort(this), tickEvent(this, p->width), cpuXC(NULL) -{ - _status = Idle; - -#if FULL_SYSTEM - cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb); -#else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0, mem); -#endif // !FULL_SYSTEM - - xcProxy = cpuXC->getProxy(); - -#if SIMPLE_CPU_MEM_ATOMIC || SIMPLE_CPU_MEM_IMMEDIATE - ifetch_req = new Request(true); - ifetch_req->setAsid(0); - // @todo fix me and get the real cpu iD!!! - ifetch_req->setCpuNum(0); - ifetch_req->setSize(sizeof(MachInst)); - ifetch_pkt = new Packet; - ifetch_pkt->cmd = Read; - ifetch_pkt->dataStatic(&inst); - ifetch_pkt->req = ifetch_req; - ifetch_pkt->size = sizeof(MachInst); - - data_read_req = new Request(true); - // @todo fix me and get the real cpu iD!!! - data_read_req->setCpuNum(0); - data_read_req->setAsid(0); - data_read_pkt = new Packet; - data_read_pkt->cmd = Read; - data_read_pkt->dataStatic(&dataReg); - data_read_pkt->req = data_read_req; - - data_write_req = new Request(true); - // @todo fix me and get the real cpu iD!!! - data_write_req->setCpuNum(0); - data_write_req->setAsid(0); - data_write_pkt = new Packet; - data_write_pkt->cmd = Write; - data_write_pkt->req = data_write_req; -#endif - - numInst = 0; - startNumInst = 0; - numLoad = 0; - startNumLoad = 0; - lastIcacheStall = 0; - lastDcacheStall = 0; - - execContexts.push_back(xcProxy); -} - -SimpleCPU::~SimpleCPU() -{ -} - -void -SimpleCPU::switchOut(Sampler *s) -{ - sampler = s; - if (status() == DcacheWaitResponse) { - DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheWaitSwitch; - } - else { - _status = SwitchedOut; - - if (tickEvent.scheduled()) - tickEvent.squash(); - - sampler->signalSwitched(); - } -} - - -void -SimpleCPU::takeOverFrom(BaseCPU *oldCPU) -{ - BaseCPU::takeOverFrom(oldCPU); - - assert(!tickEvent.scheduled()); - - // if any of this CPU's ExecContexts are active, mark the CPU as - // running and schedule its tick event. - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } -} - - -void -SimpleCPU::activateContext(int thread_num, int delay) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Idle); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; -} - - -void -SimpleCPU::suspendContext(int thread_num) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Running); - notIdleFraction--; - unscheduleTickEvent(); - _status = Idle; -} - - -void -SimpleCPU::deallocateContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::haltContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - icacheStallCycles - .name(name() + ".icache_stall_cycles") - .desc("ICache total stall cycles") - .prereq(icacheStallCycles) - ; - - dcacheStallCycles - .name(name() + ".dcache_stall_cycles") - .desc("DCache total stall cycles") - .prereq(dcacheStallCycles) - ; - - icacheRetryCycles - .name(name() + ".icache_retry_cycles") - .desc("ICache total retry cycles") - .prereq(icacheRetryCycles) - ; - - dcacheRetryCycles - .name(name() + ".dcache_retry_cycles") - .desc("DCache total retry cycles") - .prereq(dcacheRetryCycles) - ; - - idleFraction = constant(1.0) - notIdleFraction; -} - -void -SimpleCPU::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -void -SimpleCPU::serialize(ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - cpuXC->serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); - nameOut(os, csprintf("%s.cacheCompletionEvent", name())); -} - -void -SimpleCPU::unserialize(Checkpoint *cp, const string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - UNSERIALIZE_SCALAR(inst); - cpuXC->unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); -} - -void -change_thread_state(int thread_number, int activate, int priority) -{ -} - -Fault -SimpleCPU::copySrcTranslate(Addr src) -{ -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & PageMask) != ((src + blk_size) & PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address Fault fault = cpuXC->translateDataReadReq(req); - - if (fault == NoFault) { - cpuXC->copySrcAddr = src; - cpuXC->copySrcPhysAddr = memReq->paddr + offset; - } else { - assert(!fault->isAlignmentFault()); - - cpuXC->copySrcAddr = 0; - cpuXC->copySrcPhysAddr = 0; - } - return fault; -#else - return NoFault; -#endif -} - -Fault -SimpleCPU::copy(Addr dest) -{ -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(cpuXC->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & PageMask) != ((dest + blk_size) & PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(req); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = cpuXC->copySrcPhysAddr; - cpuXC->mem->read(memReq, data); - memReq->paddr = dest_addr; - cpuXC->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = cpuXC->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - dcacheInterface->access(memReq); - } - } - else - assert(!fault->isAlignmentFault()); - - return fault; -#else - panic("copy not implemented"); - return NoFault; -#endif -} - -// precise architected memory state accessor macros -template <class T> -Fault -SimpleCPU::read(Addr addr, T &data, unsigned flags) -{ - if (status() == DcacheWaitResponse || status() == DcacheWaitSwitch) { -// Fault fault = xc->read(memReq,data); - // Not sure what to check for no fault... - if (data_read_pkt->result == Success) { - data = data_read_pkt->get<T>(); - } - - if (traceData) { - traceData->setAddr(data_read_req->getVaddr()); - } - - // @todo: Figure out a way to create a Fault from the packet result. - return NoFault; - } - -// memReq->reset(addr, sizeof(T), flags); - -#if SIMPLE_CPU_MEM_TIMING - CpuRequest *data_read_req = new Request(true); -#endif - - data_read_req->setVaddr(addr); - data_read_req->setSize(sizeof(T)); - data_read_req->setFlags(flags); - data_read_req->setTime(curTick); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(data_read_req); - - // Now do the access. - if (fault == NoFault) { -#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->reset(); - data_read_pkt->addr = data_read_req->getPaddr(); - data_read_pkt->size = sizeof(T); - - 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) { - data = data_read_pkt->get<T>(); - } - - if (traceData) { - traceData->setAddr(addr); - } - - // @todo: Figure out a way to create a Fault from the packet result. - return NoFault; -#endif - } -/* - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } else { - // do functional access - fault = cpuXC->read(memReq, data); - - } - } else if(fault == NoFault) { - // do functional access - fault = cpuXC->read(memReq, data); - - } -*/ - // This will need a new way to tell if it has a dcache attached. - if (data_read_req->getFlags() & UNCACHEABLE) - recordEvent("Uncached Read"); - - return fault; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::read(Addr addr, double &data, unsigned flags) -{ - return read(addr, *(uint64_t*)&data, flags); -} - -template<> -Fault -SimpleCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} - - -template<> -Fault -SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - - -template <class T> -Fault -SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - data_write_req->setVaddr(addr); - data_write_req->setTime(curTick); - data_write_req->setSize(sizeof(T)); - data_write_req->setFlags(flags); - - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(data_write_req); - // Now do the access. - if (fault == NoFault) { -#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->allocate(); - data_write_pkt->set(data); -#else - data_write_pkt->reset(); - data = htog(data); - data_write_pkt->dataStatic(&data); -#endif - data_write_pkt->addr = data_write_req->getPaddr(); - data_write_pkt->size = sizeof(T); - - sendDcacheRequest(data_write_pkt); - } - -/* - // do functional access - if (fault == NoFault) - fault = cpuXC->write(memReq, data); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; - memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } - } -*/ - if (res && (fault == NoFault)) - *res = data_write_pkt->result; - - // This will need a new way to tell if it's hooked up to a cache or not. - if (data_write_req->getFlags() & UNCACHEABLE) - recordEvent("Uncached Write"); - - // @todo this is a hack and only works on uniprocessor systems some one else - // can implement LL/SC. - if (data_write_req->getFlags() & LOCKED) - *res = 1; - - // 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; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} - - -template<> -Fault -SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - -#if FULL_SYSTEM -Addr -SimpleCPU::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -void -SimpleCPU::sendIcacheRequest(Packet *pkt) -{ - assert(!tickEvent.scheduled()); -#if SIMPLE_CPU_MEM_TIMING - retry_pkt = pkt; - bool success = icachePort.sendTiming(*pkt); - - unscheduleTickEvent(); - - lastIcacheStall = curTick; - - if (!success) { - // Need to wait for retry - _status = IcacheRetry; - } else { - // Need to wait for cache to respond - _status = IcacheWaitResponse; - } -#elif SIMPLE_CPU_MEM_ATOMIC - Tick latency = icachePort.sendAtomic(*pkt); - - unscheduleTickEvent(); - scheduleTickEvent(latency); - - // Note that Icache miss cycles will be incorrect. Unless - // we check the status of the packet sent (is this valid?), - // we won't know if the latency is a hit or a miss. - icacheStallCycles += latency; - - _status = IcacheAccessComplete; -#elif SIMPLE_CPU_MEM_IMMEDIATE - icachePort.sendAtomic(*pkt); -#else -#error "SimpleCPU has no mem model set" -#endif -} - -void -SimpleCPU::sendDcacheRequest(Packet *pkt) -{ - assert(!tickEvent.scheduled()); -#if SIMPLE_CPU_MEM_TIMING - unscheduleTickEvent(); - - retry_pkt = pkt; - bool success = dcachePort.sendTiming(*pkt); - - lastDcacheStall = curTick; - - if (!success) { - _status = DcacheRetry; - } else { - _status = DcacheWaitResponse; - } -#elif SIMPLE_CPU_MEM_ATOMIC - unscheduleTickEvent(); - - Tick latency = dcachePort.sendAtomic(*pkt); - - scheduleTickEvent(latency); - - // Note that Dcache miss cycles will be incorrect. Unless - // we check the status of the packet sent (is this valid?), - // we won't know if the latency is a hit or a miss. - dcacheStallCycles += latency; -#elif SIMPLE_CPU_MEM_IMMEDIATE - dcachePort.sendAtomic(*pkt); -#else -#error "SimpleCPU has no mem model set" -#endif -} - -void -SimpleCPU::processResponse(Packet &response) -{ - assert(SIMPLE_CPU_MEM_TIMING); - - // For what things is the CPU the consumer of the packet it sent - // out? This may create a memory leak if that's the case and it's - // expected of the SimpleCPU to delete its own packet. - Packet *pkt = &response; - - switch (status()) { - case IcacheWaitResponse: - icacheStallCycles += curTick - lastIcacheStall; - - _status = IcacheAccessComplete; - scheduleTickEvent(1); - - // Copy the icache data into the instruction itself. - inst = pkt->get<MachInst>(); - - delete pkt; - break; - case DcacheWaitResponse: - if (pkt->cmd == Read) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - - delete pkt; - - dcacheStallCycles += curTick - lastDcacheStall; - _status = Running; - scheduleTickEvent(1); - break; - case DcacheWaitSwitch: - if (pkt->cmd == Read) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - - delete pkt; - - _status = SwitchedOut; - sampler->signalSwitched(); - case SwitchedOut: - // If this CPU has been switched out due to sampling/warm-up, - // ignore any further status changes (e.g., due to cache - // misses outstanding at the time of the switch). - delete pkt; - - return; - default: - panic("SimpleCPU::processCacheCompletion: bad state"); - break; - } -} - -Packet * -SimpleCPU::processRetry() -{ -#if SIMPLE_CPU_MEM_TIMING - switch(status()) { - case IcacheRetry: - icacheRetryCycles += curTick - lastIcacheStall; - return retry_pkt; - break; - case DcacheRetry: - dcacheRetryCycles += curTick - lastDcacheStall; - return retry_pkt; - break; - default: - panic("SimpleCPU::processRetry: bad state"); - break; - } -#else - panic("shouldn't be here"); -#endif -} - -#if FULL_SYSTEM -void -SimpleCPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (cpuXC->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - cpuXC->activate(); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -void -SimpleCPU::tick() -{ - DPRINTF(SimpleCPU,"\n\n"); - - numCycles++; - - traceData = NULL; - - Fault fault = NoFault; - -#if FULL_SYSTEM - if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode() && - status() != IcacheAccessComplete) { - int ipl = 0; - int summary = 0; - checkInterrupts = false; - - if (cpuXC->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpuXC->cpu->intr_status(); - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - - if (cpuXC->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { - cpuXC->setMiscReg(IPR_ISR, summary); - cpuXC->setMiscReg(IPR_INTID, ipl); - - Fault(new InterruptFault)->invoke(xcProxy); - - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpuXC->readMiscReg(IPR_IPLR), ipl, summary); - } - } -#endif - - // maintain $r0 semantics - cpuXC->setIntReg(ZeroReg, 0); -#if THE_ISA == ALPHA_ISA - cpuXC->setFloatReg(ZeroReg, 0.0); -#endif // ALPHA_ISA - - if (status() == IcacheAccessComplete) { - // We've already fetched an instruction and were stalled on an - // I-cache miss. No need to fetch it again. - - // Set status to running; tick event will get rescheduled if - // necessary at end of tick() function. - _status = Running; - } else { - // Try to fetch an instruction - - // set up memory request for instruction fetch - - DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(), - cpuXC->readNextPC(),cpuXC->readNextNPC()); - -#if SIMPLE_CPU_MEM_TIMING - CpuRequest *ifetch_req = new CpuRequest(); - ifetch_req->setSize(sizeof(MachInst)); -#endif - - ifetch_req->resetMin(); - ifetch_req->setVaddr(cpuXC->readPC() & ~3); - ifetch_req->setTime(curTick); -#if FULL_SYSTEM - ifetch_req->setFlags((cpuXC->readPC() & 1) ? PHYSICAL : 0); -#else - ifetch_req->setFlags(0); -#endif - - fault = cpuXC->translateInstReq(ifetch_req); - - 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->reset(); - ifetch_pkt->addr = ifetch_req->getPaddr(); - - sendIcacheRequest(ifetch_pkt); -#if SIMPLE_CPU_MEM_TIMING || SIMPLE_CPU_MEM_ATOMIC - return; -#endif -/* - if (icacheInterface && fault == NoFault) { - memReq->completionEvent = NULL; - - memReq->time = curTick; - memReq->flags |= INST_READ; - MemAccessResult result = icacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && icacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastIcacheStall = curTick; - unscheduleTickEvent(); - _status = IcacheMissStall; - return; - } - } -*/ - } - } - - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. - if (fault == NoFault) { - - // keep an instruction count - numInst++; - numInsts++; - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - // decode the instruction - inst = gtoh(inst); - curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); - - traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, - cpuXC->readPC()); - - DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", - curStaticInst->getName(),curStaticInst->getOpcode(), curStaticInst->machInst); - -#if FULL_SYSTEM - cpuXC->setInst(inst); -#endif // FULL_SYSTEM - - cpuXC->func_exe_inst++; - - fault = curStaticInst->execute(this, traceData); - -#if FULL_SYSTEM - if (system->kernelBinning->fnbin) { - assert(kernelStats); - system->kernelBinning->execute(xcProxy, inst); - } - - if (cpuXC->profile) { - bool usermode = - (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); - ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); - if (node) - cpuXC->profileNode = node; - } -#endif - - if (curStaticInst->isMemRef()) { - numMemRefs++; - } - - if (curStaticInst->isLoad()) { - ++numLoad; - comLoadEventQueue[0]->serviceEvents(numLoad); - } - - // If we have a dcache miss, then we can't finialize the instruction - // trace yet because we want to populate it with the data later - if (traceData && (status() != DcacheWaitResponse)) { - traceData->finalize(); - } - - traceFunctions(cpuXC->readPC()); - - } // if (fault == NoFault) - - if (fault != NoFault) { -#if FULL_SYSTEM - fault->invoke(xcProxy); -#else // !FULL_SYSTEM - fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC()); -#endif // FULL_SYSTEM - } - else { -#if THE_ISA == ALPHA_ISA - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); -#else - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextNPC()); - cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); -#endif - - } - -#if FULL_SYSTEM - Addr oldpc; - do { - oldpc = cpuXC->readPC(); - system->pcEventQueue.service(xcProxy); - } while (oldpc != cpuXC->readPC()); -#endif - - assert(status() == Running || - status() == Idle || - status() == DcacheWaitResponse); - - if (status() == Running && !tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); -} - -//////////////////////////////////////////////////////////////////////// -// -// SimpleCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - SimObjectParam<MemObject *> mem; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - - Param<int> clock; - - Param<bool> defer_registration; - Param<int> width; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - INIT_PARAM(mem, "memory"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(width, "cpu width"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - -CREATE_SIM_OBJECT(SimpleCPU) -{ - SimpleCPU::Params *params = new SimpleCPU::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->deferRegistration = defer_registration; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->width = width; - params->mem = mem; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - SimpleCPU *cpu = new SimpleCPU(params); - return cpu; -} - -REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) - diff --git a/cpu/simple/timing.cc b/cpu/simple/timing.cc new file mode 100644 index 000000000..a511c3dbb --- /dev/null +++ b/cpu/simple/timing.cc @@ -0,0 +1,559 @@ +/* + * 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 "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/timing.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + + +void +TimingSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(xc, xc->readCpuId()); + } +#endif +} + +Tick +TimingSimpleCPU::CpuPort::recvAtomic(Packet &pkt) +{ + panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +TimingSimpleCPU::CpuPort::recvFunctional(Packet &pkt) +{ + panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +TimingSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); +} + +TimingSimpleCPU::TimingSimpleCPU(Params *p) + : BaseSimpleCPU(p), icachePort(this), dcachePort(this) +{ + _status = Idle; + ifetch_pkt = dcache_pkt = NULL; +} + + +TimingSimpleCPU::~TimingSimpleCPU() +{ +} + +void +TimingSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + } + sampler->signalSwitched(); +} + + +void +TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + break; + } + } +} + + +void +TimingSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(cpuXC); + + assert(_status == Idle); + + notIdleFraction++; + _status = Running; + // kick things off by initiating the fetch of the next instruction + Event *e = + new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true); + e->schedule(curTick + cycles(delay)); +} + + +void +TimingSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(cpuXC); + + panic("TimingSimpleCPU::suspendContext not implemented"); + + assert(_status == Running); + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + Request *data_read_req = new Request(true); + + data_read_req->setVaddr(addr); + data_read_req->setSize(sizeof(T)); + data_read_req->setFlags(flags); + data_read_req->setTime(curTick); + + if (traceData) { + traceData->setAddr(data_read_req->getVaddr()); + } + + // translate to physical address + Fault fault = cpuXC->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + Packet *data_read_pkt = new Packet; + data_read_pkt->cmd = Read; + data_read_pkt->req = data_read_req; + data_read_pkt->dataDynamic<T>(new T); + data_read_pkt->addr = data_read_req->getPaddr(); + data_read_pkt->size = sizeof(T); + data_read_pkt->dest = Packet::Broadcast; + + if (!dcachePort.sendTiming(*data_read_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_read_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + Request *data_write_req = new Request(true); + data_write_req->setVaddr(addr); + data_write_req->setTime(curTick); + data_write_req->setSize(sizeof(T)); + data_write_req->setFlags(flags); + + // translate to physical address + Fault fault = cpuXC->translateDataWriteReq(data_write_req); + // Now do the access. + if (fault == NoFault) { + Packet *data_write_pkt = new Packet; + data_write_pkt->cmd = Write; + data_write_pkt->req = data_write_req; + data_write_pkt->allocate(); + data_write_pkt->size = sizeof(T); + data_write_pkt->set(data); + data_write_pkt->addr = data_write_req->getPaddr(); + data_write_pkt->dest = Packet::Broadcast; + + if (!dcachePort.sendTiming(*data_write_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_write_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & 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; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +TimingSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +TimingSimpleCPU::fetch() +{ + Request *ifetch_req = new Request(true); + ifetch_req->setSize(sizeof(MachInst)); + + ifetch_pkt = new Packet; + ifetch_pkt->cmd = Read; + ifetch_pkt->dataStatic(&inst); + ifetch_pkt->req = ifetch_req; + ifetch_pkt->size = sizeof(MachInst); + ifetch_pkt->dest = Packet::Broadcast; + + Fault fault = setupFetchPacket(ifetch_pkt); + if (fault == NoFault) { + if (!icachePort.sendTiming(*ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; + } + } else { + panic("TimingSimpleCPU fetch fault handling not implemented"); + } +} + + +void +TimingSimpleCPU::completeInst(Fault fault) +{ + postExecute(); + + if (traceData) { + traceData->finalize(); + } + + advancePC(fault); + + fetch(); +} + + +void +TimingSimpleCPU::completeIfetch() +{ + // received a response from the icache: execute the received + // instruction + assert(_status == IcacheWaitResponse); + _status = Running; + preExecute(); + if (curStaticInst->isMemRef()) { + // load or store: just send to dcache + Fault fault = curStaticInst->initiateAcc(this, traceData); + assert(fault == NoFault); + assert(_status == DcacheWaitResponse); + } else { + // non-memory instruction: execute completely now + Fault fault = curStaticInst->execute(this, traceData); + completeInst(fault); + } +} + + +bool +TimingSimpleCPU::IcachePort::recvTiming(Packet &pkt) +{ + cpu->completeIfetch(); + return true; +} + +Packet * +TimingSimpleCPU::IcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->ifetch_pkt != NULL); + assert(cpu->_status == IcacheRetry); + cpu->_status = IcacheWaitResponse; + Packet *tmp = cpu->ifetch_pkt; + cpu->ifetch_pkt = NULL; + return tmp; +} + +void +TimingSimpleCPU::completeDataAccess(Packet *pkt) +{ + // received a response from the dcache: complete the load or store + // instruction + assert(pkt->result == Success); + assert(_status == DcacheWaitResponse); + _status = Running; + + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); + + completeInst(fault); +} + + + +bool +TimingSimpleCPU::DcachePort::recvTiming(Packet &pkt) +{ + cpu->completeDataAccess(&pkt); + return true; +} + +Packet * +TimingSimpleCPU::DcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->dcache_pkt != NULL); + assert(cpu->_status == DcacheRetry); + cpu->_status = DcacheWaitResponse; + Packet *tmp = cpu->dcache_pkt; + cpu->dcache_pkt = NULL; + return tmp; +} + + +//////////////////////////////////////////////////////////////////////// +// +// TimingSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + +CREATE_SIM_OBJECT(TimingSimpleCPU) +{ + TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + TimingSimpleCPU *cpu = new TimingSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) + diff --git a/cpu/simple/timing.hh b/cpu/simple/timing.hh new file mode 100644 index 000000000..e1b564c69 --- /dev/null +++ b/cpu/simple/timing.hh @@ -0,0 +1,150 @@ +/* + * 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. + */ + +#ifndef __CPU_SIMPLE_TIMING_HH__ +#define __CPU_SIMPLE_TIMING_HH__ + +#include "cpu/simple/base.hh" + +class TimingSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + }; + + TimingSimpleCPU(Params *params); + virtual ~TimingSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Idle, + Running, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + class CpuPort : public Port + { + protected: + TimingSimpleCPU *cpu; + + public: + + CpuPort(TimingSimpleCPU *_cpu) + : cpu(_cpu) + { } + + protected: + + virtual Tick recvAtomic(Packet &pkt); + + virtual void recvFunctional(Packet &pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + class IcachePort : public CpuPort + { + public: + + IcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu) + { } + + protected: + + virtual bool recvTiming(Packet &pkt); + + virtual Packet *recvRetry(); + }; + + class DcachePort : public CpuPort + { + public: + + DcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu) + { } + + protected: + + virtual bool recvTiming(Packet &pkt); + + virtual Packet *recvRetry(); + }; + + IcachePort icachePort; + DcachePort dcachePort; + + Packet *ifetch_pkt; + Packet *dcache_pkt; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + void fetch(); + void completeInst(Fault fault); + void completeIfetch(); + void completeDataAccess(Packet *); +}; + +#endif // __CPU_SIMPLE_TIMING_HH__ diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index f0b75c10e..33c9144fb 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -43,12 +43,14 @@ struct AlphaSimpleImpl; class ExecContext; class DynInst; +class Packet; template <class Impl> class AlphaDynInst; class FastCPU; -class SimpleCPU; +class AtomicSimpleCPU; +class TimingSimpleCPU; class InorderCPU; class SymbolTable; diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc index 2e46f7be1..8cae10d2a 100644 --- a/dev/alpha_console.cc +++ b/dev/alpha_console.cc @@ -31,7 +31,6 @@ */ #include <cstddef> -#include <cstdio> #include <string> #include "arch/alpha/system.hh" diff --git a/dev/disk_image.cc b/dev/disk_image.cc index 447c54697..185a8b083 100644 --- a/dev/disk_image.cc +++ b/dev/disk_image.cc @@ -35,7 +35,6 @@ #include <errno.h> #include <unistd.h> -#include <cstdio> #include <cstring> #include <fstream> #include <string> diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index 891c462b5..2d04ecd09 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -260,12 +260,6 @@ class IdeDisk : public SimObject void reset(int id); /** - * Register statistics. - */ - void regStats(); - - - /** * Set the controller for this device * @param c The IDE controller */ diff --git a/dev/io_device.cc b/dev/io_device.cc index 24f33d84d..aa411d132 100644 --- a/dev/io_device.cc +++ b/dev/io_device.cc @@ -160,8 +160,7 @@ DmaPort::dmaAction(Command cmd, Addr addr, int size, Event *event, basePkt.flags = 0; basePkt.coherence = NULL; basePkt.senderState = NULL; - basePkt.src = 0; - basePkt.dest = 0; + basePkt.dest = Packet::Broadcast; basePkt.cmd = cmd; basePkt.result = Unknown; basePkt.req = NULL; diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index a2e224ed0..82b14388c 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -30,7 +30,6 @@ * Device module for modelling the National Semiconductor * DP83820 ethernet controller. Does not support priority queueing */ -#include <cstdio> #include <deque> #include <string> diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc index dfb1d48f6..a8c742b07 100644 --- a/dev/pciconfigall.cc +++ b/dev/pciconfigall.cc @@ -165,6 +165,7 @@ PciConfigAll::write(Packet &pkt) default: panic("invalid pci config write size\n"); } + pkt.result = Success; return pioDelay; } diff --git a/dev/pcidev.cc b/dev/pcidev.cc index c40ef62e4..76392ccfe 100644 --- a/dev/pcidev.cc +++ b/dev/pcidev.cc @@ -31,7 +31,6 @@ */ #include <list> -#include <sstream> #include <string> #include <vector> diff --git a/dev/sinic.cc b/dev/sinic.cc index bc6891f56..f621c1b44 100644 --- a/dev/sinic.cc +++ b/dev/sinic.cc @@ -26,7 +26,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <cstdio> #include <deque> #include <limits> #include <string> diff --git a/kern/solaris/solaris.hh b/kern/solaris/solaris.hh new file mode 100644 index 000000000..e2b61d613 --- /dev/null +++ b/kern/solaris/solaris.hh @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2004-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. + */ + +#ifndef __SOLARIS_HH__ +#define __SOLARIS_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Solaris {}; + +#else //!FULL_SYSTEM + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> // for host open() flags +#include <string.h> // for memset() +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arch/isa_traits.hh" +#include "sim/syscall_emul.hh" + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Solaris +/// syscall interface. +/// +class Solaris { + + public: + + //@{ + /// Basic Solaris types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef int32_t uid_t; + typedef int32_t gid_t; + typedef uint64_t rlim_t; + typedef uint64_t ino_t; + typedef uint64_t dev_t; + typedef uint32_t mode_t; + typedef uint32_t nlink_t; + //@} + +#if BSD_HOST + typedef struct stat hst_stat; + typedef struct stat hst_stat64; +#else + typedef struct stat hst_stat ; + typedef struct stat64 hst_stat64; +#endif + struct tgt_timespec { + int64_t tv_sec; + int64_t tv_nsec; + }; + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + // same for stat64 + struct tgt_stat64 { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 257; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). +#if !BSD_HOST + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#else + // Third version for bsd systems which no longer have any support for + // the old stat() call and stat() is actually a stat64() + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#endif + + + // Same for stat64 + static void + copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat64> tgt(addr); + + // fd == 1 checks are because libc does some checks + // that the stdout is interactive vs. a file + // this makes it work on non-solaris systems + if (fd == 1) + tgt->st_dev = htog((uint64_t)0xA); + else + tgt->st_dev = htog((uint64_t)host->st_dev); + // XXX What about STAT64_HAS_BROKEN_ST_INO ??? + tgt->st_ino = htog((uint64_t)host->st_ino); + if (fd == 1) + tgt->st_rdev = htog((uint64_t)0x880d); + else + tgt->st_rdev = htog((uint64_t)host->st_rdev); + tgt->st_size = htog((int64_t)host->st_size); + tgt->st_blocks = htog((uint64_t)host->st_blocks); + + if (fd == 1) + tgt->st_mode = htog((uint32_t)0x2190); + else + tgt->st_mode = htog((uint32_t)host->st_mode); + tgt->st_uid = htog((uint32_t)host->st_uid); + tgt->st_gid = htog((uint32_t)host->st_gid); + tgt->st_blksize = htog((uint32_t)host->st_blksize); + tgt->st_nlink = htog((uint32_t)host->st_nlink); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + + tgt.copyOut(mem); + } + +}; // class Solaris + + +#endif // FULL_SYSTEM + +#endif // __SOLARIS_HH__ diff --git a/mem/bus.cc b/mem/bus.cc index acc941434..f84e38301 100644 --- a/mem/bus.cc +++ b/mem/bus.cc @@ -48,9 +48,16 @@ Bus::init() /** Function called by the port when the bus is recieving a Timing * transaction.*/ bool -Bus::recvTiming(Packet &pkt, int id) +Bus::recvTiming(Packet &pkt) { - return findPort(pkt.addr, id)->sendTiming(pkt); + Port *port; + if (pkt.dest == Packet::Broadcast) { + port = findPort(pkt.addr, pkt.src); + } else { + assert(pkt.dest > 0 && pkt.dest < interfaces.size()); + port = interfaces[pkt.dest]; + } + return port->sendTiming(pkt); } Port * @@ -82,17 +89,19 @@ Bus::findPort(Addr addr, int id) /** Function called by the port when the bus is recieving a Atomic * transaction.*/ Tick -Bus::recvAtomic(Packet &pkt, int id) +Bus::recvAtomic(Packet &pkt) { - return findPort(pkt.addr, id)->sendAtomic(pkt); + assert(pkt.dest == Packet::Broadcast); + return findPort(pkt.addr, pkt.src)->sendAtomic(pkt); } /** Function called by the port when the bus is recieving a Functional * transaction.*/ void -Bus::recvFunctional(Packet &pkt, int id) +Bus::recvFunctional(Packet &pkt) { - findPort(pkt.addr, id)->sendFunctional(pkt); + assert(pkt.dest == Packet::Broadcast); + findPort(pkt.addr, pkt.src)->sendFunctional(pkt); } /** Function called by the port when the bus is recieving a status change.*/ diff --git a/mem/bus.hh b/mem/bus.hh index de9259a90..40d274037 100644 --- a/mem/bus.hh +++ b/mem/bus.hh @@ -57,15 +57,15 @@ class Bus : public MemObject /** Function called by the port when the bus is recieving a Timing transaction.*/ - bool recvTiming(Packet &pkt, int id); + bool recvTiming(Packet &pkt); /** Function called by the port when the bus is recieving a Atomic transaction.*/ - Tick recvAtomic(Packet &pkt, int id); + Tick recvAtomic(Packet &pkt); /** Function called by the port when the bus is recieving a Functional transaction.*/ - void recvFunctional(Packet &pkt, int id); + void recvFunctional(Packet &pkt); /** Function called by the port when the bus is recieving a status change.*/ void recvStatusChange(Port::Status status, int id); @@ -77,8 +77,7 @@ class Bus : public MemObject * loops) * @return pointer to port that the packet should be sent out of. */ - Port * - Bus::findPort(Addr addr, int id); + Port *findPort(Addr addr, int id); /** Process address range request. * @param resp addresses that we can respond to @@ -110,17 +109,17 @@ class Bus : public MemObject /** When reciving a timing request from the peer port (at id), pass it to the bus. */ virtual bool recvTiming(Packet &pkt) - { return bus->recvTiming(pkt, id); } + { pkt.src = id; return bus->recvTiming(pkt); } /** When reciving a Atomic requestfrom the peer port (at id), pass it to the bus. */ virtual Tick recvAtomic(Packet &pkt) - { return bus->recvAtomic(pkt, id); } + { pkt.src = id; return bus->recvAtomic(pkt); } /** When reciving a Functional requestfrom the peer port (at id), pass it to the bus. */ virtual void recvFunctional(Packet &pkt) - { bus->recvFunctional(pkt, id); } + { pkt.src = id; bus->recvFunctional(pkt); } /** When reciving a status changefrom the peer port (at id), pass it to the bus. */ @@ -131,7 +130,8 @@ class Bus : public MemObject // downstream from this bus, yes? That is, the union of all // the 'owned' address ranges of all the other interfaces on // this bus... - virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) { bus->addressRanges(resp, snoop, id); } // Hack to make translating port work without changes diff --git a/mem/packet.hh b/mem/packet.hh index 69d00675d..ab961e304 100644 --- a/mem/packet.hh +++ b/mem/packet.hh @@ -121,6 +121,8 @@ struct Packet /** A index of the source of the transaction. */ short src; + static const short Broadcast = -1; + /** A index to the destination of the transaction. */ short dest; diff --git a/mem/physical.cc b/mem/physical.cc index a9cefc70b..d0409995b 100644 --- a/mem/physical.cc +++ b/mem/physical.cc @@ -33,7 +33,6 @@ #include <unistd.h> #include <zlib.h> -#include <cstdio> #include <iostream> #include <string> @@ -128,6 +127,7 @@ PhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort) { doFunctionalAccess(pkt); + pkt.dest = pkt.src; MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); response->schedule(curTick + lat); diff --git a/mem/port.cc b/mem/port.cc index 32031d96c..5b1f634d6 100644 --- a/mem/port.cc +++ b/mem/port.cc @@ -31,6 +31,7 @@ */ #include "base/chunk_generator.hh" +#include "mem/packet_impl.hh" #include "mem/port.hh" void @@ -40,6 +41,7 @@ Port::blobHelper(Addr addr, uint8_t *p, int size, Command cmd) Packet pkt; pkt.req = &req; pkt.cmd = cmd; + pkt.dest = Packet::Broadcast; for (ChunkGenerator gen(addr, size, peerBlockSize()); !gen.done(); gen.next()) { diff --git a/python/m5/objects/PhysicalMemory.py b/python/m5/objects/PhysicalMemory.py index e59e94e9b..c59910093 100644 --- a/python/m5/objects/PhysicalMemory.py +++ b/python/m5/objects/PhysicalMemory.py @@ -5,4 +5,4 @@ class PhysicalMemory(MemObject): type = 'PhysicalMemory' range = Param.AddrRange("Device Address") file = Param.String('', "memory mapped file") - latency = Param.Latency('10ns', "latency of an access") + latency = Param.Latency(Parent.clock, "latency of an access") diff --git a/python/m5/objects/Root.py b/python/m5/objects/Root.py index f51516098..205a93c76 100644 --- a/python/m5/objects/Root.py +++ b/python/m5/objects/Root.py @@ -3,6 +3,7 @@ from Serialize import Serialize from Statistics import Statistics from Trace import Trace from ExeTrace import ExecutionTrace +from Debug import Debug class Root(SimObject): type = 'Root' @@ -19,3 +20,4 @@ class Root(SimObject): trace = Trace() exetrace = ExecutionTrace() serialize = Serialize() + debug = Debug() diff --git a/sim/eventq.cc b/sim/eventq.cc index 0884db994..4bfd6face 100644 --- a/sim/eventq.cc +++ b/sim/eventq.cc @@ -30,7 +30,6 @@ #include <iostream> #include <string> -#include <sstream> #include <vector> #include "cpu/smt.hh" diff --git a/sim/faults.cc b/sim/faults.cc index f7e9a0691..cb095f852 100644 --- a/sim/faults.cc +++ b/sim/faults.cc @@ -45,3 +45,8 @@ void FaultBase::invoke(ExecContext * xc) assert(!xc->misspeculating()); } #endif + +void UnimpFault::invoke(ExecContext * xc) +{ + panic("Unimpfault: %s\n", panicStr.c_str()); +} diff --git a/sim/faults.hh b/sim/faults.hh index 18601e8f1..9b3bc9103 100644 --- a/sim/faults.hh +++ b/sim/faults.hh @@ -64,4 +64,17 @@ class FaultBase : public RefCounted FaultBase * const NoFault = 0; +class UnimpFault : public FaultBase +{ + private: + std::string panicStr; + public: + UnimpFault(std::string _str) + : panicStr(_str) + { } + + FaultName name() {return "Unimplemented simulator feature";} + void invoke(ExecContext * xc); +}; + #endif // __FAULTS_HH__ diff --git a/sim/param.cc b/sim/param.cc index bc81881d3..8998d7d77 100644 --- a/sim/param.cc +++ b/sim/param.cc @@ -28,7 +28,6 @@ #include <algorithm> #include <cassert> -#include <cstdio> #include <list> #include <string> #include <vector> diff --git a/sim/process.cc b/sim/process.cc index d88716f1e..1261b8436 100644 --- a/sim/process.cc +++ b/sim/process.cc @@ -29,7 +29,6 @@ #include <unistd.h> #include <fcntl.h> -#include <cstdio> #include <string> #include "base/intmath.hh" diff --git a/sim/pseudo_inst.cc b/sim/pseudo_inst.cc index 3cdc05e78..7897b5c8b 100644 --- a/sim/pseudo_inst.cc +++ b/sim/pseudo_inst.cc @@ -29,7 +29,6 @@ #include <errno.h> #include <fcntl.h> #include <unistd.h> -#include <cstdio> #include <string> diff --git a/test/cprintftest.cc b/test/cprintftest.cc index 611f01bc2..361f84028 100644 --- a/test/cprintftest.cc +++ b/test/cprintftest.cc @@ -26,7 +26,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <cstdio> #include <iostream> #include <list> #include <string> |